Merge branch 'master' into tests_client_server
This commit is contained in:
131
CMakeLists.txt
131
CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
|
||||
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
|
||||
project(PIP)
|
||||
set(PIP_MAJOR 4)
|
||||
set(PIP_MINOR 1)
|
||||
set(PIP_MINOR 4)
|
||||
set(PIP_REVISION 0)
|
||||
set(PIP_SUFFIX )
|
||||
set(PIP_COMPANY SHS)
|
||||
@@ -75,11 +75,16 @@ option(INTROSPECTION "Build with introspection" OFF)
|
||||
option(TESTS "Build tests and perform their before install step" ${PIP_BUILD_DEBUG})
|
||||
option(COVERAGE "Build project with coverage info" OFF)
|
||||
set(PIP_UTILS 1)
|
||||
set(BUILDING_pip 1 PARENT_SCOPE)
|
||||
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
shstk_is_parent_exists(_pe)
|
||||
if (_pe)
|
||||
set(BUILDING_pip 1 PARENT_SCOPE)
|
||||
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
|
||||
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
endif()
|
||||
|
||||
|
||||
# Basic
|
||||
set(PIP_MODULES)
|
||||
@@ -92,7 +97,7 @@ set(PIP_UTILS_LIST)
|
||||
set(PIP_TESTS_LIST)
|
||||
set(PIP_EXPORTS)
|
||||
|
||||
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;client_server;cloud;lua")
|
||||
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;client_server;cloud;lua;http_server")
|
||||
foreach(_m ${PIP_SRC_MODULES})
|
||||
set(PIP_MSG_${_m} "no")
|
||||
endforeach()
|
||||
@@ -184,10 +189,12 @@ if (NOT DEFINED PIP_CMG)
|
||||
if (CMAKE_CROSSCOMPILING OR (DEFINED ANDROID_PLATFORM))
|
||||
set(PIP_CMG "pip_cmg")
|
||||
set(PIP_RC "pip_rc")
|
||||
set(PIP_TR "pip_tr")
|
||||
set(PIP_DEPLOY_TOOL "deploy_tool")
|
||||
else()
|
||||
set(PIP_CMG "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator/pip_cmg")
|
||||
set(PIP_RC "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler/pip_rc")
|
||||
set(PIP_TR "${CMAKE_CURRENT_BINARY_DIR}/utils/translator/pip_tr")
|
||||
set(PIP_DEPLOY_TOOL "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool/deploy_tool")
|
||||
endif()
|
||||
endif()
|
||||
@@ -474,17 +481,52 @@ if (NOT CROSSTOOLS)
|
||||
list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge")
|
||||
list(APPEND HDRS ${_lua_src_hdr})
|
||||
|
||||
# libmicrohttpd
|
||||
find_library(microhttpd_LIBRARIES microhttpd HINTS "${MINGW_LIB}")
|
||||
set(microhttpd_FOUND FALSE)
|
||||
if (microhttpd_LIBRARIES)
|
||||
set(microhttpd_FOUND TRUE)
|
||||
set(_microhttpd_add_libs microhttpd)
|
||||
if(WIN32)
|
||||
if("${C_COMPILER}" STREQUAL "cl.exe")
|
||||
else()
|
||||
list(APPEND _microhttpd_add_libs ws2_32)
|
||||
endif()
|
||||
else()
|
||||
list(APPEND _microhttpd_add_libs dl)
|
||||
find_library(tls_lib gnutls)
|
||||
if (tls_lib)
|
||||
set(gnutls_FOUND TRUE)
|
||||
set(gnutls_LIBRARIES "${tls_lib}")
|
||||
list(APPEND _microhttpd_add_libs gnutls)
|
||||
endif()
|
||||
if(DEFINED ENV{QNX_HOST})
|
||||
list(APPEND _microhttpd_add_libs socket)
|
||||
else()
|
||||
if (NOT DEFINED ANDROID_PLATFORM)
|
||||
list(APPEND _microhttpd_add_libs pthread util)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
#list(APPEND microhttpd_LIBRARIES "${_microhttpd_add_libs}")
|
||||
pip_module(http_server "${_microhttpd_add_libs}" "PIP HTTP server" "" "" "")
|
||||
endif()
|
||||
|
||||
# Test program
|
||||
if(PIP_UTILS)
|
||||
|
||||
#add_library(pip_plugin SHARED "test_plugin.h" "test_plugin.cpp" "ccm.h" "ccm.cpp")
|
||||
#target_link_libraries(pip_plugin pip)
|
||||
|
||||
add_executable(pip_test "main.cpp")
|
||||
target_link_libraries(pip_test pip pip_io_utils pip_client_server)
|
||||
if(sodium_FOUND)
|
||||
add_executable(pip_cloud_test "main_picloud_test.cpp")
|
||||
target_link_libraries(pip_cloud_test pip_cloud)
|
||||
if (NOT DEFINED ANDROID_PLATFORM)
|
||||
if(microhttpd_FOUND)
|
||||
add_executable(pip_test "main.cpp")
|
||||
target_link_libraries(pip_test pip pip_io_utils pip_client_server pip_http_server)
|
||||
if(sodium_FOUND)
|
||||
add_executable(pip_cloud_test "main_picloud_test.cpp")
|
||||
target_link_libraries(pip_cloud_test pip_cloud)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -498,6 +540,43 @@ endif()
|
||||
string(REPLACE ";" "," PIP_EXPORTS_STR "${PIP_EXPORTS}")
|
||||
target_compile_definitions(pip PRIVATE "PICODE_DEFINES=\"${PIP_EXPORTS_STR}\"")
|
||||
|
||||
|
||||
if(NOT PIP_FREERTOS)
|
||||
|
||||
# Auxiliary
|
||||
if (NOT CROSSTOOLS)
|
||||
add_subdirectory("utils/piterminal")
|
||||
endif()
|
||||
|
||||
# Utils
|
||||
add_subdirectory("utils/code_model_generator")
|
||||
add_subdirectory("utils/resources_compiler")
|
||||
add_subdirectory("utils/deploy_tool")
|
||||
add_subdirectory("utils/qt_support")
|
||||
add_subdirectory("utils/translator")
|
||||
add_subdirectory("utils/value_tree_translator")
|
||||
if(PIP_UTILS AND (NOT CROSSTOOLS))
|
||||
add_subdirectory("utils/system_test")
|
||||
add_subdirectory("utils/udp_file_transfer")
|
||||
if(sodium_FOUND)
|
||||
add_subdirectory("utils/system_daemon")
|
||||
add_subdirectory("utils/crypt_tool")
|
||||
add_subdirectory("utils/cloud_dispatcher")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
# Translations
|
||||
set(PIP_LANG)
|
||||
if (NOT CROSSTOOLS)
|
||||
# pip_translation(PIP_LANG lang/pip_ru.ts)
|
||||
# add_custom_target(pip_lang SOURCES "${PIP_LANG}")
|
||||
file(GLOB PIP_LANG "lang/*.btf")
|
||||
endif()
|
||||
|
||||
|
||||
# Install
|
||||
# Check if system or local install will be used (to system install use "-DLIB=" argument of cmake)
|
||||
if(NOT LOCAL)
|
||||
@@ -505,6 +584,9 @@ if(NOT LOCAL)
|
||||
if(MINGW)
|
||||
if (NOT CROSSTOOLS)
|
||||
install(FILES ${HDRS} DESTINATION ${MINGW_INCLUDE}/pip)
|
||||
if(PIP_LANG)
|
||||
install(FILES ${PIP_LANG} DESTINATION ${MINGW_INCLUDE}/../share/pip/lang)
|
||||
endif()
|
||||
if(HDR_DIRS)
|
||||
install(DIRECTORY ${HDR_DIRS} DESTINATION ${MINGW_INCLUDE}/pip)
|
||||
endif()
|
||||
@@ -518,6 +600,7 @@ if(NOT LOCAL)
|
||||
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator")
|
||||
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler")
|
||||
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool")
|
||||
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/translator")
|
||||
endif()
|
||||
else()
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pip_export.h DESTINATION include)
|
||||
@@ -525,6 +608,9 @@ if(NOT LOCAL)
|
||||
else()
|
||||
if (NOT CROSSTOOLS)
|
||||
install(FILES ${HDRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip)
|
||||
if(PIP_LANG)
|
||||
install(FILES ${PIP_LANG} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pip/lang)
|
||||
endif()
|
||||
if(HDR_DIRS)
|
||||
install(DIRECTORY ${HDR_DIRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip)
|
||||
endif()
|
||||
@@ -540,6 +626,9 @@ else()
|
||||
install(TARGETS ${PIP_MODULES} DESTINATION lib)
|
||||
endif()
|
||||
install(FILES ${HDRS} DESTINATION include/pip)
|
||||
if(PIP_LANG)
|
||||
install(FILES ${PIP_LANG} DESTINATION share/pip/lang)
|
||||
endif()
|
||||
if(HDR_DIRS)
|
||||
install(DIRECTORY ${HDR_DIRS} DESTINATION include/pip)
|
||||
endif()
|
||||
@@ -548,30 +637,6 @@ endif()
|
||||
file(GLOB CMAKES "cmake/*.cmake" "cmake/*.in")
|
||||
install(FILES ${CMAKES} DESTINATION ${CMAKE_ROOT}/Modules)
|
||||
|
||||
if(NOT PIP_FREERTOS)
|
||||
|
||||
# Auxiliary
|
||||
if (NOT CROSSTOOLS)
|
||||
add_subdirectory("utils/piterminal")
|
||||
endif()
|
||||
|
||||
# Utils
|
||||
add_subdirectory("utils/code_model_generator")
|
||||
add_subdirectory("utils/resources_compiler")
|
||||
add_subdirectory("utils/deploy_tool")
|
||||
add_subdirectory("utils/value_tree_translator")
|
||||
if(PIP_UTILS AND (NOT CROSSTOOLS))
|
||||
add_subdirectory("utils/system_test")
|
||||
add_subdirectory("utils/udp_file_transfer")
|
||||
if(sodium_FOUND)
|
||||
add_subdirectory("utils/system_daemon")
|
||||
add_subdirectory("utils/crypt_tool")
|
||||
add_subdirectory("utils/cloud_dispatcher")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
shstk_is_parent_exists(_pe)
|
||||
if (_pe)
|
||||
|
||||
@@ -12,6 +12,7 @@ Create imported targets:
|
||||
* PIP::ClientServer
|
||||
* PIP::Cloud
|
||||
* PIP::Lua
|
||||
* PIP::HTTPServer
|
||||
|
||||
These targets include directories and depends on
|
||||
main library
|
||||
@@ -23,10 +24,10 @@ include(SHSTKMacros)
|
||||
|
||||
shstk_set_find_dirs(PIP)
|
||||
|
||||
set(__libs "usb;crypt;console;fftw;compress;opencl;io_utils;client_server;cloud;lua")
|
||||
set(__libs "usb;crypt;console;fftw;compress;opencl;io_utils;client_server;cloud;lua;http_server")
|
||||
|
||||
if (BUILDING_PIP)
|
||||
#set(_libs "pip;pip_usb;pip_console;pip_crypt;pip_fftw;pip_compress;pip_opencl;pip_io_utils;pip_cloud;pip_lua")
|
||||
#set(_libs "pip;pip_usb;pip_console;pip_crypt;pip_fftw;pip_compress;pip_opencl;pip_io_utils;pip_cloud;pip_lua;pip_http_server")
|
||||
#set(_bins "pip_cmg;pip_rc;deploy_tool")
|
||||
#get_target_property(_path pip BINARY_DIR)
|
||||
#get_target_property(_path pip LIBRARY_OUTPUT_NAME)
|
||||
@@ -45,10 +46,12 @@ endif()
|
||||
if (BUILDING_PIP AND (NOT CMAKE_CROSSCOMPILING))
|
||||
set(PIP_CMG "$<TARGET_FILE_DIR:pip_cmg>/$<TARGET_FILE_NAME:pip_cmg>" CACHE STRING "")
|
||||
set(PIP_RC "$<TARGET_FILE_DIR:pip_rc>/$<TARGET_FILE_NAME:pip_rc>" CACHE STRING "")
|
||||
set(PIP_TR "$<TARGET_FILE_DIR:pip_tr>/$<TARGET_FILE_NAME:pip_tr>" CACHE STRING "")
|
||||
set(PIP_DEPLOY_TOOL "$<TARGET_FILE_DIR:deploy_tool>/$<TARGET_FILE_NAME:deploy_tool>" CACHE STRING "")
|
||||
else()
|
||||
find_program(PIP_CMG pip_cmg${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG})
|
||||
find_program(PIP_RC pip_rc${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG})
|
||||
find_program(PIP_TR pip_tr${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG})
|
||||
find_program(PIP_DEPLOY_TOOL deploy_tool${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG})
|
||||
endif()
|
||||
if (NOT PIP_LIBRARY)
|
||||
@@ -94,6 +97,7 @@ set(__module_io_utils IOUtils )
|
||||
set(__module_client_server ClientServer)
|
||||
set(__module_cloud Cloud )
|
||||
set(__module_lua Lua )
|
||||
set(__module_http_server HTTPServer )
|
||||
|
||||
foreach (_l ${__libs})
|
||||
set( __inc_${_l} "")
|
||||
|
||||
@@ -18,6 +18,14 @@
|
||||
Generate C++ files for resource file
|
||||
You should add ${<out_var>} to your target
|
||||
|
||||
|
||||
|
||||
pip_translation(<out_var> ts_file)
|
||||
|
||||
Generate *.btf (binary translation file) from *.ts file
|
||||
You should add ${<out_var>} to your target and then install it to somewhere
|
||||
for later loading in runtime by PITranslator
|
||||
|
||||
]]
|
||||
|
||||
|
||||
@@ -119,3 +127,34 @@ macro(pip_resources RESULT INPUT)
|
||||
VERBATIM)
|
||||
endmacro()
|
||||
|
||||
|
||||
macro(pip_translation RESULT INPUT)
|
||||
#message(STATUS "src = ${CCM_SRC}")
|
||||
#message(STATUS "result = ${RESULT}")
|
||||
#message(STATUS "options = \"${CCM_OPTS}\"")
|
||||
get_filename_component(BTF_FILENAME "${INPUT}" NAME_WE)
|
||||
set(BTF_FILENAME "${BTF_FILENAME}.btf")
|
||||
set(BTF_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BTF_FILENAME})
|
||||
list(APPEND ${RESULT} "${BTF_OUTPUT}")
|
||||
if(IS_ABSOLUTE "${INPUT}")
|
||||
set(IN_FILES "${INPUT}")
|
||||
else()
|
||||
set(IN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}")
|
||||
endif()
|
||||
#message(STATUS "CCM = ${RESULT}")
|
||||
if(NOT DEFINED PIP_DLL_DIR)
|
||||
set(PIP_DLL_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
#message("PIP_TR: ${PIP_TR}")
|
||||
#message("BTF_OUTPUT: ${BTF_OUTPUT}")
|
||||
#message("IN_FILES: ${IN_FILES}")
|
||||
#message("PIP_DLL_DIR: ${PIP_DLL_DIR}")
|
||||
add_custom_command(OUTPUT ${BTF_OUTPUT}
|
||||
COMMAND ${PIP_TR}
|
||||
ARGS -C -o "${BTF_OUTPUT}" "${IN_FILES}"
|
||||
DEPENDS ${IN_FILES}
|
||||
WORKING_DIRECTORY ${PIP_DLL_DIR}
|
||||
COMMENT "Generating ${BTF_FILENAME}"
|
||||
VERBATIM)
|
||||
endmacro()
|
||||
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
|
||||
\~english
|
||||
|
||||
* direct output to console (\a PICout)
|
||||
* containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
|
||||
* byte array (\a PIByteArray)
|
||||
* serialization (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON)
|
||||
* string (\a PIConstChars, \a PIString, \a PIStringList)
|
||||
* base object (events and handlers) (\a PIObject)
|
||||
* multithreading
|
||||
* Direct output to console (\a PICout)
|
||||
* Containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
|
||||
* Byte array (\a PIByteArray)
|
||||
* Serialization (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON)
|
||||
* String (\a PIConstChars, \a PIString, \a PIStringList)
|
||||
* Base object (events and handlers) (\a PIObject)
|
||||
* Multithreading
|
||||
* thread (\a PIThread)
|
||||
* blocking (\a PIMutex, \a PISpinlock)
|
||||
* executor (\a PIThreadPoolExecutor)
|
||||
* blocking (\a PIMutex, \a PISpinlock, \a PIConditionVariable, \a PISemaphore, \a PIReadWriteLock)
|
||||
* executor (\a PIThreadPoolExecutor, \a PIThreadPoolLoop)
|
||||
* blocking dequeue (\a PIBlockingDequeue)
|
||||
* timer (\a PITimer)
|
||||
* tiling console (with widgets) (\a PIScreen)
|
||||
* timer (\a PITimer)
|
||||
* Tiling console (with widgets) (\a PIScreen)
|
||||
* simple text rows
|
||||
* scroll bar
|
||||
* list
|
||||
@@ -37,7 +37,8 @@
|
||||
* peering net node (\a PIPeer)
|
||||
* connection quality diagnotic (\a PIDiagnostics)
|
||||
* Run-time libraries
|
||||
* abstract (\a PILibrary)
|
||||
* external process (\a PIProcess)
|
||||
* external library (\a PILibrary)
|
||||
* plugin (\a PIPluginLoader)
|
||||
* Mathematics
|
||||
* complex numbers
|
||||
@@ -49,24 +50,33 @@
|
||||
* CRC checksum (\a PICRC)
|
||||
* Fourier transform (\a PIFFTW, \a PIFFT)
|
||||
* expression evaluator (\a PIEvaluator)
|
||||
* command-line arguments parser (\a PICLI)
|
||||
* process (\a PIProcess)
|
||||
* Application-level
|
||||
* command-line arguments parser (\a PICLI)
|
||||
* system resources monitoring (\a PISystemMonitor)
|
||||
* single-instance application control (\a PISingleApplication)
|
||||
* high-level log (\a PILog)
|
||||
* translation support (\a PITranslator)
|
||||
* State machine ([By stantard](https://www.w3.org/TR/scxml/)) (\a PIStateMachine)
|
||||
* High-level TCP client-server
|
||||
* server (\a PIClientServer::Server, \a PIClientServer::ServerClient)
|
||||
* client (\a PIClientServer::Client)
|
||||
* Crypt support (\a PICrypt, \a PIAuth)
|
||||
|
||||
\~russian
|
||||
|
||||
* общение с консолью (\a PICout)
|
||||
* контейнеры (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
|
||||
* байтовый массив (\a PIByteArray)
|
||||
* сериализация (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream)
|
||||
* строка (\a PIConstChars, \a PIString, \a PIStringList)
|
||||
* базовый объект (события и обработчики) (\a PIObject)
|
||||
* многопоточность
|
||||
* Общение с консолью (\a PICout)
|
||||
* Контейнеры (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
|
||||
* Байтовый массив (\a PIByteArray)
|
||||
* Сериализация (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON)
|
||||
* Строка (\a PIConstChars, \a PIString, \a PIStringList)
|
||||
* Базовый объект (события и обработчики) (\a PIObject)
|
||||
* Многопоточность
|
||||
* поток (\a PIThread)
|
||||
* блокировки (\a PIMutex, \a PISpinlock)
|
||||
* исполнитель (\a PIThreadPoolExecutor)
|
||||
* блокировки (\a PIMutex, \a PISpinlock, \a PIConditionVariable, \a PISemaphore, \a PIReadWriteLock)
|
||||
* исполнитель (\a PIThreadPoolExecutor, \a PIThreadPoolLoop)
|
||||
* блокирующая очередь (\a PIBlockingDequeue)
|
||||
* таймер (\a PITimer)
|
||||
* тайлинговая консоль (с виджетами) (\a PIScreen)
|
||||
* таймер (\a PITimer)
|
||||
* Тайлинговая консоль (с виджетами) (\a PIScreen)
|
||||
* простой вывод строк
|
||||
* скроллбар
|
||||
* лист
|
||||
@@ -76,7 +86,7 @@
|
||||
* прогрессбар
|
||||
* вывод PICout
|
||||
* текстовый ввод
|
||||
* устройства ввода/вывода
|
||||
* Устройства ввода/вывода
|
||||
* базовый класс (\a PIIODevice)
|
||||
* файл (\a PIFile)
|
||||
* последовательный порт (\a PISerial)
|
||||
@@ -87,8 +97,9 @@
|
||||
* сложное составное устройство (\a PIConnection)
|
||||
* пиринговая сеть (\a PIPeer)
|
||||
* диагностика качества связи (\a PIDiagnostics)
|
||||
* поддержка библиотек времени выполнения
|
||||
* базовая функциональность (\a PILibrary)
|
||||
* Поддержка библиотек времени выполнения
|
||||
* внешний процесс (\a PIProcess)
|
||||
* внешняя библиотека (\a PILibrary)
|
||||
* плагин (\a PIPluginLoader)
|
||||
* Математика
|
||||
* комплексные числа
|
||||
@@ -100,5 +111,14 @@
|
||||
* CRC контрольная сумма (\a PICRC)
|
||||
* преобразования Фурье (\a PIFFTW, \a PIFFT)
|
||||
* вычислитель выражений (\a PIEvaluator)
|
||||
* парсер аргументов командной строки (\a PICLI)
|
||||
* процесс (\a PIProcess)
|
||||
* Уровень приложения
|
||||
* парсер аргументов командной строки (\a PICLI)
|
||||
* мониторинг ресурсов системы (\a PISystemMonitor)
|
||||
* контроль одного экземпляра приложения (\a PISingleApplication)
|
||||
* высокоуровневый лог (\a PILog)
|
||||
* поддержка перевода (\a PITranslator)
|
||||
* Машина состояний ([По стандарту](https://www.w3.org/TR/scxml/)) (\a PIStateMachine)
|
||||
* Высокоуровневый TCP клиент-сервер
|
||||
* сервер (\a PIClientServer::Server, \a PIClientServer::ServerClient)
|
||||
* клиент (\a PIClientServer::Client)
|
||||
* Поддержка шифрования (\a PICrypt, \a PIAuth)
|
||||
|
||||
1
lang/compile.bat
Normal file
1
lang/compile.bat
Normal file
@@ -0,0 +1 @@
|
||||
pip_tr --Compile -o pip_ru.btf pip_ru.ts
|
||||
BIN
lang/pip_ru.btf
Normal file
BIN
lang/pip_ru.btf
Normal file
Binary file not shown.
531
lang/pip_ru.ts
Normal file
531
lang/pip_ru.ts
Normal file
@@ -0,0 +1,531 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="ru">
|
||||
<context>
|
||||
<name>PICLI</name>
|
||||
<message>
|
||||
<location filename="../libs/main/application/picli.cpp" line="120"/>
|
||||
<source>Arguments overflow, "%1" ignored</source>
|
||||
<translation>Переизбыток аргументов, "%1" проигнорирован</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIDiag</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/pidiagnostics.cpp" line="155"/>
|
||||
<source>/s</source>
|
||||
<translation>/сек</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIFile</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pifile.cpp" line="299"/>
|
||||
<source>Downsize is not supported yet :-(</source>
|
||||
<translation>Уменьшение размера не поддерживается</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PICloud</name>
|
||||
<message>
|
||||
<location filename="../libs/cloud/picloudtcp.cpp" line="139"/>
|
||||
<source>Invalid PICloud::TCP version!</source>
|
||||
<translation>Неверная версия PICloud::TCP!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/cloud/picloudserver.cpp" line="230"/>
|
||||
<source>Error: buffer overflow, drop %1 bytes</source>
|
||||
<translation>Ошибка: переполнение буфера, отброшено %1 байт</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/cloud/picloudserver.cpp" line="251"/>
|
||||
<source>Warning: reject client with duplicated ID</source>
|
||||
<translation>Предупреждение: отклонен клиент с дублирующимся ID</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PICrypt</name>
|
||||
<message>
|
||||
<location filename="../libs/crypt/picrypt.cpp" line="205"/>
|
||||
<source>internal error: bad hash size</source>
|
||||
<translation>внутренняя ошибка: плохой размер хэша</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/crypt/picrypt.cpp" line="39"/>
|
||||
<source>Error while initialize sodium!</source>
|
||||
<translation>Ошибка инициализации sodium!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/crypt/picrypt.cpp" line="209"/>
|
||||
<source>invalid key size %1, should be %2, filled with zeros</source>
|
||||
<translation>неверный размер ключа %1, должен быть %2, заполненный нулями</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/crypt/picrypt.cpp" line="29"/>
|
||||
<source>Warning: PICrypt is disabled, to enable install sodium library and rebuild pip</source>
|
||||
<translation>Предупреждение: PICrypt неактивен, для активации установите библиотеку sodium и пересоберите PIP</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIBinLog</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="436"/>
|
||||
<source>Read record error</source>
|
||||
<translation>Ошибка чтения записи</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="432"/>
|
||||
<source>End of BinLog file</source>
|
||||
<translation>Конец BinLog файла</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="776"/>
|
||||
<source>Error, can't open "%1"</source>
|
||||
<translation>Ошибка, невозможно открыть "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="262"/>
|
||||
<source>Creating directory "%1"</source>
|
||||
<translation>Создание директории "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="785"/>
|
||||
<source>Error, can't create "%1"</source>
|
||||
<translation>Ошибка, невозможно создать "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="140"/>
|
||||
<source>Error: File is null "%1"</source>
|
||||
<translation>Ошибка, Файл пуст "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="789"/>
|
||||
<source>Start join binlogs to "%1"</source>
|
||||
<translation>Начало слияния логов в "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="514"/>
|
||||
<source>BinLogFile has too old verion</source>
|
||||
<translation>BinLogFile очень старой версии</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="513"/>
|
||||
<source>BinLogFile has invalid version</source>
|
||||
<translation>BinLogFile неверной версии</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="515"/>
|
||||
<source>BinLogFile has too new version</source>
|
||||
<translation>BinLogFile очень новой версии</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="386"/>
|
||||
<source>Can't find record with id = %1</source>
|
||||
<translation>Невозможно найти запись с ID = %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="803"/>
|
||||
<source>Error, can't write to file "%1"</source>
|
||||
<translation>Ошибка, невозможно записать в "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="126"/>
|
||||
<source>Error: Can't open file "%1": %2</source>
|
||||
<translation>Ошибка: Невозможно открыть файл "%1": %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="149"/>
|
||||
<source>Warning: Empty BinLog file "%1"</source>
|
||||
<translation>Предупреждение: Пустой BinLog файл "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="825"/>
|
||||
<source>Finish join binlogs, total time %1</source>
|
||||
<translation>Завершение слияния логов, общее время %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="440"/>
|
||||
<source>too small read buffer: %1, data size: %2</source>
|
||||
<translation>слишком маленький буфер: %1, размер данных: %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="133"/>
|
||||
<source>Error: Can't write binlog file header "%1"</source>
|
||||
<translation>Ошибка: Невозможно записать заголовок в "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="319"/>
|
||||
<source>Error: can`t write with id = 0! ID must be > 0</source>
|
||||
<translation>Ошибка: Невозможно записать с ID = 0! ID должен быть > 0</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="495"/>
|
||||
<source>BinLogFile signature is corrupted or invalid file</source>
|
||||
<translation>Неверный заголовок BinLogFile, либо файл поврежден</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="295"/>
|
||||
<source>Can't create new file, maybe path "%1" is invalid</source>
|
||||
<translation>Невозможно создать новый файл, возможно путь "%1" неверен</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="286"/>
|
||||
<source>Can't create new file, maybe LogDir "%1" is invalid</source>
|
||||
<translation>Невозможно создать новый файл, возможно LogDir "%1" неверен</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="104"/>
|
||||
<source>Error: ReadWrite mode not supported, use WriteOnly or ReadOnly</source>
|
||||
<translation>Ошибка: Режим ReadWrite не поддерживается, используйте WriteOnly или ReadOnly</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIOpenCL</name>
|
||||
<message>
|
||||
<location filename="../libs/opencl/piopencl.cpp" line="509"/>
|
||||
<source>Error: empty range</source>
|
||||
<translation>Ошибка: пустой диапазон</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/opencl/piopencl.cpp" line="586"/>
|
||||
<source>setArgValue invalid index %1</source>
|
||||
<translation>setArgValue неверный индекс %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/opencl/piopencl.cpp" line="616"/>
|
||||
<source>bindArgValue invalid index %1</source>
|
||||
<translation>bindArgValue неверный индекс %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/opencl/piopencl.cpp" line="592"/>
|
||||
<source>setArgValue set scalar to "%1 %2"</source>
|
||||
<translation>setArgValue устанавливается скаляр в "%1 %2"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/opencl/piopencl.cpp" line="93"/>
|
||||
<source>Error: OpenCL platforms not found!</source>
|
||||
<translation>Ошибка: Платформы OpenCL не найдены!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/opencl/piopencl.cpp" line="622"/>
|
||||
<source>bindArgValue set buffer to "%1 %2"</source>
|
||||
<translation>bindArgValue устанавливается буфер в "%1 %2"</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PISerial</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piserial.cpp" line="887"/>
|
||||
<source>Read error: %1</source>
|
||||
<translation>Ошибка чтения: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piserial.cpp" line="726"/>
|
||||
<source>Unable to open "%1": %2</source>
|
||||
<translation>Невозможно открыть "%1": %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piserial.cpp" line="467"/>
|
||||
<source>Warning: Custom speed %1</source>
|
||||
<translation>Предупреждение: Нестандартная скорость %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piserial.cpp" line="695"/>
|
||||
<source>Unable to find device "%1"</source>
|
||||
<translation>Невозможно найти устройство "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piserial.cpp" line="826"/>
|
||||
<source>Can`t set attributes for "%1"</source>
|
||||
<translation>Невозможно установить атрибуты для "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piserial.cpp" line="792"/>
|
||||
<source>Unable to set comm state for "%1"</source>
|
||||
<translation>Невозможно установить comm state для "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piserial.cpp" line="470"/>
|
||||
<source>Warning: Unknown speed %1, using 115200</source>
|
||||
<translation>Предупреждение: Неизвестная скорость %1, используется 115200</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIString</name>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1774"/>
|
||||
<source>B</source>
|
||||
<translation>Б</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1794"/>
|
||||
<source>EiB</source>
|
||||
<translation>ЭиБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1791"/>
|
||||
<source>GiB</source>
|
||||
<translation>ГиБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1789"/>
|
||||
<source>KiB</source>
|
||||
<translation>КиБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1790"/>
|
||||
<source>MiB</source>
|
||||
<translation>МиБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1793"/>
|
||||
<source>PiB</source>
|
||||
<translation>ПиБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1792"/>
|
||||
<source>TiB</source>
|
||||
<translation>ТиБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1796"/>
|
||||
<source>YiB</source>
|
||||
<translation>ЙиБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1795"/>
|
||||
<source>ZiB</source>
|
||||
<translation>ЗиБ</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIThread</name>
|
||||
<message>
|
||||
<location filename="../libs/main/thread/pithread.cpp" line="667"/>
|
||||
<source>Warning, terminate!</source>
|
||||
<translation>Предупреждение, прекращение потока!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/thread/pithread.cpp" line="785"/>
|
||||
<source>Error: Can`t start new thread: %1</source>
|
||||
<translation>Ошибка: Невозможно начать новый поток: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/thread/pithread.cpp" line="572"/>
|
||||
<source>[PIThread "%1"] Warning, terminate on destructor!</source>
|
||||
<translation>[PIThread "%1"] Предупреждение, прекращение в деструкторе!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIProcess</name>
|
||||
<message>
|
||||
<location filename="../libs/main/system/piprocess.cpp" line="200"/>
|
||||
<source>"CreateProcess" error: %1</source>
|
||||
<translation>Ошибка "CreateProcess": %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIVariant</name>
|
||||
<message>
|
||||
<location filename="../libs/main/types/pivariant.cpp" line="415"/>
|
||||
<source>Can`t initialize PIVariant from unregistered type "%1"!</source>
|
||||
<translation>Невозможно инициализировать PIVariant из незарегистрированного типа "%1"!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/types/pivariant.cpp" line="393"/>
|
||||
<source>Can`t initialize PIVariant from unregistered typeID "%1"!</source>
|
||||
<translation>Невозможно инициализировать PIVariant из незарегистрированного ID типа "%1"!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PICompress</name>
|
||||
<message>
|
||||
<location filename="../libs/compress/picompress.cpp" line="63"/>
|
||||
<source>Error: invalid input</source>
|
||||
<translation>Ошибка: неверный вход</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/compress/picompress.cpp" line="74"/>
|
||||
<source>Error: invalid input or not enought memory</source>
|
||||
<translation>Ошибка: неверный вход или недостаточно памяти</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/compress/picompress.cpp" line="80"/>
|
||||
<source>Warning: PICompress is disabled, to enable install zlib library and build pip_compress library</source>
|
||||
<translation>Предупреждение: PICompress неактивен, для активации установите библиотеку zlib и пересоберите PIP</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIEthernet</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piethernet.cpp" line="1233"/>
|
||||
<source>Can`t get interfaces: %1</source>
|
||||
<translation>Невозможно получить интерфейсы: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piethernet.cpp" line="903"/>
|
||||
<source>Can`t accept new connection, %1</source>
|
||||
<translation>Невозможно принять новое соединение, %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piethernet.cpp" line="1096"/>
|
||||
<source>Error allocating memory needed to call GetAdaptersInfo</source>
|
||||
<translation>Ошибка выделения памяти для вызова GetAdaptersInfo</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIIODevice</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piiodevice.cpp" line="226"/>
|
||||
<source>Error: Device is running after destructor!</source>
|
||||
<translation>Ошибка: Устройство в поточном выполнении после деструктора!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIIOString</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piiostring.cpp" line="54"/>
|
||||
<source>Error: ReadWrite mode not supported, use WriteOnly or ReadOnly</source>
|
||||
<translation>Ошибка: Режим ReadWrite не поддерживается, используйте WriteOnly или ReadOnly</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIConnection</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="146"/>
|
||||
<source>Error,</source>
|
||||
<translation>Ошибка,</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="922"/>
|
||||
<source>Null Device!</source>
|
||||
<translation>Нет Устройства!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="913"/>
|
||||
<source>No such device "%1"!</source>
|
||||
<translation>Нет устройства "%1"!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="903"/>
|
||||
<source>No such full path "%1"!</source>
|
||||
<translation>Нет полного пути "%1"!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="927"/>
|
||||
<source>Device "%1" can`t write!</source>
|
||||
<translation>Устройство "%1" не может писать!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="986"/>
|
||||
<source>Error: can`t create device "%1"!</source>
|
||||
<translation>Ошибка: Невозможно создать устройство "%1"!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="242"/>
|
||||
<source>"addFilter" error: no such device "%1"!</source>
|
||||
<translation>ошибка "addFilter": нет устройства "%1"!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="743"/>
|
||||
<source>"addSender" error: no such device "%1"!</source>
|
||||
<translation>ошибка "addSender": нет устройства "%1"!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="146"/>
|
||||
<source>names assigned to both devices and filters!</source>
|
||||
<translation>имена назначены одновременно устройствам и фильтрам!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="512"/>
|
||||
<source>"addFilter" error: no such device or filter "%1"!</source>
|
||||
<translation>ошибка "addFilter": нет устройства или фильтра "%1"!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PISystemTime</name>
|
||||
<message>
|
||||
<location filename="../libs/main/types/pisystemtime.cpp" line="335"/>
|
||||
<source>fromSystemTime() Warning: null frequency</source>
|
||||
<translation>fromSystemTime() Предупреждение: нулевая частота</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/types/pisystemtime.cpp" line="325"/>
|
||||
<source>toSystemTime() Warning: invalid hertz: %1</source>
|
||||
<translation>toSystemTime() Предупреждение: неверная частота: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIEthUtilBase</name>
|
||||
<message>
|
||||
<location filename="../libs/io_utils/piethutilbase.cpp" line="91"/>
|
||||
<source>PICrypt wasn`t built!</source>
|
||||
<translation>PICrypt не был собран!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIBaseTransfer</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="125"/>
|
||||
<source>invalid CRC</source>
|
||||
<translation>неверная CRC</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="219"/>
|
||||
<source>restart receive</source>
|
||||
<translation>перезапуск приема</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="176"/>
|
||||
<source>invalid reply id</source>
|
||||
<translation>неверный ID ответа</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="102"/>
|
||||
<source>invalid packet signature</source>
|
||||
<translation>неверная подпись пакета</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIClientServer</name>
|
||||
<message>
|
||||
<location filename="../libs/client_server/piclientserver_server.cpp" line="39"/>
|
||||
<source>ClientFactory returns nullptr!</source>
|
||||
<translation>ClientFactory вернул nullptr!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/client_server/piclientserver_server.cpp" line="33"/>
|
||||
<source>Server::newConnection overflow clients count</source>
|
||||
<translation>Server::newConnection переполнение количества клиентов</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIStateMachine</name>
|
||||
<message>
|
||||
<location filename="../libs/main/state_machine/pistatemachine_state.cpp" line="111"/>
|
||||
<source>Error: "%1" no initial state!</source>
|
||||
<translation>Ошибка: "%1" без стартового состояния!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIStreamPacker</name>
|
||||
<message>
|
||||
<location filename="../libs/io_utils/pistreampacker.cpp" line="218"/>
|
||||
<source>Warning! Not recommended to use with non-reliable device</source>
|
||||
<translation>Предупреждение! Не рекомендуется использовать с ненадежными устройствами</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PISystemMonitor</name>
|
||||
<message>
|
||||
<location filename="../libs/main/application/pisystemmonitor.cpp" line="111"/>
|
||||
<source>Can`t find process with ID = %1!</source>
|
||||
<translation>Невозможно найти процесс с ID = %1!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/application/pisystemmonitor.cpp" line="118"/>
|
||||
<source>Can`t open process with ID = %1, %2!</source>
|
||||
<translation>Невозможно открыть процесс с ID = %1, %2!</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
1
lang/update.bat
Normal file
1
lang/update.bat
Normal file
@@ -0,0 +1 @@
|
||||
pip_tr --Parse -r -l ru -o pip_ru.ts ../libs
|
||||
@@ -41,6 +41,7 @@ PIClientServer::Client::Client() {
|
||||
PIClientServer::Client::~Client() {
|
||||
if (tcp) tcp->setDebug(false);
|
||||
close();
|
||||
stopAndWait();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,14 +27,22 @@ PIClientServer::ClientBase::ClientBase() {}
|
||||
|
||||
PIClientServer::ClientBase::~ClientBase() {
|
||||
close();
|
||||
stopAndWait();
|
||||
if (own_tcp) piDeleteSafety(tcp);
|
||||
piDeleteSafety(diag);
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::ClientBase::close() {
|
||||
if (!tcp) return;
|
||||
can_write = false;
|
||||
tcp->interrupt();
|
||||
tcp->stop();
|
||||
stream.clear();
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::ClientBase::stopAndWait() {
|
||||
if (!tcp) return;
|
||||
tcp->stopAndWait(10_s);
|
||||
if (tcp->isThreadedRead()) tcp->terminateThreadedRead();
|
||||
tcp->close();
|
||||
@@ -53,17 +61,38 @@ int PIClientServer::ClientBase::write(const void * d, const size_t s) {
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::ClientBase::enableDiagnostics() {
|
||||
if (diag) return;
|
||||
diag = new PIDiagnostics();
|
||||
}
|
||||
|
||||
|
||||
PIDiagnostics::State PIClientServer::ClientBase::diagnostics() const {
|
||||
if (!diag) return {};
|
||||
return diag->state();
|
||||
}
|
||||
|
||||
|
||||
int PIClientServer::ClientBase::receivePacketProgress() const {
|
||||
return stream.receivePacketProgress();
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::ClientBase::init() {
|
||||
if (!tcp) return;
|
||||
CONNECTL(&stream, sendRequest, [this](const PIByteArray & ba) {
|
||||
if (!can_write) return;
|
||||
tcp->send(ba);
|
||||
if (diag) diag->sended(ba.size_s());
|
||||
// piMSleep(1);
|
||||
});
|
||||
CONNECTL(&stream, packetReceiveEvent, [this](PIByteArray & ba) { readed(ba); });
|
||||
CONNECTL(&stream, startPacketReceive, [this](int size) { receivePacketStart(size); });
|
||||
CONNECTL(&stream, endPacketReceive, [this]() { receivePacketEnd(); });
|
||||
CONNECTL(tcp, threadedReadEvent, [this](const uchar * readed, ssize_t size) {
|
||||
if (!can_write) return;
|
||||
stream.received(readed, size);
|
||||
if (diag) diag->received(size);
|
||||
});
|
||||
CONNECTL(tcp, connected, [this]() {
|
||||
can_write = true;
|
||||
@@ -80,8 +109,9 @@ void PIClientServer::ClientBase::init() {
|
||||
|
||||
|
||||
void PIClientServer::ClientBase::destroy() {
|
||||
can_write = false;
|
||||
write_mutex.lock();
|
||||
close();
|
||||
piDeleteSafety(tcp);
|
||||
write_mutex.unlock();
|
||||
// piCout << "Destroyed";
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "piclientserver_client.h"
|
||||
#include "piethernet.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "pitranslator.h"
|
||||
|
||||
|
||||
PIClientServer::Server::Server() {
|
||||
@@ -30,13 +30,13 @@ PIClientServer::Server::Server() {
|
||||
CONNECTL(tcp_server, newConnection, [this](PIEthernet * c) {
|
||||
PIMutexLocker guard(clients_mutex);
|
||||
if (clients.size_s() >= max_clients) {
|
||||
piCout << "Server::newConnection overflow clients count";
|
||||
piCout << "Server::newConnection overflow clients count"_tr("PIClientServer");
|
||||
delete c;
|
||||
return;
|
||||
}
|
||||
auto sc = client_factory();
|
||||
if (!sc) {
|
||||
piCout << "ClientFactory returns nullptr!";
|
||||
piCout << "ClientFactory returns nullptr!"_tr("PIClientServer");
|
||||
return;
|
||||
}
|
||||
sc->createForServer(this, c);
|
||||
@@ -90,6 +90,18 @@ void PIClientServer::Server::listen(PINetworkAddress addr) {
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::closeAll() {
|
||||
clients_mutex.lock();
|
||||
for (auto c: clients) {
|
||||
c->aboutDelete();
|
||||
c->destroy();
|
||||
delete c;
|
||||
}
|
||||
clients.clear();
|
||||
clients_mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::setMaxClients(int new_max_clients) {
|
||||
max_clients = new_max_clients;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "picloudclient.h"
|
||||
|
||||
#include "picloudtcp.h"
|
||||
#include "pitranslator.h"
|
||||
|
||||
|
||||
PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() {
|
||||
@@ -174,7 +175,7 @@ void PICloudClient::_readed(PIByteArray & ba) {
|
||||
if (is_connected) {
|
||||
mutex_buff.lock();
|
||||
if (buff.size_s() > threadedReadBufferSize()) {
|
||||
piCoutObj << "Error: buffer overflow, drop" << ba.size() << "bytes";
|
||||
piCoutObj << "Error: buffer overflow, drop %1 bytes"_tr("PICloud").arg(ba.size());
|
||||
mutex_buff.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "picloudserver.h"
|
||||
|
||||
#include "piliterals_time.h"
|
||||
#include "pitranslator.h"
|
||||
|
||||
|
||||
PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() {
|
||||
@@ -226,7 +227,7 @@ void PICloudServer::Client::pushBuffer(const PIByteArray & ba) {
|
||||
if (!is_connected) return;
|
||||
mutex_buff.lock();
|
||||
if (buff.size_s() > threadedReadBufferSize()) {
|
||||
piCoutObj << "Error: buffer overflow, drop" << ba.size() << "bytes";
|
||||
piCoutObj << "Error: buffer overflow, drop %1 bytes"_tr("PICloud").arg(ba.size());
|
||||
mutex_buff.unlock();
|
||||
return;
|
||||
}
|
||||
@@ -247,7 +248,7 @@ void PICloudServer::_readed(PIByteArray & ba) {
|
||||
Client * oc = index_clients.value(id, nullptr);
|
||||
clients_mutex.unlock();
|
||||
if (oc) {
|
||||
piCoutObj << "Warning: reject client with duplicated ID";
|
||||
piCoutObj << "Warning: reject client with duplicated ID"_tr("PICloud");
|
||||
tcp.sendDisconnected(id);
|
||||
} else {
|
||||
Client * c = new Client(this, id);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "picrypt.h"
|
||||
#include "piethernet.h"
|
||||
#include "pistreampacker.h"
|
||||
#include "pitranslator.h"
|
||||
|
||||
|
||||
const char hash_cloud_key[] = "_picloud_";
|
||||
@@ -95,7 +96,7 @@ int PICloud::TCP::sendData(const PIByteArray & data) {
|
||||
PIByteArray ba;
|
||||
ba << header;
|
||||
ba.append(data);
|
||||
// piCout << "[PICloud::TCP] sendData" << ba.toHex();
|
||||
// piCout << "[PICloud::TCP] sendData" << ba.toHex();
|
||||
mutex_send.lock();
|
||||
streampacker->send(ba);
|
||||
mutex_send.unlock();
|
||||
@@ -135,7 +136,7 @@ PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteA
|
||||
ba >> hdr;
|
||||
if (hdr.version != header.version) {
|
||||
piCout << "[PICloud]"
|
||||
<< "invalid PICloud::TCP version!";
|
||||
<< "Invalid PICloud::TCP version!"_tr("PICloud");
|
||||
return ret;
|
||||
}
|
||||
ret.first = (Type)hdr.type;
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
|
||||
#include "picompress.h"
|
||||
|
||||
#include "pitranslator.h"
|
||||
#ifdef PIP_COMPRESS
|
||||
# ifdef ESP_PLATFORM
|
||||
# include "esp32/rom/miniz.h"
|
||||
@@ -39,7 +41,7 @@ PIByteArray piCompress(const PIByteArray & ba, int level) {
|
||||
ret = compress2(zba.data(), &sz, ba.data(), ba.size(), level);
|
||||
if (ret != Z_OK) {
|
||||
piCout << "[PICompress]"
|
||||
<< "Error: invalid input or not enought memory";
|
||||
<< "Error: invalid input or not enought memory"_tr("PICompress");
|
||||
return ba;
|
||||
}
|
||||
zba.resize(sz);
|
||||
@@ -47,7 +49,7 @@ PIByteArray piCompress(const PIByteArray & ba, int level) {
|
||||
return zba;
|
||||
#else
|
||||
piCout << "[PICompress]"
|
||||
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
|
||||
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library"_tr("PICompress");
|
||||
#endif
|
||||
return ba;
|
||||
}
|
||||
@@ -58,7 +60,7 @@ PIByteArray piDecompress(const PIByteArray & zba) {
|
||||
ullong sz = 0;
|
||||
if (zba.size() < sizeof(ullong)) {
|
||||
piCout << "[PICompress]"
|
||||
<< "Error: invalid input";
|
||||
<< "Error: invalid input"_tr("PICompress");
|
||||
return zba;
|
||||
}
|
||||
PIByteArray ba(zba.data(zba.size() - sizeof(ullong)), sizeof(ullong));
|
||||
@@ -69,13 +71,13 @@ PIByteArray piDecompress(const PIByteArray & zba) {
|
||||
ret = uncompress(ba.data(), &s, zba.data(), zba.size());
|
||||
if (ret != Z_OK) {
|
||||
piCout << "[PICompress]"
|
||||
<< "Error: invalid input or not enought memory";
|
||||
<< "Error: invalid input or not enought memory"_tr("PICompress");
|
||||
return zba;
|
||||
}
|
||||
return ba;
|
||||
#else
|
||||
piCout << "[PICompress]"
|
||||
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
|
||||
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library"_tr("PICompress");
|
||||
#endif
|
||||
return zba;
|
||||
}
|
||||
|
||||
@@ -18,13 +18,15 @@
|
||||
*/
|
||||
|
||||
#include "picrypt.h"
|
||||
|
||||
#include "pitranslator.h"
|
||||
#ifdef PIP_CRYPT
|
||||
# include <sodium.h>
|
||||
#endif
|
||||
|
||||
#define PICRYPT_DISABLED_WARNING \
|
||||
piCout << "[PICrypt]" \
|
||||
<< "Warning: PICrypt is disabled, to enable install sodium library and rebuild pip";
|
||||
<< "Warning: PICrypt is disabled, to enable install sodium library and rebuild pip"_tr("PICrypt");
|
||||
|
||||
const char hash_def_key[] = "_picrypt_\0\0\0\0\0\0\0";
|
||||
const int hash_def_key_size = 9;
|
||||
@@ -34,7 +36,7 @@ PICrypt::PICrypt() {
|
||||
#ifdef PIP_CRYPT
|
||||
if (!init())
|
||||
piCout << "[PICrypt]"
|
||||
<< "Error while initialize sodium!";
|
||||
<< "Error while initialize sodium!"_tr("PICrypt");
|
||||
nonce_.resize(crypto_secretbox_NONCEBYTES);
|
||||
key_.resize(crypto_secretbox_KEYBYTES);
|
||||
randombytes_buf(key_.data(), key_.size());
|
||||
@@ -107,7 +109,7 @@ PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool * ok) {
|
||||
memcpy(nonce_.data(), crypt_data.data(crypt_data.size() - nonce_.size()), nonce_.size());
|
||||
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - nonce_.size(), nonce_.data(), key_.data()) != 0) {
|
||||
if (ok) *ok = false;
|
||||
// piCout << "[PICrypt]" << "bad key_";
|
||||
// piCout << "[PICrypt]" << "bad key_";
|
||||
return PIByteArray();
|
||||
}
|
||||
#endif
|
||||
@@ -134,7 +136,7 @@ PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bo
|
||||
memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size());
|
||||
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), key.data()) != 0) {
|
||||
if (ok) *ok = false;
|
||||
// piCout << "[PICrypt]" << "bad key_";
|
||||
// piCout << "[PICrypt]" << "bad key_";
|
||||
return PIByteArray();
|
||||
} else if (ok)
|
||||
*ok = true;
|
||||
@@ -200,11 +202,11 @@ ullong PICrypt::shorthash(const PIString & s, PIByteArray key) {
|
||||
#ifdef PIP_CRYPT
|
||||
if (crypto_shorthash_BYTES != sizeof(hash))
|
||||
piCout << "[PICrypt]"
|
||||
<< "internal error: bad hash size";
|
||||
<< "internal error: bad hash size"_tr("PICrypt");
|
||||
if (!init()) return hash;
|
||||
if (key.size() != crypto_shorthash_KEYBYTES) {
|
||||
piCout << "[PICrypt]"
|
||||
<< "invalid key size" << key.size() << ", shoud be" << crypto_shorthash_KEYBYTES << ", filled zeros";
|
||||
<< "invalid key size %1, should be %2, filled with zeros"_tr("PICrypt").arg(key.size()).arg(crypto_shorthash_KEYBYTES);
|
||||
key.resize(crypto_shorthash_KEYBYTES, 0);
|
||||
}
|
||||
PIByteArray in(s.data(), s.size());
|
||||
@@ -389,7 +391,7 @@ PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray &
|
||||
if (crypto_box_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), public_key.data(), secret_key.data()) !=
|
||||
0) {
|
||||
if (ok) *ok = false;
|
||||
// piCout << "[PICrypt]" << "bad key_";
|
||||
// piCout << "[PICrypt]" << "bad key_";
|
||||
return PIByteArray();
|
||||
} else if (ok)
|
||||
*ok = true;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#define PIFFT_P_H
|
||||
|
||||
#include "picout.h"
|
||||
#include "pimathcomplex.h"
|
||||
#include "pivector.h"
|
||||
#if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq)
|
||||
# include "fftw3.h"
|
||||
@@ -41,7 +42,7 @@ public:
|
||||
explicit PIFFTW_Private() {
|
||||
plan = 0;
|
||||
// #ifndef PIP_FFTW
|
||||
// piCout << "[PIFFTW]" << "Warning: PIFFTW is disabled, to enable install libfftw3-dev library and build pip with -DFFTW=1";
|
||||
// piCout << "[PIFFTW]" << "Warning: PIFFTW is disabled, to enable install libfftw3-dev library and build pip with -DFFTW=1";
|
||||
// #endif
|
||||
p_makeThreadSafe();
|
||||
}
|
||||
|
||||
346
libs/http_server/microhttpd_server_p.cpp
Normal file
346
libs/http_server/microhttpd_server_p.cpp
Normal file
@@ -0,0 +1,346 @@
|
||||
#include "microhttpd_server_p.h"
|
||||
|
||||
#include "piliterals_string.h"
|
||||
#include "piliterals_time.h"
|
||||
|
||||
#include <microhttpd.h>
|
||||
// clang-format off
|
||||
#ifdef QNX
|
||||
# include <arpa/inet.h>
|
||||
# include <sys/socket.h>
|
||||
# include <sys/types.h>
|
||||
# ifdef BLACKBERRY
|
||||
# include <netinet/in.h>
|
||||
# else
|
||||
# include <sys/dcmd_io-net.h>
|
||||
# endif
|
||||
#else
|
||||
# ifdef WINDOWS
|
||||
# include <io.h>
|
||||
# include <winsock2.h>
|
||||
# include <ws2tcpip.h>
|
||||
# else
|
||||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
# ifdef LWIP
|
||||
# include <lwip/sockets.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
|
||||
struct MicrohttpdServerConnection {
|
||||
bool ready();
|
||||
int send_reply(const MicrohttpdServer::Reply & r);
|
||||
int send_error();
|
||||
|
||||
bool done = false;
|
||||
MicrohttpdServer::Method method = MicrohttpdServer::Method::Unknown;
|
||||
PIString path;
|
||||
PIByteArray body;
|
||||
PIMap<PIString, PIString> headers, args, post;
|
||||
MHD_Connection * connection = nullptr;
|
||||
MicrohttpdServer * server = nullptr;
|
||||
MHD_PostProcessor * postprocessor = nullptr;
|
||||
};
|
||||
|
||||
|
||||
bool MicrohttpdServerConnection::ready() {
|
||||
if (!server) return false;
|
||||
if (done) return true;
|
||||
done = true;
|
||||
MicrohttpdServer::Reply rep;
|
||||
if (method == MicrohttpdServer::Method::Get) {
|
||||
if (path == "/favicon.ico"_a) {
|
||||
// piCout << "send favicon" << server->favicon.size() << "bytes";
|
||||
rep.setBody(server->favicon);
|
||||
send_reply(rep);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// piCout << "ready" << (int)method << path;
|
||||
MicrohttpdServer::Request req;
|
||||
req.method = method;
|
||||
req.path = path;
|
||||
req.body = body;
|
||||
req.headers = headers;
|
||||
req.args = args;
|
||||
rep.setCode(MHD_HTTP_BAD_REQUEST);
|
||||
if (server->callback) rep = server->callback(req);
|
||||
rep.addFixedHeaders();
|
||||
send_reply(rep);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int MicrohttpdServerConnection::send_reply(const MicrohttpdServer::Reply & r) {
|
||||
MHD_Response * response = MHD_create_response_from_buffer(r.body.size(), (void *)r.body.data(), MHD_RESPMEM_MUST_COPY);
|
||||
if (!response) {
|
||||
// piCout << "null response" << r.body.size() << (void *)r.body.data();
|
||||
return MHD_NO;
|
||||
}
|
||||
auto it = r.headers.makeIterator();
|
||||
while (it.next())
|
||||
MHD_add_response_header(response, it.key().dataAscii(), it.value().dataUTF8());
|
||||
// piCout << "status" << r.code;
|
||||
int ret = MHD_queue_response(connection, r.code, response);
|
||||
MHD_destroy_response(response);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int MicrohttpdServerConnection::send_error() {
|
||||
return MHD_queue_response(connection, MHD_HTTP_BAD_REQUEST, MHD_create_response_from_buffer(0, nullptr, MHD_RESPMEM_MUST_COPY));
|
||||
}
|
||||
|
||||
|
||||
void log_callback(void * cls, const char * fmt, va_list ap) {
|
||||
MicrohttpdServer * server = (MicrohttpdServer *)cls;
|
||||
piCout << "log" << server;
|
||||
if (!server) return;
|
||||
char buffer[1024];
|
||||
memset(buffer, 0, 1024);
|
||||
std::vsnprintf(buffer, 1024, fmt, ap);
|
||||
piCout << buffer;
|
||||
}
|
||||
|
||||
|
||||
int iterate_post(void * conn_cls,
|
||||
MHD_ValueKind kind,
|
||||
const char * key,
|
||||
const char * filename,
|
||||
const char * content_type,
|
||||
const char * transfer_encoding,
|
||||
const char * data,
|
||||
uint64_t off,
|
||||
size_t size) {
|
||||
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)conn_cls;
|
||||
if (!conn) return MHD_NO;
|
||||
conn->post[PIString::fromUTF8(key)] = PIString::fromUTF8(data);
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
|
||||
void request_completed(void * cls, MHD_Connection * connection, void ** con_cls, MHD_RequestTerminationCode toe) {
|
||||
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
|
||||
// piCout << "request_completed" << conn << conn->headers << conn->post << '"' << conn->body << '"';
|
||||
if (!conn) return;
|
||||
if (conn->method == MicrohttpdServer::Method::Post && conn->postprocessor) MHD_destroy_post_processor(conn->postprocessor);
|
||||
conn->ready();
|
||||
piDeleteSafety(conn);
|
||||
}
|
||||
|
||||
|
||||
int header_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
|
||||
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
|
||||
if (!conn) return MHD_NO;
|
||||
conn->headers[PIString::fromUTF8(key)] = PIString::fromUTF8(value);
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
|
||||
int args_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
|
||||
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
|
||||
if (!conn) return MHD_NO;
|
||||
conn->args[PIString::fromUTF8(key)] = PIString::fromUTF8(value);
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
|
||||
int answer_to_connection(void * cls,
|
||||
MHD_Connection * connection,
|
||||
const char * url,
|
||||
const char * method,
|
||||
const char * version,
|
||||
const char * upload_data,
|
||||
size_t * upload_data_size,
|
||||
void ** con_cls) {
|
||||
MicrohttpdServer * server = (MicrohttpdServer *)cls;
|
||||
|
||||
MicrohttpdServer::Method m = MicrohttpdServer::Method::Unknown;
|
||||
|
||||
if (0 == strcmp(method, "GET"))
|
||||
m = MicrohttpdServer::Method::Get;
|
||||
else if (0 == strcmp(method, "POST"))
|
||||
m = MicrohttpdServer::Method::Post;
|
||||
else if (0 == strcmp(method, "HEAD"))
|
||||
m = MicrohttpdServer::Method::Head;
|
||||
else if (0 == strcmp(method, "PUT"))
|
||||
m = MicrohttpdServer::Method::Put;
|
||||
else if (0 == strcmp(method, "DELETE"))
|
||||
m = MicrohttpdServer::Method::Delete;
|
||||
else if (0 == strcmp(method, "CONNECT"))
|
||||
m = MicrohttpdServer::Method::Connect;
|
||||
else if (0 == strcmp(method, "OPTIONS"))
|
||||
m = MicrohttpdServer::Method::Options;
|
||||
else if (0 == strcmp(method, "TRACE"))
|
||||
m = MicrohttpdServer::Method::Trace;
|
||||
else if (0 == strcmp(method, "PATCH"))
|
||||
m = MicrohttpdServer::Method::Patch;
|
||||
|
||||
if (m == MicrohttpdServer::Method::Unknown) {
|
||||
piCout << "[MicrohttpdServer]"
|
||||
<< "Warning:"
|
||||
<< "Unknown method!";
|
||||
return MHD_NO;
|
||||
}
|
||||
|
||||
// piCout << "answer" << url << method << server;
|
||||
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
|
||||
if (!conn) {
|
||||
conn = new MicrohttpdServerConnection();
|
||||
conn->connection = connection;
|
||||
conn->server = server;
|
||||
conn->path = PIString::fromUTF8(url);
|
||||
conn->method = m;
|
||||
MHD_get_connection_values(connection, MHD_HEADER_KIND, (MHD_KeyValueIterator)header_iterate, *con_cls);
|
||||
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, (MHD_KeyValueIterator)args_iterate, *con_cls);
|
||||
|
||||
if (m == MicrohttpdServer::Method::Post) {
|
||||
// qDebug() << "new POST" << *upload_data_size;
|
||||
conn->postprocessor = MHD_create_post_processor(connection, 65536, (MHD_PostDataIterator)iterate_post, (void *)conn);
|
||||
}
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
switch (m) {
|
||||
case MicrohttpdServer::Method::Get:
|
||||
if (!conn->ready()) return conn->send_error();
|
||||
return MHD_YES;
|
||||
case MicrohttpdServer::Method::Post:
|
||||
// qDebug() << "add POST" << *upload_data_size << PIString::fromUtf8(upload_data, *upload_data_size);
|
||||
if (*upload_data_size) {
|
||||
conn->body.append(upload_data, *upload_data_size);
|
||||
if (conn->postprocessor) MHD_post_process(conn->postprocessor, upload_data, *upload_data_size);
|
||||
*upload_data_size = 0;
|
||||
return MHD_YES;
|
||||
} else {
|
||||
// qDebug() << "answer ok";
|
||||
if (!conn->ready()) return conn->send_error();
|
||||
return MHD_YES;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return conn->send_error();
|
||||
}
|
||||
|
||||
|
||||
PRIVATE_DEFINITION_START(MicrohttpdServer)
|
||||
MHD_Daemon * daemon;
|
||||
PRIVATE_DEFINITION_END(MicrohttpdServer)
|
||||
|
||||
|
||||
MicrohttpdServer::MicrohttpdServer() {
|
||||
PRIVATE->daemon = nullptr;
|
||||
opts[Option::ConnectionLimit] = FD_SETSIZE - 4;
|
||||
opts[Option::ConnectionTimeout] = 0_s;
|
||||
}
|
||||
|
||||
|
||||
MicrohttpdServer::~MicrohttpdServer() {
|
||||
stop();
|
||||
}
|
||||
|
||||
|
||||
void MicrohttpdServer::setOption(Option o, PIVariant v) {
|
||||
opts[o] = std::move(v);
|
||||
}
|
||||
|
||||
|
||||
void MicrohttpdServer::setFavicon(const PIByteArray & im) {
|
||||
favicon = im;
|
||||
}
|
||||
|
||||
|
||||
bool MicrohttpdServer::listen(PINetworkAddress addr) {
|
||||
stop();
|
||||
uint flags = 0;
|
||||
#if MHD_VERSION <= 0x00095100
|
||||
flags |= MHD_USE_POLL_INTERNALLY;
|
||||
#else
|
||||
flags |= MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD;
|
||||
#endif
|
||||
if (opts.value(Option::HTTPSEnabled).toBool()) flags |= MHD_USE_TLS;
|
||||
mem_key = opts.value(Option::HTTPSMemKey).toByteArray();
|
||||
if (mem_key.isNotEmpty()) mem_key.append(0);
|
||||
mem_cert = opts.value(Option::HTTPSMemCert).toByteArray();
|
||||
if (mem_cert.isNotEmpty()) mem_cert.append(0);
|
||||
key_pass = opts.value(Option::HTTPSKeyPassword).toByteArray();
|
||||
if (key_pass.isNotEmpty()) key_pass.append(0);
|
||||
sockaddr_in sa_addr;
|
||||
memset(&sa_addr, 0, sizeof(sa_addr));
|
||||
sa_addr.sin_port = htons(addr.port());
|
||||
sa_addr.sin_addr.s_addr = addr.ip();
|
||||
sa_addr.sin_family = AF_INET;
|
||||
PIVector<MHD_OptionItem> options;
|
||||
options.append({MHD_OPTION_EXTERNAL_LOGGER, (intptr_t)log_callback, this});
|
||||
options.append({MHD_OPTION_NOTIFY_COMPLETED, (intptr_t)request_completed, nullptr});
|
||||
options.append({MHD_OPTION_CONNECTION_LIMIT, opts.value(Option::ConnectionLimit).toInt(), nullptr});
|
||||
options.append({MHD_OPTION_CONNECTION_TIMEOUT, piRound(opts.value(Option::ConnectionTimeout).toSystemTime().toSeconds()), nullptr});
|
||||
options.append({MHD_OPTION_SOCK_ADDR, 0, &sa_addr});
|
||||
if (opts.value(Option::HTTPSEnabled).toBool()) {
|
||||
options.append({MHD_OPTION_HTTPS_MEM_KEY, 0, mem_key.data()});
|
||||
options.append({MHD_OPTION_HTTPS_MEM_CERT, 0, mem_cert.data()});
|
||||
options.append({MHD_OPTION_HTTPS_KEY_PASSWORD, 0, key_pass.data()});
|
||||
}
|
||||
options.append({MHD_OPTION_END, 0, nullptr});
|
||||
PRIVATE->daemon = MHD_start_daemon(flags,
|
||||
addr.port(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
(MHD_AccessHandlerCallback)answer_to_connection,
|
||||
this,
|
||||
MHD_OPTION_ARRAY,
|
||||
options.data(),
|
||||
MHD_OPTION_END);
|
||||
return isListen();
|
||||
}
|
||||
|
||||
|
||||
bool MicrohttpdServer::isListen() const {
|
||||
return PRIVATE->daemon;
|
||||
}
|
||||
|
||||
|
||||
void MicrohttpdServer::stop() {
|
||||
if (PRIVATE->daemon) {
|
||||
MHD_stop_daemon(PRIVATE->daemon);
|
||||
PRIVATE->daemon = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MicrohttpdServer::Reply::addHeader(const PIString & header, const PIString & value) {
|
||||
headers[header] = value;
|
||||
}
|
||||
|
||||
|
||||
void MicrohttpdServer::Reply::removeHeader(const PIString & header) {
|
||||
headers.remove(header);
|
||||
}
|
||||
|
||||
|
||||
void MicrohttpdServer::Reply::setBody(const PIByteArray & b) {
|
||||
body = b;
|
||||
}
|
||||
|
||||
|
||||
void MicrohttpdServer::Reply::setCode(int c) {
|
||||
code = c;
|
||||
}
|
||||
|
||||
|
||||
void MicrohttpdServer::Reply::addFixedHeaders() {
|
||||
if (!headers.contains(MHD_HTTP_HEADER_CONTENT_TYPE)) {
|
||||
if (body.isNotEmpty()) {
|
||||
if (body.startsWith(PIByteArray::fromAscii("<!DOCTYPE html>")))
|
||||
addHeader(MHD_HTTP_HEADER_CONTENT_TYPE, "text/html; charset=utf-8");
|
||||
else if (body[0] == '[' || body[0] == '{')
|
||||
addHeader(MHD_HTTP_HEADER_CONTENT_TYPE, "application/json; charset=utf-8");
|
||||
}
|
||||
}
|
||||
addHeader(MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*");
|
||||
}
|
||||
49
libs/http_server/pihttpserver.cpp
Normal file
49
libs/http_server/pihttpserver.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "pihttpserver.h"
|
||||
|
||||
#include "piliterals_string.h"
|
||||
|
||||
|
||||
PIHTTPServer::PIHTTPServer() {
|
||||
setRequestCallback([this](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||
MicrohttpdServer::Reply rep;
|
||||
rep.setCode(404);
|
||||
auto in_path = r.path.split("/");
|
||||
in_path.removeAll("");
|
||||
auto it = functions.makeReverseIterator();
|
||||
while (it.next()) {
|
||||
if (it.value().function) {
|
||||
if (it.value().match(in_path)) {
|
||||
rep = it.value().function(r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto hit = reply_headers.makeIterator();
|
||||
while (hit.next())
|
||||
rep.addHeader(hit.key(), hit.value());
|
||||
return rep;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
PIHTTPServer::~PIHTTPServer() {
|
||||
stop();
|
||||
}
|
||||
|
||||
|
||||
void PIHTTPServer::registerPath(const PIString & path, RequestFunction functor) {
|
||||
auto & ep(functions[path]);
|
||||
ep.path = path.split("/");
|
||||
ep.function = functor;
|
||||
ep.path.removeAll("");
|
||||
}
|
||||
|
||||
|
||||
bool PIHTTPServer::Endpoint::match(const PIStringList & in_path) const {
|
||||
if (in_path.size() != path.size()) return false;
|
||||
for (int i = 0; i < path.size_s(); ++i) {
|
||||
if (path[i] == "*"_a) continue;
|
||||
if (path[i] != in_path[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
|
||||
#include "piethutilbase.h"
|
||||
|
||||
#include "pitranslator.h"
|
||||
#ifdef PIP_CRYPT
|
||||
# include "picrypt.h"
|
||||
#endif
|
||||
@@ -85,7 +87,8 @@ void PIEthUtilBase::createCryptKey(const PIString & k) {
|
||||
_key = PICrypt::hash("sodium_bug");
|
||||
_key = PICrypt::hash(k);
|
||||
#else
|
||||
piCout << "[PIEthUtilBase] PICrypt wasn`t built!";
|
||||
piCout << "[PIEthUtilBase]"
|
||||
<< "PICrypt wasn`t built!"_tr("PIEthUtilBase");
|
||||
#endif
|
||||
_crypt = true;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "piiodevice.h"
|
||||
#include "piliterals_bytes.h"
|
||||
#include "pitranslator.h"
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
@@ -120,6 +121,7 @@ void PIStreamPacker::send(const PIByteArray & data) {
|
||||
|
||||
|
||||
void PIStreamPacker::received(const uchar * readed, ssize_t size) {
|
||||
if (size <= 0) return;
|
||||
received(PIByteArray(readed, size));
|
||||
}
|
||||
|
||||
@@ -166,7 +168,10 @@ void PIStreamPacker::received(const PIByteArray & data) {
|
||||
stream.remove(0, hdr_size);
|
||||
packet.clear();
|
||||
packet_size = sz;
|
||||
if (packet_size == 0) packet_size = -1;
|
||||
if (packet_size == 0)
|
||||
packet_size = -1;
|
||||
else
|
||||
startPacketReceive(packet_size);
|
||||
continue;
|
||||
} else {
|
||||
int ps = piMini(stream.size_s(), packet_size - packet.size_s());
|
||||
@@ -195,6 +200,7 @@ void PIStreamPacker::received(const PIByteArray & data) {
|
||||
}
|
||||
// piCout << "decrypt" << packet.size() << "->" << cd.size() << key().size();
|
||||
if (!cd.isEmpty()) {
|
||||
endPacketReceive();
|
||||
packetReceived(cd);
|
||||
packetReceiveEvent(cd);
|
||||
}
|
||||
@@ -209,7 +215,7 @@ void PIStreamPacker::received(const PIByteArray & data) {
|
||||
void PIStreamPacker::assignDevice(PIIODevice * dev) {
|
||||
if (!dev) return;
|
||||
if (!dev->infoFlags()[PIIODevice::Reliable]) {
|
||||
piCoutObj << "Warning! Not recommended to use with non-reliable" << dev;
|
||||
piCoutObj << "Warning! Not recommended to use with non-reliable device"_tr("PIStreamPacker") << dev;
|
||||
}
|
||||
CONNECT2(void, const uchar *, ssize_t, dev, threadedReadEvent, this, received);
|
||||
CONNECT1(void, PIByteArray, this, sendRequest, dev, write);
|
||||
|
||||
@@ -52,7 +52,9 @@
|
||||
#define PIAPPLICATIONMODULE_H
|
||||
|
||||
#include "picli.h"
|
||||
#include "pilog.h"
|
||||
#include "pisingleapplication.h"
|
||||
#include "pisystemmonitor.h"
|
||||
#include "pitranslator.h"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "picli.h"
|
||||
|
||||
#include "pisysteminfo.h"
|
||||
#include "pitranslator.h"
|
||||
|
||||
|
||||
//! \class PICLI picli.h
|
||||
@@ -116,7 +117,7 @@ void PICLI::parse() {
|
||||
_args_opt << cra;
|
||||
continue;
|
||||
}
|
||||
piCoutObj << "Arguments overflow, \"" << cra << "\" ignored";
|
||||
piCoutObj << "Arguments overflow, \"%1\" ignored"_tr("PICLI").arg(cra);
|
||||
}
|
||||
if (last == 0 ? false : last->has_value) {
|
||||
last->value = cra;
|
||||
|
||||
@@ -30,44 +30,10 @@
|
||||
//! \~english \section PILog_sec0 Synopsis
|
||||
//! \~russian \section PILog_sec0 Краткий обзор
|
||||
//! \~english
|
||||
//! This class provide handy parsing of command-line arguments. First you should add
|
||||
//! arguments to %PICLI with function \a addArgument(). Then you can check if there
|
||||
//! is some argument in application command-line with function \a hasArgument(),
|
||||
//! or obtain argument value by \a argumentValue().
|
||||
//! This class provides log with optional file and console output.
|
||||
//!
|
||||
//! \~russian
|
||||
//! Этот класс предоставляет удобный механизм для разбора аргументов командной строки.
|
||||
//! Сперва необходимо добавить аргументы в %PICLI с помощью методов \a addArgument().
|
||||
//! Далее можно проверять аргументы на наличие в командной строке методом \a hasArgument(),
|
||||
//! а также получать их значения при помощи \a argumentValue().
|
||||
//!
|
||||
//! \~english \section PICLI_sec1 Example
|
||||
//! \~russian \section PICLI_sec1 Пример
|
||||
//! \~\code
|
||||
//! int main(int argc, char ** argv) {
|
||||
//! PICLI cli(argc, argv);
|
||||
//! cli.addArgument("console");
|
||||
//! cli.addArgument("debug");
|
||||
//! cli.addArgument("Value", "v", "value", true);
|
||||
//! if (cli.hasArgument("console"))
|
||||
//! piCout << "console active";
|
||||
//! if (cli.hasArgument("debug"))
|
||||
//! piCout << "debug active";
|
||||
//! piCout << "Value =" << cli.argumentValue("Value");
|
||||
//! return 0;
|
||||
//! }
|
||||
//! \endcode
|
||||
//!
|
||||
//! \~english These executions are similar:
|
||||
//! \~russian Эти вызовы будут идентичны:
|
||||
//!
|
||||
//! \~\code
|
||||
//! a.out -cd -v 10
|
||||
//! a.out --value 10 -dc
|
||||
//! a.out -c -v 10 -d
|
||||
//! a.out --console -d -v 10
|
||||
//! a.out --debug -c --value 10
|
||||
//! \endcode
|
||||
//! Этот класс предоставляет лог с опциональным выводом в файл и консоль.
|
||||
//!
|
||||
|
||||
|
||||
@@ -76,6 +42,10 @@ PILog::PILog(): PIThread(), log_ts(&log_file) {
|
||||
split_time = 8_h;
|
||||
timestamp_format = "yyyy-MM-dd hh:mm:ss.zzz";
|
||||
setLineFormat("t - c: m");
|
||||
id_by_cat[Level::Info] = PICout::registerExternalBufferID();
|
||||
id_by_cat[Level::Debug] = PICout::registerExternalBufferID();
|
||||
id_by_cat[Level::Warning] = PICout::registerExternalBufferID();
|
||||
id_by_cat[Level::Error] = PICout::registerExternalBufferID();
|
||||
CONNECTU(PICout::Notifier::object(), finished, this, coutDone);
|
||||
}
|
||||
|
||||
@@ -88,8 +58,10 @@ PILog::~PILog() {
|
||||
void PILog::setDir(const PIString & d) {
|
||||
stopAndWait();
|
||||
log_dir = d;
|
||||
PIDir::make(log_dir);
|
||||
newFile();
|
||||
if (output[File]) {
|
||||
PIDir::make(log_dir);
|
||||
newFile();
|
||||
}
|
||||
start();
|
||||
}
|
||||
|
||||
@@ -101,18 +73,28 @@ void PILog::setLineFormat(const PIString & f) {
|
||||
}
|
||||
|
||||
|
||||
PICout PILog::debug(PIObject * context) {
|
||||
return makePICout(context, Category::Debug);
|
||||
}
|
||||
|
||||
|
||||
PICout PILog::warning(PIObject * context) {
|
||||
return makePICout(context, Category::Warning);
|
||||
void PILog::setLevel(Level l) {
|
||||
max_level = l;
|
||||
}
|
||||
|
||||
|
||||
PICout PILog::error(PIObject * context) {
|
||||
return makePICout(context, Category::Error);
|
||||
return makePICout(context, Level::Error);
|
||||
}
|
||||
|
||||
|
||||
PICout PILog::warning(PIObject * context) {
|
||||
return makePICout(context, Level::Warning);
|
||||
}
|
||||
|
||||
|
||||
PICout PILog::info(PIObject * context) {
|
||||
return makePICout(context, Level::Info);
|
||||
}
|
||||
|
||||
|
||||
PICout PILog::debug(PIObject * context) {
|
||||
return makePICout(context, Level::Debug);
|
||||
}
|
||||
|
||||
|
||||
@@ -129,36 +111,27 @@ void PILog::stop() {
|
||||
|
||||
|
||||
void PILog::coutDone(int id, PIString * buffer) {
|
||||
cout_mutex.lock();
|
||||
if (!cout_cat_by_id.contains(id)) {
|
||||
cout_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
auto cat = cout_cat_by_id.take(id, PILog::Category::Debug);
|
||||
cout_mutex.unlock();
|
||||
if (!buffer) return;
|
||||
if (!id_by_cat.containsValue(id)) return;
|
||||
auto cat = id_by_cat.key(id, PILog::Level::Debug);
|
||||
if (cat > max_level) return;
|
||||
enqueue(*buffer, cat);
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
|
||||
PICout PILog::makePICout(PIObject * context, Category cat) {
|
||||
cout_mutex.lock();
|
||||
int id = ++cout_id;
|
||||
auto buffer = new PIString();
|
||||
cout_cat_by_id[id] = cat;
|
||||
cout_mutex.unlock();
|
||||
PICout PILog::makePICout(PIObject * context, Level cat) {
|
||||
auto buffer = new PIString();
|
||||
if (context) {
|
||||
*buffer = "["_a + context->className();
|
||||
if (context->name().isNotEmpty()) *buffer += " \"" + context->name() + "\"";
|
||||
*buffer += "] ";
|
||||
}
|
||||
return PICout::withExternalBuffer(buffer, id, PICoutManipulators::AddSpaces);
|
||||
return PICout::withExternalBuffer(buffer, id_by_cat.value(cat), PICoutManipulators::AddSpaces);
|
||||
}
|
||||
|
||||
|
||||
void PILog::enqueue(const PIString & msg, Category cat) {
|
||||
if (log_file.isClosed()) return;
|
||||
void PILog::enqueue(const PIString & msg, Level cat) {
|
||||
auto t = PIDateTime::fromSystemTime(PISystemTime::current());
|
||||
PIMutexLocker ml(log_mutex);
|
||||
queue.enqueue({cat, t, msg});
|
||||
@@ -166,7 +139,7 @@ void PILog::enqueue(const PIString & msg, Category cat) {
|
||||
|
||||
|
||||
PIString PILog::entryToString(const Entry & e) const {
|
||||
static PIStringList categories{"debug", "warn ", "error"};
|
||||
static PIStringList categories{"error", "warn ", "info ", "debug"};
|
||||
PIString t = e.time.toString(timestamp_format);
|
||||
PIString ret = line_format_p;
|
||||
ret.replace("${t}", t).replace("${c}", categories[static_cast<int>(e.cat)]).replace("${m}", e.msg);
|
||||
@@ -175,7 +148,7 @@ PIString PILog::entryToString(const Entry & e) const {
|
||||
|
||||
|
||||
void PILog::newFile() {
|
||||
PIString aname = app_name;
|
||||
PIString aname = log_name;
|
||||
if (aname.isNotEmpty()) aname += "__";
|
||||
log_file.open(log_dir + "/" + aname + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss") + ".log." +
|
||||
PIString::fromNumber(++part_number),
|
||||
@@ -184,9 +157,11 @@ void PILog::newFile() {
|
||||
|
||||
|
||||
void PILog::run() {
|
||||
if (split_tm.elapsed() >= split_time) {
|
||||
split_tm.reset();
|
||||
newFile();
|
||||
if (output[File]) {
|
||||
if (split_tm.elapsed() >= split_time) {
|
||||
split_tm.reset();
|
||||
newFile();
|
||||
}
|
||||
}
|
||||
log_mutex.lock();
|
||||
if (queue.isEmpty()) {
|
||||
@@ -204,7 +179,17 @@ void PILog::run() {
|
||||
auto qi = queue.dequeue();
|
||||
log_mutex.unlock();
|
||||
auto str = entryToString(qi);
|
||||
log_ts << str << "\n";
|
||||
piCout << str;
|
||||
if (log_file.isOpened()) log_ts << str << "\n";
|
||||
if (output[Console]) {
|
||||
PICout out(qi.cat == Level::Error ? piCerr : piCout);
|
||||
if (color_console) {
|
||||
switch (qi.cat) {
|
||||
case Level::Error: out << PICoutManipulators::Red; break;
|
||||
case Level::Warning: out << PICoutManipulators::Yellow; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
out << str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,61 +41,117 @@ public:
|
||||
PILog();
|
||||
~PILog();
|
||||
|
||||
//! \~english Message category
|
||||
//! \~russian Категория сообщения
|
||||
enum class Level {
|
||||
Error /** \~english Error \~russian Ошибка */,
|
||||
Warning /** \~english Warning \~russian Предупреждение */,
|
||||
Info /** \~english Information \~russian Информация */,
|
||||
Debug /** \~english Debug \~russian Отладка */,
|
||||
};
|
||||
|
||||
//! \~english Output channel
|
||||
//! \~russian Канал вывода
|
||||
enum Output {
|
||||
File /** \~english File \~russian Файл */ = 0x1,
|
||||
Console /** \~english Console \~russian Консоль */ = 0x2,
|
||||
All /** \~english All \~russian Все */ = 0xFF,
|
||||
};
|
||||
|
||||
//! \~english Set output channel \"o\" to \"on\".
|
||||
//! \~russian Установить канал вывода \"o\" в \"on\".
|
||||
void setOutput(Output o, bool on = true) { output.setFlag(o, on); }
|
||||
|
||||
//! \~english Returns prefix for filename.
|
||||
PIString applicationName() const { return app_name; }
|
||||
//! \~russian Возвращает префикс имени файла.
|
||||
PIString logName() const { return log_name; }
|
||||
|
||||
//! \~english Set prefix for filename. Should be set \b before \a setDir()!
|
||||
void setApplicationName(const PIString & n) { app_name = n; }
|
||||
//! \~russian Устанавливает префикс имени файла. Должен быть установлен \b до вызова \a setDir()!
|
||||
void setLogName(const PIString & n) { log_name = n; }
|
||||
|
||||
//! \~english Returns if color for console output enabled.
|
||||
//! \~russian Возвращает использовать ли цвет для вывода в консоль.
|
||||
bool colorConsole() const { return color_console; }
|
||||
|
||||
//! \~english Set color for console output enabled. True by default.
|
||||
//! \~russian Устанавливает использовать ли цвет для вывода в консоль. Включено по умолчанию.
|
||||
void setColorConsole(bool yes) { color_console = yes; }
|
||||
|
||||
|
||||
//! \~english Returns directory for log files.
|
||||
//! \~russian Возвращает директорию для файлов.
|
||||
PIString dir() const { return log_dir; }
|
||||
|
||||
//! \~english Set directory for log files. Should be set \b after \a setApplicationName()!
|
||||
//! \~english Set directory for log files. Should be set \b after \a setLogName()!
|
||||
//! \~russian Устанавливает директорию для файлов. Должна быть установлена \b после вызова \a setLogName()!
|
||||
void setDir(const PIString & d);
|
||||
|
||||
|
||||
//! \~english Returns lifetime for file.
|
||||
//! \~russian Возвращает время жизни файла.
|
||||
PISystemTime fileSplitTime() const { return split_time; }
|
||||
|
||||
//! \~english Set lifetime for file. Each "st" interval new file will be created.
|
||||
//! \~russian Устанавливает время жизни файла. Каждый интервал "st" будет создан новый файл.
|
||||
void setFileSplitTime(PISystemTime st) { split_time = st; }
|
||||
|
||||
|
||||
//! \~english Returns timestamp format for line.
|
||||
//! \~russian Возвращает формат метки времени для строки.
|
||||
PIString timestampFormat() const { return timestamp_format; }
|
||||
|
||||
//! \~english Set timestamp format for line. Default is "yyyy-MM-dd hh:mm:ss.zzz".
|
||||
//! \~russian Устанавливает формат метки времени для строки. По умолчанию "yyyy-MM-dd hh:mm:ss.zzz".
|
||||
void setTimestampFormat(const PIString & f) { timestamp_format = f; }
|
||||
|
||||
|
||||
//! \~english Returns line format.
|
||||
//! \~russian Возвращает формат строки.
|
||||
PIString lineFormat() const { return line_format; }
|
||||
|
||||
//! \~english Set line format. "t" is timestamp, "c" is category and "m" is message. Default is "t - c: m".
|
||||
//! \~russian Устанавливает формат строки. "t" - метка времени, "c" - категория и "m" - сообщение. По умолчанию "t - c: m".
|
||||
void setLineFormat(const PIString & f);
|
||||
|
||||
PICout debug(PIObject * context = nullptr);
|
||||
PICout warning(PIObject * context = nullptr);
|
||||
|
||||
//! \~english Returns maximum level.
|
||||
//! \~russian Возвращает максимальную категорию.
|
||||
Level level() const { return max_level; }
|
||||
|
||||
//! \~english Set maximum level. All levels greater than \"l\" will be ignored. Default is \a Level::Debug.
|
||||
//! \~russian Устанавливает максимальную категорию. Все сообщения с большей категорией, чем \"l\", будут игнорироваться. По умолчанию \a
|
||||
//! Level::Debug.
|
||||
void setLevel(Level l);
|
||||
|
||||
//! \~english Returns \a PICout for \a Level::Error level.
|
||||
//! \~russian Возвращает \a PICout для категории \a Level::Error.
|
||||
PICout error(PIObject * context = nullptr);
|
||||
|
||||
//! \~english Returns \a PICout for \a Level::Warning level.
|
||||
//! \~russian Возвращает \a PICout для категории \a Level::Warning.
|
||||
PICout warning(PIObject * context = nullptr);
|
||||
|
||||
//! \~english Returns \a PICout for \a Level::Info level.
|
||||
//! \~russian Возвращает \a PICout для категории \a Level::Info.
|
||||
PICout info(PIObject * context = nullptr);
|
||||
|
||||
//! \~english Returns \a PICout for \a Level::Debug level.
|
||||
//! \~russian Возвращает \a PICout для категории \a Level::Debug.
|
||||
PICout debug(PIObject * context = nullptr);
|
||||
|
||||
//! \~english Write all queued lines and stop. Also called in destructor.
|
||||
//! \~russian Записывает все строки из очереди и останавливается. Также вызывается в деструкторе.
|
||||
void stop();
|
||||
|
||||
private:
|
||||
enum class Category {
|
||||
Debug,
|
||||
Warning,
|
||||
Error
|
||||
};
|
||||
|
||||
EVENT_HANDLER2(void, coutDone, int, id, PIString *, buff);
|
||||
|
||||
PICout makePICout(PIObject * context, Category cat);
|
||||
void enqueue(const PIString & msg, Category cat = Category::Debug);
|
||||
PICout makePICout(PIObject * context, Level cat);
|
||||
void enqueue(const PIString & msg, Level cat = Level::Debug);
|
||||
|
||||
struct Entry {
|
||||
Category cat;
|
||||
Level cat;
|
||||
PIDateTime time;
|
||||
PIString msg;
|
||||
};
|
||||
@@ -104,14 +160,17 @@ private:
|
||||
void newFile();
|
||||
void run() override;
|
||||
|
||||
PIMutex log_mutex, cout_mutex;
|
||||
PIMutex log_mutex;
|
||||
PIFile log_file;
|
||||
PIIOTextStream log_ts;
|
||||
PITimeMeasurer split_tm;
|
||||
PISystemTime split_time;
|
||||
PIString log_dir, timestamp_format, line_format, line_format_p, app_name;
|
||||
PIString log_dir, timestamp_format, line_format, line_format_p, log_name;
|
||||
PIQueue<Entry> queue;
|
||||
PIMap<int, Category> cout_cat_by_id;
|
||||
PIMap<Level, int> id_by_cat;
|
||||
Level max_level = Level::Debug;
|
||||
PIFlags<Output> output = All;
|
||||
bool color_console = true;
|
||||
int part_number = -1, cout_id = -1;
|
||||
};
|
||||
|
||||
|
||||
@@ -19,13 +19,14 @@
|
||||
|
||||
#include "pisystemmonitor.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pidir.h"
|
||||
#include "piliterals_string.h"
|
||||
#include "piprocess.h"
|
||||
#include "pisysteminfo.h"
|
||||
#include "pitime_win.h"
|
||||
#include "pitranslator.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#ifdef WINDOWS
|
||||
# include <psapi.h>
|
||||
# include <tlhelp32.h>
|
||||
@@ -107,14 +108,14 @@ bool PISystemMonitor::startOnProcess(int pID, PISystemTime interval) {
|
||||
PRIVATE->file.open(PRIVATE->proc_dir + "stat", PIIODevice::ReadOnly);
|
||||
PRIVATE->filem.open(PRIVATE->proc_dir + "statm", PIIODevice::ReadOnly);
|
||||
if (!PRIVATE->file.isOpened()) {
|
||||
piCoutObj << "Can`t find process with ID = " << pID_ << "!";
|
||||
piCoutObj << "Can`t find process with ID = %1!"_tr("PISystemMonitor").arg(pID_);
|
||||
return false;
|
||||
}
|
||||
# endif
|
||||
# else
|
||||
PRIVATE->hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pID_);
|
||||
if (PRIVATE->hProc == 0) {
|
||||
piCoutObj << "Can`t open process with ID = " << pID_ << "," << errorString();
|
||||
piCoutObj << "Can`t open process with ID = %1, %2!"_tr("PISystemMonitor").arg(pID_).arg(errorString());
|
||||
return false;
|
||||
}
|
||||
PRIVATE->tm.reset();
|
||||
@@ -376,12 +377,12 @@ void PISystemMonitor::gatherThread(llong id) {
|
||||
FILETIME times[4];
|
||||
HANDLE thdl = OpenThread(THREAD_QUERY_INFORMATION, FALSE, DWORD(id));
|
||||
if (!thdl) {
|
||||
piCout << "[PISystemMonitor] gatherThread(" << id << "):: OpenThread() error:" << errorString();
|
||||
piCoutObj << "GatherThread(" << id << "):: OpenThread() error:" << errorString();
|
||||
return;
|
||||
}
|
||||
if (GetThreadTimes(thdl, &(times[0]), &(times[1]), &(times[2]), &(times[3])) == 0) {
|
||||
CloseHandle(thdl);
|
||||
piCout << "[PISystemMonitor] gatherThread(" << id << "):: GetThreadTimes() error:" << errorString();
|
||||
piCoutObj << "GatherThread(" << id << "):: GetThreadTimes() error:" << errorString();
|
||||
return;
|
||||
}
|
||||
CloseHandle(thdl);
|
||||
|
||||
116
libs/main/application/pitranslator.cpp
Normal file
116
libs/main/application/pitranslator.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Translation support
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pitranslator.h"
|
||||
|
||||
#include "pidir.h"
|
||||
#include "pifile.h"
|
||||
#include "piliterals_string.h"
|
||||
#include "pitranslator_p.h"
|
||||
#include "pivaluetree_conversions.h"
|
||||
|
||||
|
||||
//! \class PITranslator pitranslator.h
|
||||
//! \details
|
||||
//! \~english \section PITranslator_sec0 Synopsis
|
||||
//! \~russian \section PITranslator_sec0 Краткий обзор
|
||||
//! \~english
|
||||
//!
|
||||
//! \~russian
|
||||
//!
|
||||
|
||||
|
||||
PRIVATE_DEFINITION_START(PITranslator)
|
||||
PITranslatorPrivate::Translation content;
|
||||
PRIVATE_DEFINITION_END(PITranslator)
|
||||
|
||||
|
||||
PIString PITranslator::tr(const PIString & in, const PIString & context) {
|
||||
return instance()->PRIVATEWB->content.translate(in, context);
|
||||
}
|
||||
|
||||
|
||||
void PITranslator::clear() {
|
||||
instance()->PRIVATEWB->content.clear();
|
||||
}
|
||||
|
||||
|
||||
void PITranslator::loadLang(const PIString & short_lang, PIString dir) {
|
||||
if (dir.isEmpty()) dir = PIDir::current().absolute("lang");
|
||||
clear();
|
||||
auto files = PIDir(dir).entries();
|
||||
for (const auto & f: files) {
|
||||
if (!f.baseName().endsWith(short_lang)) continue;
|
||||
loadFile(f.path);
|
||||
}
|
||||
piCout << "Loaded %1 string for lang \"%2\""_a.arg(instance()->PRIVATEWB->content.count()).arg(short_lang);
|
||||
/*auto s = instance();
|
||||
auto vt = PIValueTreeConversions::fromText(getBuiltinConfig());
|
||||
auto lang = vt.child(short_lang.toLowerCase().trim());
|
||||
for (const auto & cn: lang.children()) {
|
||||
auto c = s->PRIVATEWB->content.createContext(cn.name());
|
||||
for (const auto & s: cn.children())
|
||||
c->add(s.name(), s.value().toString());
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
void PITranslator::loadConfig(const PIString & content) {
|
||||
auto s = instance();
|
||||
auto lang = PIValueTreeConversions::fromText(content);
|
||||
for (const auto & cn: lang.children()) {
|
||||
auto c = s->PRIVATEWB->content.createContext(cn.name());
|
||||
for (const auto & s: cn.children())
|
||||
c->add(s.name(), s.value().toString());
|
||||
}
|
||||
auto c = s->PRIVATEWB->content.createContext("");
|
||||
for (const auto & s: lang.children()) {
|
||||
if (s.hasChildren()) continue;
|
||||
c->add(s.name(), s.value().toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PITranslator::load(const PIByteArray & content) {
|
||||
return instance()->PRIVATEWB->content.load(content);
|
||||
}
|
||||
|
||||
|
||||
bool PITranslator::loadFile(const PIString & path) {
|
||||
PIFile f(path, PIIODevice::ReadOnly);
|
||||
if (f.isClosed()) return false;
|
||||
if (!PITranslatorPrivate::checkHeader(&f)) return false;
|
||||
auto data = f.readAll();
|
||||
data.remove(0, PITranslatorPrivate::headerSize());
|
||||
return load(data);
|
||||
}
|
||||
|
||||
|
||||
PITranslator::PITranslator() {}
|
||||
|
||||
|
||||
PITranslator::~PITranslator() {
|
||||
PRIVATE->content.clear();
|
||||
}
|
||||
|
||||
|
||||
PITranslator * PITranslator::instance() {
|
||||
static PITranslator ret;
|
||||
return &ret;
|
||||
}
|
||||
98
libs/main/application/pitranslator.h
Normal file
98
libs/main/application/pitranslator.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*! \file pitranslator.h
|
||||
* \ingroup Application
|
||||
* \~\brief
|
||||
* \~english Translation support
|
||||
* \~russian Поддержка перевода
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Translation support
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef pitranslator_H
|
||||
#define pitranslator_H
|
||||
|
||||
#include "pistring.h"
|
||||
|
||||
|
||||
#define piTr PITranslator::tr
|
||||
#define piTrNoOp PITranslator::trNoOp
|
||||
|
||||
//! \ingroup Application
|
||||
//! \~\brief
|
||||
//! \~english Translation support
|
||||
//! \~russian Поддержка перевода
|
||||
class PIP_EXPORT PITranslator {
|
||||
public:
|
||||
static PIString tr(const PIString & in, const PIString & context = {});
|
||||
static PIString tr(const char * in, const PIString & context = {}) { return tr(PIString::fromUTF8(in), context); }
|
||||
static PIString trNoOp(const PIString & in, const PIString & context = {}) { return in; }
|
||||
static PIString trNoOp(const char * in, const PIString & context = {}) { return trNoOp(PIString::fromUTF8(in), context); }
|
||||
|
||||
static void clear();
|
||||
static void loadLang(const PIString & short_lang, PIString dir = {});
|
||||
static void loadConfig(const PIString & content);
|
||||
static bool load(const PIByteArray & content);
|
||||
static bool loadFile(const PIString & path);
|
||||
|
||||
private:
|
||||
PITranslator();
|
||||
~PITranslator();
|
||||
NO_COPY_CLASS(PITranslator)
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
|
||||
static PITranslator * instance();
|
||||
};
|
||||
|
||||
|
||||
class PIStringContextTr {
|
||||
public:
|
||||
PIStringContextTr(PIString && s): _s(s) {}
|
||||
operator PIString() const { return PITranslator::tr(_s); }
|
||||
PIString operator()(const PIString & ctx = {}) const { return PITranslator::tr(_s, ctx); }
|
||||
|
||||
private:
|
||||
PIString _s;
|
||||
};
|
||||
|
||||
|
||||
class PIStringContextTrNoOp {
|
||||
public:
|
||||
PIStringContextTrNoOp(PIString && s): _s(s) {}
|
||||
operator PIString() const { return _s; }
|
||||
PIString operator()(const PIString & ctx = {}) const { return _s; }
|
||||
|
||||
private:
|
||||
PIString _s;
|
||||
};
|
||||
|
||||
|
||||
//! \~\brief
|
||||
//! \~english Translate string with \a PITranslator::tr()
|
||||
//! \~russian Перевести строку с помощью \a PITranslator::tr()
|
||||
inline PIStringContextTr operator""_tr(const char * v, size_t sz) {
|
||||
return PIStringContextTr(PIString::fromUTF8(v, sz));
|
||||
}
|
||||
|
||||
//! \~\brief
|
||||
//! \~english Translate string with \a PITranslator::tr()
|
||||
//! \~russian Перевести строку с помощью \a PITranslator::tr()
|
||||
inline PIStringContextTrNoOp operator""_trNoOp(const char * v, size_t sz) {
|
||||
return PIStringContextTrNoOp(PIString::fromUTF8(v, sz));
|
||||
}
|
||||
|
||||
#endif
|
||||
124
libs/main/application/pitranslator_p.cpp
Normal file
124
libs/main/application/pitranslator_p.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Translation private
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pitranslator_p.h"
|
||||
|
||||
#include "pichunkstream.h"
|
||||
#include "piiodevice.h"
|
||||
|
||||
constexpr int currentVersion = 1;
|
||||
const PIByteArray fileHeader("PIPBTF", 6);
|
||||
|
||||
|
||||
void PITranslatorPrivate::Context::add(const PIMap<uint, PIString> & sm) {
|
||||
auto it = sm.makeIterator();
|
||||
while (it.next())
|
||||
strings[it.key()] = it.value();
|
||||
}
|
||||
|
||||
|
||||
void PITranslatorPrivate::Translation::clear() {
|
||||
piDeleteAll(contexts.values());
|
||||
contexts.clear();
|
||||
lang.clear();
|
||||
}
|
||||
|
||||
|
||||
PITranslatorPrivate::Context * PITranslatorPrivate::Translation::createContext(const PIString & context) {
|
||||
return createContext(context.hash());
|
||||
}
|
||||
|
||||
|
||||
PITranslatorPrivate::Context * PITranslatorPrivate::Translation::createContext(uint hash) {
|
||||
auto & ret(contexts[hash]);
|
||||
if (!ret) ret = new Context();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PITranslatorPrivate::Translation::translate(const PIString & in, const PIString & context) {
|
||||
auto c = contexts.value(context.hash());
|
||||
if (!c) return in;
|
||||
return c->strings.value(in.hash(), in);
|
||||
}
|
||||
|
||||
|
||||
bool PITranslatorPrivate::Translation::load(const PIByteArray & data) {
|
||||
if (data.size_s() <= 4) return false;
|
||||
PIChunkStream cs(data);
|
||||
Context * ctx = nullptr;
|
||||
PIMap<uint, PIString> strings;
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1: {
|
||||
int version = cs.getData<int>();
|
||||
if (version != currentVersion) {
|
||||
piCout << "Invalid translation version!";
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
case 3: {
|
||||
uint ctx_hash = cs.getData<uint>();
|
||||
ctx = createContext(ctx_hash);
|
||||
} break;
|
||||
case 4: {
|
||||
cs.get(strings);
|
||||
if (ctx) ctx->add(strings);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int PITranslatorPrivate::Translation::count() const {
|
||||
int ret = 0;
|
||||
auto cit = contexts.makeIterator();
|
||||
while (cit.next())
|
||||
ret += cit.value()->strings.size_s();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PITranslatorPrivate::Translation::save() {
|
||||
PIChunkStream cs;
|
||||
cs.add(1, currentVersion).add(2, lang);
|
||||
auto cit = contexts.makeIterator();
|
||||
while (cit.next()) {
|
||||
cs.add(3, cit.key()).add(4, cit.value()->strings);
|
||||
}
|
||||
return cs.data();
|
||||
}
|
||||
|
||||
|
||||
int PITranslatorPrivate::headerSize() {
|
||||
return fileHeader.size_s();
|
||||
}
|
||||
|
||||
|
||||
bool PITranslatorPrivate::checkHeader(PIIODevice * d) {
|
||||
if (!d) return false;
|
||||
return d->read(fileHeader.size_s()) == fileHeader;
|
||||
}
|
||||
|
||||
|
||||
void PITranslatorPrivate::writeHeader(PIIODevice * d) {
|
||||
if (!d) return;
|
||||
d->write(fileHeader);
|
||||
}
|
||||
53
libs/main/application/pitranslator_p.h
Normal file
53
libs/main/application/pitranslator_p.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Translation private
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef pitranslator_p_H
|
||||
#define pitranslator_p_H
|
||||
|
||||
#include "pistring.h"
|
||||
|
||||
class PIIODevice;
|
||||
|
||||
namespace PITranslatorPrivate {
|
||||
|
||||
struct PIP_EXPORT Context {
|
||||
void add(const PIString & in, const PIString & out) { strings[in.hash()] = out; }
|
||||
void add(const PIMap<uint, PIString> & sm);
|
||||
PIMap<uint, PIString> strings;
|
||||
};
|
||||
|
||||
struct PIP_EXPORT Translation {
|
||||
void clear();
|
||||
Context * createContext(const PIString & context);
|
||||
Context * createContext(uint hash);
|
||||
PIString translate(const PIString & in, const PIString & context);
|
||||
bool load(const PIByteArray & data);
|
||||
int count() const;
|
||||
PIByteArray save();
|
||||
PIString lang;
|
||||
PIMap<uint, Context *> contexts;
|
||||
};
|
||||
|
||||
PIP_EXPORT int headerSize();
|
||||
PIP_EXPORT bool checkHeader(PIIODevice * d);
|
||||
PIP_EXPORT void writeHeader(PIIODevice * d);
|
||||
|
||||
} // namespace PITranslatorPrivate
|
||||
|
||||
#endif
|
||||
@@ -26,6 +26,7 @@
|
||||
#define piclientserver_client_base_H
|
||||
|
||||
#include "piclientserver_config.h"
|
||||
#include "pidiagnostics.h"
|
||||
#include "pip_client_server_export.h"
|
||||
#include "pistreampacker.h"
|
||||
|
||||
@@ -47,16 +48,23 @@ public:
|
||||
const PIEthernet * getTCP() const { return tcp; }
|
||||
|
||||
void close();
|
||||
void stopAndWait();
|
||||
|
||||
int write(const void * d, const size_t s);
|
||||
int write(const PIByteArray & ba) { return write(ba.data(), ba.size()); }
|
||||
|
||||
void enableDiagnostics();
|
||||
PIDiagnostics::State diagnostics() const;
|
||||
int receivePacketProgress() const;
|
||||
|
||||
Config & configuration() { return config; }
|
||||
|
||||
protected:
|
||||
virtual void readed(PIByteArray data) {}
|
||||
virtual void connected() {}
|
||||
virtual void disconnected() {}
|
||||
virtual void receivePacketStart(int size) {}
|
||||
virtual void receivePacketEnd() {}
|
||||
|
||||
void init();
|
||||
|
||||
@@ -70,6 +78,7 @@ private:
|
||||
|
||||
PIStreamPacker stream;
|
||||
mutable PIMutex write_mutex;
|
||||
PIDiagnostics * diag = nullptr;
|
||||
};
|
||||
|
||||
} // namespace PIClientServer
|
||||
|
||||
@@ -49,6 +49,9 @@ public:
|
||||
void listen(PINetworkAddress addr);
|
||||
void listenAll(ushort port) { listen({0, port}); }
|
||||
|
||||
void stopServer();
|
||||
void closeAll();
|
||||
|
||||
int getMaxClients() const { return max_clients; }
|
||||
void setMaxClients(int new_max_clients);
|
||||
int clientsCount() const;
|
||||
@@ -59,7 +62,6 @@ public:
|
||||
Config & configuration() { return config; }
|
||||
|
||||
private:
|
||||
void stopServer();
|
||||
void newClient(ServerClient * c);
|
||||
void clientDisconnected(ServerClient * c);
|
||||
|
||||
|
||||
57
libs/main/client_server/piclientservermodule.h
Normal file
57
libs/main/client_server/piclientservermodule.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Module includes
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//! \defgroup ClientServer ClientServer
|
||||
//! \~\brief
|
||||
//! \~english TCP Client-Server
|
||||
//! \~russian TCP Клиент-Сервер
|
||||
//!
|
||||
//! \~\details
|
||||
//! \~english \section cmake_module_ClientServer Building with CMake
|
||||
//! \~russian \section cmake_module_ClientServer Сборка с использованием CMake
|
||||
//!
|
||||
//! \~\code
|
||||
//! find_package(PIP REQUIRED)
|
||||
//! target_link_libraries([target] PIP::ClientServer)
|
||||
//! \endcode
|
||||
//!
|
||||
//! \~english \par Common
|
||||
//! \~russian \par Общее
|
||||
//!
|
||||
//! \~english
|
||||
//! These files provides server with clients dispatching for server-side and client for client-side.
|
||||
//!
|
||||
//! \~russian
|
||||
//! Эти файлы предоставляют сервер с диспетчеризацией клиентов для серверной стороны и клиента для клиентской стороны.
|
||||
//!
|
||||
//! \~\authors
|
||||
//! \~english
|
||||
//! Ivan Pelipenko peri4ko@yandex.ru;
|
||||
//! Andrey Bychkov work.a.b@yandex.ru;
|
||||
//! \~russian
|
||||
//! Иван Пелипенко peri4ko@yandex.ru;
|
||||
//! Андрей Бычков work.a.b@yandex.ru;
|
||||
//!
|
||||
|
||||
#ifndef PICLIENTSERVERMODULE_H
|
||||
#define PICLIENTSERVERMODULE_H
|
||||
|
||||
#include "piclientserver_client.h"
|
||||
#include "piclientserver_server.h"
|
||||
|
||||
#endif
|
||||
@@ -343,6 +343,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
static const PIString s_typedef = PIStringAscii("typedef");
|
||||
static const PIString s_namespace = PIStringAscii("namespace");
|
||||
static const PIString s_template = PIStringAscii("template");
|
||||
static const PIString s_L = PIStringAscii("$L");
|
||||
|
||||
bool mlc = false, cc = false;
|
||||
int mls = 0, ole = -1, /*ccs = 0,*/ end = 0;
|
||||
@@ -365,8 +366,9 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
}
|
||||
if (i > 0)
|
||||
if (c == '\\' && fc[i - 1].toAscii() != '\\') {
|
||||
fc.cutMid(i, 2);
|
||||
--i;
|
||||
fc.cutMid(i, 1);
|
||||
fc.replace(i, 1, s_L);
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (cc) continue;
|
||||
@@ -390,6 +392,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
}
|
||||
}
|
||||
pfc = procMacros(fc);
|
||||
pfc.removeAll(s_L);
|
||||
|
||||
if (main) return true;
|
||||
|
||||
@@ -495,6 +498,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
MetaMap smeta = maybeMeta(pfc);
|
||||
meta << smeta;
|
||||
}
|
||||
// piCout << "pfc E" << cur_namespace << "," << tmp;
|
||||
parseEnum(0, cur_namespace + tmp, pfc.takeRange('{', '}'), meta);
|
||||
pfc.takeSymbol();
|
||||
continue;
|
||||
@@ -610,8 +614,8 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
|
||||
int ps = -1;
|
||||
bool def = false;
|
||||
PIString prev_namespace = cur_namespace, stmp;
|
||||
if (ce) cur_namespace += ce->name + s_ns;
|
||||
// piCout << "parse class" << ce->name << "namespace" << cur_namespace;
|
||||
if (ce) cur_namespace = ce->name + s_ns;
|
||||
// piCout << "parse class" << (ce ? ce->name : "NULL") << "namespace" << cur_namespace;
|
||||
// piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
|
||||
while (!fc.isEmpty()) {
|
||||
PIString cw = fc.takeCWord(), tmp;
|
||||
@@ -663,6 +667,7 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
|
||||
MetaMap smeta = maybeMeta(fc);
|
||||
meta << smeta;
|
||||
}
|
||||
// piCout << "pc E" << cur_namespace << "," << tmp;
|
||||
parseEnum(ce, cur_namespace + tmp, fc.takeRange('{', '}'), meta);
|
||||
fc.takeSymbol();
|
||||
continue;
|
||||
@@ -1248,6 +1253,7 @@ PIString PICodeParser::procMacros(PIString fc) {
|
||||
static const PIString s_elif = PIStringAscii("elif");
|
||||
static const PIString s_else = PIStringAscii("else");
|
||||
static const PIString s_endif = PIStringAscii("endif");
|
||||
static const PIString s_L = PIStringAscii("$L");
|
||||
if (fc.isEmpty()) return PIString();
|
||||
int ifcnt = 0;
|
||||
bool grab = false, skip = false, cond_ok = false;
|
||||
@@ -1337,7 +1343,9 @@ bool PICodeParser::parseDirective(PIString d) {
|
||||
static const PIString s_define = PIStringAscii("define");
|
||||
static const PIString s_undef = PIStringAscii("undef");
|
||||
static const PIString s_PIMETA = PIStringAscii("PIMETA");
|
||||
static const PIString s_L = PIStringAscii("$L");
|
||||
if (d.isEmpty()) return true;
|
||||
d.replaceAll(s_L, '\n');
|
||||
PIString dname = d.takeCWord();
|
||||
// piCout << "parseDirective" << d;
|
||||
if (dname == s_include) {
|
||||
|
||||
@@ -220,7 +220,6 @@ void PIKbdListener::readKeyboard() {
|
||||
#ifdef WINDOWS
|
||||
INPUT_RECORD ir;
|
||||
ReadConsoleInput(PRIVATE->hIn, &ir, 1, &(PRIVATE->ret));
|
||||
// piCout << ir.EventType;
|
||||
switch (ir.EventType) {
|
||||
case KEY_EVENT: {
|
||||
KEY_EVENT_RECORD ker = ir.Event.KeyEvent;
|
||||
@@ -361,8 +360,7 @@ void PIKbdListener::readKeyboard() {
|
||||
if (mer.dwEventFlags & MOUSE_WHEELED) {
|
||||
memcpy((void *)(&we), (const void *)(&me), sizeof(me));
|
||||
we.action = MouseWheel;
|
||||
we.direction = short((mer.dwButtonState >> 8) & 0xFFFF) > 0;
|
||||
// piCout << "wheel" << we.direction;
|
||||
we.direction = short((mer.dwButtonState >> 16) & 0xFFFF) > 0;
|
||||
wheelEvent(we, kbddata_);
|
||||
break;
|
||||
} else {
|
||||
@@ -542,6 +540,11 @@ void PIKbdListener::readKeyboard() {
|
||||
}
|
||||
|
||||
|
||||
void PIKbdListener::stop() {
|
||||
PIThread::stop();
|
||||
}
|
||||
|
||||
|
||||
void PIKbdListener::end() {
|
||||
// cout << "list end" << endl;
|
||||
#ifdef WINDOWS
|
||||
|
||||
@@ -180,6 +180,8 @@ public:
|
||||
|
||||
void readKeyboard();
|
||||
|
||||
void stop();
|
||||
|
||||
//! Returns if keyboard listening is active (not running!)
|
||||
bool isActive() { return is_active; }
|
||||
|
||||
|
||||
@@ -1383,7 +1383,7 @@ public:
|
||||
if (v.isEmpty()) return *this;
|
||||
#ifndef NDEBUG
|
||||
if (&v == this) {
|
||||
printf("error with PIDeque<%s>::insert\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>::insert\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(&v != this);
|
||||
@@ -1738,7 +1738,7 @@ public:
|
||||
if (v.isEmpty()) return *this;
|
||||
#ifndef NDEBUG
|
||||
if (&v == this) {
|
||||
printf("error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(&v != this);
|
||||
@@ -2400,7 +2400,7 @@ public:
|
||||
if (isEmpty()) return ret;
|
||||
#ifndef NDEBUG
|
||||
if (rows * cols != pid_size) {
|
||||
printf("error with PIDeque<%s>::reshape\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>::reshape\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(rows * cols == pid_size);
|
||||
@@ -2689,7 +2689,7 @@ private:
|
||||
T * p_d = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(pid_data), as * sizeof(T)));
|
||||
#ifndef NDEBUG
|
||||
if (!p_d) {
|
||||
printf("error with PIDeque<%s>::alloc\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>::alloc\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(p_d);
|
||||
|
||||
@@ -355,7 +355,7 @@ public:
|
||||
inline PIMap<Key, T> & operator<<(const PIMap<Key, T> & other) {
|
||||
#ifndef NDEBUG
|
||||
if (&other == this) {
|
||||
printf("error with PIMap<%s, %s>::<<\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIMap<%s, %s>::<<\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(&other != this);
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
template<typename T>
|
||||
class PISet: public PIMap<T, uchar> {
|
||||
typedef PIMap<T, uchar> _CSet;
|
||||
template<typename P, typename T1>
|
||||
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PISet<T1> & v);
|
||||
template<typename P, typename T1>
|
||||
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PISet<T1> & v);
|
||||
|
||||
public:
|
||||
//! Contructs an empty set
|
||||
|
||||
@@ -1341,7 +1341,7 @@ public:
|
||||
if (v.isEmpty()) return *this;
|
||||
#ifndef NDEBUG
|
||||
if (&v == this) {
|
||||
printf("error with PIVector<%s>::insert\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>::insert\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(&v != this);
|
||||
@@ -1663,7 +1663,7 @@ public:
|
||||
if (v.isEmpty()) return *this;
|
||||
#ifndef NDEBUG
|
||||
if (&v == this) {
|
||||
printf("error with PIVector<%s>::push_back\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>::push_back\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(&v != this);
|
||||
@@ -2296,7 +2296,7 @@ public:
|
||||
inline PIVector<PIVector<T>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const {
|
||||
#ifndef NDEBUG
|
||||
if (rows * cols != piv_size) {
|
||||
printf("error with PIVector<%s>::reshape\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>::reshape\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(rows * cols == piv_size);
|
||||
@@ -2565,7 +2565,7 @@ private:
|
||||
T * p_d = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(piv_data), as * sizeof(T)));
|
||||
#ifndef NDEBUG
|
||||
if (!p_d) {
|
||||
printf("error with PIVector<%s>::alloc\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>::alloc\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
#endif
|
||||
assert(p_d);
|
||||
|
||||
@@ -132,9 +132,7 @@ inline void piSwapBinary(const void *& f, const void *& s) {
|
||||
//! \~english Example:\n \snippet piincludes.cpp compareBinary
|
||||
//! \~russian Пример:\n \snippet piincludes.cpp compareBinary
|
||||
inline bool piCompareBinary(const void * f, const void * s, size_t size) {
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
if (((const uchar *)f)[i] != ((const uchar *)s)[i]) return false;
|
||||
return true;
|
||||
return 0 == memcmp(f, s, size);
|
||||
}
|
||||
|
||||
//! \~\brief
|
||||
@@ -677,15 +675,28 @@ public:
|
||||
//! \~\brief
|
||||
//! \~english Destructor that executes the function if it exists
|
||||
//! \~russian Деструктор, который выполняет функцию, если она существует
|
||||
~PIScopeExitCall() {
|
||||
if (func) func();
|
||||
}
|
||||
~PIScopeExitCall() { call(); }
|
||||
|
||||
//! \~\brief
|
||||
//! \~english Method for canceling the function
|
||||
//! \~russian Метод для отмены функции
|
||||
void cancel() { func = nullptr; }
|
||||
|
||||
//! \~\brief
|
||||
//! \~english Method for call the function
|
||||
//! \~russian Метод для вызова функции
|
||||
void call() {
|
||||
if (func) func();
|
||||
}
|
||||
|
||||
//! \~\brief
|
||||
//! \~english Method for call and canceling the function
|
||||
//! \~russian Метод для вызова и отмены функции
|
||||
void callAndCancel() {
|
||||
call();
|
||||
cancel();
|
||||
}
|
||||
|
||||
private:
|
||||
NO_COPY_CLASS(PIScopeExitCall)
|
||||
|
||||
@@ -707,4 +718,20 @@ struct PIP_EXPORT PINonTriviallyCopyable {
|
||||
inline PINonTriviallyCopyable::PINonTriviallyCopyable(PINonTriviallyCopyable &&) noexcept = default;
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct FunctionType {
|
||||
using Type = void;
|
||||
};
|
||||
|
||||
template<typename Ret, typename Class, typename... Args>
|
||||
struct FunctionType<Ret (Class::*)(Args...) const> {
|
||||
using Type = std::function<Ret(Args...)>;
|
||||
};
|
||||
|
||||
template<typename L>
|
||||
typename FunctionType<decltype(&L::operator())>::Type toStdFunction(L const & func) {
|
||||
return func;
|
||||
}
|
||||
|
||||
|
||||
#endif // PIBASE_H
|
||||
|
||||
@@ -141,7 +141,7 @@ PIString & PICout::__string__() {
|
||||
return *ret;
|
||||
}
|
||||
|
||||
PICout::OutputDevices PICout::devs = PICout::StdOut;
|
||||
PICout::OutputDevices PICout::devs = PICout::Console;
|
||||
|
||||
PRIVATE_DEFINITION_START(PICout)
|
||||
PIStack<PICoutControls> cos_;
|
||||
@@ -158,45 +158,65 @@ WORD PICout::__Private__::dattr = 0;
|
||||
DWORD PICout::__Private__::smode = 0;
|
||||
#endif
|
||||
|
||||
PICout::PICout(int controls): fo_(true), cc_(false), fc_(false), act_(true), cnb_(10), co_(controls) {
|
||||
buffer_ = nullptr;
|
||||
|
||||
std::ostream & getStdStream(PICoutStdStream s) {
|
||||
switch (s) {
|
||||
case PICoutStdStream::StdOut: return std::cout;
|
||||
case PICoutStdStream::StdErr: return std::cerr;
|
||||
default: break;
|
||||
}
|
||||
return std::cout;
|
||||
}
|
||||
|
||||
std::wostream & getStdWStream(PICoutStdStream s) {
|
||||
switch (s) {
|
||||
case PICoutStdStream::StdOut: return std::wcout;
|
||||
case PICoutStdStream::StdErr: return std::wcerr;
|
||||
default: break;
|
||||
}
|
||||
return std::wcout;
|
||||
}
|
||||
|
||||
|
||||
PICout::PICout(int controls, PICoutStdStream stream): ctrl_(controls), stream_(stream) {
|
||||
init();
|
||||
}
|
||||
|
||||
PICout::PICout(bool active): fo_(true), cc_(false), fc_(false), act_(active), cnb_(10), co_(PICoutManipulators::DefaultControls) {
|
||||
buffer_ = nullptr;
|
||||
if (act_) init();
|
||||
PICout::PICout(bool active, PICoutStdStream stream): actve_(active), stream_(stream) {
|
||||
if (actve_) init();
|
||||
}
|
||||
|
||||
|
||||
PICout::PICout(const PICout & other)
|
||||
: fo_(other.fo_)
|
||||
, cc_(true)
|
||||
, fc_(false)
|
||||
, act_(other.act_)
|
||||
, cnb_(other.cnb_)
|
||||
, attr_(other.attr_)
|
||||
: first_out_(other.first_out_)
|
||||
, is_copy_(true)
|
||||
, actve_(other.actve_)
|
||||
, int_base_(other.int_base_)
|
||||
, win_attr_(other.win_attr_)
|
||||
, id_(other.id_)
|
||||
, buffer_(other.buffer_)
|
||||
, co_(other.co_) {}
|
||||
, ctrl_(other.ctrl_)
|
||||
, stream_(other.stream_) {}
|
||||
|
||||
|
||||
PICout::~PICout() {
|
||||
if (!act_) return;
|
||||
if (fc_) applyFormat(PICoutManipulators::Default);
|
||||
if (cc_) return;
|
||||
if (!actve_) return;
|
||||
if (format_changed_) applyFormat(PICoutManipulators::Default);
|
||||
if (is_copy_) return;
|
||||
newLine();
|
||||
if ((co_ & NoLock) != NoLock) {
|
||||
if ((ctrl_ & NoLock) != NoLock) {
|
||||
PICout::__mutex__().unlock();
|
||||
}
|
||||
if (buffer_) {
|
||||
((NotifierObject *)Notifier::object())->finished(id_, buffer_);
|
||||
} else {
|
||||
getStdStream(stream_).flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::operator<<(PICoutAction v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
#ifdef WINDOWS
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
COORD coord;
|
||||
@@ -204,12 +224,12 @@ PICout & PICout::operator<<(PICoutAction v) {
|
||||
#endif
|
||||
switch (v) {
|
||||
case PICoutManipulators::Flush:
|
||||
if (!buffer_ && isOutputDeviceActive(StdOut)) {
|
||||
std::cout << std::flush;
|
||||
if (!buffer_ && isOutputDeviceActive(Console)) {
|
||||
getStdStream(stream_) << std::flush;
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::Backspace:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
if (isOutputDeviceActive(Console)) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
||||
coord = sbi.dwCursorPosition;
|
||||
@@ -223,7 +243,7 @@ PICout & PICout::operator<<(PICoutAction v) {
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::ShowCursor:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
if (isOutputDeviceActive(Console)) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleCursorInfo(__Private__::hOut, &curinfo);
|
||||
curinfo.bVisible = true;
|
||||
@@ -234,7 +254,7 @@ PICout & PICout::operator<<(PICoutAction v) {
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::HideCursor:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
if (isOutputDeviceActive(Console)) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleCursorInfo(__Private__::hOut, &curinfo);
|
||||
curinfo.bVisible = false;
|
||||
@@ -245,7 +265,7 @@ PICout & PICout::operator<<(PICoutAction v) {
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::ClearLine:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
if (isOutputDeviceActive(Console)) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
||||
coord = sbi.dwCursorPosition;
|
||||
@@ -266,7 +286,7 @@ PICout & PICout::operator<<(PICoutAction v) {
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::ClearScreen:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
if (isOutputDeviceActive(Console)) {
|
||||
#ifdef WINDOWS
|
||||
/// TODO : wondows ClearScreen !!!
|
||||
#else
|
||||
@@ -282,12 +302,31 @@ PICout & PICout::operator<<(PICoutAction v) {
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::setControl(PICoutManipulators::PICoutControl c, bool on) {
|
||||
ctrl_.setFlag(c, on);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::setControls(PICoutManipulators::PICoutControls c) {
|
||||
ctrl_ = c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::saveAndSetControls(PICoutManipulators::PICoutControls c) {
|
||||
saveControls();
|
||||
ctrl_ = c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::operator<<(PICoutManipulators::PICoutFormat v) {
|
||||
switch (v) {
|
||||
case PICoutManipulators::Bin: cnb_ = 2; break;
|
||||
case PICoutManipulators::Oct: cnb_ = 8; break;
|
||||
case PICoutManipulators::Dec: cnb_ = 10; break;
|
||||
case PICoutManipulators::Hex: cnb_ = 16; break;
|
||||
case PICoutManipulators::Bin: int_base_ = 2; break;
|
||||
case PICoutManipulators::Oct: int_base_ = 8; break;
|
||||
case PICoutManipulators::Dec: int_base_ = 10; break;
|
||||
case PICoutManipulators::Hex: int_base_ = 16; break;
|
||||
default: applyFormat(v);
|
||||
};
|
||||
return *this;
|
||||
@@ -295,10 +334,10 @@ PICout & PICout::operator<<(PICoutManipulators::PICoutFormat v) {
|
||||
|
||||
|
||||
PICout & PICout::operator<<(PIFlags<PICoutManipulators::PICoutFormat> v) {
|
||||
if (v[PICoutManipulators::Bin]) cnb_ = 2;
|
||||
if (v[PICoutManipulators::Oct]) cnb_ = 8;
|
||||
if (v[PICoutManipulators::Dec]) cnb_ = 10;
|
||||
if (v[PICoutManipulators::Hex]) cnb_ = 16;
|
||||
if (v[PICoutManipulators::Bin]) int_base_ = 2;
|
||||
if (v[PICoutManipulators::Oct]) int_base_ = 8;
|
||||
if (v[PICoutManipulators::Dec]) int_base_ = 10;
|
||||
if (v[PICoutManipulators::Hex]) int_base_ = 16;
|
||||
if (v[PICoutManipulators::Bold]) applyFormat(PICoutManipulators::Bold);
|
||||
if (v[PICoutManipulators::Faint]) applyFormat(PICoutManipulators::Faint);
|
||||
if (v[PICoutManipulators::Italic]) applyFormat(PICoutManipulators::Italic);
|
||||
@@ -324,31 +363,78 @@ PICout & PICout::operator<<(PIFlags<PICoutManipulators::PICoutFormat> v) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
#define PIINTCOUT(v) \
|
||||
{ \
|
||||
if (!act_) return *this; \
|
||||
space(); \
|
||||
if (cnb_ == 10) { \
|
||||
if (buffer_) { \
|
||||
(*buffer_) += PIString::fromNumber(v); \
|
||||
} else { \
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v); \
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() += PIString::fromNumber(v); \
|
||||
} \
|
||||
} else \
|
||||
write(PIString::fromNumber(v, cnb_)); \
|
||||
return *this; \
|
||||
|
||||
void PICout::stdoutPIString(const PIString & str, PICoutStdStream s) {
|
||||
#ifdef HAS_LOCALE
|
||||
std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> utf8conv;
|
||||
getStdStream(s) << utf8conv.to_bytes((char16_t *)&(const_cast<PIString &>(str).front()),
|
||||
(char16_t *)&(const_cast<PIString &>(str).front()) + str.size());
|
||||
#else
|
||||
for (PIChar c: str)
|
||||
getStdWStream(s).put(c.toWChar());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::write(const char * str, int len) {
|
||||
if (!actve_ || !str) return *this;
|
||||
if (buffer_) {
|
||||
buffer_->append(PIString(str, len));
|
||||
} else {
|
||||
if (isOutputDeviceActive(Console)) getStdStream(stream_).write(str, len);
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__().append(PIString(str, len));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::write(const PIString & s) {
|
||||
if (!actve_) return *this;
|
||||
if (buffer_) {
|
||||
buffer_->append(s);
|
||||
} else {
|
||||
if (isOutputDeviceActive(Console)) stdoutPIString(s, stream_);
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__().append(s);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void PICout::writeChar(char c) {
|
||||
if (buffer_) {
|
||||
buffer_->append(c);
|
||||
} else {
|
||||
if (isOutputDeviceActive(Console)) getStdStream(stream_) << c;
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__().append(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define PIINTCOUT(v) \
|
||||
{ \
|
||||
if (!actve_) return *this; \
|
||||
space(); \
|
||||
if (int_base_ == 10) { \
|
||||
if (buffer_) { \
|
||||
(*buffer_) += PIString::fromNumber(v); \
|
||||
} else { \
|
||||
if (isOutputDeviceActive(Console)) getStdStream(stream_) << (v); \
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIString::fromNumber(v); \
|
||||
} \
|
||||
} else \
|
||||
write(PIString::fromNumber(v, int_base_)); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
#define PIFLOATCOUT(v) \
|
||||
{ \
|
||||
if (buffer_) { \
|
||||
(*buffer_) += PIString::fromNumber(v, 'g'); \
|
||||
} else { \
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v); \
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() += PIString::fromNumber(v, 'g'); \
|
||||
} \
|
||||
} \
|
||||
#define PIFLOATCOUT(v) \
|
||||
{ \
|
||||
if (buffer_) { \
|
||||
(*buffer_) += PIString::fromNumber(v, 'g'); \
|
||||
} else { \
|
||||
if (isOutputDeviceActive(Console)) getStdStream(stream_) << (v); \
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIString::fromNumber(v, 'g'); \
|
||||
} \
|
||||
} \
|
||||
return *this;
|
||||
|
||||
|
||||
@@ -361,7 +447,7 @@ PICout & PICout::operator<<(const PIString & v) {
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(const char * v) {
|
||||
if (!act_ || !v) return *this;
|
||||
if (!actve_ || !v) return *this;
|
||||
if (v[0] == '\0') return *this;
|
||||
space();
|
||||
quote();
|
||||
@@ -371,7 +457,7 @@ PICout & PICout::operator<<(const char * v) {
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(bool v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
space();
|
||||
if (v)
|
||||
write("true");
|
||||
@@ -381,7 +467,7 @@ PICout & PICout::operator<<(bool v) {
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(char v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
space();
|
||||
write(v);
|
||||
return *this;
|
||||
@@ -406,32 +492,32 @@ PICout & PICout::operator<<(llong v){PIINTCOUT(v)}
|
||||
PICout & PICout::operator<<(ullong v){PIINTCOUT(v)}
|
||||
|
||||
PICout & PICout::operator<<(float v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
space();
|
||||
PIFLOATCOUT(v)
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(double v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
space();
|
||||
PIFLOATCOUT(v)
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(ldouble v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
space();
|
||||
PIFLOATCOUT(v)
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(const void * v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
space();
|
||||
write("0x" + PIString::fromNumber(ullong(v), 16));
|
||||
return *this;
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(const PIObject * v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
space();
|
||||
if (v == 0)
|
||||
write("PIObject*(0x0)");
|
||||
@@ -443,74 +529,38 @@ PICout & PICout::operator<<(const PIObject * v) {
|
||||
}
|
||||
|
||||
PICout & PICout::operator<<(PICoutSpecialChar v) {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
switch (v) {
|
||||
case Null:
|
||||
if (buffer_) {
|
||||
(*buffer_) += PIChar();
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << char(0);
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIChar();
|
||||
}
|
||||
break;
|
||||
case Null: writeChar(char(0)); break;
|
||||
case NewLine:
|
||||
if (buffer_) {
|
||||
(*buffer_) += "\n";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '\n';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\n";
|
||||
}
|
||||
fo_ = true;
|
||||
break;
|
||||
case Tab:
|
||||
if (buffer_) {
|
||||
(*buffer_) += "\t";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '\t';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\t";
|
||||
}
|
||||
first_out_ = true;
|
||||
writeChar('\n');
|
||||
break;
|
||||
case Tab: writeChar('\t'); break;
|
||||
case Esc:
|
||||
#ifdef CC_VC
|
||||
if (buffer_) {
|
||||
(*buffer_) += PIChar(27);
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << char(27);
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIChar(27);
|
||||
}
|
||||
writeChar(char(27));
|
||||
#else
|
||||
if (buffer_) {
|
||||
(*buffer_) += "\e";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '\e';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\e";
|
||||
}
|
||||
writeChar('\e');
|
||||
#endif
|
||||
break;
|
||||
case Quote:
|
||||
if (buffer_) {
|
||||
(*buffer_) += "\"";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '"';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\"";
|
||||
}
|
||||
break;
|
||||
case Quote: writeChar('"'); break;
|
||||
};
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::saveControls() {
|
||||
if (!act_) return *this;
|
||||
PRIVATE->cos_.push(co_);
|
||||
if (!actve_) return *this;
|
||||
PRIVATE->cos_.push(ctrl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::restoreControls() {
|
||||
if (!act_) return *this;
|
||||
if (!actve_) return *this;
|
||||
if (!PRIVATE->cos_.isEmpty()) {
|
||||
co_ = PRIVATE->cos_.top();
|
||||
ctrl_ = PRIVATE->cos_.top();
|
||||
PRIVATE->cos_.pop();
|
||||
}
|
||||
return *this;
|
||||
@@ -524,16 +574,11 @@ PICout & PICout::restoreControls() {
|
||||
//! Добавляет пробел если это не первый вывод и установлен флаг \a AddSpaces
|
||||
//! \~\sa \a quote(), \a newLine()
|
||||
PICout & PICout::space() {
|
||||
if (!act_) return *this;
|
||||
if (!fo_ && co_[AddSpaces]) {
|
||||
if (buffer_) {
|
||||
(*buffer_) += " ";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << ' ';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += " ";
|
||||
}
|
||||
if (!actve_) return *this;
|
||||
if (!first_out_ && ctrl_[AddSpaces]) {
|
||||
writeChar(' ');
|
||||
}
|
||||
fo_ = false;
|
||||
first_out_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -544,16 +589,11 @@ PICout & PICout::space() {
|
||||
//! Добавляет кавычки если установлен флаг \a AddQuotes
|
||||
//! \~\sa \a space(), \a newLine()
|
||||
PICout & PICout::quote() {
|
||||
if (!act_) return *this;
|
||||
if (co_[AddQuotes]) {
|
||||
if (buffer_) {
|
||||
(*buffer_) += "\"";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '"';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\"";
|
||||
}
|
||||
if (!actve_) return *this;
|
||||
if (ctrl_[AddQuotes]) {
|
||||
writeChar('"');
|
||||
}
|
||||
fo_ = false;
|
||||
first_out_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -564,74 +604,28 @@ PICout & PICout::quote() {
|
||||
//! Добавляет новую строку если установлен флаг \a AddNewLine
|
||||
//! \~\sa \a space(), \a quote()
|
||||
PICout & PICout::newLine() {
|
||||
if (!act_) return *this;
|
||||
if (co_[AddNewLine]) {
|
||||
if (buffer_) {
|
||||
(*buffer_) += "\n";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << std::endl;
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\n";
|
||||
}
|
||||
if (!actve_) return *this;
|
||||
if (ctrl_[AddNewLine]) {
|
||||
writeChar('\n');
|
||||
}
|
||||
fo_ = false;
|
||||
first_out_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::write(char c) {
|
||||
if (!act_) return *this;
|
||||
if (buffer_) {
|
||||
buffer_->append(c);
|
||||
} else {
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << c;
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__().append(c);
|
||||
}
|
||||
if (!actve_) return *this;
|
||||
writeChar(c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::write(const char * str) {
|
||||
if (!act_ || !str) return *this;
|
||||
if (!actve_ || !str) return *this;
|
||||
return write(str, strlen(str));
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::write(const char * str, int len) {
|
||||
if (!act_ || !str) return *this;
|
||||
if (buffer_) {
|
||||
buffer_->append(PIString(str, len));
|
||||
} else {
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout.write(str, len);
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__().append(PIString(str, len));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::write(const PIString & s) {
|
||||
if (!act_) return *this;
|
||||
if (buffer_) {
|
||||
buffer_->append(s);
|
||||
} else {
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) stdoutPIString(s);
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__().append(s);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void PICout::stdoutPIString(const PIString & s) {
|
||||
#ifdef HAS_LOCALE
|
||||
std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> utf8conv;
|
||||
std::cout << utf8conv.to_bytes((char16_t *)&(const_cast<PIString &>(s).front()),
|
||||
(char16_t *)&(const_cast<PIString &>(s).front()) + s.size());
|
||||
#else
|
||||
for (PIChar c: s)
|
||||
std::wcout.put(c.toWChar());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PICout::init() {
|
||||
#ifdef WINDOWS
|
||||
if (__Private__::hOut == 0) {
|
||||
@@ -640,19 +634,18 @@ void PICout::init() {
|
||||
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
||||
__Private__::dattr = sbi.wAttributes;
|
||||
}
|
||||
attr_ = __Private__::dattr;
|
||||
win_attr_ = __Private__::dattr;
|
||||
#endif
|
||||
id_ = 0;
|
||||
if ((co_ & NoLock) != NoLock) {
|
||||
if ((ctrl_ & NoLock) != NoLock) {
|
||||
PICout::__mutex__().lock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PICout::applyFormat(PICoutFormat f) {
|
||||
if (!act_) return;
|
||||
if (buffer_ || !isOutputDeviceActive(StdOut)) return;
|
||||
fc_ = true;
|
||||
if (!actve_) return;
|
||||
if (buffer_ || !isOutputDeviceActive(Console)) return;
|
||||
format_changed_ = true;
|
||||
#ifdef WINDOWS
|
||||
static int mask_fore = ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
static int mask_back = ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
|
||||
@@ -661,28 +654,28 @@ void PICout::applyFormat(PICoutFormat f) {
|
||||
case Oct:
|
||||
case Dec:
|
||||
case Hex: break;
|
||||
case PICoutManipulators::Bold: attr_ |= FOREGROUND_INTENSITY; break;
|
||||
case PICoutManipulators::Underline: attr_ |= COMMON_LVB_UNDERSCORE; break;
|
||||
case PICoutManipulators::Black: attr_ = (attr_ & mask_fore); break;
|
||||
case PICoutManipulators::Red: attr_ = (attr_ & mask_fore) | FOREGROUND_RED; break;
|
||||
case PICoutManipulators::Green: attr_ = (attr_ & mask_fore) | FOREGROUND_GREEN; break;
|
||||
case PICoutManipulators::Blue: attr_ = (attr_ & mask_fore) | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::Yellow: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN; break;
|
||||
case PICoutManipulators::Magenta: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::Cyan: attr_ = (attr_ & mask_fore) | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::White: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackBlack: attr_ = (attr_ & mask_back); break;
|
||||
case PICoutManipulators::BackRed: attr_ = (attr_ & mask_back) | BACKGROUND_RED; break;
|
||||
case PICoutManipulators::BackGreen: attr_ = (attr_ & mask_back) | BACKGROUND_GREEN; break;
|
||||
case PICoutManipulators::BackBlue: attr_ = (attr_ & mask_back) | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackYellow: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN; break;
|
||||
case PICoutManipulators::BackMagenta: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackCyan: attr_ = (attr_ & mask_back) | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackWhite: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::Default: attr_ = __Private__::dattr; break;
|
||||
case PICoutManipulators::Bold: win_attr_ |= FOREGROUND_INTENSITY; break;
|
||||
case PICoutManipulators::Underline: win_attr_ |= COMMON_LVB_UNDERSCORE; break;
|
||||
case PICoutManipulators::Black: win_attr_ = (win_attr_ & mask_fore); break;
|
||||
case PICoutManipulators::Red: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_RED; break;
|
||||
case PICoutManipulators::Green: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_GREEN; break;
|
||||
case PICoutManipulators::Blue: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::Yellow: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN; break;
|
||||
case PICoutManipulators::Magenta: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::Cyan: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::White: win_attr_ = (win_attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackBlack: win_attr_ = (win_attr_ & mask_back); break;
|
||||
case PICoutManipulators::BackRed: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_RED; break;
|
||||
case PICoutManipulators::BackGreen: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_GREEN; break;
|
||||
case PICoutManipulators::BackBlue: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackYellow: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN; break;
|
||||
case PICoutManipulators::BackMagenta: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackCyan: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackWhite: win_attr_ = (win_attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::Default: win_attr_ = __Private__::dattr; break;
|
||||
default: break;
|
||||
}
|
||||
SetConsoleTextAttribute(__Private__::hOut, attr_);
|
||||
SetConsoleTextAttribute(__Private__::hOut, win_attr_);
|
||||
#else
|
||||
switch (f) {
|
||||
case Bin:
|
||||
@@ -761,3 +754,8 @@ PICout PICout::withExternalBuffer(PIString * buffer, int id, PIFlags<PICoutManip
|
||||
c.id_ = id;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
int PICout::registerExternalBufferID() {
|
||||
return Notifier::instance()->new_id.fetch_add(1);
|
||||
}
|
||||
|
||||
@@ -40,10 +40,14 @@
|
||||
# define piCoutObj
|
||||
|
||||
#else
|
||||
# define piCout PICout(piDebug)
|
||||
# define piCoutObj \
|
||||
PICout(piDebug && debug()) << (PIStringAscii("[") + className() + \
|
||||
(name().isEmpty() ? "]" : PIStringAscii(" \"") + name() + PIStringAscii("\"]")))
|
||||
# define piCout PICout(piDebug, PICoutStdStream::StdOut)
|
||||
# define piCoutObj \
|
||||
PICout(piDebug && debug(), PICoutStdStream::StdOut) \
|
||||
<< (PIStringAscii("[") + className() + (name().isEmpty() ? "]" : PIStringAscii(" \"") + name() + PIStringAscii("\"]")))
|
||||
# define piCerr PICout(piDebug, PICoutStdStream::StdErr)
|
||||
# define piCerrObj \
|
||||
PICout(piDebug && debug(), PICoutStdStream::StdErr) \
|
||||
<< (PIStringAscii("[") + className() + (name().isEmpty() ? "]" : PIStringAscii(" \"") + name() + PIStringAscii("\"]")))
|
||||
#endif
|
||||
|
||||
|
||||
@@ -55,6 +59,7 @@ class PIObject;
|
||||
//! \~russian Пространство имен содержит перечисления для контроля PICout
|
||||
namespace PICoutManipulators {
|
||||
|
||||
|
||||
//! \~english Enum contains special characters
|
||||
//! \~russian Перечисление со спецсимволами
|
||||
enum PICoutSpecialChar {
|
||||
@@ -65,6 +70,7 @@ enum PICoutSpecialChar {
|
||||
Quote /*! \~english Quote character, '\"' \~russian Кавычки, '\"' */
|
||||
};
|
||||
|
||||
|
||||
//! \~english Enum contains immediate action
|
||||
//! \~russian Перечисление с немедленными действиями
|
||||
enum PICoutAction {
|
||||
@@ -79,6 +85,7 @@ enum PICoutAction {
|
||||
restoreControl() */
|
||||
};
|
||||
|
||||
|
||||
//! \~english Enum contains control of PICout
|
||||
//! \~russian Перечисление с управлением PICout
|
||||
enum PICoutControl {
|
||||
@@ -91,6 +98,7 @@ enum PICoutControl {
|
||||
NoLock /*! \~english Don`t use mutex for output \~russian Не использовать мьютекс при выводе */ = 0x100,
|
||||
};
|
||||
|
||||
|
||||
//! \~english Enum contains output format
|
||||
//! \~russian Перечисление с форматом вывода
|
||||
enum PICoutFormat {
|
||||
@@ -122,10 +130,20 @@ enum PICoutFormat {
|
||||
Default /*! \~english Default format \~russian Формат по умолчанию */ = 0x4000000
|
||||
};
|
||||
|
||||
|
||||
typedef PIFlags<PICoutControl> PICoutControls;
|
||||
|
||||
} // namespace PICoutManipulators
|
||||
|
||||
|
||||
//! \~english Enum contains console streams
|
||||
//! \~russian Перечисление с потоками консоли
|
||||
enum class PICoutStdStream {
|
||||
StdOut /*! \~english Standard output stream \~russian Стандартный поток вывода */ = 0,
|
||||
StdErr /*! \~english Standard error stream \~russian Стандартный поток ошибок */ = 1,
|
||||
};
|
||||
|
||||
|
||||
//! \ingroup Core
|
||||
//! \~\brief
|
||||
//! \~english Universal output to console class.
|
||||
@@ -134,11 +152,11 @@ class PIP_EXPORT PICout {
|
||||
public:
|
||||
//! \~english Default constructor with default features (AddSpaces and AddNewLine)
|
||||
//! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine)
|
||||
PICout(int controls = PICoutManipulators::DefaultControls);
|
||||
PICout(int controls = PICoutManipulators::DefaultControls, PICoutStdStream stream = PICoutStdStream::StdOut);
|
||||
|
||||
//! \~english Construct with default features (AddSpaces and AddNewLine), but if \"active\" is false does nothing
|
||||
//! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine), но если не \"active\" то будет неактивным
|
||||
PICout(bool active);
|
||||
PICout(bool active, PICoutStdStream stream = PICoutStdStream::StdOut);
|
||||
|
||||
PICout(const PICout & other);
|
||||
|
||||
@@ -146,6 +164,8 @@ public:
|
||||
|
||||
|
||||
class PIP_EXPORT Notifier {
|
||||
friend class PICout;
|
||||
|
||||
public:
|
||||
//! \~english Singleton access to %PICout::Notifier
|
||||
//! \~russian Синглтон класса %PICout::Notifier
|
||||
@@ -158,15 +178,17 @@ public:
|
||||
private:
|
||||
Notifier();
|
||||
PIObject * o;
|
||||
std::atomic_int new_id = {1};
|
||||
};
|
||||
|
||||
//! \~english Enum contains output devices of %PICout
|
||||
//! \~russian Перечисление с устройствами вывода для %PICout
|
||||
enum OutputDevice {
|
||||
NoDevices /** \~english %PICout is disabled \~russian %PICout неактивен */ = 0x0,
|
||||
StdOut /** \~english Standard console output \~russian Стандартный вывод в консоль */ = 0x1,
|
||||
Buffer /** \~english Internal buffer \~russian Внутренний буфер */ = 0x2,
|
||||
AllDevices /** \~english All \~russian Все */ = 0xFFFF,
|
||||
NoDevices /** \~english %PICout is disabled \~russian %PICout неактивен */ = 0x0,
|
||||
Console /** \~english Standard console output \~russian Стандартный вывод в консоль */ = 0x1,
|
||||
StdOut DEPRECATEDM("use PICout::Console") = Console,
|
||||
Buffer /** \~english Internal buffer \~russian Внутренний буфер */ = 0x2,
|
||||
AllDevices /** \~english All \~russian Все */ = 0xFFFF,
|
||||
};
|
||||
|
||||
typedef PIFlags<OutputDevice> OutputDevices;
|
||||
@@ -261,25 +283,15 @@ public:
|
||||
|
||||
//! \~english Set control flag "c" is "on" state
|
||||
//! \~russian Установить флаг "c" в "on" состояние
|
||||
PICout & setControl(PICoutManipulators::PICoutControl c, bool on = true) {
|
||||
co_.setFlag(c, on);
|
||||
return *this;
|
||||
}
|
||||
PICout & setControl(PICoutManipulators::PICoutControl c, bool on = true);
|
||||
|
||||
//! \~english Set control flags "c"
|
||||
//! \~russian Установить флаги "c"
|
||||
PICout & setControls(PICoutManipulators::PICoutControls c) {
|
||||
co_ = c;
|
||||
return *this;
|
||||
}
|
||||
PICout & setControls(PICoutManipulators::PICoutControls c);
|
||||
|
||||
//! \~english Exec \a saveControls() and set control flags to "c"
|
||||
//! \~russian Иыполнить \a saveControls() и Установить флаги "c"
|
||||
PICout & saveAndSetControls(PICoutManipulators::PICoutControls c) {
|
||||
saveControls();
|
||||
co_ = c;
|
||||
return *this;
|
||||
}
|
||||
PICout & saveAndSetControls(PICoutManipulators::PICoutControls c);
|
||||
|
||||
//! \~english Save control flags to internal stack
|
||||
//! \~russian Сохраняет состояние флагов во внутренний стек
|
||||
@@ -321,7 +333,7 @@ public:
|
||||
|
||||
//! \~english Output \a PIString to stdout
|
||||
//! \~russian Вывод \a PIString в stdout
|
||||
static void stdoutPIString(const PIString & s);
|
||||
static void stdoutPIString(const PIString & str, PICoutStdStream s = PICoutStdStream::StdOut);
|
||||
|
||||
//! \~english Returns internal PIString buffer
|
||||
//! \~russian Возвращает внутренний PIString буфер
|
||||
@@ -368,19 +380,25 @@ public:
|
||||
PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces |
|
||||
PICoutManipulators::AddNewLine);
|
||||
|
||||
//! \~english Returns unique external buffer ID for later use in \a withExternalBuffer()
|
||||
//! \~russian Возвращает уникальный ID для внешнего буфера для дальнейшего использования в \a withExternalBuffer()
|
||||
static int registerExternalBufferID();
|
||||
|
||||
static PIMutex & __mutex__();
|
||||
static PIString & __string__();
|
||||
|
||||
private:
|
||||
void init();
|
||||
void applyFormat(PICoutManipulators::PICoutFormat f);
|
||||
void writeChar(char c);
|
||||
|
||||
static OutputDevices devs;
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
bool fo_, cc_, fc_, act_;
|
||||
int cnb_, attr_, id_;
|
||||
PIString * buffer_;
|
||||
PICoutManipulators::PICoutControls co_;
|
||||
bool first_out_ = true, is_copy_ = false, format_changed_ = false, actve_ = true;
|
||||
int int_base_ = 10, win_attr_ = 0, id_ = 0;
|
||||
PIString * buffer_ = nullptr;
|
||||
PICoutManipulators::PICoutControls ctrl_ = PICoutManipulators::DefaultControls;
|
||||
PICoutStdStream stream_ = PICoutStdStream::StdOut;
|
||||
};
|
||||
|
||||
#endif // PICOUT_H
|
||||
|
||||
@@ -340,6 +340,13 @@ bool PIInit::isBuildOptionEnabled(PIInit::BuildOption o) {
|
||||
true;
|
||||
# else
|
||||
false;
|
||||
# endif
|
||||
case boConsole:
|
||||
return
|
||||
# ifdef PIP_CONSOLE
|
||||
true;
|
||||
# else
|
||||
false;
|
||||
# endif
|
||||
default: return false;
|
||||
}
|
||||
@@ -357,6 +364,7 @@ PIStringList PIInit::buildOptions() {
|
||||
if (isBuildOptionEnabled(boCompress)) ret << "Compress";
|
||||
if (isBuildOptionEnabled(boOpenCL)) ret << "OpenCL";
|
||||
if (isBuildOptionEnabled(boCloud)) ret << "Cloud";
|
||||
if (isBuildOptionEnabled(boConsole)) ret << "Console";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ public:
|
||||
boCompress /*! \~english Zlib compression support \~russian Поддержка сжатия Zlib */ = 0x80,
|
||||
boOpenCL /*! \~english OpenCL support \~russian Поддержка OpenCL */ = 0x100,
|
||||
boCloud /*! \~english PICloud transport support \~russian Поддержка облачного транспорта PICloud */ = 0x200,
|
||||
boConsole /*! \~english Console graphics support \~russian Поддержка графики в консоли */ = 0x400,
|
||||
};
|
||||
static PIInit * instance() { return __PIInit_Initializer__::__instance__; }
|
||||
|
||||
|
||||
@@ -763,7 +763,7 @@ void dumpApplication(bool with_objects) {
|
||||
|
||||
bool dumpApplicationToFile(const PIString & path, bool with_objects) {
|
||||
PIFile f(path + "_tmp");
|
||||
f.setName("__S__DumpFile");
|
||||
f.setName("_S.DumpFile");
|
||||
f.clear();
|
||||
if (!f.open(PIIODevice::WriteOnly)) return false;
|
||||
auto out_devs = PICout::currentOutputDevices();
|
||||
|
||||
83
libs/main/http_server/microhttpd_server_p.h
Normal file
83
libs/main/http_server/microhttpd_server_p.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#ifndef MICROHTTPD_SERVER_P_H
|
||||
#define MICROHTTPD_SERVER_P_H
|
||||
|
||||
#include "pibase.h"
|
||||
#include "piobject.h"
|
||||
#include "pip_http_server_export.h"
|
||||
|
||||
struct MicrohttpdServerConnection;
|
||||
|
||||
class PIP_HTTP_SERVER_EXPORT MicrohttpdServer: public PIObject {
|
||||
PIOBJECT(MicrohttpdServer)
|
||||
friend struct MicrohttpdServerConnection;
|
||||
|
||||
public:
|
||||
MicrohttpdServer();
|
||||
virtual ~MicrohttpdServer();
|
||||
|
||||
enum class Method {
|
||||
Unknown,
|
||||
Get,
|
||||
Head,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Connect,
|
||||
Options,
|
||||
Trace,
|
||||
Patch
|
||||
};
|
||||
enum class Option {
|
||||
ConnectionLimit, // uint
|
||||
ConnectionTimeout, // uint, sec
|
||||
HTTPSEnabled, // bool
|
||||
HTTPSMemKey, // const char * to key.pem data
|
||||
HTTPSMemCert, // const char * to cert.pem data
|
||||
HTTPSKeyPassword // const char * to passwd for key.pem
|
||||
};
|
||||
|
||||
struct PIP_HTTP_SERVER_EXPORT Request {
|
||||
MicrohttpdServer::Method method;
|
||||
PIString path;
|
||||
PIByteArray body;
|
||||
PIMap<PIString, PIString> headers;
|
||||
PIMap<PIString, PIString> args;
|
||||
};
|
||||
|
||||
class PIP_HTTP_SERVER_EXPORT Reply {
|
||||
friend struct MicrohttpdServerConnection;
|
||||
|
||||
public:
|
||||
void addHeader(const PIString & header, const PIString & value);
|
||||
void removeHeader(const PIString & header);
|
||||
void setBody(const PIByteArray & b);
|
||||
void setCode(int c);
|
||||
|
||||
private:
|
||||
void addFixedHeaders();
|
||||
int code = 200;
|
||||
PIByteArray body;
|
||||
PIMap<PIString, PIString> headers;
|
||||
};
|
||||
|
||||
void setOption(Option o, PIVariant v);
|
||||
void setFavicon(const PIByteArray & im);
|
||||
|
||||
bool listen(PINetworkAddress addr);
|
||||
bool listenAll(ushort port) { return listen({0, port}); }
|
||||
bool isListen() const;
|
||||
void stop();
|
||||
|
||||
void setRequestCallback(std::function<Reply(Request)> c) { callback = c; }
|
||||
|
||||
private:
|
||||
PRIVATE_DECLARATION(PIP_HTTP_SERVER_EXPORT)
|
||||
|
||||
PIByteArray favicon;
|
||||
PIMap<Option, PIVariant> opts;
|
||||
std::function<Reply(Request)> callback;
|
||||
PIByteArray mem_key, mem_cert, key_pass;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
33
libs/main/http_server/pihttpserver.h
Normal file
33
libs/main/http_server/pihttpserver.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef PIHTTPSERVER_H
|
||||
#define PIHTTPSERVER_H
|
||||
|
||||
#include "microhttpd_server_p.h"
|
||||
#include "pip_http_server_export.h"
|
||||
|
||||
class PIP_HTTP_SERVER_EXPORT PIHTTPServer: public MicrohttpdServer {
|
||||
PIOBJECT_SUBCLASS(PIHTTPServer, MicrohttpdServer)
|
||||
|
||||
public:
|
||||
PIHTTPServer();
|
||||
virtual ~PIHTTPServer();
|
||||
|
||||
using RequestFunction = std::function<MicrohttpdServer::Reply(const MicrohttpdServer::Request &)>;
|
||||
|
||||
void registerPath(const PIString & path, RequestFunction functor);
|
||||
|
||||
void addReplyHeader(const PIString & name, const PIString & value) { reply_headers[name] = value; }
|
||||
void removeReplyHeader(const PIString & name) { reply_headers.remove(name); }
|
||||
void clearReplyHeaders() { reply_headers.clear(); }
|
||||
|
||||
private:
|
||||
struct Endpoint {
|
||||
bool match(const PIStringList & in_path) const;
|
||||
PIStringList path;
|
||||
RequestFunction function;
|
||||
};
|
||||
PIMap<PIString, PIString> reply_headers;
|
||||
PIMap<PIString, Endpoint> functions;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "piliterals_time.h"
|
||||
#include "pipropertystorage.h"
|
||||
#include "pitime.h"
|
||||
#include "pitranslator.h"
|
||||
|
||||
#define PIBINARYLOG_VERSION_OLD 0x31
|
||||
|
||||
@@ -79,7 +80,7 @@ PIBinaryLog::PIBinaryLog() {
|
||||
setLogDir(PIString());
|
||||
setFilePrefix(PIString());
|
||||
setRapidStart(false);
|
||||
file.setName("__S__PIBinaryLog::file");
|
||||
file.setName("_S.PIBinLog.file");
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +101,7 @@ bool PIBinaryLog::openDevice() {
|
||||
index.clear();
|
||||
log_size = 0;
|
||||
if (mode_ == ReadWrite) {
|
||||
piCoutObj << "Error: ReadWrite mode not supported, use WriteOnly or ReadOnly";
|
||||
piCoutObj << "Error: ReadWrite mode not supported, use WriteOnly or ReadOnly"_tr("PIBinLog");
|
||||
return false;
|
||||
}
|
||||
if (path().isEmpty() && mode_ == WriteOnly) {
|
||||
@@ -122,21 +123,21 @@ bool PIBinaryLog::openDevice() {
|
||||
}
|
||||
}
|
||||
if (!file.open(path(), mode_)) {
|
||||
piCoutObj << "Error: Can't open file" << path();
|
||||
piCoutObj << "Error: Can't open file \"%1\": %2"_tr("PIBinLog").arg(path()).arg(errorString());
|
||||
return false;
|
||||
}
|
||||
setName(path());
|
||||
if (mode_ == WriteOnly) {
|
||||
file.clear();
|
||||
if (!writeFileHeader()) {
|
||||
piCoutObj << "Error: Can't write binlog file header" << path();
|
||||
piCoutObj << "Error: Can't write binlog file header \"%1\""_tr("PIBinLog").arg(path());
|
||||
return false;
|
||||
}
|
||||
is_started = true;
|
||||
}
|
||||
if (mode_ == ReadOnly) {
|
||||
if (file.isEmpty()) {
|
||||
piCoutObj << "Error: File is null" << path();
|
||||
piCoutObj << "Error: File is null \"%1\""_tr("PIBinLog").arg(path());
|
||||
fileError();
|
||||
return false;
|
||||
}
|
||||
@@ -145,7 +146,7 @@ bool PIBinaryLog::openDevice() {
|
||||
return false;
|
||||
}
|
||||
if (isEmpty()) {
|
||||
piCoutObj << "Warning: Empty BinLog file" << path();
|
||||
piCoutObj << "Warning: Empty BinLog file \"%1\""_tr("PIBinLog").arg(path());
|
||||
fileEnd();
|
||||
}
|
||||
play_time = 0;
|
||||
@@ -175,7 +176,7 @@ bool PIBinaryLog::closeDevice() {
|
||||
|
||||
|
||||
bool PIBinaryLog::threadedRead(const uchar * readed, ssize_t size) {
|
||||
// piCout << "binlog threaded read";
|
||||
// piCout << "binlog threaded read";
|
||||
if (!canRead() || isEnd()) return PIIODevice::threadedRead(readed, size);
|
||||
is_thread_ok = false;
|
||||
logmutex.lock();
|
||||
@@ -258,7 +259,7 @@ PIString PIBinaryLog::getLogfilePath(const PIString & log_dir, const PIString &
|
||||
dir.setDir(dir.absolutePath());
|
||||
if (!dir.isExists()) {
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Creating directory" << dir.path();
|
||||
<< "Creating directory \"%1\""_tr("PIBinLog").arg(dir.path());
|
||||
dir.make(true);
|
||||
}
|
||||
const PIString npath = log_dir + PIDir::separator + prefix + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss");
|
||||
@@ -282,7 +283,7 @@ PIString PIBinaryLog::createNewFile() {
|
||||
newFile(file.path());
|
||||
return file.path();
|
||||
}
|
||||
piCoutObj << "Can't create new file, maybe LogDir" << ("\"" + logDir() + "\"") << "is invalid.";
|
||||
piCoutObj << "Can't create new file, maybe LogDir \"%1\" is invalid"_tr("PIBinLog").arg(logDir());
|
||||
return PIString();
|
||||
}
|
||||
|
||||
@@ -291,7 +292,7 @@ void PIBinaryLog::createNewFile(const PIString & path) {
|
||||
if (open(path, PIIODevice::WriteOnly)) {
|
||||
newFile(file.path());
|
||||
} else
|
||||
piCoutObj << "Can't create new file, maybe path" << ("\"" + path + "\"") << "is invalid.";
|
||||
piCoutObj << "Can't create new file, maybe path \"%1\" is invalid"_tr("PIBinLog").arg(path);
|
||||
}
|
||||
|
||||
|
||||
@@ -315,7 +316,7 @@ void PIBinaryLog::setPause(bool pause) {
|
||||
int PIBinaryLog::writeBinLog(int id, const void * data, int size) {
|
||||
if (size <= 0 || !canWrite()) return -1;
|
||||
if (id == 0) {
|
||||
piCoutObj << "Error: can`t write with id = 0! Id must be > 0";
|
||||
piCoutObj << "Error: can`t write with id = 0! ID must be > 0"_tr("PIBinLog");
|
||||
return -1;
|
||||
}
|
||||
if (is_pause) return 0;
|
||||
@@ -359,7 +360,7 @@ PIByteArray PIBinaryLog::readBinLog(int id, PISystemTime * time, int * readed_id
|
||||
Record br = readRecord();
|
||||
logmutex.unlock();
|
||||
if (br.id == -1) {
|
||||
piCoutObj << "End of BinLog file";
|
||||
piCoutObj << "End of BinLog file"_tr("PIBinLog");
|
||||
fileEnd();
|
||||
return PIByteArray();
|
||||
}
|
||||
@@ -373,7 +374,7 @@ PIByteArray PIBinaryLog::readBinLog(int id, PISystemTime * time, int * readed_id
|
||||
br = readRecord();
|
||||
logmutex.unlock();
|
||||
if (br.id == -1) {
|
||||
piCoutObj << "End of BinLog file";
|
||||
piCoutObj << "End of BinLog file"_tr("PIBinLog");
|
||||
fileEnd();
|
||||
return PIByteArray();
|
||||
}
|
||||
@@ -382,7 +383,7 @@ PIByteArray PIBinaryLog::readBinLog(int id, PISystemTime * time, int * readed_id
|
||||
if (readed_id) *readed_id = br.id;
|
||||
return br.data;
|
||||
}
|
||||
piCoutObj << "Can't find record with id =" << id;
|
||||
piCoutObj << "Can't find record with id = %1"_tr("PIBinLog").arg(id);
|
||||
return PIByteArray();
|
||||
}
|
||||
|
||||
@@ -428,15 +429,15 @@ ssize_t PIBinaryLog::readDevice(void * read_to, ssize_t max_size) {
|
||||
}
|
||||
if (br.id == -1) {
|
||||
fileEnd();
|
||||
piCoutObj << "End of BinLog file";
|
||||
piCoutObj << "End of BinLog file"_tr("PIBinLog");
|
||||
return 0;
|
||||
}
|
||||
if (br.id == 0) {
|
||||
piCoutObj << "Read record error";
|
||||
piCoutObj << "Read record error"_tr("PIBinLog");
|
||||
return -1;
|
||||
}
|
||||
const ssize_t sz = piMini(max_size, br.data.size());
|
||||
if (sz < br.data.size_s()) piCoutObj << "too small read buffer:" << max_size << ", data size:" << br.data.size();
|
||||
if (sz < br.data.size_s()) piCoutObj << "too small read buffer: %1, data size: %2"_tr("PIBinLog").arg(max_size).arg(br.data.size());
|
||||
memcpy(read_to, br.data.data(), sz);
|
||||
return sz;
|
||||
}
|
||||
@@ -491,7 +492,7 @@ bool PIBinaryLog::checkFileHeader() {
|
||||
for (uint i = 0; i < PIBINARYLOG_SIGNATURE_SIZE; i++)
|
||||
if (read_sig[i] != binlog_sig[i]) correct = false;
|
||||
if (!correct) {
|
||||
piCoutObj << "BinLogFile signature is corrupted or invalid file";
|
||||
piCoutObj << "BinLogFile signature is corrupted or invalid file"_tr("PIBinLog");
|
||||
return false;
|
||||
}
|
||||
uchar read_version = 0;
|
||||
@@ -509,9 +510,9 @@ bool PIBinaryLog::checkFileHeader() {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (read_version == 0) piCoutObj << "BinLogFile has invalid version";
|
||||
if (read_version < PIBINARYLOG_VERSION) piCoutObj << "BinLogFile has too old verion";
|
||||
if (read_version > PIBINARYLOG_VERSION) piCoutObj << "BinLogFile has too newest version";
|
||||
if (read_version == 0) piCoutObj << "BinLogFile has invalid version"_tr("PIBinLog");
|
||||
if (read_version < PIBINARYLOG_VERSION) piCoutObj << "BinLogFile has too old verion"_tr("PIBinLog");
|
||||
if (read_version > PIBINARYLOG_VERSION) piCoutObj << "BinLogFile has too new version"_tr("PIBinLog");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -545,7 +546,7 @@ PIBinaryLog::Record PIBinaryLog::readRecord() {
|
||||
if (br.id == 0) fileError();
|
||||
moveIndex(index.index_pos.value(file.pos(), -1));
|
||||
logmutex.unlock();
|
||||
// piCoutObj << "readRecord done";
|
||||
// piCoutObj << "readRecord done";
|
||||
return br;
|
||||
}
|
||||
|
||||
@@ -721,7 +722,7 @@ bool PIBinaryLog::cutBinLog(const PIBinaryLog::BinLogInfo & src, const PIString
|
||||
PIBinaryLog slog;
|
||||
if (!slog.open(src.path, PIIODevice::ReadOnly)) {
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Error, can't open" << src.path;
|
||||
<< "Error, can't open \"%1\""_tr("PIBinLog").arg(src.path);
|
||||
return false;
|
||||
}
|
||||
const PIVector<int> ids = src.records.keys();
|
||||
@@ -730,7 +731,7 @@ bool PIBinaryLog::cutBinLog(const PIBinaryLog::BinLogInfo & src, const PIString
|
||||
dlog.createNewFile(dst);
|
||||
if (!dlog.isOpened()) {
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Error, can't create" << dst;
|
||||
<< "Error, can't create \"%1\""_tr("PIBinLog").arg(dst);
|
||||
return false;
|
||||
}
|
||||
bool first = true;
|
||||
@@ -746,7 +747,7 @@ bool PIBinaryLog::cutBinLog(const PIBinaryLog::BinLogInfo & src, const PIString
|
||||
if (ids.contains(br.id)) {
|
||||
if (dlog.writeBinLog_raw(br.id, br.timestamp - st, br.data) <= 0) {
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Error, can't write to file" << dst;
|
||||
<< "Error, can't write to file \"%1\""_tr("PIBinLog").arg(dst);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -772,7 +773,7 @@ bool PIBinaryLog::joinBinLogsSerial(const PIStringList & src,
|
||||
for (const PIString & fn: src) {
|
||||
if (!slog.open(fn, PIIODevice::ReadOnly)) {
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Error, can't open" << fn;
|
||||
<< "Error, can't open \"%1\""_tr("PIBinLog").arg(fn);
|
||||
return false;
|
||||
}
|
||||
if (first) {
|
||||
@@ -781,11 +782,11 @@ bool PIBinaryLog::joinBinLogsSerial(const PIStringList & src,
|
||||
dlog.createNewFile(dst);
|
||||
if (!dlog.isOpened()) {
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Error, can't create" << dst;
|
||||
<< "Error, can't create \"%1\""_tr("PIBinLog").arg(dst);
|
||||
return false;
|
||||
}
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Start join binlogs to" << dst;
|
||||
<< "Start join binlogs to \"%1\""_tr("PIBinLog").arg(dst);
|
||||
} else {
|
||||
dtime = lt;
|
||||
}
|
||||
@@ -799,7 +800,7 @@ bool PIBinaryLog::joinBinLogsSerial(const PIStringList & src,
|
||||
lt = dtime + br.timestamp;
|
||||
if (dlog.writeBinLog_raw(br.id, lt, br.data) <= 0) {
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Error, can't write to file" << dst;
|
||||
<< "Error, can't write to file \"%1\""_tr("PIBinLog").arg(dst);
|
||||
return false;
|
||||
}
|
||||
if (tm.elapsed_s() > 0.1) {
|
||||
@@ -821,7 +822,7 @@ bool PIBinaryLog::joinBinLogsSerial(const PIStringList & src,
|
||||
// piCout << "[PIBinaryLog]" << "complete" << fn;
|
||||
}
|
||||
piCout << "[PIBinaryLog]"
|
||||
<< "Finish join binlogs, total time" << PITime::fromSystemTime(lt).toString();
|
||||
<< "Finish join binlogs, total time %1"_tr("PIBinLog").arg(PITime::fromSystemTime(lt).toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -853,7 +854,7 @@ int PIBinaryLog::posForTime(const PISystemTime & time) {
|
||||
|
||||
|
||||
void PIBinaryLog::seekTo(int rindex) {
|
||||
// piCoutObj << "seekTo";
|
||||
// piCoutObj << "seekTo";
|
||||
logmutex.lock();
|
||||
pausemutex.lock();
|
||||
if (rindex < index.index.size_s() && rindex >= 0) {
|
||||
@@ -866,7 +867,7 @@ void PIBinaryLog::seekTo(int rindex) {
|
||||
startlogtime = PISystemTime::current() - lastrecord.timestamp;
|
||||
}
|
||||
}
|
||||
// piCoutObj << "seekTo done";
|
||||
// piCoutObj << "seekTo done";
|
||||
pausemutex.unlock();
|
||||
logmutex.unlock();
|
||||
}
|
||||
@@ -947,7 +948,7 @@ void PIBinaryLog::configureFromFullPathDevice(const PIString & full_path) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// piCoutObj << "configured";
|
||||
// piCoutObj << "configured";
|
||||
}
|
||||
|
||||
|
||||
@@ -989,7 +990,7 @@ void PIBinaryLog::propertyChanged(const char * s) {
|
||||
split_time = property("splitTime").toSystemTime();
|
||||
split_size = property("splitFileSize").toLLong();
|
||||
split_count = property("splitRecordCount").toInt();
|
||||
// piCoutObj << "propertyChanged" << s << play_mode;
|
||||
// piCoutObj << "propertyChanged" << s << play_mode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -459,7 +459,7 @@ PIDir PIDir::current() {
|
||||
|
||||
PIDir PIDir::home() {
|
||||
#ifndef ESP_PLATFORM
|
||||
char * rc = 0;
|
||||
char * rc = nullptr;
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
rc = new char[1024];
|
||||
@@ -482,7 +482,7 @@ PIDir PIDir::home() {
|
||||
#else
|
||||
# ifndef ESP_PLATFORM
|
||||
rc = getenv("HOME");
|
||||
if (rc == 0) return PIDir();
|
||||
if (!rc) return PIDir();
|
||||
return PIDir(rc);
|
||||
# else
|
||||
return PIDir();
|
||||
@@ -492,7 +492,7 @@ PIDir PIDir::home() {
|
||||
|
||||
|
||||
PIDir PIDir::temporary() {
|
||||
char * rc = 0;
|
||||
char * rc = nullptr;
|
||||
#ifdef WINDOWS
|
||||
rc = new char[1024];
|
||||
memset(rc, 0, 1024);
|
||||
@@ -507,8 +507,9 @@ PIDir PIDir::temporary() {
|
||||
s.prepend(separator);
|
||||
return PIDir(s);
|
||||
#else
|
||||
rc = tmpnam(0);
|
||||
if (rc == 0) return PIDir();
|
||||
char template_rc[] = "/tmp/pidir_tmp_XXXXXX";
|
||||
rc = mkdtemp(template_rc);
|
||||
if (!rc) return PIDir();
|
||||
PIString s(rc);
|
||||
return PIDir(s.left(s.findLast(PIDir::separator)));
|
||||
#endif
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "piliterals.h"
|
||||
#include "pipropertystorage.h"
|
||||
#include "pisysteminfo.h"
|
||||
#include "pitranslator.h"
|
||||
// clang-format off
|
||||
#ifdef QNX
|
||||
# include <arpa/inet.h>
|
||||
@@ -119,7 +120,8 @@ PRIVATE_DEFINITION_END(PIEthernet)
|
||||
|
||||
PIEthernet::PIEthernet(): PIIODevice("", ReadWrite) {
|
||||
construct();
|
||||
setType(UDP);
|
||||
eth_type = UDP;
|
||||
setProperty("type", (int)UDP);
|
||||
setParameters(PIEthernet::ReuseAddress | PIEthernet::MulticastLoop | PIEthernet::KeepConnection);
|
||||
}
|
||||
|
||||
@@ -128,7 +130,8 @@ PIEthernet::PIEthernet(PIEthernet::Type type_, const PIString & ip_port, const P
|
||||
: PIIODevice(ip_port, ReadWrite) {
|
||||
construct();
|
||||
addr_r.set(ip_port);
|
||||
setType(type_);
|
||||
eth_type = type_;
|
||||
setProperty("type", (int)type_);
|
||||
setParameters(params_);
|
||||
if (type_ != UDP) init();
|
||||
}
|
||||
@@ -139,9 +142,11 @@ PIEthernet::PIEthernet(int sock_, PIString ip_port): PIIODevice("", ReadWrite) {
|
||||
addr_s.set(ip_port);
|
||||
sock = sock_;
|
||||
opened_ = connected_ = true;
|
||||
is_server_client = true;
|
||||
eth_type = TCP_Client;
|
||||
setProperty("type", (int)TCP_Client);
|
||||
init();
|
||||
setParameters(PIEthernet::ReuseAddress | PIEthernet::MulticastLoop);
|
||||
setType(TCP_Client, false);
|
||||
setPath(ip_port);
|
||||
ethNonblocking(sock);
|
||||
PRIVATE->event.create();
|
||||
@@ -161,14 +166,12 @@ PIEthernet::~PIEthernet() {
|
||||
void PIEthernet::construct() {
|
||||
// piCout << " PIEthernet" << uint(this);
|
||||
setOption(BlockingWrite);
|
||||
connected_ = connecting_ = listen_threaded = server_bounded = false;
|
||||
sock = sock_s = -1;
|
||||
setReadTimeout(10_s);
|
||||
setWriteTimeout(10_s);
|
||||
setTTL(64);
|
||||
setMulticastTTL(1);
|
||||
server_thread_.setData(this);
|
||||
server_thread_.setName("__S__server_thread"_a);
|
||||
server_thread_.setName("_S.tcpserver"_a);
|
||||
#ifdef MICRO_PIP
|
||||
setThreadedReadBufferSize(512);
|
||||
#else
|
||||
@@ -178,9 +181,9 @@ void PIEthernet::construct() {
|
||||
}
|
||||
|
||||
|
||||
bool PIEthernet::init() {
|
||||
if (isOpened()) return true;
|
||||
if (sock != -1) return true;
|
||||
void PIEthernet::init() {
|
||||
if (isOpened() || is_server_client) return;
|
||||
if (sock != -1) return;
|
||||
// piCout << "init " << type();
|
||||
PRIVATE->event.destroy();
|
||||
if (sock_s == sock) sock_s = -1;
|
||||
@@ -203,13 +206,13 @@ bool PIEthernet::init() {
|
||||
sock_s = sock;
|
||||
if (sock == -1 || sock_s == -1) {
|
||||
piCoutObj << "Can`t create socket," << ethErrorString();
|
||||
return false;
|
||||
connected_ = connecting_ = opened_ = false;
|
||||
return;
|
||||
}
|
||||
applyParameters();
|
||||
applyTimeouts();
|
||||
applyOptInt(IPPROTO_IP, IP_TTL, TTL());
|
||||
// piCoutObj << "inited" << path();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -895,8 +898,10 @@ void PIEthernet::server_func(void * eth) {
|
||||
piMSleep(10);
|
||||
return;
|
||||
}
|
||||
if (ce->debug()) piCout << "[PIEthernet] Can`t accept new connection," << ethErrorString();
|
||||
piMSleep(10);
|
||||
if (ce->debug())
|
||||
piCout << "[PIEthernet]"
|
||||
<< "Can`t accept new connection, %1"_tr("PIEthernet").arg(ethErrorString());
|
||||
piMSleep(50);
|
||||
return;
|
||||
}
|
||||
PIString ip = PIStringAscii(inet_ntoa(client_addr.sin_addr));
|
||||
@@ -1079,14 +1084,16 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
ulong ulOutBufLen = sizeof(IP_ADAPTER_INFO);
|
||||
PIP_ADAPTER_INFO pAdapterInfo = (PIP_ADAPTER_INFO)HeapAlloc(GetProcessHeap(), 0, sizeof(IP_ADAPTER_INFO));
|
||||
if (!pAdapterInfo) {
|
||||
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersInfo";
|
||||
piCout << "[PIEthernet]"
|
||||
<< "Error allocating memory needed to call GetAdaptersInfo"_tr("PIEthernet");
|
||||
return il;
|
||||
}
|
||||
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
|
||||
HeapFree(GetProcessHeap(), 0, pAdapterInfo);
|
||||
pAdapterInfo = (PIP_ADAPTER_INFO)HeapAlloc(GetProcessHeap(), 0, ulOutBufLen);
|
||||
if (!pAdapterInfo) {
|
||||
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersInfo";
|
||||
piCout << "[PIEthernet]"
|
||||
<< "Error allocating memory needed to call GetAdaptersInfo"_tr("PIEthernet");
|
||||
return il;
|
||||
}
|
||||
}
|
||||
@@ -1132,7 +1139,8 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
ifc.ifc_len = 256;
|
||||
ifc.ifc_buf = new char[ifc.ifc_len];
|
||||
if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
|
||||
piCout << "[PIEthernet] Can`t get interfaces:" << errorString();
|
||||
piCout << "[PIEthernet]"
|
||||
<< "Can`t get interfaces: %1"_tr("PIEthernet").arg(errorString());
|
||||
delete[] ifc.ifc_buf;
|
||||
return il;
|
||||
}
|
||||
@@ -1221,7 +1229,8 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
}
|
||||
freeifaddrs(ret);
|
||||
} else
|
||||
piCout << "[PIEthernet] Can`t get interfaces:" << errorString();
|
||||
piCout << "[PIEthernet]"
|
||||
<< "Can`t get interfaces: %1"_tr("PIEthernet").arg(errorString());
|
||||
if (s != -1) ::close(s);
|
||||
# endif
|
||||
# endif
|
||||
|
||||
@@ -472,7 +472,7 @@ protected:
|
||||
virtual void received(const void * data, int size) { ; }
|
||||
|
||||
void construct();
|
||||
bool init();
|
||||
void init();
|
||||
bool openDevice() override;
|
||||
bool closeDevice() override;
|
||||
void closeSocket(int & sd);
|
||||
@@ -481,8 +481,9 @@ protected:
|
||||
void applyOptInt(int level, int opt, int val);
|
||||
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
int sock, sock_s;
|
||||
std::atomic_bool connected_, connecting_, listen_threaded, server_bounded;
|
||||
int sock = -1, sock_s = -1;
|
||||
std::atomic_bool connected_ = {false}, connecting_ = {false}, listen_threaded = {false}, server_bounded = {false};
|
||||
bool is_server_client = false;
|
||||
mutable PINetworkAddress addr_r, addr_s, addr_lr;
|
||||
Type eth_type;
|
||||
PIThread server_thread_;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "piincludes_p.h"
|
||||
#include "piiostream.h"
|
||||
#include "pitime_win.h"
|
||||
#include "pitranslator.h"
|
||||
#ifdef WINDOWS
|
||||
# undef S_IFDIR
|
||||
# undef S_IFREG
|
||||
@@ -295,7 +296,7 @@ void PIFile::resize(llong new_size, uchar fill_) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
piCoutObj << "Downsize is not supported yet :-(";
|
||||
piCoutObj << "Downsize is not supported yet :-("_tr("PIFile");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -56,12 +56,12 @@ bool PIIOByteArray::open(const PIByteArray & buffer) {
|
||||
|
||||
|
||||
ssize_t PIIOByteArray::readDevice(void * read_to, ssize_t size) {
|
||||
// piCout << "PIIOByteArray::read" << data_ << size << canRead();
|
||||
// piCout << "PIIOByteArray::read" << data_ << size << canRead();
|
||||
if (!canRead() || !data_) return -1;
|
||||
int ret = piMini(size, data_->size_s() - pos);
|
||||
if (ret <= 0) return -1;
|
||||
memcpy(read_to, data_->data(pos), ret);
|
||||
// piCout << "readed" << ret;
|
||||
// piCout << "readed" << ret;
|
||||
pos += size;
|
||||
if (pos > data_->size_s()) pos = data_->size_s();
|
||||
return ret;
|
||||
@@ -69,12 +69,12 @@ ssize_t PIIOByteArray::readDevice(void * read_to, ssize_t size) {
|
||||
|
||||
|
||||
ssize_t PIIOByteArray::writeDevice(const void * data, ssize_t size) {
|
||||
// piCout << "PIIOByteArray::write" << data << size << canWrite();
|
||||
// piCout << "PIIOByteArray::write" << data << size << canWrite();
|
||||
if (!canWrite() || !data) return -1;
|
||||
// piCout << "write" << data;
|
||||
if (pos > data_->size_s()) pos = data_->size_s();
|
||||
PIByteArray rs = PIByteArray(data, size);
|
||||
// piCoutObj << rs;
|
||||
// piCoutObj << rs;
|
||||
data_->insert(pos, rs);
|
||||
pos += rs.size_s();
|
||||
return rs.size_s();
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "piliterals_time.h"
|
||||
#include "pipropertystorage.h"
|
||||
#include "pitime.h"
|
||||
#include "pitranslator.h"
|
||||
|
||||
|
||||
//! \class PIIODevice piiodevice.h
|
||||
@@ -222,7 +223,7 @@ void PIIODevice::stopThreadedRead() {
|
||||
if (!destroying) {
|
||||
interrupt();
|
||||
} else {
|
||||
piCoutObj << "Error: Device is running after destructor!";
|
||||
piCoutObj << "Error: Device is running after destructor!"_tr("PIIODevice");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -337,8 +338,8 @@ void PIIODevice::_init() {
|
||||
#else
|
||||
threaded_read_buffer_size = 4_KiB;
|
||||
#endif
|
||||
read_thread.setName("__S__.PIIODevice.read_thread");
|
||||
write_thread.setName("__S__.PIIODevice.write_thread");
|
||||
read_thread.setName("_S.PIIODev.read");
|
||||
write_thread.setName("_S.PIIODev.write");
|
||||
CONNECT(void, &write_thread, started, this, write_func);
|
||||
CONNECTL(&read_thread, started, [this]() {
|
||||
if (!isOpened()) open();
|
||||
@@ -384,9 +385,10 @@ void PIIODevice::read_func() {
|
||||
ok = open();
|
||||
}
|
||||
}
|
||||
if (!ok) return;
|
||||
if (!ok || read_thread.isStopping()) return;
|
||||
}
|
||||
ssize_t readed_ = read(buffer_tr.data(), buffer_tr.size_s());
|
||||
if (read_thread.isStopping()) return;
|
||||
if (readed_ <= 0) {
|
||||
piMSleep(10);
|
||||
// cout << readed_ << ", " << errno << ", " << errorString() << endl;
|
||||
@@ -528,12 +530,13 @@ void PIIODevice::configureFromVariant(const PIVariantTypes::IODevice & d) {
|
||||
|
||||
|
||||
void PIIODevice::splitFullPath(PIString fpwm, PIString * full_path, DeviceMode * mode, DeviceOptions * opts) {
|
||||
fpwm.trim();
|
||||
int dm = 0;
|
||||
DeviceOptions op = 0;
|
||||
if (fpwm.find('(') > 0 && fpwm.find(')') > 0) {
|
||||
PIString dms(fpwm.right(fpwm.length() - fpwm.findLast('(')).takeRange('(', ')').trim().toLowerCase().removeAll(' '));
|
||||
PIStringList opts(dms.split(","));
|
||||
piForeachC(PIString & o, opts) {
|
||||
for (const auto & o: opts) {
|
||||
// piCout << dms;
|
||||
if (o == "r"_a || o == "ro"_a || o == "read"_a || o == "readonly"_a) dm |= ReadOnly;
|
||||
if (o == "w"_a || o == "wo"_a || o == "write"_a || o == "writeonly"_a) dm |= WriteOnly;
|
||||
@@ -616,11 +619,12 @@ PIString PIIODevice::fullPathOptions() const {
|
||||
//! В метод \a configureFromFullPath() "full_path" передается без \a fullPathPrefix() и "://".
|
||||
//! См. \ref PIIODevice_sec7
|
||||
PIIODevice * PIIODevice::createFromFullPath(const PIString & full_path) {
|
||||
PIString prefix = full_path.left(full_path.find(":"));
|
||||
PIString fp = full_path.trimmed();
|
||||
PIString prefix = fp.left(fp.find(":"));
|
||||
PIIODevice * nd = newDeviceByPrefix(prefix.dataAscii());
|
||||
if (!nd) return nullptr;
|
||||
nd->configureFromFullPath(full_path.mid(prefix.length() + 3));
|
||||
cacheFullPath(full_path, nd);
|
||||
nd->configureFromFullPath(fp.mid(prefix.length() + 3));
|
||||
cacheFullPath(fp, nd);
|
||||
return nd;
|
||||
}
|
||||
|
||||
@@ -663,7 +667,7 @@ PIMap<PIConstChars, PIIODevice::FabricInfo> & PIIODevice::fabrics() {
|
||||
|
||||
|
||||
bool PIIODevice::threadedRead(const uchar * readed, ssize_t size) {
|
||||
// piCout << "iodevice threaded read";
|
||||
// piCout << "iodevice threaded read";
|
||||
if (func_read) return func_read(readed, size, ret_data_);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "piiostring.h"
|
||||
|
||||
#include "pitranslator.h"
|
||||
|
||||
|
||||
//! \class PIIOString piiostring.h
|
||||
//! \details
|
||||
@@ -49,7 +51,7 @@ void PIIOString::clear() {
|
||||
|
||||
bool PIIOString::open(PIString * string, PIIODevice::DeviceMode mode) {
|
||||
if (mode == PIIODevice::ReadWrite) {
|
||||
piCoutObj << "Error: ReadWrite mode not supported, use WriteOnly or ReadOnly";
|
||||
piCoutObj << "Error: ReadWrite mode not supported, use WriteOnly or ReadOnly"_tr("PIIOString");
|
||||
str = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ PIPeer::PIPeer(const PIString & n)
|
||||
, eth_tcp_cli(PIEthernet::TCP_Client)
|
||||
, diag_s(false)
|
||||
, diag_d(false) {
|
||||
sync_timer.setName("__S__.PIPeer.sync_timer");
|
||||
sync_timer.setName("_S.PIPeer.sync");
|
||||
// piCout << " PIPeer" << uint(this);
|
||||
destroyed = false;
|
||||
setDebug(false);
|
||||
@@ -229,7 +229,7 @@ void PIPeer::initEths(PIStringList al) {
|
||||
piForeachC(PIString & a, al) {
|
||||
ce = new PIEthernet();
|
||||
ce->setDebug(false);
|
||||
ce->setName("__S__PIPeer_traffic_eth_rec_" + a);
|
||||
ce->setName("_S.PIPeer.traf_rec_" + a);
|
||||
ce->setParameters(0);
|
||||
bool ok = false;
|
||||
for (int p = _PIPEER_TRAFFIC_PORT_S; p < _PIPEER_TRAFFIC_PORT_E; ++p) {
|
||||
@@ -249,7 +249,7 @@ void PIPeer::initEths(PIStringList al) {
|
||||
if (!ok) delete ce;
|
||||
}
|
||||
eth_send.setDebug(false);
|
||||
eth_send.setName("__S__PIPeer_traffic_eth_send");
|
||||
eth_send.setName("_S.PIPeer.traf_send");
|
||||
eth_send.setParameters(0);
|
||||
// piCoutObj << "initEths ok";
|
||||
}
|
||||
@@ -265,7 +265,7 @@ void PIPeer::initMBcasts(PIStringList al) {
|
||||
// piCout << "mcast try" << a;
|
||||
ce = new PIEthernet();
|
||||
ce->setDebug(false);
|
||||
ce->setName("__S__PIPeer_mcast_eth_" + a);
|
||||
ce->setName("_S.PIPeer.mcast_" + a);
|
||||
ce->setParameters(0);
|
||||
ce->setSendAddress(_PIPEER_MULTICAST_IP, _PIPEER_MULTICAST_PORT);
|
||||
ce->setReadAddress(a, _PIPEER_MULTICAST_PORT);
|
||||
@@ -285,7 +285,7 @@ void PIPeer::initMBcasts(PIStringList al) {
|
||||
piForeachC(PIString & a, al) {
|
||||
ce = new PIEthernet();
|
||||
ce->setDebug(false);
|
||||
ce->setName("__S__PIPeer_bcast_eth_" + a);
|
||||
ce->setName("_S.PIPeer.bcast_" + a);
|
||||
ce->setParameters(PIEthernet::Broadcast);
|
||||
cint = prev_ifaces.getByAddress(a);
|
||||
nm = (cint == 0) ? "255.255.255.0" : cint->netmask;
|
||||
@@ -302,7 +302,7 @@ void PIPeer::initMBcasts(PIStringList al) {
|
||||
// piCoutObj << "invalid address for bcast" << a;
|
||||
}
|
||||
}
|
||||
eth_lo.setName("__S__PIPeer_eth_loopback");
|
||||
eth_lo.setName("_S.PIPeer.lo");
|
||||
eth_lo.setParameters(PIEthernet::SeparateSockets);
|
||||
eth_lo.init();
|
||||
cint = prev_ifaces.getByAddress("127.0.0.1");
|
||||
@@ -317,13 +317,13 @@ void PIPeer::initMBcasts(PIStringList al) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
eth_tcp_srv.setName("__S__PIPeer_eth_TCP_Server");
|
||||
eth_tcp_srv.setName("_S.PIPeer.TCP_Server");
|
||||
eth_tcp_srv.init();
|
||||
eth_tcp_srv.listen("0.0.0.0", _PIPEER_TCP_PORT, true);
|
||||
eth_tcp_srv.setDebug(false);
|
||||
CONNECT1(void, PIEthernet *, ð_tcp_srv, newConnection, this, newTcpClient);
|
||||
eth_tcp_srv.startThreadedRead();
|
||||
eth_tcp_cli.setName("__S__PIPeer_eth_TCP_Client");
|
||||
eth_tcp_cli.setName("_S.PIPeer.TCP_Client");
|
||||
eth_tcp_cli.init();
|
||||
eth_tcp_cli.setDebug(false);
|
||||
tcpClientReconnect();
|
||||
@@ -987,7 +987,7 @@ void PIPeer::interrupt() {
|
||||
|
||||
|
||||
void PIPeer::newTcpClient(PIEthernet * client) {
|
||||
client->setName("__S__PIPeer_eth_TCP_ServerClient" + client->path());
|
||||
client->setName("_S.PIPeer.TCP_ServerClient" + client->path());
|
||||
piCoutObj << "client" << client->path();
|
||||
CONNECT2(void, const uchar *, ssize_t, client, threadedReadEvent, this, mbcastRead);
|
||||
client->startThreadedRead();
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "piincludes_p.h"
|
||||
#include "pipropertystorage.h"
|
||||
#include "pitime.h"
|
||||
#include "pitranslator.h"
|
||||
#include "piwaitevent_p.h"
|
||||
|
||||
#include <errno.h>
|
||||
@@ -463,10 +464,10 @@ int PISerial::convertSpeed(PISerial::Speed speed) {
|
||||
default: break;
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
piCoutObj << "Warning: Custom speed" << (int)speed;
|
||||
piCoutObj << "Warning: Custom speed %1"_tr("PISerial").arg((int)speed);
|
||||
return (int)speed;
|
||||
#else
|
||||
piCoutObj << "Warning: Unknown speed" << (int)speed << ", using 115200";
|
||||
piCoutObj << "Warning: Unknown speed %1, using 115200"_tr("PISerial").arg((int)speed);
|
||||
return B115200;
|
||||
#endif
|
||||
}
|
||||
@@ -691,7 +692,7 @@ bool PISerial::openDevice() {
|
||||
}
|
||||
}
|
||||
if (p.isEmpty()) {
|
||||
piCoutObj << "Unable to find device \"" << pl << "\"";
|
||||
piCoutObj << "Unable to find device \"%1\""_tr("PISerial").arg(pl);
|
||||
}
|
||||
}
|
||||
if (p.isEmpty()) return false;
|
||||
@@ -708,7 +709,7 @@ bool PISerial::openDevice() {
|
||||
PIString wp = "//./" + p;
|
||||
PRIVATE->hCom = CreateFileA(wp.dataAscii(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
|
||||
if (PRIVATE->hCom == INVALID_HANDLE_VALUE) {
|
||||
piCoutObj << "Unable to open \"" << p << "\"" << errorString();
|
||||
piCoutObj << "Unable to open \"%1\": %2"_tr("PISerial").arg(p).arg(errorString());
|
||||
fd = -1;
|
||||
return false;
|
||||
}
|
||||
@@ -722,7 +723,7 @@ bool PISerial::openDevice() {
|
||||
}
|
||||
fd = ::open(p.data(), O_NOCTTY | om);
|
||||
if (fd == -1) {
|
||||
piCoutObj << "Unable to open \"" << p << "\"";
|
||||
piCoutObj << "Unable to open \"%1\": %2"_tr("PISerial").arg(p).arg(errorString());
|
||||
return false;
|
||||
}
|
||||
tcgetattr(fd, &PRIVATE->desc);
|
||||
@@ -747,7 +748,7 @@ bool PISerial::closeDevice() {
|
||||
#ifdef WINDOWS
|
||||
SetCommState(PRIVATE->hCom, &PRIVATE->sdesc);
|
||||
SetCommMask(PRIVATE->hCom, PRIVATE->mask);
|
||||
// piCoutObj << "close" <<
|
||||
// piCoutObj << "close" <<
|
||||
CloseHandle(PRIVATE->hCom);
|
||||
PRIVATE->hCom = 0;
|
||||
#else
|
||||
@@ -788,7 +789,7 @@ void PISerial::applySettings() {
|
||||
}
|
||||
PRIVATE->desc.StopBits = params[PISerial::TwoStopBits] ? TWOSTOPBITS : ONESTOPBIT;
|
||||
if (SetCommState(PRIVATE->hCom, &PRIVATE->desc) == -1) {
|
||||
piCoutObj << "Unable to set comm state for \"" << path() << "\"";
|
||||
piCoutObj << "Unable to set comm state for \"%1\""_tr("PISerial").arg(path());
|
||||
return;
|
||||
}
|
||||
#else
|
||||
@@ -822,7 +823,7 @@ void PISerial::applySettings() {
|
||||
setTimeouts();
|
||||
|
||||
if (tcsetattr(fd, TCSANOW, &PRIVATE->desc) < 0) {
|
||||
piCoutObj << "Can`t set attributes for \"" << path() << "\"";
|
||||
piCoutObj << "Can`t set attributes for \"%1\""_tr("PISerial").arg(path());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -871,7 +872,7 @@ ssize_t PISerial::readDevice(void * read_to, ssize_t max_size) {
|
||||
// piCoutObj << "read ..." << PRIVATE->hCom << max_size;
|
||||
DWORD mask = 0;
|
||||
if (GetCommMask(PRIVATE->hCom, &mask) == FALSE) {
|
||||
piCoutObj << "read error" << errorString();
|
||||
piCoutObj << "Read error: %1"_tr("PISerial").arg(errorString());
|
||||
stop();
|
||||
close();
|
||||
return 0;
|
||||
@@ -883,7 +884,7 @@ ssize_t PISerial::readDevice(void * read_to, ssize_t max_size) {
|
||||
DWORD err = GetLastError();
|
||||
// piCoutObj << "read" << err;
|
||||
if (err == ERROR_BAD_COMMAND || err == ERROR_ACCESS_DENIED) {
|
||||
piCoutObj << "read error" << errorString();
|
||||
piCoutObj << "Read error: %1"_tr("PISerial").arg(errorString());
|
||||
stop();
|
||||
close();
|
||||
return 0;
|
||||
|
||||
@@ -21,9 +21,12 @@
|
||||
|
||||
#include "piliterals_time.h"
|
||||
#include "pitime.h"
|
||||
#include "pitranslator.h"
|
||||
|
||||
|
||||
const uint PIBaseTransfer::signature = 0x54424950;
|
||||
|
||||
|
||||
PIBaseTransfer::PIBaseTransfer(): crc(standardCRC_16()), diag(false) {
|
||||
header.sig = signature;
|
||||
crc_enabled = true;
|
||||
@@ -96,7 +99,7 @@ void PIBaseTransfer::received(PIByteArray data) {
|
||||
data >> h;
|
||||
PacketType pt = (PacketType)h.type;
|
||||
if (!h.check_sig()) {
|
||||
piCoutObj << "invalid packet signature";
|
||||
piCoutObj << "invalid packet signature"_tr("PIBaseTransfer");
|
||||
diag.received(data.size(), false);
|
||||
return;
|
||||
} else
|
||||
@@ -119,7 +122,7 @@ void PIBaseTransfer::received(PIByteArray data) {
|
||||
ccrc = 0;
|
||||
if (rcrc != ccrc) {
|
||||
header.id = h.id;
|
||||
piCoutObj << "invalid CRC";
|
||||
piCoutObj << "invalid CRC"_tr("PIBaseTransfer");
|
||||
sendReply(pt_ReplyInvalid);
|
||||
} else {
|
||||
mutex_session.lock();
|
||||
@@ -170,9 +173,9 @@ void PIBaseTransfer::received(PIByteArray data) {
|
||||
if (send_up > 20 && send_up > packets_count * 2) packets_count += piMaxi(packets_count / 10, 1);
|
||||
// piCoutObj << packets_count;
|
||||
} else
|
||||
piCoutObj << "invalid reply id";
|
||||
piCoutObj << "invalid reply id"_tr("PIBaseTransfer");
|
||||
mutex_session.unlock();
|
||||
// piCoutObj << "Done Packet" << h.id;
|
||||
// piCoutObj << "Done Packet" << h.id;
|
||||
}
|
||||
if (is_receiving && h.id == 0) {
|
||||
if (pt == pt_ReplySuccess) {
|
||||
@@ -213,7 +216,7 @@ void PIBaseTransfer::received(PIByteArray data) {
|
||||
}
|
||||
if (is_receiving) {
|
||||
if (header.session_id != h.session_id) {
|
||||
piCoutObj << "restart receive";
|
||||
piCoutObj << "restart receive"_tr("PIBaseTransfer");
|
||||
mutex_header.unlock();
|
||||
finish_receive(false, true);
|
||||
} else {
|
||||
@@ -344,7 +347,7 @@ bool PIBaseTransfer::send_process() {
|
||||
mutex_send.unlock();
|
||||
if (break_) return finish_send(false);
|
||||
}
|
||||
// piCoutObj << "send done, checking";
|
||||
// piCoutObj << "send done, checking";
|
||||
PITimeMeasurer rtm;
|
||||
int prev_chk = 0;
|
||||
mutex_send.lock();
|
||||
@@ -516,7 +519,7 @@ bool PIBaseTransfer::getStartRequest() {
|
||||
diag.sended(ba.size_s());
|
||||
sendRequest(ba);
|
||||
if (break_) return false;
|
||||
// piCoutObj << replies[0];
|
||||
// piCoutObj << replies[0];
|
||||
mutex_session.lock();
|
||||
if (replies[0] == pt_ReplySuccess) {
|
||||
state_string = "send permited!";
|
||||
@@ -532,7 +535,7 @@ bool PIBaseTransfer::getStartRequest() {
|
||||
|
||||
|
||||
void PIBaseTransfer::processData(int id, PIByteArray & data) {
|
||||
// piCoutObj << "received packet" << id << ", size" << data.size();
|
||||
// piCoutObj << "received packet" << id << ", size" << data.size();
|
||||
if (id < 1 || id > replies.size_s()) return;
|
||||
if (!session[id - 1].isEmpty()) {
|
||||
header.id = id;
|
||||
@@ -595,7 +598,7 @@ PIByteArray PIBaseTransfer::build_packet(int id) {
|
||||
hdr << header;
|
||||
mutex_header.unlock();
|
||||
ret.insert(0, hdr);
|
||||
// piCoutObj << "Send Packet" << header.id << ret.size();
|
||||
// piCoutObj << "Send Packet" << header.id << ret.size();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "piiostream.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "pitime.h"
|
||||
#include "pitranslator.h"
|
||||
|
||||
/** \class PIConnection
|
||||
* \brief Complex Input/Output point
|
||||
@@ -142,7 +143,7 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
|
||||
// piCout << name_list << flt_list << chk_set;
|
||||
chk_set.remove("");
|
||||
if (!chk_set.isEmpty()) {
|
||||
piCoutObj << "Error," << chk_set.toVector() << "names assigned to both devices and filters!";
|
||||
piCoutObj << "Error,"_tr("PIConnection") << chk_set.toVector() << "names assigned to both devices and filters!"_tr("PIConnection");
|
||||
return false;
|
||||
}
|
||||
PIMap<PIString, PIString> dev_aliases;
|
||||
@@ -238,7 +239,7 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
|
||||
}
|
||||
setDebug(pdebug);
|
||||
for (const PIString & f: filter_fails) {
|
||||
piCoutObj << "\"addFilter\" error: no such device \"" << f << "\"!";
|
||||
piCoutObj << "\"addFilter\" error: no such device \"%1\"!"_tr("PIConnection").arg(f);
|
||||
}
|
||||
for (const PIConfig::Entry * e: cb) {
|
||||
PIString f(e->getValue("from").value()), t(e->getValue("to").value());
|
||||
@@ -469,7 +470,7 @@ PIPacketExtractor * PIConnection::addFilter(const PIString & name_, const PIStri
|
||||
if (extractors.value(full_path, nullptr)) pe = extractors.value(full_path, nullptr)->extractor;
|
||||
if (pe) dev = pe;
|
||||
if (!dev) {
|
||||
piCoutObj << "\"addFilter\" error: no such device or filter \"" << full_path << "\"!";
|
||||
piCoutObj << "\"addFilter\" error: no such device or filter \"%1\"!"_tr("PIConnection").arg(full_path);
|
||||
return nullptr;
|
||||
}
|
||||
if (!e) {
|
||||
@@ -508,7 +509,7 @@ PIPacketExtractor * PIConnection::addFilter(PIPacketExtractor * filter, const PI
|
||||
if (pe) {
|
||||
dev = pe;
|
||||
} else {
|
||||
piCoutObj << "\"addFilter\" error: no such device or filter \"" << full_path << "\"!";
|
||||
piCoutObj << "\"addFilter\" error: no such device or filter \"%1\"!"_tr("PIConnection").arg(full_path);
|
||||
return nullptr;
|
||||
}
|
||||
if (!e) {
|
||||
@@ -739,7 +740,7 @@ void PIConnection::addSender(const PIString & name_, const PIString & full_path_
|
||||
}
|
||||
PIIODevice * dev = devByString(full_path_name);
|
||||
if (!dev) {
|
||||
piCoutObj << "\"addSender\" error: no such device \"" << full_path_name << "\"!";
|
||||
piCoutObj << "\"addSender\" error: no such device \"%1\"!"_tr("PIConnection").arg(full_path_name);
|
||||
return;
|
||||
}
|
||||
if (!s->isRunning() && start_) {
|
||||
@@ -899,7 +900,7 @@ int PIConnection::writeByFullPath(const PIString & full_path, const PIByteArray
|
||||
PIIODevice * dev = __device_pool__->device(fp);
|
||||
// piCout << "SEND" << full_path << fp;
|
||||
if (!dev) {
|
||||
piCoutObj << "No such full path \"" << full_path << "\"!";
|
||||
piCoutObj << "No such full path \"%1\"!"_tr("PIConnection").arg(full_path);
|
||||
return -1;
|
||||
}
|
||||
return write(dev, data);
|
||||
@@ -909,7 +910,7 @@ int PIConnection::writeByFullPath(const PIString & full_path, const PIByteArray
|
||||
int PIConnection::writeByName(const PIString & name_, const PIByteArray & data) {
|
||||
PIIODevice * dev = deviceByName(name_);
|
||||
if (!dev) {
|
||||
piCoutObj << "No such device \"" << name_ << "\"!";
|
||||
piCoutObj << "No such device \"%1\"!"_tr("PIConnection").arg(name_);
|
||||
return -1;
|
||||
}
|
||||
return write(dev, data);
|
||||
@@ -918,12 +919,12 @@ int PIConnection::writeByName(const PIString & name_, const PIByteArray & data)
|
||||
|
||||
int PIConnection::write(PIIODevice * dev, const PIByteArray & data) {
|
||||
if (!dev) {
|
||||
piCoutObj << "Null Device!";
|
||||
piCoutObj << "Null Device!"_tr("PIConnection");
|
||||
return -1;
|
||||
}
|
||||
if (!dev->isOpened()) return -1;
|
||||
if (!dev->canWrite()) {
|
||||
piCoutObj << "Device \"" << dev->constructFullPath() << "\" can`t write!";
|
||||
piCoutObj << "Device \"%1\" can`t write!"_tr("PIConnection").arg(dev->constructFullPath());
|
||||
return -1;
|
||||
}
|
||||
int ret = dev->write(data);
|
||||
@@ -982,7 +983,7 @@ PIIODevice * PIConnection::DevicePool::addDevice(PIConnection * parent, const PI
|
||||
// piCout << "new device" << fp;
|
||||
dd->dev = PIIODevice::createFromFullPath(fp);
|
||||
if (!dd->dev) {
|
||||
piCoutObj << "Error: can`t create device \"" << fp << "\"!"; //:" << errorString();
|
||||
piCoutObj << "Error: can`t create device \"%1\"!"_tr("PIConnection").arg(fp);
|
||||
return nullptr;
|
||||
}
|
||||
dd->dev->setProperty("__fullPath__", fp);
|
||||
@@ -998,7 +999,7 @@ PIIODevice * PIConnection::DevicePool::addDevice(PIConnection * parent, const PI
|
||||
dd->started = false;
|
||||
}
|
||||
dd->rthread = new PIThread(dd, __DevicePool_threadReadDP);
|
||||
dd->rthread->setName("__S__connection_" + fp + "_read_thread");
|
||||
dd->rthread->setName("_S.Conn." + fp + ".read");
|
||||
need_start = true;
|
||||
pmode |= PIIODevice::ReadOnly;
|
||||
}
|
||||
@@ -1211,7 +1212,7 @@ PIConnection::Extractor::~Extractor() {
|
||||
|
||||
|
||||
PIConnection::Sender::Sender(PIConnection * parent_): parent(parent_) {
|
||||
setName("__S__.PIConnection.Sender");
|
||||
setName("_S.PIConn.Sender");
|
||||
needLockRun(true);
|
||||
}
|
||||
|
||||
@@ -1258,7 +1259,7 @@ void PIConnection::unboundExtractor(PIPacketExtractor * pe) {
|
||||
void PIConnection::packetExtractorReceived(const uchar * data, int size) {
|
||||
PIString from(emitter() ? emitter()->name() : PIString());
|
||||
PIIODevice * cd = (PIIODevice *)emitter();
|
||||
// piCout << "packetExtractorReceived" << from << cd;
|
||||
// piCout << "packetExtractorReceived" << from << cd;
|
||||
if (cd) {
|
||||
PIVector<PIPacketExtractor *> be(bounded_extractors.value(cd));
|
||||
// piCout << be << (void*)data << size;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "pidiagnostics.h"
|
||||
|
||||
#include "piliterals_time.h"
|
||||
#include "pitranslator.h"
|
||||
|
||||
|
||||
/** \class PIDiagnostics
|
||||
@@ -40,7 +41,7 @@
|
||||
|
||||
|
||||
PIDiagnostics::State::State() {
|
||||
receive_speed = send_speed = PIString::readableSize(0) + "/s";
|
||||
receive_speed = send_speed = PIString::readableSize(0) + PITranslator::tr("/s", "PIDiag");
|
||||
}
|
||||
|
||||
|
||||
@@ -151,6 +152,7 @@ void PIDiagnostics::sended(int size) {
|
||||
|
||||
|
||||
void PIDiagnostics::tick(int) {
|
||||
auto speed_sec = "/s"_tr("PIDiag");
|
||||
mutex_state.lock();
|
||||
// piCoutObj << "lock";
|
||||
int tcnt_recv = 0;
|
||||
@@ -176,8 +178,8 @@ void PIDiagnostics::tick(int) {
|
||||
cur_state.sended_bytes_per_sec = ullong(double(send.bytes_ok) / its);
|
||||
}
|
||||
// piCoutObj << "tick" << recv.cnt_ok << send.cnt_ok;
|
||||
cur_state.receive_speed = PIString::readableSize(cur_state.received_bytes_per_sec) + "/s";
|
||||
cur_state.send_speed = PIString::readableSize(cur_state.sended_bytes_per_sec) + "/s";
|
||||
cur_state.receive_speed = PIString::readableSize(cur_state.received_bytes_per_sec) + speed_sec;
|
||||
cur_state.send_speed = PIString::readableSize(cur_state.sended_bytes_per_sec) + speed_sec;
|
||||
int arc = recv.cnt_ok + recv.cnt_fail;
|
||||
float good_percents = 0.f;
|
||||
if (arc > 0) good_percents = (float)recv.cnt_ok / arc * 100.f;
|
||||
@@ -195,7 +197,7 @@ void PIDiagnostics::tick(int) {
|
||||
diag = PIDiagnostics::Good;
|
||||
}
|
||||
if ((tcnt_send + tcnt_recv) != 0) {
|
||||
// piCoutObj << tcnt_recv << tcnt_send;
|
||||
// piCoutObj << tcnt_recv << tcnt_send;
|
||||
history_rec.dequeue();
|
||||
history_send.dequeue();
|
||||
Entry e;
|
||||
@@ -223,7 +225,7 @@ PIDiagnostics::Entry PIDiagnostics::calcHistory(PIQueue<Entry> & hist, int & cnt
|
||||
if (!hist[i].empty) cnt++;
|
||||
}
|
||||
e.empty = false;
|
||||
// piCoutObj << hist.size() << cnt;
|
||||
// piCoutObj << hist.size() << cnt;
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
* This class helps to deserialize and invoke neccessarily methods.
|
||||
*
|
||||
* Data packets with header and various data types can be automated by this class.
|
||||
* Every key value mapped to event handler or lambda-function.
|
||||
* Every key value mapped to object member function, lambda-function or functor.
|
||||
*
|
||||
* This class can remove \b switch-case with deserialization code and
|
||||
* replace it with several \a assign() calls, binded to ready-to-use event handlers.
|
||||
@@ -48,30 +48,15 @@
|
||||
*
|
||||
*
|
||||
* \section PIParseHelper_usage Usage
|
||||
* There are two variants: subclassing and aggregating.
|
||||
*
|
||||
* ### Subclass
|
||||
* Create instance of %PIParseHelper, or subclass.
|
||||
*
|
||||
* Inherit your class from %PIParseHelper and construct it with \b this.
|
||||
*
|
||||
* In \a assign() methods you can use event handlers with 0 or 1 arguments,
|
||||
* using HANDLER() macro.
|
||||
*
|
||||
* ### Aggregate
|
||||
*
|
||||
* Create instance of %PIParseHelper and construct it with target object.
|
||||
*
|
||||
* In \a assign() methods you can use event handlers with 0 or 1 arguments,
|
||||
* using HANDLER() macro in target object namespace (e.g. \"o.HANDLER(slot)\").
|
||||
* In \a assign() methods you can use object member function, lambda-function
|
||||
* or functor with 0 or 1 arguments,
|
||||
*
|
||||
*
|
||||
* \section PIParseHelper_lambda Lambda-functions
|
||||
* Assign methods that receive lambda-functions can`t accept direct lambda (\"[](){}\")
|
||||
* with template type deducation because of C++ specific. E.g.
|
||||
* \code assign(1, [this](SomeStruct s){}) \endcode
|
||||
* doesn`t compile, but these variants allowed:
|
||||
* \code assign(1, std::function<void(SomeStruct)>([this](SomeStruct s){})) \endcode
|
||||
* \code assign<SomeStruct>(1, [this](SomeStruct s){}) \endcode
|
||||
* \code assign(1, [this](const SomeStruct & s){}) \endcode
|
||||
*
|
||||
*
|
||||
* \section PIParseHelper_examples Examples
|
||||
@@ -87,56 +72,21 @@
|
||||
template<typename Key>
|
||||
class PIParseHelper {
|
||||
public:
|
||||
//! \brief Construct %PIParseHelper with target object \"p\"
|
||||
PIParseHelper(PIObject * p): parent(p) {}
|
||||
//! \brief Construct %PIParseHelper
|
||||
PIParseHelper() {}
|
||||
|
||||
|
||||
//! \brief Assign key \"key\" to event handler \"handler\" with 1 argument
|
||||
template<typename T, typename Ret>
|
||||
void assign(Key key, Ret (*handler)(void *, T)) {
|
||||
if (!parent) return;
|
||||
auto mf = PIObject::__meta_data().value(parent->classNameID());
|
||||
auto it = mf.eh_func.makeIterator();
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
if (it.value().addr == handler) {
|
||||
void * addr = it.value().addr;
|
||||
auto func = [addr](PIObject * o, PIByteArray data) {
|
||||
T v;
|
||||
data >> v;
|
||||
((void (*)(void *, T))addr)(o, v);
|
||||
};
|
||||
functions[key] << func;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! \brief Assign key \"key\" to event handler \"handler\" without arguments
|
||||
template<typename Ret>
|
||||
void assign(Key key, Ret (*handler)(void *)) {
|
||||
if (!parent) return;
|
||||
auto mf = PIObject::__meta_data().value(parent->classNameID());
|
||||
auto it = mf.eh_func.makeIterator();
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
if (it.value().addr == handler) {
|
||||
void * addr = it.value().addr;
|
||||
auto func = [addr](PIObject * o, PIByteArray) { ((void (*)(void *))addr)(o); };
|
||||
functions[key] << func;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//! \brief Assign key \"key\" to lambda-function \"func\" without arguments
|
||||
void assign(Key key, std::function<void()> func) {
|
||||
auto lf = [func](PIByteArray) { func(); };
|
||||
functions[key] << lf;
|
||||
}
|
||||
|
||||
|
||||
//! \brief Assign key \"key\" to lambda-function \"func\" with 1 argument
|
||||
//! \note Important! Direct lambda functions are not allowed, see \ref PIParseHelper_lambda
|
||||
template<typename T>
|
||||
void assign(Key key, std::function<void(T)> func) {
|
||||
if (!parent) return;
|
||||
auto lf = [func](PIObject *, PIByteArray data) {
|
||||
void assign(Key key, std::function<void(const T &)> func) {
|
||||
auto lf = [func](PIByteArray data) {
|
||||
if (!data.isEmpty()) {
|
||||
T v;
|
||||
data >> v;
|
||||
@@ -147,26 +97,44 @@ public:
|
||||
}
|
||||
|
||||
|
||||
//! \brief Assign key \"key\" to lambda-function \"func\" without arguments
|
||||
//! \note Important! Direct lambda functions are not allowed, see \ref PIParseHelper_lambda
|
||||
void assign(Key key, std::function<void()> func) {
|
||||
if (!parent) return;
|
||||
auto lf = [func](PIObject *, PIByteArray) { func(); };
|
||||
//! \brief Assign key \"key\" to member function of object \"obj\" without arguments
|
||||
template<typename O>
|
||||
void assign(Key key, O * obj, void (O::*member_func)()) {
|
||||
auto lf = [member_func, obj](PIByteArray) { (obj->*member_func)(); };
|
||||
functions[key] << lf;
|
||||
}
|
||||
|
||||
|
||||
//! \brief Assign key \"key\" to member function of object \"obj\" with 1 argument
|
||||
template<typename T, typename O>
|
||||
void assign(Key key, O * obj, void (O::*member_func)(const T &)) {
|
||||
auto lf = [member_func, obj](PIByteArray data) {
|
||||
if (!data.isEmpty()) {
|
||||
T v;
|
||||
data >> v;
|
||||
(obj->*member_func)(v);
|
||||
}
|
||||
};
|
||||
functions[key] << lf;
|
||||
}
|
||||
|
||||
|
||||
//! \brief Assign key \"key\" to functor \"func\" with 0 or 1 argument
|
||||
template<typename L>
|
||||
void assign(Key key, L func) {
|
||||
return assign(key, toStdFunction(func));
|
||||
}
|
||||
|
||||
|
||||
//! \brief Deserialize data and invoke assigned to \"key\" methods
|
||||
void parse(Key key, PIByteArray ba) {
|
||||
if (!parent) return;
|
||||
auto fl = functions.value(key);
|
||||
for (auto f: fl)
|
||||
f(parent, ba);
|
||||
f(ba);
|
||||
}
|
||||
|
||||
private:
|
||||
PIMap<Key, PIVector<std::function<void(PIObject *, PIByteArray)>>> functions;
|
||||
PIObject * parent;
|
||||
PIMap<Key, PIVector<std::function<void(PIByteArray)>>> functions;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -56,6 +56,9 @@ public:
|
||||
//! Returns packet sinature, default 0xAFBE
|
||||
ushort packetSign() const { return packet_sign; }
|
||||
|
||||
//! Returns progress of current packet receive in bytes
|
||||
int receivePacketProgress() const { return packet.size_s(); }
|
||||
|
||||
|
||||
//! Set receive aggressive optimization. If yes then %PIStreamPacker doesn`t
|
||||
//! check every byte in incoming stream but check only begin of each read()
|
||||
@@ -90,6 +93,8 @@ public:
|
||||
void assignDevice(PIIODevice * dev);
|
||||
|
||||
EVENT1(packetReceiveEvent, PIByteArray &, data);
|
||||
EVENT1(startPacketReceive, int, size);
|
||||
EVENT0(endPacketReceive);
|
||||
EVENT1(sendRequest, PIByteArray, data);
|
||||
|
||||
//! \handlers
|
||||
@@ -107,6 +112,12 @@ public:
|
||||
//! \fn void packetReceiveEvent(PIByteArray data)
|
||||
//! \brief Raise on packet successfully received
|
||||
|
||||
//! \fn void startPacketReceive(int size)
|
||||
//! \brief Raise on start receive packet with overall size \"size\"
|
||||
|
||||
//! \fn void endPacketReceive()
|
||||
//! \brief Raise on finish receive packet
|
||||
|
||||
//! \fn void sendRequest(PIByteArray data)
|
||||
//! \brief Raise from \a send() function. This data should
|
||||
//! be directly sended to your device. You can
|
||||
|
||||
@@ -36,6 +36,12 @@
|
||||
|
||||
using std::complex;
|
||||
|
||||
template<typename T>
|
||||
struct is_complex: std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct is_complex<std::complex<T>>: std::true_type {};
|
||||
|
||||
typedef complex<int> complexi;
|
||||
typedef complex<short> complexs;
|
||||
typedef complex<float> complexf;
|
||||
|
||||
@@ -63,7 +63,7 @@ class PIP_EXPORT PIMathMatrixT {
|
||||
typedef PIMathMatrixT<Cols, Rows, Type> _CMatrixI;
|
||||
typedef PIMathVectorT<Rows, Type> _CMCol;
|
||||
typedef PIMathVectorT<Cols, Type> _CMRow;
|
||||
static_assert(std::is_arithmetic<Type>::value, "Type must be arithmetic");
|
||||
static_assert(std::is_arithmetic<Type>::value || is_complex<Type>::value, "Type must be arithmetic or complex");
|
||||
static_assert(Rows > 0, "Row count must be > 0");
|
||||
static_assert(Cols > 0, "Column count must be > 0");
|
||||
|
||||
@@ -386,7 +386,7 @@ public:
|
||||
//! \brief Деление с присваиванием с матрицей `v`.
|
||||
//! \param sm матрица для деления с присваиванием.
|
||||
void operator/=(const Type & v) {
|
||||
assert(piAbs<Type>(v) > PIMATHVECTOR_ZERO_CMP);
|
||||
assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP);
|
||||
PIMM_FOR m[r][c] /= v;
|
||||
}
|
||||
|
||||
@@ -453,7 +453,7 @@ public:
|
||||
//! \param v делитель.
|
||||
//! \return результат деления.
|
||||
PIMathMatrixT<Rows, Cols, Type> operator/(const Type & v) const {
|
||||
assert(piAbs<Type>(v) > PIMATHVECTOR_ZERO_CMP);
|
||||
assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP);
|
||||
PIMathMatrixT<Rows, Cols, Type> tm = PIMathMatrixT<Rows, Cols, Type>(*this);
|
||||
PIMM_FOR tm.m[r][c] /= v;
|
||||
return tm;
|
||||
@@ -517,7 +517,7 @@ public:
|
||||
for (uint i = 0; i < Cols; ++i) {
|
||||
ndet = true;
|
||||
for (uint j = 0; j < Rows; ++j)
|
||||
if (smat.m[i][j] != 0) ndet = false;
|
||||
if (smat.m[i][j] != Type{}) ndet = false;
|
||||
if (ndet) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
@@ -525,15 +525,16 @@ public:
|
||||
}
|
||||
for (uint i = 0; i < Cols; ++i) {
|
||||
crow = i;
|
||||
while (smat.m[i][i] == Type(0))
|
||||
while (smat.m[i][i] == Type{}) {
|
||||
smat.swapRows(i, ++crow);
|
||||
}
|
||||
for (uint j = i + 1; j < Rows; ++j) {
|
||||
mul = smat.m[i][j] / smat.m[i][i];
|
||||
for (uint k = i; k < Cols; ++k)
|
||||
smat.m[k][j] -= mul * smat.m[k][i];
|
||||
}
|
||||
if (i < Cols - 1) {
|
||||
if (piAbs<Type>(smat.m[i + 1][i + 1]) < Type(1E-200)) {
|
||||
if (std::abs(smat.m[i + 1][i + 1]) < PIMATHVECTOR_ZERO_CMP) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
@@ -562,8 +563,9 @@ public:
|
||||
Type mul, iddiv;
|
||||
for (uint i = 0; i < Cols; ++i) {
|
||||
ndet = true;
|
||||
for (uint j = 0; j < Rows; ++j)
|
||||
if (smat.m[i][j] != 0) ndet = false;
|
||||
for (uint j = 0; j < Rows; ++j) {
|
||||
if (std::abs(smat.m[i][j]) >= PIMATHVECTOR_ZERO_CMP) ndet = false;
|
||||
}
|
||||
if (ndet) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
@@ -571,7 +573,7 @@ public:
|
||||
}
|
||||
for (uint i = 0; i < Cols; ++i) {
|
||||
crow = i;
|
||||
while (smat.m[i][i] == Type(0)) {
|
||||
while (std::abs(smat.m[i][i]) < PIMATHVECTOR_ZERO_CMP) {
|
||||
++crow;
|
||||
smat.swapRows(i, crow);
|
||||
mtmp.swapRows(i, crow);
|
||||
@@ -584,7 +586,7 @@ public:
|
||||
mtmp.m[k][j] -= mul * mtmp.m[k][i];
|
||||
}
|
||||
if (i < Cols - 1) {
|
||||
if (piAbs<Type>(smat.m[i + 1][i + 1]) < Type(1E-200)) {
|
||||
if (std::abs(smat.m[i + 1][i + 1]) < PIMATHVECTOR_ZERO_CMP) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
@@ -650,7 +652,7 @@ public:
|
||||
static_assert(Rows == 2 && Cols == 2, "Works only with 2x2 matrix");
|
||||
Type c = std::cos(angle);
|
||||
Type s = std::sin(angle);
|
||||
PIMathMatrixT<2u, 2u> tm;
|
||||
PIMathMatrixT<2u, 2u, Type> tm;
|
||||
tm[0][0] = tm[1][1] = c;
|
||||
tm[0][1] = -s;
|
||||
tm[1][0] = s;
|
||||
@@ -671,7 +673,7 @@ public:
|
||||
PIMathMatrixT<Cols, Rows, Type> outm;
|
||||
Type c = std::cos(angle);
|
||||
Type s = std::sin(angle);
|
||||
PIMathMatrixT<2u, 2u> tm;
|
||||
PIMathMatrixT<2u, 2u, Type> tm;
|
||||
tm[0][0] = tm[1][1] = c;
|
||||
tm[0][1] = -s;
|
||||
tm[1][0] = s;
|
||||
|
||||
@@ -27,12 +27,13 @@
|
||||
#define PIMATHVECTOR_H
|
||||
|
||||
#include "pimathbase.h"
|
||||
#include "pimathcomplex.h"
|
||||
|
||||
|
||||
template<uint Cols, uint Rows, typename Type>
|
||||
class PIMathMatrixT;
|
||||
|
||||
#define PIMATHVECTOR_ZERO_CMP Type(1E-100)
|
||||
#define PIMATHVECTOR_ZERO_CMP (1E-100)
|
||||
|
||||
|
||||
/// Vector templated
|
||||
@@ -42,7 +43,7 @@ class PIMathMatrixT;
|
||||
template<uint Size, typename Type = double>
|
||||
class PIP_EXPORT PIMathVectorT {
|
||||
typedef PIMathVectorT<Size, Type> _CVector;
|
||||
static_assert(std::is_arithmetic<Type>::value, "Type must be arithmetic");
|
||||
static_assert(std::is_arithmetic<Type>::value || is_complex<Type>::value, "Type must be arithmetic or complex");
|
||||
static_assert(Size > 0, "Size must be > 0");
|
||||
|
||||
public:
|
||||
@@ -83,35 +84,71 @@ public:
|
||||
PIMV_FOR tv += c[i] * c[i];
|
||||
return tv;
|
||||
}
|
||||
Type length() const { return std::sqrt(lengthSqr()); }
|
||||
|
||||
Type length() const {
|
||||
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
|
||||
if (std::is_arithmetic<Type>::value) return std::sqrt(lengthSqr());
|
||||
// if (is_complex<Type>::value) return 1000.; // std::sqrt(lengthSqr());
|
||||
}
|
||||
|
||||
Type manhattanLength() const {
|
||||
Type tv(0);
|
||||
PIMV_FOR tv += piAbs<Type>(c[i]);
|
||||
return tv;
|
||||
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
|
||||
if (std::is_arithmetic<Type>::value) {
|
||||
Type tv(0);
|
||||
PIMV_FOR tv += piAbs<Type>(c[i]);
|
||||
return tv;
|
||||
}
|
||||
}
|
||||
Type angleCos(const _CVector & v) const {
|
||||
Type tv = v.length() * length();
|
||||
assert(piAbs<Type>(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
return dot(v) / tv;
|
||||
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
|
||||
if (std::is_arithmetic<Type>::value) {
|
||||
Type tv = v.length() * length();
|
||||
assert(piAbs<Type>(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
return dot(v) / tv;
|
||||
}
|
||||
}
|
||||
Type angleSin(const _CVector & v) const {
|
||||
Type tv = angleCos(v);
|
||||
return std::sqrt(Type(1) - tv * tv);
|
||||
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
|
||||
if (std::is_arithmetic<Type>::value) {
|
||||
Type tv = angleCos(v);
|
||||
return std::sqrt(Type(1) - tv * tv);
|
||||
}
|
||||
}
|
||||
Type angleRad(const _CVector & v) const {
|
||||
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
|
||||
if (std::is_arithmetic<Type>::value) {
|
||||
return std::acos(angleCos(v));
|
||||
}
|
||||
}
|
||||
Type angleDeg(const _CVector & v) const {
|
||||
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
|
||||
if (std::is_arithmetic<Type>::value) {
|
||||
return toDeg(angleRad(v));
|
||||
}
|
||||
}
|
||||
Type angleElevation(const _CVector & v) const {
|
||||
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
|
||||
if (std::is_arithmetic<Type>::value) {
|
||||
return 90.0 - angleDeg(v - *this);
|
||||
}
|
||||
}
|
||||
Type angleRad(const _CVector & v) const { return std::acos(angleCos(v)); }
|
||||
Type angleDeg(const _CVector & v) const { return toDeg(angleRad(v)); }
|
||||
Type angleElevation(const _CVector & v) const { return 90.0 - angleDeg(v - *this); }
|
||||
_CVector projection(const _CVector & v) {
|
||||
Type tv = v.length();
|
||||
assert(piAbs<Type>(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
return v * (dot(v) / tv);
|
||||
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
|
||||
if (std::is_arithmetic<Type>::value) {
|
||||
Type tv = v.length();
|
||||
assert(piAbs<Type>(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
return v * (dot(v) / tv);
|
||||
}
|
||||
}
|
||||
_CVector & normalize() {
|
||||
Type tv = length();
|
||||
assert(piAbs<Type>(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
if (tv == Type(1)) return *this;
|
||||
PIMV_FOR c[i] /= tv;
|
||||
return *this;
|
||||
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
|
||||
if (std::is_arithmetic<Type>::value) {
|
||||
Type tv = length();
|
||||
assert(piAbs<Type>(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
if (tv == Type(1)) return *this;
|
||||
PIMV_FOR c[i] /= tv;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
_CVector normalized() {
|
||||
_CVector tv(*this);
|
||||
@@ -119,10 +156,10 @@ public:
|
||||
return tv;
|
||||
}
|
||||
bool isNull() const {
|
||||
PIMV_FOR if (c[i] != Type(0)) return false;
|
||||
PIMV_FOR if (c[i] != Type{}) return false;
|
||||
return true;
|
||||
}
|
||||
bool isOrtho(const _CVector & v) const { return ((*this) ^ v) == Type(0); }
|
||||
bool isOrtho(const _CVector & v) const { return ((*this) ^ v) == Type{}; }
|
||||
|
||||
Type & operator[](uint index) { return c[index]; }
|
||||
const Type & operator[](uint index) const { return c[index]; }
|
||||
@@ -145,7 +182,7 @@ public:
|
||||
void operator-=(const _CVector & v) { PIMV_FOR c[i] -= v[i]; }
|
||||
void operator*=(const Type & v) { PIMV_FOR c[i] *= v; }
|
||||
void operator/=(const Type & v) {
|
||||
assert(piAbs<Type>(v) > PIMATHVECTOR_ZERO_CMP);
|
||||
assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP);
|
||||
PIMV_FOR c[i] /= v;
|
||||
}
|
||||
_CVector operator-() const {
|
||||
@@ -169,7 +206,7 @@ public:
|
||||
return tv;
|
||||
}
|
||||
_CVector operator/(const Type & v) const {
|
||||
assert(piAbs<Type>(v) > PIMATHVECTOR_ZERO_CMP);
|
||||
assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP);
|
||||
_CVector tv = _CVector(*this);
|
||||
PIMV_FOR tv[i] /= v;
|
||||
return tv;
|
||||
@@ -184,7 +221,7 @@ public:
|
||||
return tv;
|
||||
}
|
||||
Type dot(const _CVector & v) const {
|
||||
Type tv(0);
|
||||
Type tv{};
|
||||
PIMV_FOR tv += c[i] * v[i];
|
||||
return tv;
|
||||
}
|
||||
@@ -197,7 +234,7 @@ public:
|
||||
_CVector div(const _CVector & v) const {
|
||||
_CVector tv(*this);
|
||||
PIMV_FOR {
|
||||
assert(piAbs<Type>(v[i]) > PIMATHVECTOR_ZERO_CMP);
|
||||
assert(std::abs(v[i]) > PIMATHVECTOR_ZERO_CMP);
|
||||
tv[i] /= v[i];
|
||||
}
|
||||
return tv;
|
||||
@@ -211,11 +248,14 @@ public:
|
||||
}
|
||||
|
||||
Type distToLine(const _CVector & lp0, const _CVector & lp1) {
|
||||
_CVector a(lp0, lp1);
|
||||
Type tv = a.length();
|
||||
assert(piAbs<Type>(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
_CVector b(lp0, *this);
|
||||
return piAbs<Type>(a[0] * b[1] - a[1] * b[0]) / tv;
|
||||
static_assert(std::is_arithmetic<Type>::value, "Unavailable for complex");
|
||||
if (std::is_arithmetic<Type>::value) {
|
||||
_CVector a(lp0, lp1);
|
||||
Type tv = a.length();
|
||||
assert(std::abs(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
_CVector b(lp0, *this);
|
||||
return piAbs<Type>(a[0] * b[1] - a[1] * b[0]) / tv;
|
||||
}
|
||||
}
|
||||
|
||||
template<uint Size1, typename Type1> /// vector {Size, Type} to vector {Size1, Type1}
|
||||
@@ -394,7 +434,7 @@ public:
|
||||
Type angleCos(const _CVector & v) const {
|
||||
assert(c.size() == v.size());
|
||||
Type tv = v.length() * length();
|
||||
assert(piAbs<Type>(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
assert(std::abs(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
return dot(v) / tv;
|
||||
}
|
||||
Type angleSin(const _CVector & v) const {
|
||||
@@ -407,12 +447,12 @@ public:
|
||||
_CVector projection(const _CVector & v) {
|
||||
assert(c.size() == v.size());
|
||||
Type tv = v.length();
|
||||
assert(piAbs<Type>(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
assert(std::abs(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
return v * (dot(v) / tv);
|
||||
}
|
||||
_CVector & normalize() {
|
||||
Type tv = length();
|
||||
assert(piAbs<Type>(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
assert(std::abs(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
if (tv == Type(1)) return *this;
|
||||
PIMV_FOR c[i] /= tv;
|
||||
return *this;
|
||||
@@ -451,7 +491,7 @@ public:
|
||||
}
|
||||
void operator*=(const Type & v) { PIMV_FOR c[i] *= v; }
|
||||
void operator/=(const Type & v) {
|
||||
assert(piAbs<Type>(v) > PIMATHVECTOR_ZERO_CMP);
|
||||
assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP);
|
||||
PIMV_FOR c[i] /= v;
|
||||
}
|
||||
_CVector operator-() const {
|
||||
@@ -477,7 +517,7 @@ public:
|
||||
return tv;
|
||||
}
|
||||
_CVector operator/(const Type & v) const {
|
||||
assert(piAbs<Type>(v) > PIMATHVECTOR_ZERO_CMP);
|
||||
assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP);
|
||||
_CVector tv(*this);
|
||||
PIMV_FOR tv[i] /= v;
|
||||
return tv;
|
||||
@@ -508,7 +548,7 @@ public:
|
||||
assert(c.size() == v.size());
|
||||
_CVector tv(*this);
|
||||
PIMV_FOR {
|
||||
assert(piAbs<Type>(v[i]) > PIMATHVECTOR_ZERO_CMP);
|
||||
assert(std::abs(v[i]) > PIMATHVECTOR_ZERO_CMP);
|
||||
tv[i] /= v[i];
|
||||
}
|
||||
return tv;
|
||||
@@ -520,7 +560,7 @@ public:
|
||||
assert(c.size() == lp1.size());
|
||||
_CVector a = _CVector::fromTwoPoints(lp0, lp1);
|
||||
Type tv = a.length();
|
||||
assert(piAbs<Type>(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
assert(std::abs(tv) > PIMATHVECTOR_ZERO_CMP);
|
||||
_CVector b = _CVector::fromTwoPoints(lp0, *this);
|
||||
return piAbs<Type>(a[0] * b[1] - a[1] * b[0]) / tv;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "piresourcesstorage.h"
|
||||
|
||||
#include "pichunkstream.h"
|
||||
#include "piset.h"
|
||||
|
||||
|
||||
@@ -42,11 +41,11 @@ void PIResourcesStorage::Section::add(const PIResourcesStorage::Section & s) {
|
||||
void PIResourcesStorage::Section::purge() {
|
||||
PIVector<PIByteArray *> bav = entries.values();
|
||||
PISet<PIByteArray *> bas;
|
||||
piForeach(PIByteArray * i, bav) {
|
||||
for (auto i: bav) {
|
||||
if (i) bas << i;
|
||||
}
|
||||
bav = bas.toVector();
|
||||
piForeach(PIByteArray * i, bav)
|
||||
for (auto i: bav)
|
||||
delete i;
|
||||
entries.clear();
|
||||
}
|
||||
@@ -76,14 +75,14 @@ void PIResourcesStorage::registerSection(const uchar * rc_data, const uchar * rc
|
||||
PIVector<PIResourcesStorage::__RCEntry> el;
|
||||
dba >> el;
|
||||
PIMap<PIString, PIVector<PIResourcesStorage::__RCEntry>> ebs;
|
||||
piForeachC(PIResourcesStorage::__RCEntry & e, el) {
|
||||
for (const auto & e: el) {
|
||||
ebs[e.section] << e;
|
||||
}
|
||||
auto it = ebs.makeIterator();
|
||||
while (it.next()) {
|
||||
PIResourcesStorage::Section s;
|
||||
const PIVector<PIResourcesStorage::__RCEntry> & itv(it.value());
|
||||
piForeachC(PIResourcesStorage::__RCEntry & e, itv) {
|
||||
for (const auto & e: itv) {
|
||||
// piCout << "add" << e.name << e.alias << PIString::readableSize(e.size);
|
||||
PIByteArray * eba = new PIByteArray(&(rc_data[e.offset]), e.size);
|
||||
s.entries[e.name] = eba;
|
||||
@@ -123,7 +122,7 @@ PIByteArray PIResourcesStorage::get(const PIString & entry_name) const {
|
||||
void PIResourcesStorage::clear() {
|
||||
// piCout << "PIResourcesStorage clear";
|
||||
PIVector<Section *> sv = sections.values();
|
||||
piForeach(Section * i, sv) {
|
||||
for (auto i: sv) {
|
||||
if (i) i->purge();
|
||||
}
|
||||
sections.clear();
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "pibitarray.h"
|
||||
#include "pimap.h"
|
||||
#include "pimemoryblock.h"
|
||||
#include "piset.h"
|
||||
#include "pivector2d.h"
|
||||
|
||||
#define PIP_BINARY_STREAM
|
||||
@@ -70,7 +71,7 @@ public:
|
||||
bool binaryStreamAppend(const void * d, size_t s) {
|
||||
if (!static_cast<P *>(this)->binaryStreamAppendImp(d, s)) {
|
||||
return false;
|
||||
printf("[PIBinaryStream] binaryStreamAppend() error\n");
|
||||
fprintf(stderr, "[PIBinaryStream] binaryStreamAppend() error\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -81,7 +82,7 @@ public:
|
||||
if (!static_cast<P *>(this)->binaryStreamTakeImp(d, s)) {
|
||||
_was_read_error_ = true;
|
||||
return false;
|
||||
printf("[PIBinaryStream] binaryStreamTake() error\n");
|
||||
fprintf(stderr, "[PIBinaryStream] binaryStreamTake() error\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -323,7 +324,7 @@ template<typename P,
|
||||
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIBinaryStreamTrivialRef<P> operator>>(PIBinaryStream<P> & s, T & v) {
|
||||
if (!s.binaryStreamTake(&v, sizeof(v))) {
|
||||
printf("error with %s\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with %s\n", __PIP_TYPENAME__(T));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -341,13 +342,13 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
// piCout << ">> vector trivial default";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
v._resizeRaw(sz);
|
||||
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
}
|
||||
return s;
|
||||
@@ -362,7 +363,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
// piCout << ">> vector trivial custom";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -370,7 +371,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
s >> v[i];
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -391,13 +392,13 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
// piCout << ">> deque trivial default";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
v._resizeRaw(sz);
|
||||
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
}
|
||||
return s;
|
||||
@@ -412,7 +413,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
// piCout << ">> deque trivial custom";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -420,7 +421,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
s >> v[i];
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -443,13 +444,13 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
|
||||
r = s.binaryStreamTakeInt();
|
||||
c = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
v._resizeRaw(r, c);
|
||||
if (!s.binaryStreamTake(v.data(), v.size() * sizeof(T))) {
|
||||
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
}
|
||||
return s;
|
||||
@@ -468,7 +469,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
|
||||
c = s.binaryStreamTakeInt();
|
||||
s >> tmp;
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -543,7 +544,7 @@ template<typename P, typename T, typename std::enable_if<!std::is_trivially_copy
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -551,7 +552,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
s >> v[i];
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -566,7 +567,7 @@ template<typename P, typename T, typename std::enable_if<!std::is_trivially_copy
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -574,7 +575,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
s >> v[i];
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -593,7 +594,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
|
||||
c = s.binaryStreamTakeInt();
|
||||
s >> tmp;
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -625,7 +626,7 @@ template<typename P, typename Key, typename T>
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v) {
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -635,7 +636,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v)
|
||||
ind = s.binaryStreamTakeInt();
|
||||
s >> v.pim_index[i].key;
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -643,7 +644,7 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v)
|
||||
}
|
||||
s >> v.pim_content;
|
||||
if (s.wasReadError()) {
|
||||
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
fprintf(stderr, "error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
@@ -655,6 +656,46 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v)
|
||||
}
|
||||
|
||||
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
template<typename P, typename Key>
|
||||
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PISet<Key> & v) {
|
||||
s.binaryStreamAppend((int)v.pim_index.size_s());
|
||||
for (uint i = 0; i < v.size(); ++i) {
|
||||
s.binaryStreamAppend((int)v.pim_index[i].index);
|
||||
s << v.pim_index[i].key;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
template<typename P, typename Key>
|
||||
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PISet<Key> & v) {
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
if (s.wasReadError()) {
|
||||
fprintf(stderr, "error with PISet<%s>\n", __PIP_TYPENAME__(Key));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
v.pim_index.resize(sz);
|
||||
v.pim_content.resize(sz, 0);
|
||||
int ind = 0;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
ind = s.binaryStreamTakeInt();
|
||||
s >> v.pim_index[i].key;
|
||||
if (s.wasReadError()) {
|
||||
fprintf(stderr, "error with PISet<%s>\n", __PIP_TYPENAME__(Key));
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
v.pim_index[i].index = ind;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
// non-defined complex types
|
||||
|
||||
|
||||
|
||||
@@ -31,21 +31,6 @@
|
||||
|
||||
namespace PIStateMachineHelpers {
|
||||
|
||||
template<typename T>
|
||||
struct FunctionType {
|
||||
using Type = void;
|
||||
};
|
||||
|
||||
template<typename Ret, typename Class, typename... Args>
|
||||
struct FunctionType<Ret (Class::*)(Args...) const> {
|
||||
using Type = std::function<Ret(Args...)>;
|
||||
};
|
||||
|
||||
template<typename L>
|
||||
typename FunctionType<decltype(&L::operator())>::Type toStdFunction(L const & func) {
|
||||
return func;
|
||||
}
|
||||
|
||||
class FunctionBase {
|
||||
public:
|
||||
virtual ~FunctionBase() {}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "pistatemachine_state.h"
|
||||
|
||||
#include "pistatemachine_transition.h"
|
||||
|
||||
#include "pitranslator.h"
|
||||
|
||||
PIStateBase::~PIStateBase() {
|
||||
piDeleteAll(transitions);
|
||||
@@ -108,7 +108,7 @@ bool PIStateBase::start(bool force) {
|
||||
setActive(true);
|
||||
return initial_state->start();
|
||||
} else {
|
||||
piCout << "error:" << getName() << "no initial state!";
|
||||
piCout << "Error: \"%1\" no initial state!"_tr("PIStateMachine").arg(getName());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
|
||||
template<typename L>
|
||||
PITransitionBase * addGuard(L f) {
|
||||
return addGuard(PIStateMachineHelpers::toStdFunction(f));
|
||||
return addGuard(toStdFunction(f));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "piliterals_time.h"
|
||||
#include "pitime.h"
|
||||
#include "pitranslator.h"
|
||||
#ifndef MICRO_PIP
|
||||
|
||||
# include "piincludes_p.h"
|
||||
@@ -196,7 +197,7 @@ void PIProcess::startProc(bool detached) {
|
||||
CloseHandle(PRIVATE->pi.hThread);
|
||||
CloseHandle(PRIVATE->pi.hProcess);
|
||||
} else
|
||||
piCoutObj << "\"CreateProcess\" error, " << errorString();
|
||||
piCoutObj << "\"CreateProcess\" error: %1"_tr("PIProcess").arg(errorString());
|
||||
# else
|
||||
|
||||
// cout << "exec " << tf_in << ", " << tf_out << ", " << tf_err << endl;
|
||||
|
||||
@@ -60,6 +60,33 @@ void PISignals::grabSignals(PIFlags<PISignals::Signal> signals_) {
|
||||
}
|
||||
|
||||
|
||||
void PISignals::releaseSignals(PIFlags<Signal> signals_) {
|
||||
if (signals_[PISignals::Interrupt]) signal(signalCode(PISignals::Interrupt), SIG_DFL);
|
||||
if (signals_[PISignals::Illegal]) signal(signalCode(PISignals::Illegal), SIG_DFL);
|
||||
if (signals_[PISignals::Abort]) signal(signalCode(PISignals::Abort), SIG_DFL);
|
||||
if (signals_[PISignals::FPE]) signal(signalCode(PISignals::FPE), SIG_DFL);
|
||||
if (signals_[PISignals::SegFault]) signal(signalCode(PISignals::SegFault), SIG_DFL);
|
||||
if (signals_[PISignals::Termination]) signal(signalCode(PISignals::Termination), SIG_DFL);
|
||||
#ifndef CC_VC
|
||||
if (signals_[PISignals::UserDefined1]) signal(signalCode(PISignals::UserDefined1), SIG_DFL);
|
||||
if (signals_[PISignals::UserDefined2]) signal(signalCode(PISignals::UserDefined2), SIG_DFL);
|
||||
#endif
|
||||
#ifndef WINDOWS
|
||||
if (signals_[PISignals::Hangup]) signal(signalCode(PISignals::Hangup), SIG_DFL);
|
||||
if (signals_[PISignals::Quit]) signal(signalCode(PISignals::Quit), SIG_DFL);
|
||||
if (signals_[PISignals::Kill]) signal(signalCode(PISignals::Kill), SIG_DFL);
|
||||
if (signals_[PISignals::BrokenPipe]) signal(signalCode(PISignals::BrokenPipe), SIG_DFL);
|
||||
if (signals_[PISignals::Timer]) signal(signalCode(PISignals::Timer), SIG_DFL);
|
||||
if (signals_[PISignals::ChildStopped]) signal(signalCode(PISignals::ChildStopped), SIG_DFL);
|
||||
if (signals_[PISignals::Continue]) signal(signalCode(PISignals::Continue), SIG_DFL);
|
||||
if (signals_[PISignals::StopProcess]) signal(signalCode(PISignals::StopProcess), SIG_DFL);
|
||||
if (signals_[PISignals::StopTTY]) signal(signalCode(PISignals::StopTTY), SIG_DFL);
|
||||
if (signals_[PISignals::StopTTYInput]) signal(signalCode(PISignals::StopTTYInput), SIG_DFL);
|
||||
if (signals_[PISignals::StopTTYOutput]) signal(signalCode(PISignals::StopTTYOutput), SIG_DFL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PISignals::raiseSignal(PISignals::Signal signal) {
|
||||
raise(signalCode(signal));
|
||||
}
|
||||
@@ -90,7 +117,7 @@ int PISignals::signalCode(PISignals::Signal signal) {
|
||||
case PISignals::StopTTYInput: return SIGTTIN;
|
||||
case PISignals::StopTTYOutput: return SIGTTOU;
|
||||
#endif
|
||||
default:;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -121,13 +148,13 @@ PISignals::Signal PISignals::signalFromCode(int signal) {
|
||||
case SIGTTIN: return PISignals::StopTTYInput;
|
||||
case SIGTTOU: return PISignals::StopTTYOutput;
|
||||
#endif
|
||||
default:;
|
||||
default: break;
|
||||
}
|
||||
return PISignals::Termination;
|
||||
}
|
||||
|
||||
|
||||
void PISignals::signal_event(int signal) {
|
||||
if (PISignals::ret_func == 0) return;
|
||||
if (!PISignals::ret_func) return;
|
||||
PISignals::ret_func(PISignals::signalFromCode(signal));
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ public:
|
||||
// slot is any function format "void(PISignals::Signal)"
|
||||
static void setSlot(SignalEvent slot) { ret_func = slot; }
|
||||
static void grabSignals(PIFlags<PISignals::Signal> signals_);
|
||||
static void releaseSignals(PIFlags<PISignals::Signal> signals_);
|
||||
static void raiseSignal(PISignals::Signal signal);
|
||||
|
||||
private:
|
||||
|
||||
@@ -99,8 +99,8 @@ public:
|
||||
//! \~russian Оператор сравнения
|
||||
bool operator<=(const PIChar & o) const;
|
||||
|
||||
//! \~english Returns \b true if symbol is digit ('0' to '9')
|
||||
//! \~russian Возвращает \b true если символ является
|
||||
//! \~english Returns \b true if symbol is digit (from '0' to '9')
|
||||
//! \~russian Возвращает \b true если символ является цифрой (от '0' до '9')
|
||||
bool isDigit() const;
|
||||
|
||||
//! \~english Returns \b true if symbol is HEX digit ('0' to '9', 'a' to 'f', 'A' to 'F')
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "piliterals.h"
|
||||
#include "pimathbase.h"
|
||||
#include "pistringlist.h"
|
||||
#include "pitranslator.h"
|
||||
#ifdef PIP_ICU
|
||||
# define U_NOEXCEPT
|
||||
# include "unicode/ucnv.h"
|
||||
@@ -296,7 +297,7 @@ llong PIString::toNumberBase(const PIString & value, int base, bool * ok) {
|
||||
|
||||
|
||||
void PIString::appendFromChars(const char * c, int s, const char * codepage) {
|
||||
// piCout << "appendFromChars";
|
||||
// piCout << "appendFromChars";
|
||||
if (s == 0) return;
|
||||
int old_sz = size_s();
|
||||
if (s == -1) s = strlen(c);
|
||||
@@ -522,11 +523,47 @@ void PIString::trimsubstr(int & st, int & fn) const {
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::minArgPlaceholder() {
|
||||
if (size() < 2) return {};
|
||||
int min = -1;
|
||||
PIString ret, tmp;
|
||||
for (int i = 0; i < size_s(); ++i) {
|
||||
if (at(i) == '%') {
|
||||
int j = 0;
|
||||
for (j = i + 1; j < size_s(); ++j) {
|
||||
if (!at(j).isDigit()) break;
|
||||
}
|
||||
bool ok = false;
|
||||
tmp = mid(i + 1, j - i - 1);
|
||||
int cur = tmp.toInt(10, &ok);
|
||||
if (!ok) continue;
|
||||
if (min < 0 || min > cur) {
|
||||
min = cur;
|
||||
ret = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret.isEmpty()) return {};
|
||||
return "%" + ret;
|
||||
}
|
||||
|
||||
|
||||
uint PIString::hash() const {
|
||||
return piHashData((const uchar *)d.data(), d.size() * sizeof(PIChar));
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIString::toAscii() const {
|
||||
if (isEmpty()) return PIByteArray();
|
||||
PIByteArray ret;
|
||||
ret.resize(size());
|
||||
for (int i = 0; i < size_s(); ++i) {
|
||||
ret[i] = uchar(at(i).ch);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIString::toSystem() const {
|
||||
if (isEmpty()) return PIByteArray();
|
||||
buildData(__syslocname__);
|
||||
@@ -1197,6 +1234,28 @@ int PIString::entries(const PIChar c) const {
|
||||
}
|
||||
|
||||
|
||||
int PIString::entries(const PIString & str) const {
|
||||
int sz = size_s(), ssz = str.size_s();
|
||||
if (ssz == 0 || sz < ssz) return 0;
|
||||
int btc = str.size_s() * sizeof(PIChar), ret = 0;
|
||||
for (int i = 0; i < sz - ssz + 1; ++i) {
|
||||
if (piCompareBinary(d.data(i), str.d.data(0), btc)) ++ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int PIString::lineNumber(int pos) const {
|
||||
if (isEmpty()) return 0;
|
||||
if (pos < 0 || pos >= size_s()) pos = size_s() - 1;
|
||||
int line = 1;
|
||||
for (int i = 0; i < pos; ++i) {
|
||||
if (at(i) == '\n') ++line;
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
bool PIString::startsWith(const PIChar c) const {
|
||||
if (isEmpty()) return false;
|
||||
return front() == c;
|
||||
@@ -1723,41 +1782,36 @@ ldouble PIString::toLDouble() const {
|
||||
PIString & PIString::setReadableSize(llong bytes) {
|
||||
clear();
|
||||
if (bytes < 1024) {
|
||||
*this += (PIString::fromNumber(bytes) + " B"_a);
|
||||
*this += (PIString::fromNumber(bytes) + " "_a + "B"_tr("PIString"));
|
||||
return *this;
|
||||
}
|
||||
double fres = bytes / 1024.;
|
||||
llong res = bytes / 1024;
|
||||
fres -= res;
|
||||
if (res < 1024) {
|
||||
*this += (PIString::fromNumber(res) + "."_a + PIString::fromNumber(llong(fres * 10)).left(1) + " KiB"_a);
|
||||
return *this;
|
||||
}
|
||||
fres = res / 1024.;
|
||||
res /= 1024;
|
||||
fres -= res;
|
||||
if (res < 1024) {
|
||||
*this += (PIString::fromNumber(res) + "."_a + PIString::fromNumber(llong(fres * 10)).left(1) + " MiB"_a);
|
||||
return *this;
|
||||
}
|
||||
fres = res / 1024.;
|
||||
res /= 1024;
|
||||
fres -= res;
|
||||
if (res < 1024) {
|
||||
*this += (PIString::fromNumber(res) + "."_a + PIString::fromNumber(llong(fres * 10)).left(1) + " GiB"_a);
|
||||
return *this;
|
||||
}
|
||||
fres = res / 1024.;
|
||||
res /= 1024;
|
||||
fres -= res;
|
||||
if (res < 1024) {
|
||||
*this += (PIString::fromNumber(res) + "."_a + PIString::fromNumber(llong(fres * 10)).left(1) + " TiB"_a);
|
||||
return *this;
|
||||
}
|
||||
fres = res / 1024.;
|
||||
res /= 1024;
|
||||
fres -= res;
|
||||
*this += (PIString::fromNumber(res) + "."_a + PIString::fromNumber(llong(fres * 10)).left(1) + " PiB"_a);
|
||||
double fres = bytes;
|
||||
llong res = bytes;
|
||||
auto checkRange = [this, &fres, &res](const PIString & unit, bool last = false) {
|
||||
fres = res / 1024.;
|
||||
res /= 1024;
|
||||
fres -= res;
|
||||
if (res < 1024 || last) {
|
||||
*this += (PIString::fromNumber(res) + "."_a + PIString::fromNumber(llong(fres * 10)).left(1) + " "_a + unit);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (checkRange("KiB"_tr("PIString"))) return *this;
|
||||
if (checkRange("MiB"_tr("PIString"))) return *this;
|
||||
if (checkRange("GiB"_tr("PIString"))) return *this;
|
||||
if (checkRange("TiB"_tr("PIString"))) return *this;
|
||||
if (checkRange("PiB"_tr("PIString"))) return *this;
|
||||
if (checkRange("EiB"_tr("PIString"))) return *this;
|
||||
if (checkRange("ZiB"_tr("PIString"))) return *this;
|
||||
checkRange("YiB"_tr("PIString"), true);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::arg(const PIString & v) {
|
||||
auto ph = minArgPlaceholder();
|
||||
if (!ph.isEmpty()) replaceAll(ph, v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1107,6 +1107,10 @@ public:
|
||||
//! \~russian Тоже самое, что \a toUTF8().
|
||||
PIByteArray toByteArray() const { return toUTF8(); }
|
||||
|
||||
//! \~english Returns \a PIByteArray contains \a dataAscii() of this string without terminating null-char.
|
||||
//! \~russian Возвращает \a PIByteArray содержащий \a dataAscii() строки без завершающего нулевого байта.
|
||||
PIByteArray toAscii() const;
|
||||
|
||||
//! \~english Returns \a PIByteArray contains \a data() of this string without terminating null-char.
|
||||
//! \~russian Возвращает \a PIByteArray содержащий \a data() строки без завершающего нулевого байта.
|
||||
PIByteArray toSystem() const;
|
||||
@@ -1271,6 +1275,20 @@ public:
|
||||
//! piCout << PIString(".str.0").entries("0"); // 1
|
||||
//! \endcode
|
||||
int entries(const PIChar c) const;
|
||||
int entries(char c) const { return entries(PIChar(c)); }
|
||||
|
||||
//! \~english Returns number of occurrences of string "str".
|
||||
//! \~russian Возвращает число вхождений строк "str".
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! piCout << PIString("hello locale").entries("lo"); // 2
|
||||
//! piCout << PIString("hello locale").entries("lo lo"); // 1
|
||||
//! \endcode
|
||||
int entries(const PIString & str) const;
|
||||
|
||||
//! \~english Returns line number of position "pos". Lines starts from 1.
|
||||
//! \~russian Возвращает номер строки позиции "pos". Строки начинаются с 1.
|
||||
int lineNumber(int pos) const;
|
||||
|
||||
//! \~english Returns if string starts with "c".
|
||||
//! \~russian Возвращает начинается ли строка с "c".
|
||||
@@ -1668,6 +1686,69 @@ public:
|
||||
//! \~\sa PIString::readableSize()
|
||||
PIString & setReadableSize(llong bytes);
|
||||
|
||||
|
||||
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
|
||||
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! piCout << PIString("color %1 is not %2, but %1").arg("red").arg("green"); // color red is not green, but red
|
||||
//! \endcode
|
||||
PIString & arg(const PIString & v);
|
||||
|
||||
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
|
||||
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
|
||||
PIString & arg(short v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
|
||||
|
||||
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
|
||||
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
|
||||
PIString & arg(ushort v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
|
||||
|
||||
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
|
||||
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! piCout << PIString("ten = %1").arg(10); // ten = 10
|
||||
//! piCout << PIString("'%1' is max hex letter (%2 in dec)").arg(0xF, 16).arg(0xF); // 'F' is max hex letter (15 in dec)
|
||||
//! \endcode
|
||||
PIString & arg(int v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
|
||||
|
||||
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
|
||||
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
|
||||
PIString & arg(uint v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
|
||||
|
||||
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
|
||||
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
|
||||
PIString & arg(long v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
|
||||
|
||||
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
|
||||
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
|
||||
PIString & arg(ulong v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
|
||||
|
||||
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
|
||||
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
|
||||
PIString & arg(llong v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
|
||||
|
||||
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
|
||||
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
|
||||
PIString & arg(ullong v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
|
||||
|
||||
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
|
||||
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
|
||||
PIString & arg(float v, char format = 'f', int precision = 8) { return arg(PIString::fromNumber(v, format, precision)); }
|
||||
|
||||
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
|
||||
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! piCout << PIString("light speed = %1 %2").arg(M_LIGHT_SPEED, 'g', 4).arg("m/s"); // light speed = 2.998e+08 m/s
|
||||
//! \endcode
|
||||
PIString & arg(double v, char format = 'f', int precision = 8) { return arg(PIString::fromNumber(v, format, precision)); }
|
||||
|
||||
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
|
||||
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
|
||||
PIString & arg(ldouble v, char format = 'f', int precision = 8) { return arg(PIString::fromNumber(v, format, precision)); }
|
||||
|
||||
|
||||
//! \~english Returns string contains numeric representation of "value" in base "base".
|
||||
//! \~russian Возвращает строковое представление числа "value" по основанию "base".
|
||||
//! \~\details
|
||||
@@ -1853,6 +1934,7 @@ private:
|
||||
void buildData(const char * cp = __syslocname__) const;
|
||||
void deleteData() const;
|
||||
void trimsubstr(int & st, int & fn) const;
|
||||
PIString minArgPlaceholder();
|
||||
|
||||
PIDeque<PIChar> d;
|
||||
mutable bool changed_ = true;
|
||||
|
||||
74
libs/main/thread/piprotectedvariable.h
Normal file
74
libs/main/thread/piprotectedvariable.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*! \file piprotectedvariable.h
|
||||
* \ingroup Thread
|
||||
* \~\brief
|
||||
* \~english Thread-safe variable
|
||||
* \~russian Потокобезопасная переменная
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Thread-safe variable
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Stephan Fomenko, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIPROTECTEDVARIABLE_H
|
||||
#define PIPROTECTEDVARIABLE_H
|
||||
|
||||
#include "pimutex.h"
|
||||
|
||||
|
||||
template<typename T>
|
||||
class PIP_EXPORT PIProtectedVariable {
|
||||
public:
|
||||
//! \~english Sets value to \"v\"
|
||||
//! \~russian Устанавливает значение как \"v\"
|
||||
void set(T v) {
|
||||
PIMutexLocker _ml(mutex);
|
||||
var = std::move(v);
|
||||
}
|
||||
|
||||
//! \~english Returns copy of value
|
||||
//! \~russian Возвращает копию значения
|
||||
T get() const {
|
||||
PIMutexLocker _ml(mutex);
|
||||
return var;
|
||||
}
|
||||
|
||||
//! \~english Lock mutex and returns reference of value
|
||||
//! \~russian Блокирует мьютекс и возвращает ссылку на значение
|
||||
T & lock() {
|
||||
mutex.lock();
|
||||
return var;
|
||||
}
|
||||
|
||||
//! \~english Unlock mutex
|
||||
//! \~russian Разблокирует мьютекс
|
||||
void unlock() { mutex.unlock(); }
|
||||
|
||||
//! \~english Sets value to \"v\"
|
||||
//! \~russian Устанавливает значение как \"v\"
|
||||
PIProtectedVariable<T> & operator=(T v) {
|
||||
set(std::move(v));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
mutable PIMutex mutex;
|
||||
T var;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
234
libs/main/thread/pireadwritelock.cpp
Normal file
234
libs/main/thread/pireadwritelock.cpp
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
PIReadWriteLock, PIReadLocker, PIWriteLocker
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//! \addtogroup Thread
|
||||
//! \{
|
||||
//! \class PIReadWriteLock pireadwritelock.h
|
||||
//!
|
||||
//! \~\brief
|
||||
//! \~english Read/Write lock
|
||||
//! \~russian Блокировка чтения/записи
|
||||
//!
|
||||
//!
|
||||
//! \~\details
|
||||
//! \~english \section PIReadWriteLock_sec0 Synopsis
|
||||
//! \~russian \section PIReadWriteLock_sec0 Краткий обзор
|
||||
//!
|
||||
//! \~english
|
||||
//! %PIReadWriteLock provides more complex critical code section defence between several threads.
|
||||
//! %PIReadWriteLock permit only one thread to modify data, besides multiple thread can read data
|
||||
//! simultaneously. Conatains methods:
|
||||
//! \a lockWrite(), \a tryLockWrite(), \a unlockWrite(), \a lockRead(), \a tryLockRead() and \a unlockRead().
|
||||
//!
|
||||
//! For automatic read and write locks use \a PIReadLocker and \a PIWriteLocker.
|
||||
//!
|
||||
//! \~russian
|
||||
//! %PIReadWriteLock предоставляет более сложную межпотоковую защиту критических секций кода.
|
||||
//! %PIReadWriteLock разрешает только одному потоку изменять данные, в то время как читать данные
|
||||
//! могут одновременно несколько потоков.
|
||||
//! Содержит методы:
|
||||
//! \a lockWrite(), \a tryLockWrite(), \a unlockWrite(), \a lockRead(), \a tryLockRead() и \a unlockRead().
|
||||
//!
|
||||
//! Для автоматической блокировки на чтение и запись используйте \a PIReadLocker и \a PIWriteLocker.
|
||||
//!
|
||||
//! \~english \section PIReadWriteLock_sec1 Usage
|
||||
//! \~russian \section PIReadWriteLock_sec1 Использование
|
||||
//!
|
||||
//! \~english
|
||||
//! When one thread lock for write with \a lockWrite(), all other threads (read and write) can`t access data until this thread
|
||||
//! call \a unlockWrite(). In this way, write lock works similar to mutex.
|
||||
//!
|
||||
//! On the other hand, several threads can simultaneously read data. In other words, \a lockRead() increase read threads counter
|
||||
//! and \a unlockRead() decrease. But thread can`t read data while other thread locked for write.
|
||||
//!
|
||||
//! \~russian
|
||||
//! Когда один поток блокирует запись с помощью функции \a lockWrite(), все остальные потоки (чтение и запись) не смогут получить
|
||||
//! доступ к данным, пока этот поток не вызовет \a unlockWrite(). Таким образом, блокировка записи работает аналогично мьютексу.
|
||||
//!
|
||||
//! С другой стороны, несколько потоков могут одновременно считывать данные. Другими словами, функция \a lockRead() увеличивает счетчик
|
||||
//! потоков чтения, а функция \a unlockRead() уменьшает. Но поток не может считывать данные, пока другой поток заблокирован для записи.
|
||||
//!
|
||||
//! \~\code
|
||||
//! \endcode
|
||||
//! \}
|
||||
|
||||
|
||||
//! \addtogroup Thread
|
||||
//! \{
|
||||
//! \class PIReadLocker pireadwritelock.h
|
||||
//!
|
||||
//! \~\brief
|
||||
//! \~english %PIReadWriteLock read autolocker
|
||||
//! \~russian Автоблокировщик на чтение %PIReadWriteLock
|
||||
//!
|
||||
//!
|
||||
//! \~\details
|
||||
//!
|
||||
//! \~english
|
||||
//! When a %PIReadLocker object is created, it lock %PIReadWriteLock for read, if "condition" \c true.
|
||||
//! When control leaves the scope in which the %PIReadLocker object was created,
|
||||
//! the %PIReadLocker is destructed and unlock for read, if "condition" was \c true.
|
||||
//!
|
||||
//! If "condition" \c false this class do nothing.
|
||||
//!
|
||||
//! The %PIReadLocker class is non-copyable.
|
||||
//!
|
||||
//! \~russian
|
||||
//! При создании экземпляра %PIReadLocker он блокирует %PIReadWriteLock на чтение, если "condition" \c true.
|
||||
//! Когда выполнение покидает область жизни объекта, вызывается его деструктор и освобождается блокировка на чтение,
|
||||
//! если "condition" был \c true.
|
||||
//!
|
||||
//! Если "condition" \c false, то этот объект ничего не делает.
|
||||
//!
|
||||
//! Класс %PIReadLocker некопируемый.
|
||||
//!
|
||||
//! \~\code
|
||||
//! // critical section start
|
||||
//! {
|
||||
//! PIReadLocker locker(rw_lock);
|
||||
//! // ... your read code here
|
||||
//! }
|
||||
//! // critical section end
|
||||
//! \endcode
|
||||
//! \}
|
||||
|
||||
|
||||
//! \addtogroup Thread
|
||||
//! \{
|
||||
//! \class PIWriteLocker pireadwritelock.h
|
||||
//!
|
||||
//! \~\brief
|
||||
//! \~english %PIReadWriteLock write autolocker
|
||||
//! \~russian Автоблокировщик на запись %PIReadWriteLock
|
||||
//!
|
||||
//!
|
||||
//! \~\details
|
||||
//!
|
||||
//! \~english
|
||||
//! When a %PIWriteLocker object is created, it lock %PIReadWriteLock for write, if "condition" \c true.
|
||||
//! When control leaves the scope in which the %PIWriteLocker object was created,
|
||||
//! the %PIWriteLocker is destructed and unlock for write, if "condition" was \c true.
|
||||
//!
|
||||
//! If "condition" \c false this class do nothing.
|
||||
//!
|
||||
//! The %PIWriteLocker class is non-copyable.
|
||||
//!
|
||||
//! \~russian
|
||||
//! При создании экземпляра %PIWriteLocker он блокирует %PIReadWriteLock на запись, если "condition" \c true.
|
||||
//! Когда выполнение покидает область жизни объекта, вызывается его деструктор и освобождается блокировка на запись,
|
||||
//! если "condition" был \c true.
|
||||
//!
|
||||
//! Если "condition" \c false, то этот объект ничего не делает.
|
||||
//!
|
||||
//! Класс %PIWriteLocker некопируемый.
|
||||
//!
|
||||
//! \~\code
|
||||
//! // critical section start
|
||||
//! {
|
||||
//! PIWriteLocker locker(rw_lock);
|
||||
//! // ... your write code here
|
||||
//! }
|
||||
//! // critical section end
|
||||
//! \endcode
|
||||
//! \}
|
||||
|
||||
|
||||
#include "pireadwritelock.h"
|
||||
|
||||
|
||||
PIReadWriteLock::PIReadWriteLock() {}
|
||||
|
||||
|
||||
PIReadWriteLock::~PIReadWriteLock() {
|
||||
var.notifyAll();
|
||||
}
|
||||
|
||||
|
||||
void PIReadWriteLock::lockWrite() {
|
||||
PIMutexLocker _ml(mutex);
|
||||
while (reading > 0 || writing) {
|
||||
var.wait(mutex);
|
||||
}
|
||||
writing = true;
|
||||
}
|
||||
|
||||
|
||||
bool PIReadWriteLock::tryLockWrite() {
|
||||
PIMutexLocker _ml(mutex);
|
||||
if (reading > 0 || writing) return false;
|
||||
writing = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIReadWriteLock::tryLockWrite(PISystemTime timeout) {
|
||||
PITimeMeasurer tm;
|
||||
PIMutexLocker _ml(mutex);
|
||||
while (reading > 0 || writing) {
|
||||
PISystemTime remain = timeout - tm.elapsed();
|
||||
if (remain.isNegative()) return false;
|
||||
var.waitFor(mutex, remain);
|
||||
}
|
||||
writing = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIReadWriteLock::unlockWrite() {
|
||||
PIMutexLocker _ml(mutex);
|
||||
writing = false;
|
||||
var.notifyAll();
|
||||
}
|
||||
|
||||
|
||||
void PIReadWriteLock::lockRead() {
|
||||
PIMutexLocker _ml(mutex);
|
||||
while (writing) {
|
||||
var.wait(mutex);
|
||||
}
|
||||
++reading;
|
||||
}
|
||||
|
||||
|
||||
bool PIReadWriteLock::tryLockRead() {
|
||||
PIMutexLocker _ml(mutex);
|
||||
if (writing) return false;
|
||||
++reading;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIReadWriteLock::tryLockRead(PISystemTime timeout) {
|
||||
PITimeMeasurer tm;
|
||||
PIMutexLocker _ml(mutex);
|
||||
while (writing) {
|
||||
PISystemTime remain = timeout - tm.elapsed();
|
||||
if (remain.isNegative()) return false;
|
||||
var.waitFor(mutex, remain);
|
||||
}
|
||||
++reading;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIReadWriteLock::unlockRead() {
|
||||
PIMutexLocker _ml(mutex);
|
||||
--reading;
|
||||
var.notifyAll();
|
||||
}
|
||||
130
libs/main/thread/pireadwritelock.h
Normal file
130
libs/main/thread/pireadwritelock.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*! \file pireadwritelock.h
|
||||
* \ingroup Read/Write lock
|
||||
* \~\brief
|
||||
* \~english Read/Write lock
|
||||
* \~russian Блокировка чтения/записи
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
PIReadWriteLock, PIReadLocker, PIWriteLocker
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIREADWRITELOCK_H
|
||||
#define PIREADWRITELOCK_H
|
||||
|
||||
#include "piconditionvar.h"
|
||||
|
||||
|
||||
class PIP_EXPORT PIReadWriteLock {
|
||||
public:
|
||||
NO_COPY_CLASS(PIReadWriteLock)
|
||||
|
||||
//! \~english Constructs %PIReadWriteLock.
|
||||
//! \~russian Создает %PIReadWriteLock.
|
||||
PIReadWriteLock();
|
||||
|
||||
//! \~english Destroy %PIReadWriteLock.
|
||||
//! \~russian Деструктор %PIReadWriteLock.
|
||||
~PIReadWriteLock();
|
||||
|
||||
|
||||
//! \~english Lock for write. If already locked for write or read, than wait until all locks released.
|
||||
//! \~russian Заблокировать на запись. Если уже заблокировано на запись или чтение, то ждёт освобождения блокировок.
|
||||
void lockWrite();
|
||||
|
||||
//! \~english Try to lock for write. Returns if operation was successfull.
|
||||
//! \~russian Пробует заблокировать на запись. Возвращает успех операции.
|
||||
bool tryLockWrite();
|
||||
|
||||
//! \~english Try to lock for write for \"timeout\". Returns if operation was successfull (timeout has not expired).
|
||||
//! \~russian Пробует заблокировать на запись в течении \"timeout\". Возвращает успех операции (не истек ли тайм-аут).
|
||||
bool tryLockWrite(PISystemTime timeout);
|
||||
|
||||
//! \~english Release lock for write.
|
||||
//! \~russian Освобождает блокировку на запись.
|
||||
void unlockWrite();
|
||||
|
||||
|
||||
//! \~english Lock for read. If already locked for write, than wait until write lock released.
|
||||
//! \~russian Заблокировать на чтение. Если уже заблокировано на запись, то ждёт освобождения записывающей блокировки.
|
||||
void lockRead();
|
||||
|
||||
//! \~english Try to lock for read. Returns if operation was successfull.
|
||||
//! \~russian Пробует заблокировать на чтение. Возвращает успех операции.
|
||||
bool tryLockRead();
|
||||
|
||||
//! \~english Try to lock for read for \"timeout\". Returns if operation was successfull (timeout has not expired).
|
||||
//! \~russian Пробует заблокировать на чтение в течении \"timeout\". Возвращает успех операции (не истек ли тайм-аут).
|
||||
bool tryLockRead(PISystemTime timeout);
|
||||
|
||||
//! \~english Release lock for read.
|
||||
//! \~russian Освобождает блокировку на чтение.
|
||||
void unlockRead();
|
||||
|
||||
private:
|
||||
int reading = 0;
|
||||
bool writing = false;
|
||||
PIMutex mutex;
|
||||
PIConditionVariable var;
|
||||
};
|
||||
|
||||
|
||||
class PIP_EXPORT PIReadLocker {
|
||||
public:
|
||||
NO_COPY_CLASS(PIReadLocker);
|
||||
|
||||
//! \~english Constructs and lock for read %PIReadWriteLock "l" if "condition" is \c true.
|
||||
//! \~russian Создается и блокирует на чтение %PIReadWriteLock "l" если "condition" \c true.
|
||||
PIReadLocker(PIReadWriteLock & l, bool condition = true): rwl(l), cond(condition) {
|
||||
if (cond) rwl.lockRead();
|
||||
}
|
||||
|
||||
//! \~english Release read lock on %PIReadWriteLock if "condition" was \c true.
|
||||
//! \~russian Освобождает блокировку на чтение %PIReadWriteLock если "condition" был \c true.
|
||||
~PIReadLocker() {
|
||||
if (cond) rwl.unlockRead();
|
||||
}
|
||||
|
||||
private:
|
||||
PIReadWriteLock & rwl;
|
||||
bool cond = true;
|
||||
};
|
||||
|
||||
|
||||
class PIP_EXPORT PIWriteLocker {
|
||||
public:
|
||||
NO_COPY_CLASS(PIWriteLocker);
|
||||
|
||||
//! \~english Constructs and lock for write %PIReadWriteLock "l" if "condition" is \c true.
|
||||
//! \~russian Создается и блокирует на запись %PIReadWriteLock "l" если "condition" \c true.
|
||||
PIWriteLocker(PIReadWriteLock & l, bool condition = true): rwl(l), cond(condition) {
|
||||
if (cond) rwl.lockWrite();
|
||||
}
|
||||
|
||||
//! \~english Release write lock on %PIReadWriteLock if "condition" was \c true.
|
||||
//! \~russian Освобождает блокировку на запись %PIReadWriteLock если "condition" был \c true.
|
||||
~PIWriteLocker() {
|
||||
if (cond) rwl.unlockWrite();
|
||||
}
|
||||
|
||||
private:
|
||||
PIReadWriteLock & rwl;
|
||||
bool cond = true;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
152
libs/main/thread/pisemaphore.cpp
Normal file
152
libs/main/thread/pisemaphore.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
PISemaphore, PISemaphoreLocker
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//! \addtogroup Thread
|
||||
//! \{
|
||||
//! \class PISemaphore pisemaphore.h
|
||||
//!
|
||||
//! \~\brief
|
||||
//! \~english Basic semaphore
|
||||
//! \~russian Простой семафор
|
||||
//!
|
||||
//!
|
||||
//! \~\details
|
||||
//! \~english \section PISemaphore_sec0 Synopsis
|
||||
//! \~russian \section PISemaphore_sec0 Краткий обзор
|
||||
//!
|
||||
//! \~english
|
||||
//! %PISemaphore provides critical code section defence between several threads with resource counting.
|
||||
//! Semaphore contains logic counter and functions to change it:
|
||||
//! \a release(), \a acquire() and \a tryAcquire().
|
||||
//!
|
||||
//! For automatic acquire-release use \a PISemaphoreLocker.
|
||||
//!
|
||||
//! \~russian
|
||||
//! %PISemaphore предоставляет межпотоковую защиту критических секций кода с подсчетом ресурсов.
|
||||
//! Семафор состоит из логического счетчика и методов для его изменения:
|
||||
//! \a release(), \a acquire() and \a tryAcquire().
|
||||
//!
|
||||
//! Для автоматического захвата-освобождения используйте \a PISemaphoreLocker.
|
||||
//!
|
||||
//! \~english \section PISemaphore_sec1 Usage
|
||||
//! \~russian \section PISemaphore_sec1 Использование
|
||||
//!
|
||||
//! \~english
|
||||
//!
|
||||
//! \~russian
|
||||
//!
|
||||
//! \~\code
|
||||
//! \endcode
|
||||
//! \}
|
||||
|
||||
|
||||
//! \addtogroup Thread
|
||||
//! \{
|
||||
//! \class PISemaphoreLocker pisemaphore.h
|
||||
//!
|
||||
//! \~\brief
|
||||
//! \~english %PISemaphore autolocker
|
||||
//! \~russian Автоблокировщик %PISemaphore
|
||||
//!
|
||||
//!
|
||||
//! \~\details
|
||||
//!
|
||||
//! \~english
|
||||
//! When a %PISemaphoreLocker object is created, it attempts to acquire the semaphore resources, if "condition" \c true.
|
||||
//! When control leaves the scope in which the %PISemaphoreLocker object was created,
|
||||
//! the %PISemaphoreLocker is destructed and the resources are released, if "condition" was \c true.
|
||||
//!
|
||||
//! If "condition" \c false this class do nothing.
|
||||
//!
|
||||
//! The %PISemaphoreLocker class is non-copyable.
|
||||
//!
|
||||
//! \~russian
|
||||
//! При создании экземпляра %PISemaphoreLocker захватываются ресурсы семафора, если "condition" \c true.
|
||||
//! Когда выполнение покидает область жизни объекта, вызывается его деструктор и ресурсы
|
||||
//! освобождаются, если "condition" был \c true.
|
||||
//!
|
||||
//! Если "condition" \c false, то этот объект ничего не делает.
|
||||
//!
|
||||
//! Класс %PISemaphoreLocker некопируемый.
|
||||
//!
|
||||
//! \~\code
|
||||
//! // critical section start
|
||||
//! {
|
||||
//! PISemaphoreLocker locker(mutex, 5);
|
||||
//! // ... your code here
|
||||
//! }
|
||||
//! // critical section end
|
||||
//! \endcode
|
||||
//! \}
|
||||
|
||||
|
||||
#include "pisemaphore.h"
|
||||
|
||||
|
||||
PISemaphore::PISemaphore(int initial) {
|
||||
count = initial;
|
||||
}
|
||||
|
||||
|
||||
PISemaphore::~PISemaphore() {
|
||||
var.notifyAll();
|
||||
}
|
||||
|
||||
|
||||
void PISemaphore::acquire(int cnt) {
|
||||
PIMutexLocker _ml(mutex);
|
||||
while (count < cnt) {
|
||||
var.wait(mutex);
|
||||
}
|
||||
count -= cnt;
|
||||
}
|
||||
|
||||
|
||||
bool PISemaphore::tryAcquire(int cnt) {
|
||||
PIMutexLocker _ml(mutex);
|
||||
if (count < cnt) return false;
|
||||
count -= cnt;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PISemaphore::tryAcquire(int cnt, PISystemTime timeout) {
|
||||
PITimeMeasurer tm;
|
||||
PIMutexLocker _ml(mutex);
|
||||
while (count < cnt) {
|
||||
PISystemTime remain = timeout - tm.elapsed();
|
||||
if (remain.isNegative()) return false;
|
||||
var.waitFor(mutex, remain);
|
||||
}
|
||||
count -= cnt;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PISemaphore::release(int cnt) {
|
||||
PIMutexLocker _ml(mutex);
|
||||
count += cnt;
|
||||
var.notifyAll();
|
||||
}
|
||||
|
||||
|
||||
int PISemaphore::available() const {
|
||||
PIMutexLocker _ml(mutex);
|
||||
return count;
|
||||
}
|
||||
95
libs/main/thread/pisemaphore.h
Normal file
95
libs/main/thread/pisemaphore.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*! \file pisemaphore.h
|
||||
* \ingroup Semaphore
|
||||
* \~\brief
|
||||
* \~english Basic semaphore
|
||||
* \~russian Простой семафор
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
PISemaphore, PISemaphoreLocker
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PISEMAPHORE_H
|
||||
#define PISEMAPHORE_H
|
||||
|
||||
#include "piconditionvar.h"
|
||||
|
||||
|
||||
class PIP_EXPORT PISemaphore {
|
||||
public:
|
||||
NO_COPY_CLASS(PISemaphore)
|
||||
|
||||
//! \~english Constructs semaphore with \"initial\" available resources.
|
||||
//! \~russian Создает семафор с \"initial\" начальными свободными ресурсами.
|
||||
PISemaphore(int initial = 0);
|
||||
|
||||
//! \~english Destroy semaphore.
|
||||
//! \~russian Деструктор семафора.
|
||||
~PISemaphore();
|
||||
|
||||
|
||||
//! \~english Acquire \"cnt\" resources. If no available resources, than blocks until they freed.
|
||||
//! \~russian Захватывает \"cnt\" ресурсов. Если свободных ресурсов недостаточно, то блокирует до их появления.
|
||||
void acquire(int cnt = 1);
|
||||
|
||||
//! \~english Try to acquire \"cnt\" resources. Returns if operation was successfull.
|
||||
//! \~russian Пробует захватывает \"cnt\" ресурсов. Возвращает успех захвата.
|
||||
bool tryAcquire(int cnt = 1);
|
||||
|
||||
//! \~english Try to acquire \"cnt\" resources for \"timeout\". Returns if operation was successfull (timeout has not expired).
|
||||
//! \~russian Пробует захватывает \"cnt\" ресурсов в течении \"timeout\". Возвращает успех захвата (не истек ли тайм-аут).
|
||||
bool tryAcquire(int cnt, PISystemTime timeout);
|
||||
|
||||
//! \~english Release \"cnt\" resources.
|
||||
//! \~russian Освобождает \"cnt\" ресурсов.
|
||||
void release(int cnt = 1);
|
||||
|
||||
//! \~english Returns available resources count.
|
||||
//! \~russian Возвращает количество свободных ресурсов.
|
||||
int available() const;
|
||||
|
||||
private:
|
||||
int count = 0;
|
||||
mutable PIMutex mutex;
|
||||
PIConditionVariable var;
|
||||
};
|
||||
|
||||
|
||||
class PIP_EXPORT PISemaphoreLocker {
|
||||
public:
|
||||
NO_COPY_CLASS(PISemaphoreLocker);
|
||||
|
||||
//! \~english Constructs and acquire \"cnt\" resources on semaphore "s" if "condition" is \c true.
|
||||
//! \~russian Создается и захватывает \"cnt\" ресурсов у семафора "s" если "condition" \c true.
|
||||
PISemaphoreLocker(PISemaphore & s, int cnt = 1, bool condition = true): sem(s), count(cnt), cond(condition) {
|
||||
if (cond) sem.acquire(count);
|
||||
}
|
||||
|
||||
//! \~english Release "cnt" resources on semaphore if "condition" was \c true.
|
||||
//! \~russian Освобождает "cnt" ресурсов у семафора если "condition" был \c true.
|
||||
~PISemaphoreLocker() {
|
||||
if (cond) sem.release(count);
|
||||
}
|
||||
|
||||
private:
|
||||
PISemaphore & sem;
|
||||
int count = 1;
|
||||
bool cond = true;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "piincludes_p.h"
|
||||
#include "piintrospection_threads.h"
|
||||
#include "pitime.h"
|
||||
#include "pitranslator.h"
|
||||
#ifndef MICRO_PIP
|
||||
# include "pisystemtests.h"
|
||||
#endif
|
||||
@@ -568,7 +569,7 @@ PIThread::PIThread(bool startNow, PISystemTime loop_delay): PIObject() {
|
||||
PIThread::~PIThread() {
|
||||
PIINTROSPECTION_THREAD_DELETE(this);
|
||||
if (!running_ || PRIVATE->thread == 0) return;
|
||||
piCout << "[PIThread \"" << name() << "\"] Warning, terminate on destructor!";
|
||||
piCout << "[PIThread \"%1\"] Warning, terminate on destructor!"_tr("PIThread").arg(name());
|
||||
#ifdef FREERTOS
|
||||
// void * ret(0);
|
||||
// PICout(PICoutManipulators::DefaultControls) << "~PIThread" << PRIVATE->thread;
|
||||
@@ -663,7 +664,7 @@ void PIThread::stop() {
|
||||
|
||||
|
||||
void PIThread::terminate() {
|
||||
piCoutObj << "Warning, terminate!";
|
||||
piCoutObj << "Warning, terminate!"_tr("PIThread");
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "terminate ..." << running_;
|
||||
#ifdef FREERTOS
|
||||
PICout(PICoutManipulators::DefaultControls) << "FreeRTOS can't terminate pthreads! waiting for stop";
|
||||
@@ -781,7 +782,7 @@ bool PIThread::_startThread(void * func) {
|
||||
|
||||
running_ = false;
|
||||
PRIVATE->thread = 0;
|
||||
piCoutObj << "Error: Can`t start new thread:" << errorString();
|
||||
piCoutObj << "Error: Can`t start new thread: %1"_tr("PIThread").arg(errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -919,6 +920,10 @@ void PIThread::_runThread() {
|
||||
|
||||
|
||||
void PIThread::_endThread() {
|
||||
PIScopeExitCall ec([this] {
|
||||
terminating = running_ = false;
|
||||
tid_ = -1;
|
||||
});
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "...";
|
||||
stopped();
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
|
||||
@@ -927,14 +932,13 @@ void PIThread::_endThread() {
|
||||
end();
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
|
||||
if (lockRun) thread_mutex.unlock();
|
||||
terminating = running_ = false;
|
||||
tid_ = -1;
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "exit";
|
||||
// cout << "thread " << t << " exiting ... " << endl;
|
||||
// PICout(PICoutManipulators::DefaultControls) << "pthread_exit" << (__privateinitializer__.p)->thread;
|
||||
UNREGISTER_THREAD(this);
|
||||
PIINTROSPECTION_THREAD_STOP(this);
|
||||
#if defined(WINDOWS)
|
||||
ec.callAndCancel();
|
||||
# ifdef CC_GCC
|
||||
_endthreadex(0);
|
||||
# else
|
||||
@@ -943,7 +947,7 @@ void PIThread::_endThread() {
|
||||
#elif defined(FREERTOS)
|
||||
PRIVATE->thread = 0;
|
||||
#else
|
||||
pthread_detach(PRIVATE->thread);
|
||||
// pthread_detach(PRIVATE->thread);
|
||||
PRIVATE->thread = 0;
|
||||
pthread_exit(0);
|
||||
#endif
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
#include "pigrabberbase.h"
|
||||
#include "pimutex.h"
|
||||
#include "pipipelinethread.h"
|
||||
#include "piprotectedvariable.h"
|
||||
#include "pireadwritelock.h"
|
||||
#include "pisemaphore.h"
|
||||
#include "pispinlock.h"
|
||||
#include "pithread.h"
|
||||
#include "pithreadnotifier.h"
|
||||
|
||||
@@ -171,7 +171,7 @@ bool PITimer::waitForFinish(PISystemTime timeout) {
|
||||
|
||||
void PITimer::initFirst() {
|
||||
thread = new PIThread([this] { threadFunc(); });
|
||||
thread->setName("__S__.PITimer.thread");
|
||||
thread->setName("_S.PITimer.thread");
|
||||
setProperty("interval", PISystemTime());
|
||||
}
|
||||
|
||||
|
||||
@@ -129,6 +129,20 @@ struct base64HelpStruct {
|
||||
// clang-format on
|
||||
|
||||
|
||||
bool PIByteArray::startsWith(const PIByteArray & o) const {
|
||||
if (o.isEmpty()) return false;
|
||||
if (size() < o.size()) return false;
|
||||
return piCompareBinary(data(), o.data(), o.size());
|
||||
}
|
||||
|
||||
|
||||
bool PIByteArray::endsWith(const PIByteArray & o) const {
|
||||
if (o.isEmpty()) return false;
|
||||
if (size() < o.size()) return false;
|
||||
return piCompareBinary(data(size() - o.size()), o.data(), o.size());
|
||||
}
|
||||
|
||||
|
||||
PIByteArray & PIByteArray::convertToBase64() {
|
||||
return *this = toBase64();
|
||||
}
|
||||
@@ -396,6 +410,17 @@ PIByteArray PIByteArray::fromHex(PIString str) {
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIByteArray::fromAscii(const char * str) {
|
||||
PIByteArray ret;
|
||||
int ind = 0;
|
||||
while (str[ind] != 0) {
|
||||
ret.append(str[ind]);
|
||||
++ind;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PICout operator<<(PICout s, const PIByteArray & ba) {
|
||||
s.space();
|
||||
s.saveAndSetControls(0);
|
||||
|
||||
@@ -340,6 +340,10 @@ public:
|
||||
//! \~\sa \a every(), \a any(), \a contains(), \a indexWhere()
|
||||
inline int entries(std::function<bool(uchar e)> test, ssize_t start = 0) const { return d.entries(test, start); }
|
||||
|
||||
bool startsWith(const PIByteArray & o) const;
|
||||
|
||||
bool endsWith(const PIByteArray & o) const;
|
||||
|
||||
//! \~english Returns the first index at which a given element `e`
|
||||
//! can be found in the array, or `-1` if it is not present.
|
||||
//! \~russian Возвращает первый индекс, по которому данный элемент `e`
|
||||
@@ -1165,6 +1169,8 @@ public:
|
||||
|
||||
static PIByteArray fromHex(PIString str);
|
||||
|
||||
static PIByteArray fromAscii(const char * str);
|
||||
|
||||
//! \~english Return converted from Base 64 data
|
||||
//! \~russian Возвращает массив из Base 64 представления
|
||||
static PIByteArray fromBase64(const PIByteArray & base64);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "piiostream.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "pitime.h"
|
||||
#include "pitranslator.h"
|
||||
|
||||
#include <ctime>
|
||||
#ifdef QNX
|
||||
@@ -320,7 +321,8 @@ PISystemTime PITimeMeasurer::elapsed() const {
|
||||
|
||||
PISystemTime PISystemTime::Frequency::toSystemTime() const {
|
||||
if (value_hz <= 0.) {
|
||||
piCout << "[PISystemTime::Frequency] toSystemTime() warning: invalid hertz" << value_hz;
|
||||
piCout << "[PISystemTime::Frequency]"
|
||||
<< "toSystemTime() Warning: invalid hertz: %1"_tr("PISystemTime").arg(value_hz);
|
||||
return PISystemTime();
|
||||
}
|
||||
return PISystemTime::fromSeconds(1. / value_hz);
|
||||
@@ -329,7 +331,8 @@ PISystemTime PISystemTime::Frequency::toSystemTime() const {
|
||||
|
||||
PISystemTime::Frequency PISystemTime::Frequency::fromSystemTime(const PISystemTime & st) {
|
||||
if (st == PISystemTime()) {
|
||||
piCout << "[PISystemTime::Frequency] fromSystemTime() warning: null frequency";
|
||||
piCout << "[PISystemTime::Frequency]"
|
||||
<< "fromSystemTime() Warning: null frequency"_tr("PISystemTime");
|
||||
return Frequency();
|
||||
}
|
||||
return Frequency(1. / st.toSeconds());
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "pivariant.h"
|
||||
|
||||
#include "pitranslator.h"
|
||||
|
||||
|
||||
//! \class PIVariant pivariant.h
|
||||
//! \details
|
||||
@@ -388,7 +390,7 @@ PIVariant PIVariant::fromValue(const PIByteArray & c, uint type_id) {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
piCout << "Can`t initialize PIVariant from unregistered typeID \"" << type_id << "\"!";
|
||||
piCout << "Can`t initialize PIVariant from unregistered typeID \"%1\"!"_tr("PIVariant").arg(type_id);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -410,7 +412,7 @@ PIVariant PIVariant::fromValue(const PIByteArray & c, const PIString & type) {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
piCout << "Can`t initialize PIVariant from unregistered type \"" << type << "\"!";
|
||||
piCout << "Can`t initialize PIVariant from unregistered type \"%1\"!"_tr("PIVariant").arg(type);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "piopencl.h"
|
||||
|
||||
#include "piresources.h"
|
||||
#include "pitranslator.h"
|
||||
#define CL_USE_DEPRECATED_OPENCL_1_2_APIS
|
||||
#define CL_USE_DEPRECATED_OPENCL_2_0_APIS
|
||||
#define CL_TARGET_OPENCL_VERSION 120
|
||||
@@ -88,7 +89,8 @@ void PIOpenCL::Initializer::init() {
|
||||
cl_uint plat_num = 0;
|
||||
ret = clGetPlatformIDs(max_size, cl_platforms, &plat_num);
|
||||
if (ret != 0) {
|
||||
piCout << "[PIOpenCL] Error: OpenCL platforms not found!";
|
||||
piCout << "[PIOpenCL]"
|
||||
<< "Error: OpenCL platforms not found!"_tr("PIOpenCL");
|
||||
return;
|
||||
}
|
||||
for (uint i = 0; i < plat_num; i++) {
|
||||
@@ -504,7 +506,7 @@ bool PIOpenCL::Program::initKernels(PIVector<void *> kerns) {
|
||||
bool PIOpenCL::Kernel::execute() {
|
||||
if (dims.isEmpty()) {
|
||||
piCout << "[PIOpenCL::Kernel]"
|
||||
<< "Error: empty range";
|
||||
<< "Error: empty range"_tr("PIOpenCL");
|
||||
return false;
|
||||
}
|
||||
cl_int ret = clEnqueueNDRangeKernel(context_->PRIVATEWB->queue, PRIVATE->kernel, dims.size(), 0, dims.data(), 0, 0, 0, 0);
|
||||
@@ -581,13 +583,13 @@ void setArgV(cl_kernel k, int index, T v) {
|
||||
bool PIOpenCL::Kernel::setArgValueS(int index, const PIVariant & value) {
|
||||
if (index < 0 || index >= args_.size_s()) {
|
||||
piCout << "[PIOpenCL::Kernel]"
|
||||
<< "setArgValue invalid index" << index;
|
||||
<< "setArgValue invalid index %1"_tr("PIOpenCL").arg(index);
|
||||
return false;
|
||||
}
|
||||
KernelArg & ka(args_[index]);
|
||||
if (ka.dims > 0) {
|
||||
piCout << "[PIOpenCL::Kernel]"
|
||||
<< "setArgValue set scalar to \"" << ka.type_name << ka.arg_name << "\"";
|
||||
<< "setArgValue set scalar to \"%1 %2\""_tr("PIOpenCL").arg(ka.type_name).arg(ka.arg_name);
|
||||
return false;
|
||||
}
|
||||
switch (ka.arg_type) {
|
||||
@@ -611,13 +613,13 @@ bool PIOpenCL::Kernel::bindArgValue(int index, Buffer * buffer) {
|
||||
if (!buffer) return false;
|
||||
if (index < 0 || index >= args_.size_s()) {
|
||||
piCout << "[PIOpenCL::Kernel]"
|
||||
<< "bindArgValue invalid index" << index;
|
||||
<< "bindArgValue invalid index %1"_tr("PIOpenCL").arg(index);
|
||||
return false;
|
||||
}
|
||||
KernelArg & ka(args_[index]);
|
||||
if (ka.dims <= 0) {
|
||||
piCout << "[PIOpenCL::Kernel]"
|
||||
<< "bindArgValue set buffer to \"" << ka.type_name << ka.arg_name << "\"";
|
||||
<< "bindArgValue set buffer to \"%1 %2\""_tr("PIOpenCL").arg(ka.type_name).arg(ka.arg_name);
|
||||
return false;
|
||||
}
|
||||
clSetKernelArg(PRIVATE->kernel, index, sizeof(buffer->PRIVATEWB->buffer), &(buffer->PRIVATEWB->buffer));
|
||||
|
||||
385
main.cpp
385
main.cpp
@@ -1,361 +1,66 @@
|
||||
#include "pibytearray.h"
|
||||
#include "piclientserver_client.h"
|
||||
#include "piclientserver_server.h"
|
||||
#include "picodeparser.h"
|
||||
#include "piintrospection_server.h"
|
||||
#include "piiostream.h"
|
||||
#include "pijson.h"
|
||||
#include "pilog.h"
|
||||
#include "pimathbase.h"
|
||||
#include "pihttpserver.h"
|
||||
#include "pip.h"
|
||||
#include "pivaluetree_conversions.h"
|
||||
|
||||
using namespace PICoutManipulators;
|
||||
|
||||
|
||||
enum MyEvent {
|
||||
meVoid,
|
||||
meInt,
|
||||
meString,
|
||||
meIntString,
|
||||
};
|
||||
|
||||
PIKbdListener kbd;
|
||||
|
||||
|
||||
class MyServerClient: public PIClientServer::ServerClient {
|
||||
public:
|
||||
~MyServerClient() { send_thread.stopAndWait(); }
|
||||
|
||||
protected:
|
||||
void readed(PIByteArray data) override { piCout << "readed" << (data.size()); }
|
||||
// void aboutDelete() override { piCout << "aboutDelete"; }
|
||||
// void disconnected() override { piCout << "disconnected"; }
|
||||
void connected() override {
|
||||
// piCout << "connected";
|
||||
send_thread.start(
|
||||
[this] {
|
||||
// write((PIString::fromNumber(++counter)).toUTF8());
|
||||
PIByteArray ba(64_KiB);
|
||||
write(ba);
|
||||
},
|
||||
2_Hz);
|
||||
}
|
||||
PIThread send_thread;
|
||||
int counter = 0;
|
||||
};
|
||||
|
||||
|
||||
class MyClient: public PIClientServer::Client {
|
||||
public:
|
||||
~MyClient() { send_thread.stopAndWait(); }
|
||||
|
||||
protected:
|
||||
void readed(PIByteArray data) override { piCout << "readed" << (data.size()); }
|
||||
void disconnected() override { piCout << "disconnected"; }
|
||||
void connected() override {
|
||||
piCout << "connected";
|
||||
send_thread.start(
|
||||
[this] {
|
||||
// write((PIString::fromNumber(++counter)).toUTF8());
|
||||
write(PIByteArray(64_KiB));
|
||||
},
|
||||
2_Hz);
|
||||
}
|
||||
PIThread send_thread;
|
||||
int counter = 0;
|
||||
};
|
||||
const char * pageTitle = "<!DOCTYPE html>"
|
||||
"<html>"
|
||||
"<body>"
|
||||
"<h1>Title</h1>"
|
||||
"</body>"
|
||||
"</html>";
|
||||
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
PILog log;
|
||||
log.setApplicationName("test");
|
||||
log.setDir("logs");
|
||||
// log.setTimestampFormat("hh-mm-ss");
|
||||
// log.setLineFormat("[c] m (t)");
|
||||
log.start();
|
||||
|
||||
// log.enqueue("debug msg");
|
||||
// log.enqueue("warn msg with ${c}", PILog::Category::Warning);
|
||||
// log.enqueue("ERROR${m}${t}", PILog::Category::Error);
|
||||
|
||||
log.debug(&log) << "some msg";
|
||||
piMSleep(50);
|
||||
log.warning() << "another!";
|
||||
piMSleep(50);
|
||||
log.error() << "blahblahblag";
|
||||
|
||||
// log.stop();
|
||||
return 0;
|
||||
/*PIPeer p("123");
|
||||
|
||||
piCout << "start ...";
|
||||
p.start();
|
||||
piCout << "start ok";
|
||||
|
||||
piSleep(1.);
|
||||
|
||||
piCout << "stop ...";
|
||||
p.stopAndWait();
|
||||
piCout << "stop ok";
|
||||
|
||||
piSleep(1.);
|
||||
|
||||
piCout << "exit";
|
||||
return 0;*/
|
||||
|
||||
if (argc > 1) {
|
||||
PIINTROSPECTION_START(server);
|
||||
} else {
|
||||
PIINTROSPECTION_START(client);
|
||||
}
|
||||
|
||||
kbd.enableExitCapture();
|
||||
|
||||
PIHTTPServer server;
|
||||
|
||||
PIClientServer::Server * s = nullptr;
|
||||
PIThread * s_thread = new PIThread();
|
||||
PIVector<PIClientServer::Client *> cv;
|
||||
server.setFavicon(PIFile::readAll("logo.png", false));
|
||||
// server.setOption(MicrohttpdServer::Option::HTTPSEnabled, true);
|
||||
server.listen({"127.0.0.1", 7777});
|
||||
// server.listen({"192.168.1.10", 7778});
|
||||
|
||||
if (argc > 1) {
|
||||
piCout << "Server";
|
||||
s = new PIClientServer::Server();
|
||||
s->setClientFactory([] { return new MyServerClient(); });
|
||||
s->configuration().enableSymmetricEncryption("1122334455667788"_hex);
|
||||
s->listenAll(12345);
|
||||
s_thread->start(
|
||||
[s] {
|
||||
piCout << "*** clients" << s->clientsCount();
|
||||
int i = 0;
|
||||
s->forEachClient([&i](PIClientServer::ServerClient * c) {
|
||||
// piCout << "client" << ++i << c;
|
||||
c->write(PIByteArray(1_KiB));
|
||||
// c->close();
|
||||
// piMSleep(200);
|
||||
});
|
||||
},
|
||||
1._Hz);
|
||||
} else {
|
||||
piCout << "Client";
|
||||
piForTimes(2) {
|
||||
piMSleep(25);
|
||||
auto c = new MyClient();
|
||||
c->configuration().enableSymmetricEncryption("1122334455667788"_hex);
|
||||
c->connect(PINetworkAddress::resolve("127.0.0.1", 12345));
|
||||
cv << c;
|
||||
}
|
||||
}
|
||||
|
||||
WAIT_FOR_EXIT;
|
||||
|
||||
s_thread->stopAndWait();
|
||||
|
||||
piDeleteSafety(s);
|
||||
piDeleteAllAndClear(cv);
|
||||
|
||||
PIINTROSPECTION_STOP
|
||||
|
||||
return 0;
|
||||
/*PIPackedTCP * tcp_s =
|
||||
PIIODevice::createFromFullPath("ptcp://s::8000")->cast<PIPackedTCP>(); // new PIPackedTCP(PIPackedTCP::Server, {"0.0.0.0:8000"});
|
||||
PIPackedTCP * tcp_c = PIIODevice::createFromFullPath("ptcp://c:127.0.0.1:8000")
|
||||
->cast<PIPackedTCP>(); // new PIPackedTCP(PIPackedTCP::Client, {"127.0.0.1:8000"});
|
||||
piCout << tcp_s << tcp_c;
|
||||
// CONNECTL(&tcp_s, opened, []() { piCout << "Srv opened"; });
|
||||
// CONNECTL(&tcp_c, opened, []() { piCout << "Cli opened"; });
|
||||
// CONNECTL(&tcp_s, closed, []() { piCout << "Srv closed"; });
|
||||
// CONNECTL(&tcp_c, closed, []() { piCout << "Cli closed"; });
|
||||
CONNECTL(tcp_s, connected, []() { piCout << "Srv conn"; });
|
||||
CONNECTL(tcp_c, connected, []() { piCout << "Cli conn"; });
|
||||
CONNECTL(tcp_s, disconnected, []() { piCout << "Srv disconn"; });
|
||||
CONNECTL(tcp_c, disconnected, []() { piCout << "Cli disconn"; });
|
||||
CONNECTL(tcp_s, threadedReadEvent, [](const uchar * readed, ssize_t size) {
|
||||
PIByteArray d(readed, size);
|
||||
piCout << "Srv readed" << d;
|
||||
server.registerPath("/", [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||
MicrohttpdServer::Reply ret;
|
||||
ret.setBody(PIByteArray::fromAscii(pageTitle));
|
||||
return ret;
|
||||
});
|
||||
CONNECTL(tcp_c, threadedReadEvent, [](const uchar * readed, ssize_t size) {
|
||||
PIByteArray d(readed, size);
|
||||
piCout << "Cli readed" << d;
|
||||
|
||||
server.registerPath("/html", [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||
MicrohttpdServer::Reply ret;
|
||||
ret.setBody("<!DOCTYPE html><html><body><p>arg=%1</p></body></html>"_a.arg(r.args.value("a0")).toUTF8());
|
||||
return ret;
|
||||
});
|
||||
// tcp_s->open();
|
||||
// tcp_c->open();
|
||||
tcp_s->startThreadedRead();
|
||||
tcp_c->startThreadedRead();
|
||||
piForTimes(5) {
|
||||
piCout << "\n1";
|
||||
piMSleep(200);
|
||||
piCout << "2";
|
||||
// tcp_c->close();
|
||||
piCout << "2+";
|
||||
// tcp_s->close();
|
||||
piCout << "3";
|
||||
// tcp_c->open();
|
||||
piCout << "3+";
|
||||
// tcp_s->open();
|
||||
piCout << "4";
|
||||
piMSleep(500);
|
||||
// piCout << "5";
|
||||
tcp_c->write("1234567890"_a.toByteArray());
|
||||
// piCout << "6";
|
||||
tcp_s->write("1234567890"_a.toByteArray());
|
||||
// piCout << "7";
|
||||
piMSleep(200);
|
||||
}
|
||||
// piCout << &tcp_s;
|
||||
// piCout << tcp_s->path();
|
||||
// piCout << tcp_s->constructFullPath();
|
||||
delete tcp_s;
|
||||
delete tcp_c;
|
||||
return 0;*/
|
||||
/*PITimer timer(tfunc);
|
||||
// timer.addDelimiter(2);
|
||||
timer.addDelimiter(40, tfunc4);
|
||||
|
||||
tm.reset();
|
||||
timer.start(0.5_Hz);
|
||||
piMSleep(2200);
|
||||
piCout << tm.elapsed_m() << cnt;
|
||||
server.registerPath("/api", [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||
MicrohttpdServer::Reply ret;
|
||||
ret.setBody(PIByteArray::fromAscii("<!DOCTYPE html><html><body>API</body></html>"));
|
||||
return ret;
|
||||
});
|
||||
|
||||
timer.stop();
|
||||
timer.waitForFinish();
|
||||
return 0;*/
|
||||
server.registerPath("/api/*", [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||
MicrohttpdServer::Reply ret;
|
||||
ret.setBody("<!DOCTYPE html><html><body>API etry %1</body></html>"_a.arg(r.path).toUTF8());
|
||||
ret.setCode(405);
|
||||
return ret;
|
||||
});
|
||||
|
||||
/*server.setRequestCallback([](MicrohttpdServer::Request r) -> MicrohttpdServer::Reply {
|
||||
MicrohttpdServer::Reply rep;
|
||||
piCout << "request" << r.path;
|
||||
piCout << " header" << r.headers;
|
||||
piCout << " args" << r.args;
|
||||
piCout << " body" << r.body;
|
||||
piCout << "";
|
||||
rep.setBody(PIByteArray::fromAscii("[{\"value1\": true, \"value2\": \"ыекштп\"}]"));
|
||||
return rep;
|
||||
});*/
|
||||
piCout << "start" << server.isListen();
|
||||
|
||||
bool posted;
|
||||
PIStateMachine * root = new PIStateMachine("Machine");
|
||||
root->setOnFinish([] { piCout << "finish"; });
|
||||
|
||||
PIStateLambda * s1 = new PIStateLambda([] { piCout << "+ enter s1"; }, [] { piCout << "- exit s1"; }, "s1");
|
||||
PIStateLambda * s2 = new PIStateLambda([] { piCout << "+ enter s2"; }, [] { piCout << "- exit s2"; }, "s2");
|
||||
PIStateLambda * s3 = new PIStateLambda([] { piCout << "+ enter s3"; }, [] { piCout << "- exit s3"; }, "s3");
|
||||
PIStateLambda * s4 = new PIStateLambda([] { piCout << "+ enter s4"; }, [] { piCout << "- exit s4"; }, "s4");
|
||||
PIStateLambda * s11 = new PIStateLambda([] { piCout << " + enter s11"; }, [] { piCout << " - exit s11"; }, "s11");
|
||||
PIStateLambda * s12 = new PIStateLambda([] { piCout << " + enter s12"; }, [] { piCout << " - exit s12"; }, "s12");
|
||||
PIStateLambda * s13 = new PIStateLambda([] { piCout << " + enter s13"; }, [] { piCout << " - exit s13"; }, "s13");
|
||||
PIStateLambda * s21 = new PIStateLambda([] { piCout << " + enter s21"; }, [] { piCout << " - exit s21"; }, "s21");
|
||||
PIStateLambda * s22 = new PIStateLambda([] { piCout << " + enter s22"; }, [] { piCout << " - exit s22"; }, "s22");
|
||||
PIStateLambda * s23 = new PIStateLambda([] { piCout << " + enter s23"; }, [] { piCout << " - exit s23"; }, "s23");
|
||||
PIStateLambda * s211 = new PIStateLambda([] { piCout << " + enter s211"; }, [] { piCout << " - exit s211"; }, "s211");
|
||||
PIStateLambda * s212 = new PIStateLambda([] { piCout << " + enter s212"; }, [] { piCout << " - exit s212"; }, "s212");
|
||||
PIStateLambda * s213 = new PIStateLambda([] { piCout << " + enter s213"; }, [] { piCout << " - exit s213"; }, "s213");
|
||||
PIStateFinal * s214 = new PIStateFinal([] { piCout << " + enter s214 final"; }, "s214f");
|
||||
|
||||
root->addStates({s1, s2, s3, s4});
|
||||
// s1->addStates({s11, s12, s13});
|
||||
// s2->addStates({s21, s22, s23});
|
||||
// s21->addStates({s211, s212, s213});
|
||||
// root->addState(s214);
|
||||
|
||||
s2->setParallel(true);
|
||||
|
||||
root->setInitialState(s1);
|
||||
s1->setInitialState(s11);
|
||||
s2->setInitialState(s21);
|
||||
s21->setInitialState(s213);
|
||||
|
||||
// s213->addTransition(s13, meVoid)->addAction([] { piCout << "action transition s21 -> s22"; });
|
||||
// s3->addTransition(s212, meVoid)->addAction([] { piCout << "action transition s1 -> s213"; });
|
||||
s1->addTransition(s2, meVoid)->addAction([root] { root->postEvent(meInt, 1); });
|
||||
s2->addTransition(s3, meInt)->addGuard([](int i) { return i == 1; })->addAction([root] { root->postEvent(meInt, 2); });
|
||||
s3->addTransition(s4, meInt)->addGuard([](int i) { return i == 2; })->addAction([root] { root->postEvent(meInt, 3); });
|
||||
// s2->addTimeoutTransition(s3, .5_s);
|
||||
// s3->addTransition(s1, meIntString)->addGuard([](int i, PIString str) { return i == 2 && str == "hello"; });
|
||||
|
||||
root->start();
|
||||
piCout << "initial" << root->isRunning() << "\n";
|
||||
// piCout << "active atomics" << root->activeAtomics();
|
||||
root->print();
|
||||
|
||||
piCout << "\npost event";
|
||||
posted = root->postEvent(meVoid);
|
||||
piCout << "posted" << posted << "\n";
|
||||
// piCout << "active atomics" << root->activeAtomics();
|
||||
piSleep(1.);
|
||||
root->print();
|
||||
|
||||
// piCout << "\npost event";
|
||||
// posted = root->postEvent(meVoid);
|
||||
// piCout << "posted" << posted << "\n";
|
||||
// root->print();
|
||||
|
||||
/*root->addStates({s1, s2, s3});
|
||||
root->setInitialState(s1);
|
||||
root->start();
|
||||
|
||||
piCout << root->postEvent(meVoid);
|
||||
piCout << "";
|
||||
piCout << root->postEvent(meInt, 0.5f);
|
||||
piCout << "";
|
||||
piCout << root->postEvent(meInt, 0);
|
||||
piCout << "";
|
||||
piCout << root->postEvent(meInt, 1);
|
||||
piCout << "";
|
||||
piCout << root->postEvent(meIntString, 2, "hello");
|
||||
piCout << "";
|
||||
piCout << root->postEvent(meIntString, 2, PIString("hello"));
|
||||
piCout << "";*/
|
||||
delete root;
|
||||
|
||||
/*PISerial ser;
|
||||
ser.setSpeed(PISerial::S115200);
|
||||
piCout << ser.open("COM15", PIIODevice::ReadWrite);
|
||||
CONNECTL(&ser, threadedReadEvent, ([](const uchar * data, ssize_t size) { piCout << PIByteArray(data, size); }));
|
||||
ser.startThreadedRead();
|
||||
(2_s).sleep();
|
||||
ser.stopAndWait();*/
|
||||
|
||||
/*auto test = [](PISystemTime t) {
|
||||
piCout << "---------------";
|
||||
piCout << t << t.toString();
|
||||
piCout << PISystemTime::fromString(t.toString()) << PISystemTime::fromString(t.toString()).toString();
|
||||
piCout << PIVariant(t);
|
||||
piCout << PIVariant(t).toString();
|
||||
};
|
||||
auto test_str = [](PIString s) {
|
||||
piCout << "---------------";
|
||||
piCout << s;
|
||||
piCout << PISystemTime::fromString(s) << PISystemTime::fromString(s).toString();
|
||||
};
|
||||
|
||||
test(PISystemTime::current());
|
||||
test(1000.123_d);
|
||||
test(61_s);
|
||||
test(59_s);
|
||||
test(1234_us);
|
||||
test(5000001_ns);
|
||||
|
||||
test_str("");
|
||||
test_str("2020-05-04");
|
||||
test_str("2020-05-04 11:12:13");
|
||||
test_str("11:12:13");
|
||||
test_str("11:12:13.405");
|
||||
test_str("100");
|
||||
test_str("5 s");
|
||||
test_str("5s");
|
||||
test_str("1000 d 2 h 57 m 7 s 200 ms 2 ns");
|
||||
test_str("0.2 d");
|
||||
test_str(".5d");
|
||||
test_str("3E+2us");
|
||||
test_str("0.1d 200millis");
|
||||
test_str("2h 15 seconds");
|
||||
test_str("4secs 2hours 100 ns 3m 5ms 1 day 6 micros ");
|
||||
|
||||
test_str("1hz");
|
||||
test_str("5.123khz");
|
||||
test_str("5khz 123 hz");
|
||||
test_str("2mhz");
|
||||
test_str("1ghz");
|
||||
test_str("1hz 1hz");*/
|
||||
|
||||
// PIPair<int, PIString> p = createPIPair(0, "");
|
||||
/*PIConfig conf("model.conf");
|
||||
piCout << "****** config\n" << conf.allLeaves() << "******\n";
|
||||
|
||||
PIValueTree vt = PIValueTreeConversions::fromTextFile("model.conf");
|
||||
piCout << "****** tree";
|
||||
vt.forEachRecursive(
|
||||
[](const PIValueTree & v, const PIString & fn) { piCout << fn << "=" << v.value().toString() << "#" << v.comment(); });
|
||||
piCout << "******";*/
|
||||
WAIT_FOR_EXIT
|
||||
|
||||
server.stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -13,10 +13,13 @@ PIClientServer::Server * createServer() {
|
||||
|
||||
bool waitLoop(std::function<bool()> exit_loop, const PISystemTime & timeout) {
|
||||
PITimeMeasurer tm;
|
||||
while (!exit_loop() && (tm.elapsed() < timeout)) {
|
||||
while (tm.elapsed() < timeout) {
|
||||
if (exit_loop()) {
|
||||
return true;
|
||||
}
|
||||
piMinSleep();
|
||||
}
|
||||
return tm.elapsed() < timeout;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Client>
|
||||
@@ -52,10 +55,13 @@ TEST(ClientServer, OneClient) {
|
||||
|
||||
|
||||
class ClientSendThread {
|
||||
using ClientType = TestClient<false, false, 100_KiB>;
|
||||
using ClientType = TestClient<false, false, 10_KiB>;
|
||||
|
||||
public:
|
||||
ClientSendThread() { client = createAndConnectClient<ClientType>(); }
|
||||
ClientSendThread() {
|
||||
client = createAndConnectClient<ClientType>();
|
||||
sendThread.setName("clSend");
|
||||
}
|
||||
|
||||
~ClientSendThread() {
|
||||
sendThread.stopAndWait();
|
||||
@@ -63,11 +69,10 @@ public:
|
||||
}
|
||||
|
||||
void startSend() {
|
||||
auto c = client;
|
||||
sendThread.start([c] { c->ping(); }, 100._Hz);
|
||||
sendThread.start([this] { client->ping(); }, 100._Hz);
|
||||
}
|
||||
|
||||
void sendOnce() {client->ping();}
|
||||
|
||||
void sendOnce() { client->ping(); }
|
||||
|
||||
ClientType * client = nullptr;
|
||||
PIThread sendThread;
|
||||
@@ -75,28 +80,24 @@ public:
|
||||
|
||||
|
||||
int getServerPongs(PIClientServer::Server * s) {
|
||||
int pongs = 0;
|
||||
s->forEachClient([&pongs](PIClientServer::ServerClient * sc){
|
||||
const auto c = static_cast<TestServerClient<> *>(sc);
|
||||
pongs += c->pongCnt();
|
||||
});
|
||||
return pongs;
|
||||
int pongs = 0;
|
||||
s->forEachClient([&pongs](PIClientServer::ServerClient * sc) {
|
||||
const auto c = static_cast<TestServerClient<> *>(sc);
|
||||
pongs += c->pongCnt();
|
||||
});
|
||||
return pongs;
|
||||
}
|
||||
|
||||
int getClientsPongs(const PIVector<ClientSendThread *> & clients) {
|
||||
int pongs = 0;
|
||||
clients.forEach([&pongs](ClientSendThread * c){
|
||||
pongs += c->client->pongCnt();
|
||||
});
|
||||
return pongs;
|
||||
int pongs = 0;
|
||||
clients.forEach([&pongs](ClientSendThread * c) { pongs += c->client->pongCnt(); });
|
||||
return pongs;
|
||||
}
|
||||
|
||||
int getClientsPings(const PIVector<ClientSendThread *> & clients) {
|
||||
int pings = 0;
|
||||
clients.forEach([&pings](ClientSendThread * c){
|
||||
pings += c->client->pingCnt();
|
||||
});
|
||||
return pings;
|
||||
int pings = 0;
|
||||
clients.forEach([&pings](ClientSendThread * c) { pings += c->client->pingCnt(); });
|
||||
return pings;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,98 +114,109 @@ TEST(ClientServer, ManyClients) {
|
||||
|
||||
waitLoop([s]() { return s->clientsCount() == clients_count; }, loop_timeout);
|
||||
EXPECT_EQ(clients_count, s->clientsCount());
|
||||
|
||||
EXPECT_EQ(0, getServerPongs(s));
|
||||
|
||||
EXPECT_EQ(getClientsPings(clients), 0);
|
||||
|
||||
for (const auto c : clients) {
|
||||
c->sendOnce();
|
||||
}
|
||||
|
||||
EXPECT_EQ(getClientsPings(clients), clients_count);
|
||||
EXPECT_TRUE(clients.every([](ClientSendThread * c){return c->client->pingCnt() == 1;}));
|
||||
EXPECT_TRUE(clients.every([](ClientSendThread * c){return c->client->pongCnt() == 0;}));
|
||||
waitLoop([s]() { return getServerPongs(s) >= clients_count; }, loop_timeout);
|
||||
EXPECT_EQ(clients_count, getServerPongs(s));
|
||||
|
||||
s->forEachClient([](PIClientServer::ServerClient * sc) { static_cast<TestServerClient<> *>(sc)->ping(); });
|
||||
const auto clientCheckPong = [&clients](){return clients.every([](ClientSendThread * c){return c->client->pongCnt() == 1;});};
|
||||
waitLoop([&clientCheckPong]() { return clientCheckPong(); }, loop_timeout);
|
||||
EXPECT_TRUE(clientCheckPong());
|
||||
|
||||
for (const auto c : clients) {
|
||||
c->startSend();
|
||||
}
|
||||
(100_ms).sleep();
|
||||
EXPECT_TRUE(getClientsPings(clients) > clients_count*2);
|
||||
EXPECT_TRUE(getServerPongs(s) > clients_count*2);
|
||||
piDeleteAllAndClear(clients);
|
||||
waitLoop([s]() { return s->clientsCount() == 0; }, loop_timeout);
|
||||
EXPECT_EQ(0, s->clientsCount());
|
||||
delete s;
|
||||
|
||||
EXPECT_EQ(0, getServerPongs(s));
|
||||
|
||||
EXPECT_EQ(getClientsPings(clients), 0);
|
||||
|
||||
for (const auto c: clients) {
|
||||
c->sendOnce();
|
||||
}
|
||||
|
||||
EXPECT_EQ(getClientsPings(clients), clients_count);
|
||||
EXPECT_TRUE(clients.every([](ClientSendThread * c) { return c->client->pingCnt() == 1; }));
|
||||
EXPECT_TRUE(clients.every([](ClientSendThread * c) { return c->client->pongCnt() == 0; }));
|
||||
waitLoop([s]() { return getServerPongs(s) >= clients_count; }, loop_timeout);
|
||||
EXPECT_EQ(clients_count, getServerPongs(s));
|
||||
|
||||
s->forEachClient([](PIClientServer::ServerClient * sc) { static_cast<TestServerClient<> *>(sc)->ping(); });
|
||||
const auto clientCheckPong = [&clients]() { return clients.every([](ClientSendThread * c) { return c->client->pongCnt() == 1; }); };
|
||||
waitLoop([&clientCheckPong]() { return clientCheckPong(); }, loop_timeout);
|
||||
EXPECT_TRUE(clientCheckPong());
|
||||
|
||||
for (const auto c: clients) {
|
||||
c->startSend();
|
||||
}
|
||||
(100_ms).sleep();
|
||||
EXPECT_TRUE(getClientsPings(clients) > clients_count * 2);
|
||||
EXPECT_TRUE(getServerPongs(s) > clients_count * 2);
|
||||
piDeleteAllAndClear(clients);
|
||||
waitLoop([s]() { return s->clientsCount() == 0; }, loop_timeout);
|
||||
EXPECT_EQ(0, s->clientsCount());
|
||||
delete s;
|
||||
}
|
||||
|
||||
TEST(ClientServer, DynamicClients) {
|
||||
auto const loop_timeout = 1000_ms;
|
||||
auto const loop_timeout = 1000_ms;
|
||||
constexpr int clients_count = 20;
|
||||
PIVector<ClientSendThread *> clients;
|
||||
PIMutex clients_mutex;
|
||||
auto s = createServer<true, true, 100_KiB>();
|
||||
|
||||
const auto spawnClient = [&clients, &clients_mutex]() {
|
||||
auto c = new ClientSendThread();
|
||||
c->startSend();
|
||||
clients_mutex.lock();
|
||||
clients << c;
|
||||
clients_mutex.unlock();
|
||||
piCout << "new client" << clients.size();
|
||||
};
|
||||
|
||||
piForTimes(clients_count) {
|
||||
PIVector<ClientSendThread *> clients;
|
||||
PIMutex clients_mutex;
|
||||
auto s = createServer<true, true, 10_KiB>();
|
||||
|
||||
const auto spawnClient = [&clients, &clients_mutex]() {
|
||||
// if (clients.size() > 100) return;
|
||||
auto c = new ClientSendThread();
|
||||
c->startSend();
|
||||
clients_mutex.lock();
|
||||
clients << c;
|
||||
clients_mutex.unlock();
|
||||
piCout << "new client" << clients.size();
|
||||
};
|
||||
|
||||
piForTimes(clients_count) {
|
||||
spawnClient();
|
||||
}
|
||||
|
||||
PIThread spawnThread;
|
||||
PIThread deleteThread;
|
||||
|
||||
spawnThread.start([&spawnClient](){
|
||||
const int new_cnt = randomi() % 10;
|
||||
piForTimes(new_cnt) {
|
||||
spawnClient();
|
||||
}
|
||||
}, 12_Hz);
|
||||
|
||||
deleteThread.start([&clients, &clients_mutex](){
|
||||
const int rm_cnt = randomi() % 10;
|
||||
piForTimes(rm_cnt) {
|
||||
ClientSendThread * c = nullptr;
|
||||
clients_mutex.lock();
|
||||
if (clients.size() > 10) {
|
||||
c = clients.take_back();
|
||||
}
|
||||
clients_mutex.unlock();
|
||||
if (c) {
|
||||
delete c;
|
||||
piCout << "remove client" << clients.size();
|
||||
}
|
||||
}
|
||||
}, 13_Hz);
|
||||
|
||||
(1_s).sleep();
|
||||
|
||||
EXPECT_GE(s->clientsCount(), 10);
|
||||
|
||||
piCout << "now clients" << clients.size();
|
||||
|
||||
//delete s;
|
||||
|
||||
deleteThread.stopAndWait();
|
||||
spawnThread.stopAndWait();
|
||||
|
||||
piCout << "total clients" << clients.size();
|
||||
|
||||
piDeleteAllAndClear(clients);
|
||||
waitLoop([s]() { return s->clientsCount() == 0; }, loop_timeout);
|
||||
EXPECT_EQ(0, s->clientsCount());
|
||||
|
||||
PIThread spawnThread;
|
||||
PIThread deleteThread;
|
||||
spawnThread.setName("spawn");
|
||||
deleteThread.setName("delete");
|
||||
|
||||
spawnThread.start(
|
||||
[&spawnClient]() {
|
||||
const int new_cnt = 7;
|
||||
piForTimes(new_cnt) {
|
||||
spawnClient();
|
||||
}
|
||||
piCout << "+++++++";
|
||||
},
|
||||
12_Hz);
|
||||
|
||||
deleteThread.start(
|
||||
[&clients, &clients_mutex]() {
|
||||
const int rm_cnt = 8;
|
||||
piForTimes(rm_cnt) {
|
||||
ClientSendThread * c = nullptr;
|
||||
clients_mutex.lock();
|
||||
if (clients.size() > 10) {
|
||||
c = clients.take_front();
|
||||
}
|
||||
clients_mutex.unlock();
|
||||
if (c) {
|
||||
delete c;
|
||||
piCout << "remove client" << clients.size();
|
||||
}
|
||||
}
|
||||
piCout << "----------";
|
||||
},
|
||||
13_Hz);
|
||||
|
||||
(2_s).sleep();
|
||||
|
||||
EXPECT_GE(s->clientsCount(), 10);
|
||||
|
||||
piCout << "now clients" << clients.size();
|
||||
|
||||
|
||||
deleteThread.stopAndWait();
|
||||
spawnThread.stopAndWait();
|
||||
|
||||
|
||||
piCout << "total clients" << clients.size();
|
||||
|
||||
piDeleteAllAndClear(clients);
|
||||
waitLoop([s]() { return s->clientsCount() == 0; }, loop_timeout);
|
||||
EXPECT_EQ(0, s->clientsCount());
|
||||
|
||||
delete s;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
int pingCnt() const { return ping_cnt; }
|
||||
|
||||
void ping() {
|
||||
const auto data = PIByteArray(WriteSize);
|
||||
const auto data = PIByteArray(WriteSize);
|
||||
writeInternal(data);
|
||||
ping_cnt++;
|
||||
}
|
||||
@@ -43,6 +43,12 @@ class TestServerClient
|
||||
, public TestClientBase<WriteSize, WithPong> {
|
||||
using Base = TestClientBase<WriteSize, WithPong>;
|
||||
|
||||
public:
|
||||
~TestServerClient() {
|
||||
close();
|
||||
stopAndWait();
|
||||
}
|
||||
|
||||
private:
|
||||
void readed(PIByteArray data) override { Base::readInternal(data); }
|
||||
|
||||
@@ -62,6 +68,12 @@ class TestClient
|
||||
, public TestClientBase<WriteSize, WithPong> {
|
||||
using Base = TestClientBase<WriteSize, WithPong>;
|
||||
|
||||
public:
|
||||
~TestClient() {
|
||||
close();
|
||||
stopAndWait();
|
||||
}
|
||||
|
||||
private:
|
||||
void readed(PIByteArray data) override { Base::readInternal(data); }
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
const uint rows = 3;
|
||||
const uint cols = 3;
|
||||
using Type = double;
|
||||
|
||||
bool cmpSquareMatrixWithValue(PIMathMatrixT<rows, cols, double> matrix, double val, int num) {
|
||||
bool cmpSquareMatrixWithValue(PIMathMatrixT<rows, cols, Type> matrix, Type val, int num) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
for (int j = 0; j < num; j++) {
|
||||
if (matrix.at(i, j) != val) {
|
||||
@@ -17,50 +18,50 @@ bool cmpSquareMatrixWithValue(PIMathMatrixT<rows, cols, double> matrix, double v
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, identity) {
|
||||
auto matrix = PIMathMatrixT<rows, cols, double>::identity();
|
||||
auto matrix = PIMathMatrixT<rows, cols, Type>::identity();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
if (i != j) {
|
||||
if (matrix[i][j] != 0.0) {
|
||||
ASSERT_TRUE(false);
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
} else {
|
||||
if (matrix[i][i] != 1.0) {
|
||||
ASSERT_TRUE(false);
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(true);
|
||||
EXPECT_TRUE(true);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, at) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>::identity();
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>::identity();
|
||||
for (uint i = 0; i < rows; i++) {
|
||||
if (matrix1.at(i, i) != 1.0) {
|
||||
ASSERT_TRUE(false);
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(true);
|
||||
EXPECT_TRUE(true);
|
||||
}
|
||||
TEST(PIMathMatrixT_Test, filled) {
|
||||
auto matr = PIMathMatrixT<rows, cols, double>(1.0);
|
||||
ASSERT_TRUE(cmpSquareMatrixWithValue(matr, 1.0, rows));
|
||||
auto matr = PIMathMatrixT<rows, cols, Type>(1.0);
|
||||
EXPECT_TRUE(cmpSquareMatrixWithValue(matr, 1.0, rows));
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, cols) {
|
||||
PIMathMatrixT<rows, cols, double> matr;
|
||||
ASSERT_EQ(cols, matr.cols());
|
||||
PIMathMatrixT<rows, cols, Type> matr;
|
||||
EXPECT_EQ(cols, matr.cols());
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, rows) {
|
||||
PIMathMatrixT<rows, cols, double> matr;
|
||||
ASSERT_EQ(rows, matr.rows());
|
||||
PIMathMatrixT<rows, cols, Type> matr;
|
||||
EXPECT_EQ(rows, matr.rows());
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, col) {
|
||||
PIMathMatrixT<rows, cols, double> matr;
|
||||
PIMathVectorT<rows, double> vect;
|
||||
PIMathMatrixT<rows, cols, Type> matr;
|
||||
PIMathVectorT<rows, Type> vect;
|
||||
uint g = 2;
|
||||
matr.element(0, 0) = 3;
|
||||
matr.element(0, 1) = 6;
|
||||
@@ -74,15 +75,15 @@ TEST(PIMathMatrixT_Test, col) {
|
||||
vect = matr.col(g);
|
||||
for (uint i = 0; i < matr.cols(); i++) {
|
||||
if (matr.element(i, g) != vect[i]) {
|
||||
ASSERT_TRUE(false);
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(true);
|
||||
EXPECT_TRUE(true);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, row) {
|
||||
PIMathMatrixT<rows, cols, double> matr;
|
||||
PIMathVectorT<rows, double> vect;
|
||||
PIMathMatrixT<rows, cols, Type> matr;
|
||||
PIMathVectorT<rows, Type> vect;
|
||||
uint g = 2;
|
||||
matr.element(0, 0) = 3;
|
||||
matr.element(0, 1) = 6;
|
||||
@@ -96,15 +97,15 @@ TEST(PIMathMatrixT_Test, row) {
|
||||
vect = matr.row(g);
|
||||
for (uint i = 0; i < matr.rows(); i++) {
|
||||
if (matr.element(g, i) != vect[i]) {
|
||||
ASSERT_TRUE(false);
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(true);
|
||||
EXPECT_TRUE(true);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, setCol) {
|
||||
PIMathMatrixT<rows, cols, double> matr;
|
||||
PIMathVectorT<rows, double> vect;
|
||||
PIMathMatrixT<rows, cols, Type> matr;
|
||||
PIMathVectorT<rows, Type> vect;
|
||||
vect[0] = 1.0;
|
||||
vect[1] = 3.0;
|
||||
vect[2] = 5.0;
|
||||
@@ -112,15 +113,15 @@ TEST(PIMathMatrixT_Test, setCol) {
|
||||
matr.setCol(g, vect);
|
||||
for (uint i = 0; i < vect.size(); i++) {
|
||||
if (matr.element(i, g) != vect[i]) {
|
||||
ASSERT_TRUE(false);
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(true);
|
||||
EXPECT_TRUE(true);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, setRow) {
|
||||
PIMathMatrixT<rows, cols, double> matr;
|
||||
PIMathVectorT<rows, double> vect;
|
||||
PIMathMatrixT<rows, cols, Type> matr;
|
||||
PIMathVectorT<rows, Type> vect;
|
||||
vect[0] = 1.0;
|
||||
vect[1] = 3.0;
|
||||
vect[2] = 5.0;
|
||||
@@ -128,114 +129,114 @@ TEST(PIMathMatrixT_Test, setRow) {
|
||||
matr.setRow(g, vect);
|
||||
for (uint i = 0; i < vect.size(); i++) {
|
||||
if (matr.element(g, i) != vect[i]) {
|
||||
ASSERT_TRUE(false);
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(true);
|
||||
EXPECT_TRUE(true);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, swapCols) {
|
||||
PIMathMatrixT<rows, cols, double> matr;
|
||||
PIMathMatrixT<rows, cols, Type> matr;
|
||||
int g1 = 1, g2 = 2;
|
||||
matr.element(0, 0) = 3;
|
||||
matr.element(0, 1) = 6;
|
||||
matr.element(0, 2) = 8;
|
||||
matr.element(1, 0) = 2;
|
||||
matr.element(1, 1) = 1;
|
||||
matr.element(1, 2) = 4;
|
||||
matr.element(2, 0) = 6;
|
||||
matr.element(2, 1) = 2;
|
||||
matr.element(2, 2) = 5;
|
||||
const PIMathVectorT<rows, double> before_Vect1 = matr.col(g1);
|
||||
const PIMathVectorT<rows, double> before_Vect2 = matr.col(g2);
|
||||
matr.element(0, 0) = 3;
|
||||
matr.element(0, 1) = 6;
|
||||
matr.element(0, 2) = 8;
|
||||
matr.element(1, 0) = 2;
|
||||
matr.element(1, 1) = 1;
|
||||
matr.element(1, 2) = 4;
|
||||
matr.element(2, 0) = 6;
|
||||
matr.element(2, 1) = 2;
|
||||
matr.element(2, 2) = 5;
|
||||
const PIMathVectorT<rows, Type> before_Vect1 = matr.col(g1);
|
||||
const PIMathVectorT<rows, Type> before_Vect2 = matr.col(g2);
|
||||
matr.swapCols(g1, g2);
|
||||
const PIMathVectorT<rows, double> after_Vect1 = matr.col(g1);
|
||||
const PIMathVectorT<rows, double> after_Vect2 = matr.col(g2);
|
||||
const PIMathVectorT<rows, Type> after_Vect1 = matr.col(g1);
|
||||
const PIMathVectorT<rows, Type> after_Vect2 = matr.col(g2);
|
||||
if ((before_Vect1 == after_Vect2) && (before_Vect2 == after_Vect1)) {
|
||||
ASSERT_TRUE(true);
|
||||
EXPECT_TRUE(true);
|
||||
} else {
|
||||
ASSERT_TRUE(false);
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, swapRows) {
|
||||
PIMathMatrixT<rows, cols, double> matr;
|
||||
PIMathMatrixT<rows, cols, Type> matr;
|
||||
int g1 = 1, g2 = 2;
|
||||
matr.element(0, 0) = 3;
|
||||
matr.element(0, 1) = 6;
|
||||
matr.element(0, 2) = 8;
|
||||
matr.element(1, 0) = 2;
|
||||
matr.element(1, 1) = 1;
|
||||
matr.element(1, 2) = 4;
|
||||
matr.element(2, 0) = 6;
|
||||
matr.element(2, 1) = 2;
|
||||
matr.element(2, 2) = 5;
|
||||
const PIMathVectorT<rows, double> before_Vect1 = matr.row(g1);
|
||||
const PIMathVectorT<rows, double> before_Vect2 = matr.row(g2);
|
||||
matr.element(0, 0) = 3;
|
||||
matr.element(0, 1) = 6;
|
||||
matr.element(0, 2) = 8;
|
||||
matr.element(1, 0) = 2;
|
||||
matr.element(1, 1) = 1;
|
||||
matr.element(1, 2) = 4;
|
||||
matr.element(2, 0) = 6;
|
||||
matr.element(2, 1) = 2;
|
||||
matr.element(2, 2) = 5;
|
||||
const PIMathVectorT<rows, Type> before_Vect1 = matr.row(g1);
|
||||
const PIMathVectorT<rows, Type> before_Vect2 = matr.row(g2);
|
||||
matr.swapRows(g1, g2);
|
||||
const PIMathVectorT<rows, double> after_Vect1 = matr.row(g1);
|
||||
const PIMathVectorT<rows, double> after_Vect2 = matr.row(g2);
|
||||
const PIMathVectorT<rows, Type> after_Vect1 = matr.row(g1);
|
||||
const PIMathVectorT<rows, Type> after_Vect2 = matr.row(g2);
|
||||
if ((before_Vect1 == after_Vect2) && (before_Vect2 == after_Vect1)) {
|
||||
ASSERT_TRUE(true);
|
||||
EXPECT_TRUE(true);
|
||||
} else {
|
||||
ASSERT_TRUE(false);
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, fill) {
|
||||
PIMathMatrixT<rows, cols, double> matr;
|
||||
PIMathMatrixT<rows, cols, double> matrix1;
|
||||
double g = 1.0;
|
||||
PIMathMatrixT<rows, cols, Type> matr;
|
||||
PIMathMatrixT<rows, cols, Type> matrix1;
|
||||
Type g = 1.0;
|
||||
matr.fill(g);
|
||||
for (uint i = 0; i < cols; i++) {
|
||||
for (uint j = 0; j < rows; j++) {
|
||||
matrix1.element(j, i) = g;
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(matr == matrix1);
|
||||
EXPECT_TRUE(matr == matrix1);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, isSquareTrue) {
|
||||
PIMathMatrixT<rows, cols, double> matrix1;
|
||||
ASSERT_TRUE(matrix1.isSquare());
|
||||
PIMathMatrixT<rows, cols, Type> matrix1;
|
||||
EXPECT_TRUE(matrix1.isSquare());
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, isSquareFalse) {
|
||||
const uint new_Cols = 4;
|
||||
PIMathMatrixT<rows, new_Cols, double> matrix2;
|
||||
ASSERT_FALSE(matrix2.isSquare());
|
||||
PIMathMatrixT<rows, new_Cols, Type> matrix2;
|
||||
EXPECT_FALSE(matrix2.isSquare());
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, isIdentityTrue) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>::identity();
|
||||
ASSERT_TRUE(matrix1.isIdentity());
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>::identity();
|
||||
EXPECT_TRUE(matrix1.isIdentity());
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, isIdentityFalse) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>(2.5);
|
||||
ASSERT_FALSE(matrix1.isIdentity());
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>(2.5);
|
||||
EXPECT_FALSE(matrix1.isIdentity());
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, isNullTrue) {
|
||||
PIMathMatrixT<rows, cols, double> matrix1;
|
||||
ASSERT_TRUE(matrix1.isNull());
|
||||
PIMathMatrixT<rows, cols, Type> matrix1;
|
||||
EXPECT_TRUE(matrix1.isNull());
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, isNullFalse) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>::identity();
|
||||
ASSERT_FALSE(matrix1.isNull());
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>::identity();
|
||||
EXPECT_FALSE(matrix1.isNull());
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, operator_Assignment) {
|
||||
PIMathMatrixT<rows, cols, double> matrix1;
|
||||
auto matrix2 = PIMathMatrixT<rows, cols, double>(6.72);
|
||||
PIMathMatrixT<rows, cols, Type> matrix1;
|
||||
auto matrix2 = PIMathMatrixT<rows, cols, Type>(6.72);
|
||||
matrix1 = matrix2;
|
||||
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1, 6.72, rows));
|
||||
EXPECT_TRUE(cmpSquareMatrixWithValue(matrix1, 6.72, rows));
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, operator_EqualTrue) {
|
||||
PIMathMatrixT<rows, cols, double> matrix1;
|
||||
PIMathMatrixT<rows, cols, double> matrix2;
|
||||
PIMathMatrixT<rows, cols, Type> matrix1;
|
||||
PIMathMatrixT<rows, cols, Type> matrix2;
|
||||
matrix1.element(0, 0) = 5.1;
|
||||
matrix1.element(0, 1) = 1.21;
|
||||
matrix1.element(1, 1) = 0.671;
|
||||
@@ -244,12 +245,12 @@ TEST(PIMathMatrixT_Test, operator_EqualTrue) {
|
||||
matrix2.element(0, 1) = 1.21;
|
||||
matrix2.element(1, 1) = 0.671;
|
||||
matrix2.element(1, 0) = 2.623;
|
||||
ASSERT_TRUE(matrix1 == matrix2);
|
||||
EXPECT_TRUE(matrix1 == matrix2);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, operator_EqualFalse) {
|
||||
PIMathMatrixT<rows, cols, double> matrix1;
|
||||
PIMathMatrixT<rows, cols, double> matrix2;
|
||||
PIMathMatrixT<rows, cols, Type> matrix1;
|
||||
PIMathMatrixT<rows, cols, Type> matrix2;
|
||||
matrix1.element(0, 0) = 5.1;
|
||||
matrix1.element(0, 1) = 1.21;
|
||||
matrix1.element(1, 1) = 0.671;
|
||||
@@ -258,12 +259,12 @@ TEST(PIMathMatrixT_Test, operator_EqualFalse) {
|
||||
matrix2.element(0, 1) = 1.21;
|
||||
matrix2.element(1, 1) = 665.671;
|
||||
matrix2.element(1, 0) = 2.623;
|
||||
ASSERT_FALSE(matrix1 == matrix2);
|
||||
EXPECT_FALSE(matrix1 == matrix2);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, operator_Not_EqualTrue) {
|
||||
PIMathMatrixT<rows, cols, double> matrix1;
|
||||
PIMathMatrixT<rows, cols, double> matrix2;
|
||||
PIMathMatrixT<rows, cols, Type> matrix1;
|
||||
PIMathMatrixT<rows, cols, Type> matrix2;
|
||||
matrix1.element(0, 0) = 5.1;
|
||||
matrix1.element(0, 1) = 1.21;
|
||||
matrix1.element(1, 1) = 0.671;
|
||||
@@ -272,12 +273,12 @@ TEST(PIMathMatrixT_Test, operator_Not_EqualTrue) {
|
||||
matrix2.element(0, 1) = 1.21;
|
||||
matrix2.element(1, 1) = 665.671;
|
||||
matrix2.element(1, 0) = 2.623;
|
||||
ASSERT_TRUE(matrix1 != matrix2);
|
||||
EXPECT_TRUE(matrix1 != matrix2);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, operator_Not_EqualFalse) {
|
||||
PIMathMatrixT<rows, cols, double> matrix1;
|
||||
PIMathMatrixT<rows, cols, double> matrix2;
|
||||
PIMathMatrixT<rows, cols, Type> matrix1;
|
||||
PIMathMatrixT<rows, cols, Type> matrix2;
|
||||
matrix1.element(0, 0) = 5.1;
|
||||
matrix1.element(0, 1) = 1.21;
|
||||
matrix1.element(1, 1) = 0.671;
|
||||
@@ -286,60 +287,60 @@ TEST(PIMathMatrixT_Test, operator_Not_EqualFalse) {
|
||||
matrix2.element(0, 1) = 1.21;
|
||||
matrix2.element(1, 1) = 0.671;
|
||||
matrix2.element(1, 0) = 2.623;
|
||||
ASSERT_FALSE(matrix1 != matrix2);
|
||||
EXPECT_FALSE(matrix1 != matrix2);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, operator_Addition_Assignment) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>(6.72);
|
||||
auto matrix2 = PIMathMatrixT<rows, cols, double>(1.0);
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>(6.72);
|
||||
auto matrix2 = PIMathMatrixT<rows, cols, Type>(1.0);
|
||||
matrix1 += matrix2;
|
||||
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1, 7.72, rows));
|
||||
EXPECT_TRUE(cmpSquareMatrixWithValue(matrix1, 7.72, rows));
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, operator_Subtraction_Assignment) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>(1.0);
|
||||
auto matrix2 = PIMathMatrixT<rows, cols, double>(6.72);
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>(1.0);
|
||||
auto matrix2 = PIMathMatrixT<rows, cols, Type>(6.72);
|
||||
matrix1 -= matrix2;
|
||||
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1, -5.72, rows));
|
||||
EXPECT_TRUE(cmpSquareMatrixWithValue(matrix1, -5.72, rows));
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, operator_Multiplication_Assignment) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>(6.72);
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>(6.72);
|
||||
matrix1 *= 2.0;
|
||||
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1, 13.44, rows));
|
||||
EXPECT_TRUE(cmpSquareMatrixWithValue(matrix1, 13.44, rows));
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, operator_Division_Assignment) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>(6.72);
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>(6.72);
|
||||
matrix1 /= 2.0;
|
||||
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1, 3.36, rows));
|
||||
EXPECT_TRUE(cmpSquareMatrixWithValue(matrix1, 3.36, rows));
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, operator_Addition) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>(6.72);
|
||||
auto matrix2 = PIMathMatrixT<rows, cols, double>(8.28);
|
||||
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1 + matrix2, 15.0, rows));
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>(6.72);
|
||||
auto matrix2 = PIMathMatrixT<rows, cols, Type>(8.28);
|
||||
EXPECT_TRUE(cmpSquareMatrixWithValue(matrix1 + matrix2, 15.0, rows));
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, operator_Subtraction) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>(6.0);
|
||||
auto matrix2 = PIMathMatrixT<rows, cols, double>(5.0);
|
||||
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1 - matrix2, 1.0, rows));
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>(6.0);
|
||||
auto matrix2 = PIMathMatrixT<rows, cols, Type>(5.0);
|
||||
EXPECT_TRUE(cmpSquareMatrixWithValue(matrix1 - matrix2, 1.0, rows));
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, operator_Multiplication) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>(6.72);
|
||||
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1 * 4.0, 26.88, rows));
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>(6.72);
|
||||
EXPECT_TRUE(cmpSquareMatrixWithValue(matrix1 * 4.0, 26.88, rows));
|
||||
}
|
||||
TEST(PIMathMatrixT_Test, operator_Division) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>(6.72);
|
||||
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1 / 4.0, 1.68, rows));
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>(6.72);
|
||||
EXPECT_TRUE(cmpSquareMatrixWithValue(matrix1 / 4.0, 1.68, rows));
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, determinantIfSquare) {
|
||||
double d;
|
||||
double i = 59.0;
|
||||
PIMathMatrixT<rows, cols, double> matr;
|
||||
Type d;
|
||||
Type i = 59.0;
|
||||
PIMathMatrixT<rows, cols, Type> matr;
|
||||
matr.element(0, 0) = 3;
|
||||
matr.element(0, 1) = 6;
|
||||
matr.element(0, 2) = 8;
|
||||
@@ -350,15 +351,15 @@ TEST(PIMathMatrixT_Test, determinantIfSquare) {
|
||||
matr.element(2, 1) = 2;
|
||||
matr.element(2, 2) = 5;
|
||||
d = matr.determinant();
|
||||
ASSERT_DOUBLE_EQ(i, d);
|
||||
EXPECT_DOUBLE_EQ(std::abs(i - d), 0.);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, invert) {
|
||||
PIMathMatrixT<rows, cols, double> matrix1;
|
||||
PIMathMatrixT<rows, cols, double> matrix2;
|
||||
PIMathMatrixT<rows, cols, double> matrix3;
|
||||
PIMathMatrixT<rows, cols, double> matr;
|
||||
double d1, d2;
|
||||
PIMathMatrixT<rows, cols, Type> matrix1;
|
||||
PIMathMatrixT<rows, cols, Type> matrix2;
|
||||
PIMathMatrixT<rows, cols, Type> matrix3;
|
||||
PIMathMatrixT<rows, cols, Type> matr;
|
||||
Type d1, d2;
|
||||
matr.element(0, 0) = 3;
|
||||
matr.element(0, 1) = 6;
|
||||
matr.element(0, 2) = 8;
|
||||
@@ -374,15 +375,16 @@ TEST(PIMathMatrixT_Test, invert) {
|
||||
d2 = matrix2.determinant();
|
||||
matrix3 = matrix1;
|
||||
matrix1.invert();
|
||||
ASSERT_TRUE((matrix1 == matrix3) && piCompare(d1, 1 / d2));
|
||||
EXPECT_EQ(matrix1, matrix3);
|
||||
EXPECT_DOUBLE_EQ(std::abs(d1 - (1. / d2)), 0.);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, inverted) {
|
||||
PIMathMatrixT<rows, cols, double> matrix1;
|
||||
PIMathMatrixT<rows, cols, double> matrix2;
|
||||
PIMathMatrixT<rows, cols, double> matrix3;
|
||||
PIMathMatrixT<rows, cols, double> matr;
|
||||
double d1, d2;
|
||||
PIMathMatrixT<rows, cols, Type> matrix1;
|
||||
PIMathMatrixT<rows, cols, Type> matrix2;
|
||||
PIMathMatrixT<rows, cols, Type> matrix3;
|
||||
PIMathMatrixT<rows, cols, Type> matr;
|
||||
Type d1, d2;
|
||||
matrix1 = matr.identity();
|
||||
matr.element(0, 0) = 3;
|
||||
matr.element(0, 1) = 6;
|
||||
@@ -397,13 +399,14 @@ TEST(PIMathMatrixT_Test, inverted) {
|
||||
d1 = matr.determinant();
|
||||
d2 = matrix2.determinant();
|
||||
matrix3 = matrix1.inverted();
|
||||
ASSERT_TRUE((matrix1 == matrix3) && (round((1 / d1) * 10000) / 10000 == round(d2 * 10000) / 10000));
|
||||
EXPECT_EQ(matrix1, matrix3);
|
||||
EXPECT_DOUBLE_EQ(std::abs(d1 - (1. / d2)), 0.);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, toUpperTriangular) {
|
||||
PIMathMatrixT<rows, cols, double> matrix;
|
||||
double d1, d2 = 1;
|
||||
PIMathMatrixT<rows, cols, double> matr;
|
||||
PIMathMatrixT<rows, cols, Type> matrix;
|
||||
Type d1, d2 = 1;
|
||||
PIMathMatrixT<rows, cols, Type> matr;
|
||||
matr.element(0, 0) = 3;
|
||||
matr.element(0, 1) = 6;
|
||||
matr.element(0, 2) = 8;
|
||||
@@ -418,14 +421,14 @@ TEST(PIMathMatrixT_Test, toUpperTriangular) {
|
||||
for (uint i = 0; i < cols; i++) {
|
||||
d2 = d2 * matrix.at(i, i);
|
||||
}
|
||||
ASSERT_DOUBLE_EQ(d1, d2);
|
||||
EXPECT_LE(std::abs(d1 - d2), PIMATHVECTOR_ZERO_CMP);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, transposed) {
|
||||
PIMathMatrixT<rows, cols, double> matrix1;
|
||||
PIMathMatrixT<rows, cols, double> matrix2;
|
||||
PIMathMatrixT<rows, cols, double> matr;
|
||||
double d1, d2;
|
||||
PIMathMatrixT<rows, cols, Type> matrix1;
|
||||
PIMathMatrixT<rows, cols, Type> matrix2;
|
||||
PIMathMatrixT<rows, cols, Type> matr;
|
||||
Type d1, d2;
|
||||
matr.element(0, 0) = 3;
|
||||
matr.element(0, 1) = 6;
|
||||
matr.element(0, 2) = 8;
|
||||
@@ -439,46 +442,46 @@ TEST(PIMathMatrixT_Test, transposed) {
|
||||
matrix1 = matr.transposed();
|
||||
d2 = matrix1.determinant();
|
||||
matrix2 = matrix1.transposed();
|
||||
ASSERT_TRUE((d1 == d2) && (matr == matrix2));
|
||||
EXPECT_TRUE((d1 == d2) && (matr == matrix2));
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, rotation_2x2) {
|
||||
double angle = 1.0;
|
||||
auto matrix = PIMathMatrixT<2u, 2u, double>::identity();
|
||||
Type angle = 1.0;
|
||||
auto matrix = PIMathMatrixT<2u, 2u, Type>::identity();
|
||||
matrix.rotate(angle);
|
||||
double c = cos(angle);
|
||||
double s = sin(angle);
|
||||
ASSERT_TRUE((c == matrix.at(1u, 1u)) && (c == matrix.at(0u, 0u)) && (-s == matrix.at(0u, 1u)) && (s == matrix.at(1u, 0u)));
|
||||
Type c = cos(angle);
|
||||
Type s = sin(angle);
|
||||
EXPECT_TRUE((c == matrix.at(1u, 1u)) && (c == matrix.at(0u, 0u)) && (-s == matrix.at(0u, 1u)) && (s == matrix.at(1u, 0u)));
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, matrixMultiplication) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>(1.5);
|
||||
auto matrix2 = PIMathMatrixT<rows, cols, double>(2.5);
|
||||
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1 * matrix2, 11.25, 3));
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>(1.5);
|
||||
auto matrix2 = PIMathMatrixT<rows, cols, Type>(2.5);
|
||||
EXPECT_TRUE(cmpSquareMatrixWithValue(matrix1 * matrix2, 11.25, 3));
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, matrixAndVectorMultiplication) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>(1.5);
|
||||
auto vector = PIMathVectorT<rows, double>(2.5);
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>(1.5);
|
||||
auto vector = PIMathVectorT<rows, Type>(2.5);
|
||||
for (uint i = 0; i < 2; i++) {
|
||||
if ((matrix1 * vector)[i] != 11.25) {
|
||||
ASSERT_TRUE(false);
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(true);
|
||||
EXPECT_TRUE(true);
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, vectorAndMatrixMultiplication) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>(1.5);
|
||||
auto vector = PIMathVectorT<rows, double>(2.5);
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>(1.5);
|
||||
auto vector = PIMathVectorT<rows, Type>(2.5);
|
||||
for (uint i = 0; i < 2; i++) {
|
||||
if ((vector * matrix1)[i] != 11.25) {
|
||||
ASSERT_TRUE(false);
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, valAndMatrixMultiplication) {
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, double>(1.5);
|
||||
ASSERT_TRUE(cmpSquareMatrixWithValue(25.0 * matrix1, 37.5, 3));
|
||||
auto matrix1 = PIMathMatrixT<rows, cols, Type>(1.5);
|
||||
EXPECT_TRUE(cmpSquareMatrixWithValue(Type(25.) * matrix1, 37.5, 3));
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ void DispatcherServer::picoutStatus() {
|
||||
|
||||
|
||||
void DispatcherServer::cleanClients() {
|
||||
wd_cnt++;
|
||||
PIMutexLocker locker(map_mutex);
|
||||
for (auto s: rmrf_servers)
|
||||
s->close();
|
||||
@@ -194,6 +195,23 @@ void DispatcherServer::setMaxConnections(uint max_count) {
|
||||
}
|
||||
|
||||
|
||||
void DispatcherServer::startWatchdog() {
|
||||
wd_cnt++;
|
||||
PIThread * thread = new PIThread(
|
||||
[this]() {
|
||||
if (wd_cnt == 0) {
|
||||
piCout << "Deadlock detected, abort";
|
||||
std::abort();
|
||||
return;
|
||||
}
|
||||
wd_cnt = 0;
|
||||
},
|
||||
true,
|
||||
10_s);
|
||||
NO_UNUSED(thread);
|
||||
}
|
||||
|
||||
|
||||
void DispatcherServer::disconnectClient(DispatcherClient * client) {
|
||||
PIMutexLocker locker(map_mutex);
|
||||
if (!clients.contains(client)) {
|
||||
|
||||
@@ -25,6 +25,8 @@ public:
|
||||
uint maxConnections() const { return max_connections; }
|
||||
EVENT_HANDLER0(void, picoutStatus);
|
||||
|
||||
void startWatchdog();
|
||||
|
||||
private:
|
||||
EVENT_HANDLER1(void, newConnection, PIEthernet *, cl);
|
||||
EVENT_HANDLER1(void, disconnectClient, DispatcherClient *, client);
|
||||
@@ -40,6 +42,7 @@ private:
|
||||
PIVector<CloudServer *> rmrf_servers;
|
||||
PITimer timeout_timer;
|
||||
PIMutex map_mutex;
|
||||
std::atomic_int wd_cnt = {0};
|
||||
uint client_gid;
|
||||
uint max_connections;
|
||||
};
|
||||
|
||||
@@ -34,13 +34,14 @@ using namespace PICoutManipulators;
|
||||
void usage() {
|
||||
piCout << Bold << "PIP Cloud Dispatcher";
|
||||
piCout << Cyan << "Version" << Bold << PIPVersion() << NewLine;
|
||||
piCout << Green << Bold << "Usage:" << Default << "\"picloud [-hsv] [-i <ip>] [-p <port>]\"" << NewLine;
|
||||
piCout << Green << Bold << "Usage:" << Default << "\"picloud [-hswv] [-i <ip>] [-p <port>]\"" << NewLine;
|
||||
piCout << Green << Bold << "Details:";
|
||||
piCout << "-h --help " << Green << "- display this message and exit";
|
||||
piCout << "-i --ip " << Green << "- listen address, default \"0.0.0.0\"";
|
||||
piCout << "-p --port " << Green << "- listen port, default 10101";
|
||||
piCout << "-s --screen " << Green << "- start with console UI";
|
||||
piCout << "-v --verbose" << Green << "- print state (--screen ignore this flag)";
|
||||
piCout << "-h --help " << Green << "- display this message and exit";
|
||||
piCout << "-i --ip " << Green << "- listen address, default \"0.0.0.0\"";
|
||||
piCout << "-p --port " << Green << "- listen port, default 10101";
|
||||
piCout << "-s --screen " << Green << "- start with console UI";
|
||||
piCout << "-w --watchdog" << Green << "- kill itself on deadlock";
|
||||
piCout << "-v --verbose " << Green << "- print state (--screen ignore this flag)";
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +65,7 @@ int main(int argc, char * argv[]) {
|
||||
cli.addArgument("ip", true);
|
||||
cli.addArgument("port", true);
|
||||
cli.addArgument("screen");
|
||||
cli.addArgument("watchdog");
|
||||
cli.addArgument("verbose");
|
||||
|
||||
if (cli.hasArgument("help")) {
|
||||
@@ -154,6 +156,7 @@ int main(int argc, char * argv[]) {
|
||||
ls.enableExitCapture(PIKbdListener::F10);
|
||||
ls.start();
|
||||
server.start();
|
||||
if (cli.hasArgument("watchdog")) server.startWatchdog();
|
||||
if (cli.hasArgument("verbose")) {
|
||||
CONNECTU(&status_timer, tickEvent, &server, picoutStatus);
|
||||
status_timer.start(1_Hz);
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
#include "picli.h"
|
||||
#include "picodeparser.h"
|
||||
#include "piiostream.h"
|
||||
|
||||
#include <iostream>
|
||||
#include "pitranslator.h"
|
||||
|
||||
using namespace PICoutManipulators;
|
||||
|
||||
@@ -107,10 +106,6 @@ void help() {
|
||||
piCout << help_string;
|
||||
}
|
||||
|
||||
void printError(const PIString & msg) {
|
||||
std::cerr << msg.data() << std::endl;
|
||||
}
|
||||
|
||||
|
||||
PIString toCName(const PIString & s) {
|
||||
PIString ret(s.trimmed());
|
||||
@@ -307,7 +302,7 @@ bool writeClassStreamMembersOut(PIIOTextStream & ts, const PICodeParser::Entity
|
||||
++cnt;
|
||||
if (m.meta.contains("id")) cnt = m.meta.value("id").toInt();
|
||||
if (used_id[cnt]) {
|
||||
printError("Error with \"" + e->name + "\" stream operator: ID " + PIString::fromNumber(cnt) + " already used");
|
||||
piCerr << "Error with \"%1\" stream operator: ID %2 already used"_tr("pip_cmg").arg(e->name).arg(cnt);
|
||||
return false;
|
||||
}
|
||||
if (m.dims.isEmpty()) {
|
||||
@@ -361,7 +356,7 @@ bool writeClassStreamMembersIn(PIIOTextStream & ts, const PICodeParser::Entity *
|
||||
++cnt;
|
||||
if (m.meta.contains("id")) cnt = m.meta.value("id").toInt();
|
||||
if (used_id[cnt]) {
|
||||
printError("Error with \"" + e->name + "\" stream operator: ID " + PIString::fromNumber(cnt) + " already used");
|
||||
piCerr << "Error with \"%1\" stream operator: ID %2 already used"_tr("pip_cmg").arg(e->name).arg(cnt);
|
||||
return false;
|
||||
}
|
||||
used_id << cnt;
|
||||
@@ -496,7 +491,7 @@ bool writeModel(PICodeParser & parser, PICLI & cli, const PIString out, bool met
|
||||
PIFile f(out + ".cpp");
|
||||
f.clear();
|
||||
if (!f.open(PIIODevice::WriteOnly)) {
|
||||
piCout << "Error: can`t open out file" << f.path();
|
||||
piCerr << "Error: can`t open output file \"%1\""_tr("pip_cmg").arg(f.path());
|
||||
return false;
|
||||
}
|
||||
PIIOTextStream ts(&f);
|
||||
@@ -585,7 +580,7 @@ bool writeModel(PICodeParser & parser, PICLI & cli, const PIString out, bool met
|
||||
f.setPath(out + ".h");
|
||||
f.clear();
|
||||
if (!f.open(PIIODevice::WriteOnly)) {
|
||||
piCout << "Error: can`t open out file" << f.path();
|
||||
piCerr << "Error: can`t open output file \"%1\""_tr("pip_cmg").arg(f.path());
|
||||
return false;
|
||||
}
|
||||
ts << "// Generated by \"PIP Code model generator\" " << PIDateTime::current().toString("dd.MM.yyyy hh:mm:ss\n");
|
||||
|
||||
@@ -640,7 +640,7 @@ int main(int argc, char * argv[]) {
|
||||
if (!objdump.isEmpty()) ++etcnt;
|
||||
if (!otool.isEmpty()) ++etcnt;
|
||||
if (etcnt > 1) {
|
||||
piCout << "Can use only one of \"readelf\", \"objdump\" and \"otool\"!";
|
||||
piCerr << "Can use only one of \"readelf\", \"objdump\" and \"otool\"!";
|
||||
return 1;
|
||||
}
|
||||
if (etcnt > 0) is_ldd = false;
|
||||
|
||||
4
utils/qt_support/CMakeLists.txt
Normal file
4
utils/qt_support/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
file(GLOB SRC "*.h" "*.cpp")
|
||||
add_library(pip_qt_support STATIC ${SRC})
|
||||
target_include_directories(pip_qt_support PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
target_link_libraries(pip_qt_support pip)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user