pip 0.4.2 alpha
git-svn-id: svn://db.shs.com.ru/pip@2 12ceb7fc-bf1f-11e4-8940-5bc7170c53b5
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
doc
|
||||
|
||||
164
CMakeLists.txt
164
CMakeLists.txt
@@ -1,15 +1,50 @@
|
||||
project(pip)
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR} .)
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3")
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
include(CheckFunctionExists)
|
||||
set(VERSION "0.0400")
|
||||
|
||||
# Version
|
||||
file(READ "src/piversion.h" VERSION_OFFSET LIMIT 4 OFFSET 3)
|
||||
file(READ "src/piversion.h" VERSION_MAJOR LIMIT 1 OFFSET ${VERSION_OFFSET})
|
||||
file(READ "src/piversion.h" VERSION_OFFSET LIMIT 4 OFFSET 7)
|
||||
file(READ "src/piversion.h" VERSION_MINOR LIMIT 1 OFFSET ${VERSION_OFFSET})
|
||||
file(READ "src/piversion.h" VERSION_OFFSET LIMIT 4 OFFSET 11)
|
||||
file(READ "src/piversion.h" VERSION_REVISION LIMIT 1 OFFSET ${VERSION_OFFSET})
|
||||
file(STRINGS "src/piversion.h" VERSION_SUFFIX REGEX "\".*\"")
|
||||
string(REGEX MATCH "\".*\"" VERSION_SUFFIX ${VERSION_SUFFIX})
|
||||
string(LENGTH ${VERSION_SUFFIX} SL)
|
||||
math(EXPR SL '${SL}-2')
|
||||
string(SUBSTRING ${VERSION_SUFFIX} 1 ${SL} VERSION_SUFFIX)
|
||||
string(LENGTH ${VERSION_MAJOR} SL)
|
||||
math(EXPR SL '${SL}-1')
|
||||
string(SUBSTRING ${VERSION_MAJOR} 0 ${SL} VERSION_MAJOR)
|
||||
string(LENGTH ${VERSION_MINOR} SL)
|
||||
math(EXPR SL '${SL}-1')
|
||||
string(SUBSTRING ${VERSION_MINOR} 0 ${SL} VERSION_MINOR)
|
||||
string(LENGTH ${VERSION_REVISION} SL)
|
||||
math(EXPR SL '${SL}-1')
|
||||
string(SUBSTRING ${VERSION_REVISION} 0 ${SL} VERSION_REVISION)
|
||||
set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}")
|
||||
set(SOVERSION ${VERSION})
|
||||
message(STATUS "Building PIP version ${VERSION}${VERSION_SUFFIX}")
|
||||
file(WRITE "src/pip_version_str.h" "#define __PIP_VERSION_STR__ \"${VERSION}${VERSION_SUFFIX}\"\n")
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
set(LIBS)
|
||||
file(GLOB HDRS "pi*.h")
|
||||
file(GLOB CPPS "pi*.cpp")
|
||||
|
||||
|
||||
# Sources
|
||||
set(PIP_FOLDERS "." "code" "containers" "core" "io" "math" "system" "thread")
|
||||
include_directories("src")
|
||||
foreach(F ${PIP_FOLDERS})
|
||||
include_directories("src/${F}")
|
||||
file(GLOB HS "src/${F}/*.h")
|
||||
file(GLOB CS "src/${F}/*.cpp")
|
||||
list(APPEND HDRS ${HS})
|
||||
list(APPEND CPPS ${CS})
|
||||
endforeach(F)
|
||||
|
||||
# Check Bessel functions
|
||||
set(CMAKE_REQUIRED_INCLUDES math.h)
|
||||
set(CMAKE_REQUIRED_LIBRARIES m)
|
||||
@@ -19,23 +54,41 @@ CHECK_FUNCTION_EXISTS(jn PIP_MATH_JN)
|
||||
CHECK_FUNCTION_EXISTS(y0 PIP_MATH_Y0)
|
||||
CHECK_FUNCTION_EXISTS(y1 PIP_MATH_Y1)
|
||||
CHECK_FUNCTION_EXISTS(yn PIP_MATH_YN)
|
||||
if (DEFINED PIP_MATH_J0)
|
||||
add_definitions("-DPIP_MATH_J0")
|
||||
if (PIP_MATH_J0)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPIP_MATH_J0")
|
||||
endif ()
|
||||
if (DEFINED PIP_MATH_J1)
|
||||
add_definitions("-DPIP_MATH_J1")
|
||||
if (PIP_MATH_J1)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPIP_MATH_J1")
|
||||
endif ()
|
||||
if (DEFINED PIP_MATH_JN)
|
||||
add_definitions("-DPIP_MATH_JN")
|
||||
if (PIP_MATH_JN)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPIP_MATH_JN")
|
||||
endif ()
|
||||
if (DEFINED PIP_MATH_Y0)
|
||||
add_definitions("-DPIP_MATH_Y0")
|
||||
if (PIP_MATH_Y0)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPIP_MATH_Y0")
|
||||
endif ()
|
||||
if (DEFINED PIP_MATH_Y1)
|
||||
add_definitions("-DPIP_MATH_Y1")
|
||||
if (PIP_MATH_Y1)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPIP_MATH_Y1")
|
||||
endif ()
|
||||
if (DEFINED PIP_MATH_YN)
|
||||
add_definitions("-DPIP_MATH_YN")
|
||||
if (PIP_MATH_YN)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPIP_MATH_YN")
|
||||
endif ()
|
||||
|
||||
|
||||
# Check if RT timers exists
|
||||
set(CMAKE_REQUIRED_INCLUDES time.h)
|
||||
if (DEFINED ENV{QNX_HOST})
|
||||
set(CMAKE_REQUIRED_LIBRARIES )
|
||||
else ()
|
||||
set(CMAKE_REQUIRED_LIBRARIES rt)
|
||||
endif ()
|
||||
CHECK_FUNCTION_EXISTS(timer_create PIP_TIMER_RT_0)
|
||||
CHECK_FUNCTION_EXISTS(timer_settime PIP_TIMER_RT_1)
|
||||
CHECK_FUNCTION_EXISTS(timer_delete PIP_TIMER_RT_2)
|
||||
if (PIP_TIMER_RT_0 AND PIP_TIMER_RT_1 AND PIP_TIMER_RT_2)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPIP_TIMER_RT")
|
||||
message(STATUS "Available timers: Thread, ThreadRT, Pool")
|
||||
else ()
|
||||
message(STATUS "Available timers: Thread, Pool")
|
||||
endif ()
|
||||
|
||||
|
||||
@@ -43,85 +96,94 @@ endif ()
|
||||
if (DEFINED USB)
|
||||
message(STATUS "Building with USB support")
|
||||
unset(USB)
|
||||
add_definitions("-DPIP_USB")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPIP_USB")
|
||||
list(APPEND LIBS usb)
|
||||
else ()
|
||||
message(STATUS "Building without USB support")
|
||||
endif ()
|
||||
|
||||
|
||||
# Check if STL containers is on (to enable use "-DPIP_CONTAINERS_STL=" argument of cmake)
|
||||
if (DEFINED PIP_CONTAINERS_STL)
|
||||
# Check if STL containers is on (to enable use "-DSTL=" argument of cmake)
|
||||
if (DEFINED STL)
|
||||
message(STATUS "Building with STL containers")
|
||||
unset(PIP_CONTAINERS_STL)
|
||||
add_definitions("-DPIP_CONTAINERS_STL")
|
||||
unset(STL)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPIP_CONTAINERS_STL")
|
||||
else ()
|
||||
message(STATUS "Building with PIP containers")
|
||||
endif ()
|
||||
|
||||
|
||||
# Add library
|
||||
if (${WIN32})
|
||||
list(APPEND LIBS ws2_32 Iphlpapi)
|
||||
execute_process(COMMAND "make_rc_win.bat" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
list(APPEND CPPS "pip_resource_win.o")
|
||||
list(APPEND LIBS ws2_32 Iphlpapi Psapi)
|
||||
#execute_process(COMMAND "make_rc_win.bat" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_QUIET)
|
||||
#list(APPEND CPPS "pip_resource_win.o")
|
||||
list(APPEND CPPS "pip_resource_win.rc")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPSAPI_VERSION=1")
|
||||
add_library(pip SHARED ${CPPS})
|
||||
if (${CMAKE_C_COMPILER} STREQUAL "cl")
|
||||
include(GenerateExportHeader)
|
||||
generate_export_header(pip)
|
||||
add_definitions("/O2 /Ob2 /Ot")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /O2 /Ob2 /Ot")
|
||||
#set(${CMAKE_C_FLAGS} "/O2 /Ob2 /Ot")
|
||||
else ()
|
||||
add_definitions("-O2")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
|
||||
#set(${CMAKE_CXX_FLAGS} "-O2")
|
||||
endif ()
|
||||
else ()
|
||||
add_definitions("-O2")
|
||||
set(${CMAKE_CXX_FLAGS} "-O2")
|
||||
if (DEFINED ENV{QNX_HOST})
|
||||
list(APPEND LIBS socket)
|
||||
add_definitions("-ftemplate-depth-32")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth-32")
|
||||
add_library(pip STATIC ${CPPS})
|
||||
else ()
|
||||
list(APPEND LIBS pthread)
|
||||
if (NOT APPLE)
|
||||
list(APPEND LIBS rt)
|
||||
endif()
|
||||
add_definitions("-Wall")
|
||||
add_definitions("-g3")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3")
|
||||
add_library(pip SHARED ${CPPS})
|
||||
endif ()
|
||||
endif ()
|
||||
target_link_libraries(pip ${LIBS})
|
||||
#install(TARGETS pip DESTINATION bin)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
|
||||
# Test program
|
||||
find_package(Qt4 REQUIRED)
|
||||
include_directories(${QT_INCLUDES})
|
||||
#find_package(Qt4 REQUIRED)
|
||||
#include_directories(${QT_INCLUDES})
|
||||
add_executable(pip_test "main.cpp")
|
||||
target_link_libraries(pip_test pip ${QT_QTCORE_LIBRARY})
|
||||
target_link_libraries(pip_test pip)# ${QT_QTCORE_LIBRARY})
|
||||
#target_link_libraries(pip_test pip)
|
||||
|
||||
|
||||
add_subdirectory(system_test)
|
||||
add_subdirectory(remote_console)
|
||||
add_subdirectory(code_model_generator)
|
||||
|
||||
# Install
|
||||
# Check if system or local install will be used (to system install use "-DLIB=" argument of cmake)
|
||||
if (DEFINED LIB)
|
||||
unset(LIB)
|
||||
set(LIB 1)
|
||||
if (${WIN32})
|
||||
get_filename_component(MGWDIR ${CMAKE_C_COMPILER} PATH)
|
||||
find_path(MGWINCLUDE windows.h HINTS ${MGWDIR}/include)
|
||||
file(RELATIVE_PATH MGWINCLUDE "${MGWDIR}" ${MGWINCLUDE})
|
||||
get_filename_component(MGWINCLUDE ${MGWINCLUDE} PATH)
|
||||
string(SUBSTRING ${MGWINCLUDE} 1 -1 MGWINCLUDE)
|
||||
message(STATUS "MGWINCLUDE = ${MGWINCLUDE}/include")
|
||||
set(CMAKE_INSTALL_PREFIX ${MGWDIR}/..)
|
||||
install(FILES ${HDRS} DESTINATION ${MGWINCLUDE}/include/pip)
|
||||
install(TARGETS pip DESTINATION ${MGWINCLUDE}/lib)
|
||||
find_package(MinGW REQUIRED)
|
||||
set(CMAKE_INSTALL_PREFIX ${MINGW_DIR})
|
||||
install(FILES ${HDRS} DESTINATION ${MINGW_INCLUDE}/pip)
|
||||
install(TARGETS pip DESTINATION ${MINGW_LIB})
|
||||
else ()
|
||||
set(CMAKE_INSTALL_PREFIX /usr)
|
||||
install(TARGETS pip DESTINATION lib)
|
||||
install(FILES ${HDRS} DESTINATION include/pip)
|
||||
install(FILES ${HDRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip)
|
||||
install(TARGETS pip DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
|
||||
endif ()
|
||||
message(STATUS "Install to system \"${CMAKE_INSTALL_PREFIX}\"")
|
||||
# Precompiled header
|
||||
#add_custom_target(pip_pch ALL COMMAND ${CMAKE_CXX_COMPILER} -O2 -fPIC -g3 ${CMAKE_INSTALL_PREFIX}/include/pip/pip.h DEPENDS pip SOURCES ${HDRS})
|
||||
#list(APPEND HDRS "pip.h.gch")
|
||||
install(FILES "FindPIP.cmake" DESTINATION ${CMAKE_ROOT}/Modules)
|
||||
else ()
|
||||
install(TARGETS pip DESTINATION bin)
|
||||
install(TARGETS pip DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
message(STATUS "Install to local \"bin\"")
|
||||
endif ()
|
||||
|
||||
# Utils
|
||||
add_subdirectory("utils/system_test")
|
||||
add_subdirectory("utils/remote_console")
|
||||
add_subdirectory("utils/code_model_generator")
|
||||
add_subdirectory("utils/system_daemon")
|
||||
|
||||
222
CMakeLists.txt.user
Normal file
222
CMakeLists.txt.user
Normal file
@@ -0,0 +1,222 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 3.2.1, 2015-02-19T18:12:48. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{948faa78-0b50-402e-a285-1bca3b08de64}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="int">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">false</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap"/>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">DesktopBuild</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">DesktopBuild</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{3c749452-9483-442d-b011-933a1b5dac10}</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="bool" key="CMakeProjectManager.CMakeBuildConfiguration.UseNinja">false</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/libs/pip</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments">-j8</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"/>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments">clean</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"/>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">all</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Установка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Локальная установка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguation.Title">pip_test</value>
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.Arguments"></value>
|
||||
<value type="bool" key="CMakeProjectManager.CMakeRunConfiguration.UseTerminal">false</value>
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory"></value>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">pip_test</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.pip_test</value>
|
||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1">
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguation.Title">pip_system_test</value>
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.Arguments"></value>
|
||||
<value type="bool" key="CMakeProjectManager.CMakeRunConfiguration.UseTerminal">false</value>
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory"></value>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">pip_system_test</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.pip_system_test</value>
|
||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.2">
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguation.Title">pip_remote_console</value>
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.Arguments"></value>
|
||||
<value type="bool" key="CMakeProjectManager.CMakeRunConfiguration.UseTerminal">false</value>
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory"></value>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">pip_remote_console</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.pip_remote_console</value>
|
||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.3">
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguation.Title">pip_cmg</value>
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.Arguments"></value>
|
||||
<value type="bool" key="CMakeProjectManager.CMakeRunConfiguration.UseTerminal">false</value>
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory"></value>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">pip_cmg</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.pip_cmg</value>
|
||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.4">
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguation.Title">pisd</value>
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.Arguments"></value>
|
||||
<value type="bool" key="CMakeProjectManager.CMakeRunConfiguration.UseTerminal">true</value>
|
||||
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory"></value>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">pisd</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.pisd</value>
|
||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">5</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="int">1</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||
<value type="int">16</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>Version</variable>
|
||||
<value type="int">16</value>
|
||||
</data>
|
||||
</qtcreator>
|
||||
177
Doxyfile
177
Doxyfile
@@ -1,4 +1,4 @@
|
||||
# Doxyfile 1.8.6
|
||||
# Doxyfile 1.8.8
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# doxygen (www.doxygen.org) for a project.
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = PIP
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 0.4.0
|
||||
PROJECT_NUMBER = 0.4.1_alpha3
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
@@ -70,6 +70,14 @@ OUTPUT_DIRECTORY = doc
|
||||
|
||||
CREATE_SUBDIRS = NO
|
||||
|
||||
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
|
||||
# characters to appear in the names of generated files. If set to NO, non-ASCII
|
||||
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
|
||||
# U+3044.
|
||||
# The default value is: NO.
|
||||
|
||||
ALLOW_UNICODE_NAMES = NO
|
||||
|
||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
# information to generate all constant output in the proper language.
|
||||
@@ -274,9 +282,12 @@ OPTIMIZE_OUTPUT_VHDL = NO
|
||||
# extension. Doxygen has a built-in mapping, but you can override or extend it
|
||||
# using this tag. The format is ext=language, where ext is a file extension, and
|
||||
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
|
||||
# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
|
||||
# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
|
||||
# (default is Fortran), use: inc=Fortran f=C.
|
||||
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
|
||||
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
|
||||
# Fortran. In the later case the parser tries to guess whether the code is fixed
|
||||
# or free formatted code, this is the default for Fortran type files), VHDL. For
|
||||
# instance to make doxygen treat .inc files as Fortran files (default is PHP),
|
||||
# and .f files as C (default is Fortran), use: inc=Fortran f=C.
|
||||
#
|
||||
# Note For files without extension you can use no_extension as a placeholder.
|
||||
#
|
||||
@@ -532,7 +543,7 @@ FORCE_LOCAL_INCLUDES = NO
|
||||
# documentation for inline members.
|
||||
# The default value is: YES.
|
||||
|
||||
INLINE_INFO = YES
|
||||
INLINE_INFO = NO
|
||||
|
||||
# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
|
||||
# (detailed) documentation of file and class members alphabetically by member
|
||||
@@ -682,8 +693,7 @@ LAYOUT_FILE =
|
||||
# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
|
||||
# For LaTeX the style of the bibliography can be controlled using
|
||||
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
|
||||
# search path. Do not use file names with spaces, bibtex cannot handle them. See
|
||||
# also \cite for info how to create references.
|
||||
# search path. See also \cite for info how to create references.
|
||||
|
||||
CITE_BIB_FILES =
|
||||
|
||||
@@ -756,7 +766,7 @@ WARN_LOGFILE =
|
||||
# spaces.
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = .
|
||||
INPUT = src
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
@@ -777,45 +787,17 @@ INPUT_ENCODING = UTF-8
|
||||
# *.qsf, *.as and *.js.
|
||||
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cc \
|
||||
*.cxx \
|
||||
*.cpp \
|
||||
*.c++ \
|
||||
*.d \
|
||||
*.java \
|
||||
*.ii \
|
||||
*.ixx \
|
||||
*.ipp \
|
||||
*.i++ \
|
||||
*.inl \
|
||||
*.h \
|
||||
*.hh \
|
||||
*.hxx \
|
||||
*.hpp \
|
||||
*.h++ \
|
||||
*.idl \
|
||||
*.odl \
|
||||
*.cs \
|
||||
*.php \
|
||||
*.php3 \
|
||||
*.inc \
|
||||
*.m \
|
||||
*.markdown \
|
||||
*.md \
|
||||
*.mm \
|
||||
*.dox \
|
||||
*.py \
|
||||
*.f90 \
|
||||
*.f \
|
||||
*.for \
|
||||
*.vhd \
|
||||
*.vhdl
|
||||
|
||||
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
||||
# be searched for input files as well.
|
||||
# The default value is: NO.
|
||||
|
||||
RECURSIVE = NO
|
||||
RECURSIVE = YES
|
||||
|
||||
# The EXCLUDE tag can be used to specify files and/or directories that should be
|
||||
# excluded from the INPUT source files. This way you can easily exclude a
|
||||
@@ -1013,6 +995,25 @@ USE_HTAGS = NO
|
||||
|
||||
VERBATIM_HEADERS = NO
|
||||
|
||||
# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
|
||||
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
|
||||
# cost of reduced performance. This can be particularly helpful with template
|
||||
# rich C++ code for which doxygen's built-in parser lacks the necessary type
|
||||
# information.
|
||||
# Note: The availability of this option depends on whether or not doxygen was
|
||||
# compiled with the --with-libclang option.
|
||||
# The default value is: NO.
|
||||
|
||||
CLANG_ASSISTED_PARSING = NO
|
||||
|
||||
# If clang assisted parsing is enabled you can provide the compiler with command
|
||||
# line options that you would normally use when invoking the compiler. Note that
|
||||
# the include paths will already be set by doxygen for the files and directories
|
||||
# specified with INPUT and INCLUDE_PATH.
|
||||
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
|
||||
|
||||
CLANG_OPTIONS =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -1105,13 +1106,15 @@ HTML_FOOTER =
|
||||
|
||||
HTML_STYLESHEET =
|
||||
|
||||
# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
|
||||
# defined cascading style sheet that is included after the standard style sheets
|
||||
# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
|
||||
# cascading style sheets that are included after the standard style sheets
|
||||
# created by doxygen. Using this option one can overrule certain style aspects.
|
||||
# This is preferred over using HTML_STYLESHEET since it does not replace the
|
||||
# standard style sheet and is therefor more robust against future updates.
|
||||
# Doxygen will copy the style sheet file to the output directory. For an example
|
||||
# see the documentation.
|
||||
# Doxygen will copy the style sheet files to the output directory.
|
||||
# Note: The order of the extra stylesheet files is of importance (e.g. the last
|
||||
# stylesheet in the list overrules the setting of the previous ones in the
|
||||
# list). For an example see the documentation.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_EXTRA_STYLESHEET =
|
||||
@@ -1276,7 +1279,8 @@ GENERATE_CHI = NO
|
||||
CHM_INDEX_ENCODING =
|
||||
|
||||
# The BINARY_TOC flag controls whether a binary table of contents is generated (
|
||||
# YES) or a normal table of contents ( NO) in the .chm file.
|
||||
# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
|
||||
# enables the Previous and Next buttons.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
|
||||
|
||||
@@ -1516,11 +1520,11 @@ SEARCHENGINE = YES
|
||||
|
||||
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
|
||||
# implemented using a web server instead of a web client using Javascript. There
|
||||
# are two flavours of web server based searching depending on the
|
||||
# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
|
||||
# searching and an index file used by the script. When EXTERNAL_SEARCH is
|
||||
# enabled the indexing and searching needs to be provided by external tools. See
|
||||
# the section "External Indexing and Searching" for details.
|
||||
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
|
||||
# setting. When disabled, doxygen will generate a PHP script for searching and
|
||||
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
|
||||
# and searching needs to be provided by external tools. See the section
|
||||
# "External Indexing and Searching" for details.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag SEARCHENGINE is set to YES.
|
||||
|
||||
@@ -1648,17 +1652,19 @@ EXTRA_PACKAGES =
|
||||
#
|
||||
# Note: Only use a user-defined header if you know what you are doing! The
|
||||
# following commands have a special meaning inside the header: $title,
|
||||
# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
|
||||
# replace them by respectively the title of the page, the current date and time,
|
||||
# only the current date, the version number of doxygen, the project name (see
|
||||
# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
|
||||
# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
|
||||
# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
|
||||
# for the replacement values of the other commands the user is refered to
|
||||
# HTML_HEADER.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
LATEX_HEADER =
|
||||
|
||||
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
|
||||
# generated LaTeX document. The footer should contain everything after the last
|
||||
# chapter. If it is left blank doxygen will generate a standard footer.
|
||||
# chapter. If it is left blank doxygen will generate a standard footer. See
|
||||
# LATEX_HEADER for more information on how to generate a default footer and what
|
||||
# special commands can be used inside the footer.
|
||||
#
|
||||
# Note: Only use a user-defined footer if you know what you are doing!
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
@@ -1682,7 +1688,7 @@ LATEX_EXTRA_FILES =
|
||||
|
||||
PDF_HYPERLINKS = YES
|
||||
|
||||
# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
|
||||
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
|
||||
# the PDF file directly from the LaTeX files. Set this option to YES to get a
|
||||
# higher quality PDF documentation.
|
||||
# The default value is: YES.
|
||||
@@ -1808,6 +1814,13 @@ MAN_OUTPUT = man
|
||||
|
||||
MAN_EXTENSION = .3
|
||||
|
||||
# The MAN_SUBDIR tag determines the name of the directory created within
|
||||
# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
|
||||
# MAN_EXTENSION with the initial . removed.
|
||||
# This tag requires that the tag GENERATE_MAN is set to YES.
|
||||
|
||||
MAN_SUBDIR =
|
||||
|
||||
# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
|
||||
# will generate one additional man file for each entity documented in the real
|
||||
# man page(s). These additional files only source the real man page, but without
|
||||
@@ -1835,18 +1848,6 @@ GENERATE_XML = NO
|
||||
|
||||
XML_OUTPUT = xml
|
||||
|
||||
# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
|
||||
# validating XML parser to check the syntax of the XML files.
|
||||
# This tag requires that the tag GENERATE_XML is set to YES.
|
||||
|
||||
XML_SCHEMA =
|
||||
|
||||
# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
|
||||
# validating XML parser to check the syntax of the XML files.
|
||||
# This tag requires that the tag GENERATE_XML is set to YES.
|
||||
|
||||
XML_DTD =
|
||||
|
||||
# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
|
||||
# listings (including syntax highlighting and cross-referencing information) to
|
||||
# the XML output. Note that enabling this will significantly increase the size
|
||||
@@ -1874,6 +1875,15 @@ GENERATE_DOCBOOK = NO
|
||||
|
||||
DOCBOOK_OUTPUT = docbook
|
||||
|
||||
# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
|
||||
# program listings (including syntax highlighting and cross-referencing
|
||||
# information) to the DOCBOOK output. Note that enabling this will significantly
|
||||
# increase the size of the DOCBOOK output.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
|
||||
|
||||
DOCBOOK_PROGRAMLISTING = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -1956,14 +1966,20 @@ EXPAND_ONLY_PREDEF = NO
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
SEARCH_INCLUDES = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
|
||||
# The INCLUDE_PATH tag can be used to specify one or more directories that
|
||||
# contain include files that are not input files but should be processed by the
|
||||
# preprocessor.
|
||||
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
|
||||
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_PATH = src/code \
|
||||
src/containers \
|
||||
src/core \
|
||||
src/io \
|
||||
src/math \
|
||||
src/system \
|
||||
src/thread
|
||||
|
||||
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
|
||||
# patterns (like *.h and *.hpp) to filter out the header-files in the
|
||||
@@ -1994,9 +2010,9 @@ PREDEFINED = DOXYGEN \
|
||||
EXPAND_AS_DEFINED =
|
||||
|
||||
# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
|
||||
# remove all refrences to function-like macros that are alone on a line, have an
|
||||
# all uppercase name, and do not end with a semicolon. Such function macros are
|
||||
# typically used for boiler-plate code, and will confuse the parser if not
|
||||
# remove all references to function-like macros that are alone on a line, have
|
||||
# an all uppercase name, and do not end with a semicolon. Such function macros
|
||||
# are typically used for boiler-plate code, and will confuse the parser if not
|
||||
# removed.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
@@ -2016,7 +2032,7 @@ SKIP_FUNCTION_MACROS = NO
|
||||
# where loc1 and loc2 can be relative or absolute paths or URLs. See the
|
||||
# section "Linking to external documentation" for more information about the use
|
||||
# of tag files.
|
||||
# Note: Each tag file must have an unique name (where the name does NOT include
|
||||
# Note: Each tag file must have a unique name (where the name does NOT include
|
||||
# the path). If a tag file is not located in the directory in which doxygen is
|
||||
# run, you must also specify the path to the tagfile here.
|
||||
|
||||
@@ -2094,7 +2110,7 @@ HIDE_UNDOC_RELATIONS = YES
|
||||
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
|
||||
# Bell Labs. The other options in this section have no effect if this option is
|
||||
# set to NO
|
||||
# The default value is: NO.
|
||||
# The default value is: YES.
|
||||
|
||||
HAVE_DOT = YES
|
||||
|
||||
@@ -2108,7 +2124,7 @@ HAVE_DOT = YES
|
||||
|
||||
DOT_NUM_THREADS = 8
|
||||
|
||||
# When you want a differently looking font n the dot files that doxygen
|
||||
# When you want a differently looking font in the dot files that doxygen
|
||||
# generates you can specify the font name using DOT_FONTNAME. You need to make
|
||||
# sure dot is able to find the font, which can be done by putting it in a
|
||||
# standard location or by setting the DOTFONTPATH environment variable or by
|
||||
@@ -2246,7 +2262,9 @@ DIRECTORY_GRAPH = YES
|
||||
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
|
||||
# to make the SVG files visible in IE 9+ (other browsers do not have this
|
||||
# requirement).
|
||||
# Possible values are: png, jpg, gif and svg.
|
||||
# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
|
||||
# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
|
||||
# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
|
||||
# The default value is: png.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
@@ -2289,6 +2307,15 @@ MSCFILE_DIRS =
|
||||
|
||||
DIAFILE_DIRS =
|
||||
|
||||
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
|
||||
# path where java can find the plantuml.jar file. If left blank, it is assumed
|
||||
# PlantUML is not used or called during a preprocessing step. Doxygen will
|
||||
# generate a warning when it encounters a \startuml command in this case and
|
||||
# will not generate output for the diagram.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
PLANTUML_JAR_PATH =
|
||||
|
||||
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
|
||||
# that will be shown in the graph. If the number of nodes in a graph becomes
|
||||
# larger than this value, doxygen will truncate the graph, which is visualized
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
if (${WIN32})
|
||||
get_filename_component(MGWDIR ${CMAKE_C_COMPILER} PATH)
|
||||
find_path(MGWINCLUDE windows.h HINTS ${MGWDIR}/include)
|
||||
get_filename_component(MGWINCLUDE ${MGWINCLUDE} PATH)
|
||||
#file(RELATIVE_PATH MGWINCLUDE "${MGWDIR}" ${MGWINCLUDE})
|
||||
#string(SUBSTRING ${MGWINCLUDE} 1 -1 MGWINCLUDE)
|
||||
#message(STATUS "MGWINCLUDE = ${MGWINCLUDE}/include")
|
||||
#get_filename_component(MGWDIR ${CMAKE_C_COMPILER} PATH)
|
||||
find_library(PIP_LIBRARY pip ${MGWINCLUDE}/lib)
|
||||
set(PIP_INCLUDES ${MGWINCLUDE}/include/pip)
|
||||
set(PIP_CMG ${MGWDIR}/pip_cmg.exe)
|
||||
find_package(MinGW REQUIRED)
|
||||
find_library(PIP_LIBRARY pip ${MINGW_LIB})
|
||||
set(PIP_INCLUDES ${MINGW_INCLUDE}/pip)
|
||||
set(PIP_CMG ${MINGW_BIN}/pip_cmg.exe)
|
||||
else ()
|
||||
find_library(PIP_LIBRARY pip /usr/lib/)
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
@@ -53,7 +47,7 @@ macro (pip_code_model SRC RESULT)
|
||||
endif ()
|
||||
if (NEED_PARSE)
|
||||
message(STATUS "Creating code model based on \"${SRC}\", please wait ... ")
|
||||
execute_process(COMMAND ${PIP_CMG} -qP -o ${PROJECT_NAME}_ccm -I${PIP_INCLUDES} ${SRC} OUTPUT_VARIABLE CMG_OUT)
|
||||
execute_process(COMMAND ${PIP_CMG} -qPEs -o ${PROJECT_NAME}_ccm -I${PIP_INCLUDES} ${SRC} OUTPUT_VARIABLE CMG_OUT)
|
||||
message(STATUS "Creating code model done, to use it include \"${PROJECT_NAME}_ccm.h\"")
|
||||
string(REPLACE "\n" ";" CMG_LIST ${CMG_OUT})
|
||||
string(REPLACE "\n" " " CMG_LIST_S ${CMG_OUT})
|
||||
|
||||
15
clean
15
clean
@@ -2,15 +2,18 @@
|
||||
VERBOSE=1 make clean
|
||||
rm -rvf ./CMakeFiles
|
||||
rm -vf ./CMakeCache.txt ./Makefile ./cmake_install.cmake ./install_manifest.txt ./*~ ./*cxx ./moc_* ./*.o ./core
|
||||
cd system_test
|
||||
cd utils/system_test
|
||||
VERBOSE=1 make clean
|
||||
rm -rvf ./CMakeFiles
|
||||
rm -vf ./CMakeCache.txt ./Makefile ./cmake_install.cmake ./install_manifest.txt ./*~ ./*cxx ./moc_* ./*.o ./core
|
||||
cd ..
|
||||
cd remote_console
|
||||
cd ../../
|
||||
cd utils/remote_console
|
||||
VERBOSE=1 make clean
|
||||
rm -rvf ./CMakeFiles
|
||||
rm -vf ./CMakeCache.txt ./Makefile ./cmake_install.cmake ./install_manifest.txt ./*~ ./*cxx ./moc_* ./*.o ./core
|
||||
cd ..
|
||||
cd code_model_generator
|
||||
cd ../../
|
||||
cd utils/code_model_generator
|
||||
VERBOSE=1 make clean
|
||||
rm -rvf ./CMakeFiles
|
||||
rm -vf ./CMakeCache.txt ./Makefile ./cmake_install.cmake ./install_manifest.txt ./*~ ./*cxx ./moc_* ./*.o ./core
|
||||
cd ..
|
||||
cd ../../
|
||||
|
||||
12
clean.bat
12
clean.bat
@@ -2,13 +2,21 @@
|
||||
del /q /f /s CMakeFiles
|
||||
rmdir /q /s CMakeFiles
|
||||
del /q /f CMakeCache.txt Makefile cmake_install.cmake install_manifest.txt *~ *cxx moc_* *.o *.exe *.a *.dll *.lib core
|
||||
cd system_test
|
||||
cd utils\system_test
|
||||
del /q /f /s CMakeFiles
|
||||
rmdir /q /s CMakeFiles
|
||||
del /q /f CMakeCache.txt Makefile cmake_install.cmake install_manifest.txt *~ *cxx moc_* *.o *.exe *.a *.dll *.lib core
|
||||
cd ..
|
||||
cd remote_console
|
||||
cd ..
|
||||
cd utils\remote_console
|
||||
del /q /f /s CMakeFiles
|
||||
rmdir /q /s CMakeFiles
|
||||
del /q /f CMakeCache.txt Makefile cmake_install.cmake install_manifest.txt *~ *cxx moc_* *.o *.exe *.a *.dll *.lib core
|
||||
cd ..
|
||||
cd ..
|
||||
cd utils\code_model_generator
|
||||
del /q /f /s CMakeFiles
|
||||
rmdir /q /s CMakeFiles
|
||||
del /q /f CMakeCache.txt Makefile cmake_install.cmake install_manifest.txt *~ *cxx moc_* *.o *.exe *.a *.dll *.lib core
|
||||
cd ..
|
||||
cd ..
|
||||
|
||||
281
main.cpp
281
main.cpp
@@ -1,188 +1,129 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Test program
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//#define PIP_DEBUG
|
||||
/*#include "pip.h"
|
||||
|
||||
|
||||
class ElementA: public PIObject {
|
||||
PIOBJECT(ElementA)
|
||||
// ...
|
||||
};
|
||||
ADD_NEW_TO_COLLECTION(ab_group, ElementA)
|
||||
|
||||
class ElementB: public PIObject {
|
||||
PIOBJECT(ElementB)
|
||||
// ...
|
||||
};
|
||||
ADD_NEW_TO_COLLECTION(ab_group, ElementB)
|
||||
|
||||
class ElementC: public PIObject {
|
||||
PIOBJECT(ElementC)
|
||||
// ...
|
||||
};
|
||||
ADD_NEW_TO_COLLECTION(c_group, ElementC)
|
||||
|
||||
class ElementD: public PIObject {
|
||||
PIOBJECT(ElementD)
|
||||
// ...
|
||||
};
|
||||
*/
|
||||
#include "pip.h"
|
||||
#include "pivariant.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "picodeparser.h"
|
||||
#include "pidir.h"
|
||||
#include "piconnection.h"
|
||||
#include <QList>
|
||||
|
||||
bool readed(void*, uchar * data, int size) {
|
||||
piCout << Hex << "readed" << PIByteArray(data, size);
|
||||
//piCout << PIString((char*)data, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
class A: public PIObject {
|
||||
PIOBJECT(A)
|
||||
class Ob: public PIObject {
|
||||
PIOBJECT(Ob)
|
||||
public:
|
||||
EVENT_HANDLER2(void, cr, const PIString &, from, const PIByteArray &, data) {
|
||||
piCout << "A readed" << from << Hex << data;
|
||||
Ob() {
|
||||
sft.setName("sft");
|
||||
sft.setDirectory(sft.directory().cd("..\\"));
|
||||
piCout << "Send File Transfer DIrectory" << sft.directory().absolutePath();
|
||||
CONNECTU(&sft, sendRequest, this, ssend);
|
||||
|
||||
rft.setName("rft");
|
||||
rft.setDirectory(rft.directory().cd("..\\1"));
|
||||
piCout << "Receive File Transfer DIrectory" << rft.directory().absolutePath();
|
||||
CONNECTU(&rft, sendRequest, this, rsend);
|
||||
}
|
||||
EVENT_HANDLER2(void, per, uchar *, data, int, size) {
|
||||
piCout << "A readed" << size << ":\"" << PIString((const char *)data, size) << "\"" << NewLine;
|
||||
//piCout << "A readed \"";
|
||||
|
||||
void startsend() {
|
||||
PIDir dir = PIDir::current();
|
||||
dir.cd("..\\");
|
||||
piCout << dir.absolutePath();
|
||||
PIVector<PIDir::DirEntry> des = dir.allEntries();
|
||||
piCout << "all entries" << des.size();
|
||||
PIDir::DirEntry sde;
|
||||
piForeachC(PIDir::DirEntry de, des) {
|
||||
//piCout << (de.isDir() ? "dir:" : "file") << de.name << de.size;
|
||||
if (de.name == "0") sde = de;
|
||||
}
|
||||
//sft.setPacketSize(64096);
|
||||
sft.send(sde);
|
||||
}
|
||||
|
||||
private:
|
||||
EVENT_HANDLER1(void, ssend, PIByteArray &, data) {
|
||||
// piCout << "[sender]" << sft.stateString() << ". datasize =" << data.size()
|
||||
// << "(" << PIString::readableSize(sft.bytesFileCur()) << "/" << PIString::readableSize(sft.bytesFileAll()) << ", "
|
||||
// << PIString::readableSize(sft.bytesTotalCur()) << "/" << PIString::readableSize(sft.bytesTotalAll()) << ")";
|
||||
if(rand()%100 != 90) rft.received(data);
|
||||
}
|
||||
|
||||
EVENT_HANDLER1(void, rsend, PIByteArray &, data) {
|
||||
// piCout << "[receiver]" << rft.stateString() << ". datasize =" << data.size()
|
||||
// << "(" << PIString::readableSize(rft.bytesFileCur()) << "/" << PIString::readableSize(rft.bytesFileAll()) << ", "
|
||||
// << PIString::readableSize(rft.bytesTotalCur()) << "/" << PIString::readableSize(rft.bytesTotalAll()) << ")";
|
||||
if(rand()%100 != 90) sft.received(data);
|
||||
}
|
||||
|
||||
PIFileTransfer sft;
|
||||
PIFileTransfer rft;
|
||||
};
|
||||
|
||||
class TC: public PIConnection {
|
||||
|
||||
class UDPFileTransfer: public PITimer {
|
||||
PIOBJECT_SUBCLASS(UDPFileTransfer, PITimer)
|
||||
public:
|
||||
TC() {
|
||||
PIPacketExtractor * pe = addFilter("h&f", addDevice("file://piiodevice.h", PIIODevice::ReadOnly, false), PIPacketExtractor::HeaderAndFooter);
|
||||
pe->setHeader(PIString("//!").toByteArray());
|
||||
pe->setFooter(PIString("\n").toByteArray());
|
||||
pe = addFilter(" h ", "file://piiodevice.h", PIPacketExtractor::Header);
|
||||
addChannel(pe, addDevice("file://out.txt", PIIODevice::WriteOnly));
|
||||
pe->setHeader(PIString("PI").toByteArray());
|
||||
pe->setPayloadSize(3);
|
||||
startAllThreadedReads();
|
||||
UDPFileTransfer(const PIString &src_ip_port, const PIString &dst_ip_port) {
|
||||
eth.setReadAddress(src_ip_port);
|
||||
eth.setSendAddress(dst_ip_port);
|
||||
//ft.setPacketSize(65000);
|
||||
CONNECTU(&ft, sendRequest, this, ftsend);
|
||||
CONNECTU(&ft, startSend, this, ftevent);
|
||||
CONNECTU(&ft, finishSend, this, ftevent);
|
||||
CONNECTU(&ft, startReceive, this, ftevent);
|
||||
CONNECTU(&ft, finishReceive, this, ftevent);
|
||||
CONNECTU(ð, threadedReadEvent, this, received);
|
||||
start(50);
|
||||
eth.open();
|
||||
eth.startThreadedRead();
|
||||
}
|
||||
virtual void dataReceived(const PIString & from, const PIByteArray & data) {
|
||||
piCout << "dataReceived" << from << (data.size());
|
||||
|
||||
void startSend(const PIString &file) {
|
||||
ft.send(file);
|
||||
}
|
||||
virtual void packetReceived(const PIString & from, const PIByteArray & data) {
|
||||
piCout << "packetReceived" << from << (data.size()) << PIString(data);
|
||||
|
||||
PIFileTransfer ft;
|
||||
|
||||
private:
|
||||
PIEthernet eth;
|
||||
|
||||
void tick(void *, int) {
|
||||
if (ft.isSending() || ft.isReceiving()) ftevent();
|
||||
}
|
||||
virtual bool filterValidatePayload(const PIString & filter_name, uchar * rec, int size) {
|
||||
//piCout << "filterValidatePayload" << filter_name << PIString((char*)rec, size);
|
||||
if (filter_name == " h ") return PIString((char*)rec, size) == "IOD";
|
||||
return false;
|
||||
|
||||
EVENT_HANDLER(void, ftevent) {
|
||||
piCout << ft.stateString()
|
||||
<< "(" << PIString::readableSize(ft.bytesFileCur()) << "/" << PIString::readableSize(ft.bytesFileAll()) << ", "
|
||||
<< PIString::readableSize(ft.bytesTotalCur()) << "/" << PIString::readableSize(ft.bytesTotalAll()) << ")";
|
||||
}
|
||||
|
||||
EVENT_HANDLER1(void, ftsend, PIByteArray &, data) {
|
||||
eth.send(data);
|
||||
}
|
||||
|
||||
EVENT_HANDLER2(void, received, uchar * , readed, int, size) {
|
||||
PIByteArray ba(readed, size);
|
||||
ft.received(ba);
|
||||
}
|
||||
};
|
||||
|
||||
int main (int argc, char * argv[]) {
|
||||
/*A a_;
|
||||
PIFile file("piiodevice.h", PIIODevice::ReadOnly);
|
||||
PIByteArray header = PIString("PI").toByteArray();
|
||||
PIByteArray footer = PIString("}").toByteArray();
|
||||
PIPacketExtractor pe(&file);
|
||||
//pe.setPacketData(header.data(), header.size_s(), 10);
|
||||
pe.setSplitMode(PIPacketExtractor::Footer);
|
||||
pe.setHeader(header);
|
||||
pe.setFooter(footer);
|
||||
pe.setPayloadSize(3);
|
||||
pe.setThreadedReadBufferSize(40);
|
||||
//pe.setBufferSize(256);
|
||||
//pe.setPacketData(0, 0, 20);
|
||||
CONNECT2(void, uchar * , int , &pe, packetReceived, &a_, per)
|
||||
pe.startThreadedRead();
|
||||
piMSleep(500);*/
|
||||
|
||||
TC tc;
|
||||
piMSleep(500);
|
||||
piCout << tc.makeConfig();
|
||||
return 0;
|
||||
|
||||
/*tm = PISystemTime::current();
|
||||
for (int i = 0; i < 10000000; ++i) {
|
||||
ql.append(i*10);
|
||||
ql.prepend(i*10 + 1);
|
||||
if (!(argc == 3 || argc == 4)) {
|
||||
piCout << "UDPFileTransfer";
|
||||
piCout << "USE: piptest [src_ip_port] [dst_ip_port] {filename}";
|
||||
return 0;
|
||||
}
|
||||
piCout << (PISystemTime::current() - tm).toMicroseconds();
|
||||
*/
|
||||
//tm = PISystemTime::current();
|
||||
/*for (int i = 0; i < 100000000; ++i) {
|
||||
pl.append(i*10);
|
||||
pl.prepend(i*10 + 1);
|
||||
}*/
|
||||
//PICodeParser cd_;
|
||||
//cd.includeDirectory("../qpicalculator");
|
||||
//cd_.parseFile("piincludes.h");
|
||||
//piCout << (PISystemTime::current() - tm).toMilliseconds();
|
||||
/*piCout << NewLine;
|
||||
piForeachCA (i, pl)
|
||||
piCout << i;
|
||||
|
||||
pl.remove(1, 2).prepend(111).prepend(222);
|
||||
pl.remove(1, 1);
|
||||
piCout << NewLine;
|
||||
piForeachCA (i, pl)
|
||||
piCout << i;*/
|
||||
/*piCout << NewLine;
|
||||
for (int i = 0; i < pl.size_s(); ++i)
|
||||
piCout << pl[i];
|
||||
*/
|
||||
|
||||
/*PIEthernet eth(PIEthernet::UDP);
|
||||
eth.setReadAddress("192.168.0.30:4001");
|
||||
eth.setSendAddress("192.168.0.50:4001");
|
||||
eth.startThreadedRead(readed);
|
||||
piCout << "Connected";
|
||||
//eth.send(PIString("This is test string!\n").toByteArray());
|
||||
FOREVER_WAIT*/
|
||||
|
||||
if (argc < 2) return 0;
|
||||
PICodeParser cd;
|
||||
//cd.includeDirectory("../qpicalculator");
|
||||
cd.parseFile(argv[1]);
|
||||
piForeachC (PICodeParser::Enum & e, cd.enums)
|
||||
piCout << e.name << e.members;
|
||||
|
||||
|
||||
//piCout << v.toType<float>();
|
||||
//piCout << v.toType<float>().toType<PIString>();
|
||||
//PIFile::remove("ki");
|
||||
/*PIConfig conf("protocols_commod.conf");
|
||||
piCout << conf.allTree();
|
||||
conf.setValue("rmd.123", 456);*/
|
||||
|
||||
/*PITimer tm;
|
||||
piCout << tm.debug() << tm.properties();
|
||||
tm.setDebug(false);
|
||||
piCout << tm.debug() << tm.properties();
|
||||
tm.setDebug(true);
|
||||
piCout << tm.debug() << tm.properties();*/
|
||||
|
||||
//PIObject * ser = (PIObject * )PIIODevice::createFromFullPath("file://OM2:38400:7");
|
||||
//piCout << ser << NewLine << ser->properties();
|
||||
PIKbdListener kbd;
|
||||
kbd.enableExitCapture();
|
||||
PIString src = argv[1];
|
||||
PIString dst = argv[2];
|
||||
UDPFileTransfer f(src, dst);
|
||||
piCout << "work directory" << f.ft.directory().absolutePath() << ", listen on" << src << ",send to" << dst;
|
||||
if (argc == 4) {
|
||||
PIString file = argv[3];
|
||||
piCout << "send file" << file;
|
||||
f.startSend(file);
|
||||
return 0;
|
||||
} else {
|
||||
piCout << "wait for receiving";
|
||||
}
|
||||
WAIT_FOR_EXIT
|
||||
return 0;
|
||||
// Ob o;
|
||||
// ft.setPacketSize(65536);
|
||||
// PITimeMeasurer tm;
|
||||
// o.startsend();
|
||||
// piCout << tm.elapsed_s();
|
||||
// return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
294
main_.cpp
Normal file
294
main_.cpp
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Test program
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//#define PIP_DEBUG
|
||||
#include "pip.h"
|
||||
//#include "pivariant.h"
|
||||
//#include "picodeparser.h"
|
||||
//#include "pidir.h"
|
||||
#include "piconnection.h"
|
||||
//#include <QList>
|
||||
|
||||
PIMutex mutex;
|
||||
PIDeque<int> deq;
|
||||
|
||||
void timerE(void * t, int d) {
|
||||
//PIMutexLocker l(mutex);
|
||||
/*if (d == 1)
|
||||
deq.push_back(int(t));
|
||||
else
|
||||
deq.push_front(int(t));*/
|
||||
//printf("%d\n", deq.size());
|
||||
piCout << "tick" << (int)t << d;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class A: public PIObject {
|
||||
PIOBJECT(A)
|
||||
public:
|
||||
A() {}
|
||||
EVENT_HANDLER1(void, handlerA1, PIString, s) {piCout << "handlerA1 s" << s;}
|
||||
EVENT_HANDLER1(void, handlerA1, float, f) {piCout << "handlerA1 f" << f;}
|
||||
//uchar _[0x10];
|
||||
};
|
||||
|
||||
|
||||
class B: public PIObject {
|
||||
PIOBJECT(B)
|
||||
public:
|
||||
B() {}
|
||||
EVENT1(eventB1, float, f);
|
||||
EVENT1(eventB2, PIString, s);
|
||||
//uchar _[0x20];
|
||||
};
|
||||
|
||||
|
||||
class C: public A, public B {
|
||||
public:
|
||||
C() {}
|
||||
};
|
||||
|
||||
int main (int argc, char * argv[]) {
|
||||
PIFile f("test.txt");
|
||||
f.clear();
|
||||
f << "1234566789\n";
|
||||
piCout << f.size();
|
||||
f.close();
|
||||
piCout << f.size();
|
||||
|
||||
/*CONNECTU(&b, eventB1, &a, handlerA1)
|
||||
CONNECTU(&b, eventB2, &a, handlerA1)
|
||||
a.dump();
|
||||
b.dump();
|
||||
b.eventB1(0.33);
|
||||
b.eventB2("str");*/
|
||||
|
||||
|
||||
|
||||
//conf.dump();
|
||||
/*PIObject * t_o = &timer, * a_o = &a, * b_o = &b;
|
||||
CONNECTU(t_o, tickEvent, a_o, handlerT)
|
||||
CONNECTU(b_o, eventB1, &a, handlerA1)
|
||||
CONNECTU(&b, eventB2, a_o, hAAA)
|
||||
a_o->dump("* ");
|
||||
b_o->dump("# ");
|
||||
//dumpApplication();
|
||||
b.eventB(10, "str");
|
||||
b.eventB1(10.5);
|
||||
b.eventB2("test");*/
|
||||
|
||||
/*PIKbdListener kbd;
|
||||
PITimer timer(timerE);
|
||||
timer.start(100);
|
||||
kbd.enableExitCapture();
|
||||
WAIT_FOR_EXIT*/
|
||||
|
||||
/*
|
||||
PIMathVectorT3d v(1., -2., 3.);
|
||||
PIMathMatrixT33d m0;
|
||||
m0.setCol(0, v.normalized());
|
||||
m0.setCol(1, PIMathVectorT3d(v[1], -v[0], 0.).normalized());
|
||||
m0.setCol(2, m0.col(1) * m0.col(0));
|
||||
|
||||
piCout << m0.determinant();
|
||||
//m0.setRow(1, PIMathVectorT3d(1., 2., 3.));
|
||||
//piCout << m0 << NewLine << NewLine << m0.;
|
||||
//PIMathMatrixT33d m0_(-1., 2., 3., 4., -5., 6., 7., 8., -9.);
|
||||
//PIMathMatrixT33d m1_(10., 2., 30., 4., 50., 6., 70., 8., 90.);
|
||||
//piCout << m0_.determinant() << m1_.determinant();
|
||||
*/
|
||||
|
||||
/*
|
||||
PITimer::TimerImplementation ti_ = PITimer::ThreadRT;
|
||||
PITimer t_(timerE, 0, ti_);
|
||||
t_.setData((void*)0x10);
|
||||
t_.start(100);
|
||||
piSleep(1);
|
||||
piCout << "end";
|
||||
t_.stop();
|
||||
piCout << "end 1";
|
||||
t_.waitForFinish();
|
||||
piCout << "end 2";
|
||||
*/
|
||||
|
||||
/*
|
||||
PIVector<PITimer*> timers;
|
||||
int tc = PIString(argv[1]).toInt();
|
||||
piCout << "create ...";
|
||||
for (int i = 0; i < tc; ++i) {
|
||||
PITimer * t = new PITimer(timerE, 0, PITimer::Thread);
|
||||
t->setData((void*)i);
|
||||
//t->dump();
|
||||
timers << t;
|
||||
if (i > 10) t->addDelimiter(i / 10);
|
||||
t->start(100);
|
||||
}
|
||||
piCout << "create ok";
|
||||
piSleep(1);
|
||||
dumpApplication();
|
||||
piCout << "delete ...";
|
||||
piForeach (PITimer * t, timers)
|
||||
t->stop();
|
||||
piForeach (PITimer * t, timers)
|
||||
delete t;
|
||||
piCout << "delete ok";
|
||||
*/
|
||||
|
||||
/*
|
||||
PIConsole console(false);
|
||||
PISystemMonitor mon;
|
||||
console.addVariable("", &mon);
|
||||
mon.startOnSelf();
|
||||
console.enableExitCapture();
|
||||
console.start();
|
||||
console.waitForFinish();
|
||||
return 0;
|
||||
*/
|
||||
|
||||
/*PITimeMeasurer tm_;
|
||||
piCout << PIIODevice::normalizeFullPath("ser:///dev/ttyS1");
|
||||
piCout << tm_.elapsed_u();
|
||||
tm_.reset();
|
||||
piCout << PIIODevice::normalizeFullPath("ser:///dev/ttyS2");
|
||||
piCout << tm_.elapsed_u();
|
||||
tm_.reset();
|
||||
piCout << PIIODevice::normalizeFullPath("ser:///dev/ttyS3");
|
||||
piCout << tm_.elapsed_u();
|
||||
tm_.reset();
|
||||
piCout << PIIODevice::normalizeFullPath("ser:///dev/ttyS1");
|
||||
piCout << tm_.elapsed_u();
|
||||
tm_.reset();*/
|
||||
//msleep(6000000);
|
||||
|
||||
/*A a_;
|
||||
PIFile file("piiodevice.h", PIIODevice::ReadOnly);
|
||||
PIByteArray header = PIString("PI").toByteArray();
|
||||
PIByteArray footer = PIString("}").toByteArray();
|
||||
PIPacketExtractor pe(&file);
|
||||
//pe.setPacketData(header.data(), header.size_s(), 10);
|
||||
pe.setSplitMode(PIPacketExtractor::Footer);
|
||||
pe.setHeader(header);
|
||||
pe.setFooter(footer);
|
||||
pe.setPayloadSize(3);
|
||||
pe.setThreadedReadBufferSize(40);
|
||||
//pe.setBufferSize(256);
|
||||
//pe.setPacketData(0, 0, 20);
|
||||
CONNECT2(void, uchar * , int , &pe, packetReceived, &a_, per)
|
||||
pe.startThreadedRead();
|
||||
piMSleep(500);*/
|
||||
|
||||
/*TC tc;
|
||||
piMSleep(2000);
|
||||
//piCout << tc.diagnostic("file://piiodevice.h")->receiveBytesPerSec();
|
||||
piCout << tc.makeConfig();*/
|
||||
|
||||
/*PITimer timer;
|
||||
piForTimes (50) {
|
||||
piUSleep(10);
|
||||
piCout << PISystemTime::current() << timer.elapsed_u();
|
||||
}
|
||||
piCout << NewLine;
|
||||
piForTimes (50) {
|
||||
piUSleep(100);
|
||||
piCout << PISystemTime::current(true) << timer.elapsed_u();
|
||||
}*/
|
||||
|
||||
/*PIConsole console;
|
||||
PIEthernet eth(PIEthernet::TCP_Client);
|
||||
eth.connect("192.168.20:5006");
|
||||
eth.startThreadedRead(readed);
|
||||
console.enableExitCapture();
|
||||
console.start();
|
||||
console.waitForFinish();*/
|
||||
|
||||
/*PIBinaryLog log_;
|
||||
GPS_Data gps;
|
||||
log_.open("log_gps__2014_07_03__11_22_18", PIIODevice::ReadOnly);
|
||||
while (!log_.isEnd()) {
|
||||
log_.read(&gps, sizeof(gps));
|
||||
printf("%f %f\n", gps.lat, gps.lng);
|
||||
}*/
|
||||
return 0;
|
||||
|
||||
/*tm = PISystemTime::current();
|
||||
for (int i = 0; i < 10000000; ++i) {
|
||||
ql.append(i*10);
|
||||
ql.prepend(i*10 + 1);
|
||||
}
|
||||
piCout << (PISystemTime::current() - tm).toMicroseconds();
|
||||
*/
|
||||
//tm = PISystemTime::current();
|
||||
/*for (int i = 0; i < 100000000; ++i) {
|
||||
pl.append(i*10);
|
||||
pl.prepend(i*10 + 1);
|
||||
}*/
|
||||
//PICodeParser cd_;
|
||||
//cd.includeDirectory("../qpicalculator");
|
||||
//cd_.parseFile("piincludes.h");
|
||||
//piCout << (PISystemTime::current() - tm).toMilliseconds();
|
||||
/*piCout << NewLine;
|
||||
piForeachCA (i, pl)
|
||||
piCout << i;
|
||||
|
||||
pl.remove(1, 2).prepend(111).prepend(222);
|
||||
pl.remove(1, 1);
|
||||
piCout << NewLine;
|
||||
piForeachCA (i, pl)
|
||||
piCout << i;*/
|
||||
/*piCout << NewLine;
|
||||
for (int i = 0; i < pl.size_s(); ++i)
|
||||
piCout << pl[i];
|
||||
*/
|
||||
|
||||
/*PIEthernet eth(PIEthernet::UDP);
|
||||
eth.setReadAddress("192.168.0.30:4001");
|
||||
eth.setSendAddress("192.168.0.50:4001");
|
||||
eth.startThreadedRead(readed);
|
||||
piCout << "Connected";
|
||||
//eth.send(PIString("This is test string!\n").toByteArray());
|
||||
FOREVER_WAIT*/
|
||||
|
||||
/*
|
||||
if (argc < 2) return 0;
|
||||
PICodeParser cd;
|
||||
//cd.includeDirectory("../qpicalculator");
|
||||
cd.parseFile(argv[1]);
|
||||
piForeachC (PICodeParser::Enum & e, cd.enums)
|
||||
piCout << e.name << e.members;
|
||||
*/
|
||||
|
||||
//piCout << v.toType<float>();
|
||||
//piCout << v.toType<float>().toType<PIString>();
|
||||
//PIFile::remove("ki");
|
||||
/*PIConfig conf("protocols_commod.conf");
|
||||
piCout << conf.allTree();
|
||||
conf.setValue("rmd.123", 456);*/
|
||||
|
||||
/*PITimer tm;
|
||||
piCout << tm.debug() << tm.properties();
|
||||
tm.setDebug(false);
|
||||
piCout << tm.debug() << tm.properties();
|
||||
tm.setDebug(true);
|
||||
piCout << tm.debug() << tm.properties();*/
|
||||
|
||||
//PIObject * ser = (PIObject * )PIIODevice::createFromFullPath("file://OM2:38400:7");
|
||||
//piCout << ser << NewLine << ser->properties();
|
||||
}
|
||||
|
||||
|
||||
93
main_tcp_server.cpp
Normal file
93
main_tcp_server.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
#include "pip.h"
|
||||
|
||||
class Client: public PIObject {
|
||||
PIOBJECT(Client);
|
||||
public:
|
||||
Client(PIEthernet * eth_) {
|
||||
eth = eth_;
|
||||
eth->startThreadedRead();
|
||||
CONNECTU(eth, threadedReadEvent, this, readed);
|
||||
CONNECTU(eth, disconnected, this, disconnected);
|
||||
piCoutObj << uint(eth) << "client connected";
|
||||
}
|
||||
~Client() {}
|
||||
EVENT_HANDLER2(void, readed, uchar * , data, int, size) {
|
||||
PIByteArray ba(data, size)
|
||||
piCoutObj << uint(eth) << "readed" << size << "bytes" << Hex << ba;
|
||||
eth->write(ba);
|
||||
}
|
||||
EVENT_HANDLER1(void, disconnected, bool, withError) {
|
||||
piCoutObj << uint(eth) << "client disconnected";
|
||||
disconnect(this);
|
||||
}
|
||||
void send() {
|
||||
PIByteArray ba;
|
||||
ba << uchar(0) << uchar(1) << uchar(2);
|
||||
piCoutObj << uint(eth) << "client send" << ba;
|
||||
eth->write(ba);
|
||||
}
|
||||
PIEthernet * eth;
|
||||
|
||||
EVENT1(disconnect, Client *, client)
|
||||
};
|
||||
|
||||
class Server: public PIObject {
|
||||
PIOBJECT(Server);
|
||||
public:
|
||||
Server(int port) {
|
||||
eth = new PIEthernet(PIEthernet::TCP_Server);
|
||||
eth->setParameter(PIEthernet::ReuseAddress);
|
||||
CONNECTU(eth, newConnection, this, newConnection);
|
||||
PIString path = "0.0.0.0:" + PIString::fromNumber(port);
|
||||
eth->listen(path, true);
|
||||
piCoutObj << uint(eth) << "server started" << path;
|
||||
}
|
||||
~Server() {
|
||||
eth->close();
|
||||
piCoutObj << uint(eth) << "server stoped";
|
||||
delete eth;
|
||||
}
|
||||
EVENT_HANDLER1(void, newConnection, PIEthernet * , cl) {
|
||||
piCoutObj << uint(eth) << "add client";
|
||||
Client * client = new Client(cl);
|
||||
CONNECTU(client, disconnect, this, disconnect);
|
||||
clients.push_back(client);
|
||||
}
|
||||
EVENT_HANDLER1(void, disconnect, Client *, client) {
|
||||
piCoutObj << uint(eth) << "remove client";
|
||||
delete client;
|
||||
clients.removeOne(client);
|
||||
}
|
||||
PIEthernet * eth;
|
||||
PIVector<Client*> clients;
|
||||
void send() {
|
||||
for (int i=0; i<clients.size(); i++) {
|
||||
clients[i]->send();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Server sl(10001);
|
||||
Server s2(10002);
|
||||
|
||||
|
||||
void keyEvent(char key, void*) {
|
||||
switch (key) {
|
||||
case '1': sl.send(); break;
|
||||
case '2': s2.send(); break;
|
||||
};
|
||||
};
|
||||
|
||||
void timerEvent(void * , int) {
|
||||
//sl.send();
|
||||
};
|
||||
|
||||
PITimer timer(timerEvent);
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
timer.start(1000.);
|
||||
PIKbdListener kbd(keyEvent);
|
||||
kbd.enableExitCapture();
|
||||
WAIT_FOR_EXIT;
|
||||
return 0;
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
cmake_mgw -DLIB= && make install
|
||||
cmake_mgw -DLIB= && make install %*
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
windres -i pip_resource_win.rc -o pip_resource_win.o --include-dir=.
|
||||
327
pibinarylog.cpp
327
pibinarylog.cpp
@@ -1,327 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Class for write binary data to logfile, and read or playback this data
|
||||
Copyright (C) 2014 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pibinarylog.h"
|
||||
|
||||
|
||||
/*! \class PIBinaryLog
|
||||
* \brief Class for read and write binary data to logfile, and playback this data in realtime
|
||||
*
|
||||
* \section PIBinaryLog_sec0 Synopsis
|
||||
* Binary Log is a file with simle header, where you can read and write some binary data.
|
||||
* Any written data include special header with ID, size and timestamp.
|
||||
* This header provides separation different messages from the one file by choosing different IDs.
|
||||
* With \a filterID or special functions, like \a readBinLog() you can choose IDs what you want to read.
|
||||
* With function \a writeBinLog() or \a setDefaultID() you can choose ID that mark you data.
|
||||
* By default ID = 1, and \a filterID is empty, that mean you read any ID without filtering.
|
||||
* ThreadedRead provide you playback data, with delay that you write data.
|
||||
* You can choose realtime playbak or variable speed play back by set \a PlayMode.
|
||||
*
|
||||
* \section PIBinaryLog_sec1 Basic usage
|
||||
* This class provide all functions of \a PIIODevice, such \a open(), \a close(),
|
||||
* \a read() ,\a write(), and threaded read/write.
|
||||
* function \a setLogDir() need to set directory for BinLog files
|
||||
* function \a createNewFile() need to create new binlog file
|
||||
* function \a restart() need start from the begining of binlog file
|
||||
*
|
||||
*/
|
||||
|
||||
REGISTER_DEVICE(PIBinaryLog);
|
||||
|
||||
|
||||
PIBinaryLog::PIBinaryLog() {
|
||||
binlog_sig[0] = 'B';
|
||||
binlog_sig[1] = 'I';
|
||||
binlog_sig[2] = 'N';
|
||||
binlog_sig[3] = 'L';
|
||||
binlog_sig[4] = 'O';
|
||||
binlog_sig[5] = 'G';
|
||||
setThreadedReadBufferSize(65536);
|
||||
is_started = false;
|
||||
setPlaySpeed(1.f);
|
||||
setDefaultID(1);
|
||||
setPlayMode(PlayVariableSpeed);
|
||||
setLogDir(PIString());
|
||||
setFilePrefix(PIString());
|
||||
setRapidStart(false);
|
||||
}
|
||||
|
||||
|
||||
bool PIBinaryLog::openDevice() {
|
||||
lastrecord.timestamp = PISystemTime();
|
||||
lastrecord.id = 0;
|
||||
is_started = false;
|
||||
is_thread_ok = true;
|
||||
if (mode_ == ReadWrite) {
|
||||
piCoutObj << "Error: ReadWrite mode not supported, use WriteOnly or ReadOnly";
|
||||
return false;
|
||||
}
|
||||
if (!file.open(path(), mode_))
|
||||
return false;
|
||||
setName(path());
|
||||
if (mode_ == WriteOnly) {
|
||||
file.resize(0);
|
||||
if (!writeFileHeader()) {
|
||||
piCoutObj << "Error: Can't write binlog file header";
|
||||
return false;
|
||||
}
|
||||
is_started = true;
|
||||
}
|
||||
if (mode_ == ReadOnly) {
|
||||
if (file.isEmpty()) {
|
||||
piCoutObj << "Error: File is null";
|
||||
fileError();
|
||||
return false;
|
||||
}
|
||||
if (!checkFileHeader()) {
|
||||
fileError();
|
||||
return false;
|
||||
}
|
||||
if (isEmpty()) piCoutObj << "Error: Empty BinLog file";
|
||||
// startlogtime = PISystemTime::current();
|
||||
play_time = 0;
|
||||
// nextrecord = readsRecord();
|
||||
if (!rapidStart()) is_started = true;
|
||||
}
|
||||
startlogtime = PISystemTime::current();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIBinaryLog::closeDevice() {
|
||||
if (canWrite() && isEmpty()) {
|
||||
file.remove();
|
||||
return true;
|
||||
}
|
||||
return file.close();
|
||||
}
|
||||
|
||||
|
||||
bool PIBinaryLog::threadedRead(uchar *readed, int size) {
|
||||
is_thread_ok = false;
|
||||
PISystemTime pt;
|
||||
double delay;
|
||||
switch (playMode()) {
|
||||
case PlayRealTime:
|
||||
pt = PISystemTime::current() - startlogtime;
|
||||
// if (real_speedX > 0)
|
||||
// for (int i=0; i<real_speedX-1; i++) pt += pt;
|
||||
// piCout << pt << lastrecord.timestamp << lastrecord.timestamp - pt;
|
||||
if (is_started) {
|
||||
if (lastrecord.timestamp > pt)
|
||||
(lastrecord.timestamp - pt).sleep();
|
||||
} else {
|
||||
startlogtime = PISystemTime::current() - lastrecord.timestamp;
|
||||
is_started = true;
|
||||
}
|
||||
// int delay = piRoundd(lastread_timestamp.toMilliseconds() - (PISystemTime::current() - startlogtime).toMilliseconds());
|
||||
break;
|
||||
case PlayVariableSpeed:
|
||||
delay = lastrecord.timestamp.toMilliseconds() - play_time;
|
||||
delay /= playSpeed();
|
||||
if (is_started) {
|
||||
if (delay > 0)
|
||||
PISystemTime::fromMilliseconds(delay).sleep();
|
||||
} else is_started = true;
|
||||
play_time = lastrecord.timestamp.toMilliseconds();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
bool res = PIIODevice::threadedRead(readed, size);
|
||||
is_thread_ok = true;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
PIString PIBinaryLog::createNewFile() {
|
||||
if (!file.close()) return PIString();
|
||||
if (open(logDir() + "/" + filePrefix() + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss.binlog"), PIIODevice::WriteOnly))
|
||||
return file.path();
|
||||
piCoutObj << "Can't create new file, maybe LogDir is invalid.";
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
int PIBinaryLog::writeBinLog(int id, const void *data, int size) {
|
||||
if (size <= 0 || !canWrite()) return -1;
|
||||
PIByteArray logdata;
|
||||
logdata << id << size << (PISystemTime::current() - startlogtime) << PIByteArray::RawData(data, size);
|
||||
int res = file.write(logdata.data(), logdata.size());
|
||||
file.flush();
|
||||
if (res > 0) return size;
|
||||
else return res;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIBinaryLog::readBinLog(int id) {
|
||||
if (!canRead()) return PIByteArray();
|
||||
BinLogRecord br = readRecord();
|
||||
if (br.id == -1) {
|
||||
piCoutObj << "End of BinLog file";
|
||||
fileEnd();
|
||||
return PIByteArray();
|
||||
}
|
||||
if (id == 0 && br.id > 0) return br.data;
|
||||
while (br.id != id && !isEnd()) br = readRecord();
|
||||
if (br.id == -1) {
|
||||
piCoutObj << "End of BinLog file";
|
||||
fileEnd();
|
||||
return PIByteArray();
|
||||
}
|
||||
if (br.id == id) return br.data;
|
||||
piCoutObj << "Can't find record with id =" << id;
|
||||
return PIByteArray();
|
||||
}
|
||||
|
||||
|
||||
int PIBinaryLog::readBinLog(int id, void *read_to, int max_size) {
|
||||
if (max_size <= 0 || read_to == 0) return -1;
|
||||
PIByteArray ba = readBinLog(id);
|
||||
if (ba.isEmpty()) return -1;
|
||||
int sz = piMini(max_size, ba.size());
|
||||
memcpy(read_to, ba.data(), sz);
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int PIBinaryLog::read(void *read_to, int max_size) {
|
||||
// piCoutObj << "read";
|
||||
if (lastrecord.id == -1 || isEnd()) return 0;
|
||||
if(!is_thread_ok && lastrecord.id > 0) return lastrecord.data.size();
|
||||
if (!canRead()) return -1;
|
||||
if (max_size <= 0 || read_to == 0) return -1;
|
||||
BinLogRecord br;
|
||||
br.id = 0;
|
||||
if (filterID.isEmpty()) br = readRecord();
|
||||
else {
|
||||
while (!filterID.contains(br.id) && !isEnd()) br = readRecord();
|
||||
}
|
||||
if (br.id == -1) {
|
||||
fileEnd();
|
||||
piCoutObj << "End of BinLog file";
|
||||
//stopThreadedRead();
|
||||
return 0;
|
||||
}
|
||||
if (br.id <= 0) {
|
||||
piCoutObj << "Read record error";
|
||||
return -1;
|
||||
}
|
||||
int sz = piMini(max_size, br.data.size());
|
||||
memcpy(read_to, br.data.data(), sz);
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
void PIBinaryLog::restart() {
|
||||
bool th = isRunning();
|
||||
if (th) stopThreadedRead();
|
||||
if (!canRead()) return;
|
||||
lastrecord.timestamp = PISystemTime();
|
||||
lastrecord.id = 0;
|
||||
is_thread_ok = true;
|
||||
if (rapidStart()) is_started = false;
|
||||
else is_started = true;
|
||||
play_time = 0;
|
||||
file.seekToBegin();
|
||||
checkFileHeader();
|
||||
startlogtime = PISystemTime::current();
|
||||
if (th) startThreadedRead();
|
||||
}
|
||||
|
||||
|
||||
bool PIBinaryLog::writeFileHeader() {
|
||||
if (file.write(&binlog_sig, PIBINARYLOG_SIGNATURE_SIZE) <= 0) return false;
|
||||
uchar version = PIBINARYLOG_VERSION;
|
||||
if (file.write(&version, 1) <= 0) return false;
|
||||
file.flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIBinaryLog::checkFileHeader() {
|
||||
uchar read_sig[PIBINARYLOG_SIGNATURE_SIZE];
|
||||
for (int i=0; i<PIBINARYLOG_SIGNATURE_SIZE; i++) read_sig[i] = 0;
|
||||
if (file.read(read_sig, PIBINARYLOG_SIGNATURE_SIZE) < 0) return false;
|
||||
bool correct = true;
|
||||
for (int 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";
|
||||
return false;
|
||||
}
|
||||
uchar read_version = 0;
|
||||
if (file.read(&read_version, 1) < 0) return false;
|
||||
if (read_version == PIBINARYLOG_VERSION) 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";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PIBinaryLog::BinLogRecord PIBinaryLog::readRecord() {
|
||||
// piCoutObj << "readRecord";
|
||||
PIByteArray ba;
|
||||
BinLogRecord br;
|
||||
lastrecord.id = 0;
|
||||
lastrecord.data.clear();
|
||||
lastrecord.timestamp = PISystemTime();
|
||||
ba.resize(sizeof(BinLogRecord) - sizeof(PIByteArray));
|
||||
if(file.read(ba.data(), ba.size_s()) > 0) {
|
||||
ba >> br.id >> br.size >> br.timestamp;
|
||||
// piCoutObj << "read" << br.id << br.size << br.timestamp;
|
||||
} else {
|
||||
br.id = -1;
|
||||
return br;
|
||||
}
|
||||
if (br.id > 0 && br.size > 0) {
|
||||
ba.resize(br.size);
|
||||
if(file.read(ba.data(), ba.size_s()) > 0) br.data = ba;
|
||||
else br.id = 0;
|
||||
} else br.id = 0;
|
||||
lastrecord = br;
|
||||
if (br.id == 0) fileError();
|
||||
return br;
|
||||
}
|
||||
|
||||
|
||||
PIString PIBinaryLog::constructFullPath() const {
|
||||
PIString ret(fullPathPrefix() + "://");
|
||||
ret << logDir() << ":" << filePrefix() << ":" << defaultID();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PIBinaryLog::configureFromFullPath(const PIString & full_path) {
|
||||
PIStringList pl = full_path.split(":");
|
||||
for (int i = 0; i < pl.size_s(); ++i) {
|
||||
PIString p(pl[i]);
|
||||
switch (i) {
|
||||
case 0: setLogDir(p); break;
|
||||
case 1: setFilePrefix(p); break;
|
||||
case 2: setDefaultID(p.toInt()); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
175
pibinarylog.h
175
pibinarylog.h
@@ -1,175 +0,0 @@
|
||||
/*! \file pibinarylog.h
|
||||
* \brief Binary log
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Class for write binary data to logfile, and read or playback this data
|
||||
Copyright (C) 2014 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIBINARYLOG_H
|
||||
#define PIBINARYLOG_H
|
||||
|
||||
#include "pifile.h"
|
||||
|
||||
#define PIBINARYLOG_VERSION 0x31
|
||||
#define PIBINARYLOG_SIGNATURE_SIZE 6
|
||||
|
||||
|
||||
class PIBinaryLog: public PIIODevice
|
||||
{
|
||||
PIIODEVICE(PIBinaryLog)
|
||||
public:
|
||||
PIBinaryLog();
|
||||
~PIBinaryLog() {closeDevice();}
|
||||
|
||||
//! \brief Play modes for \a PIBinaryLog
|
||||
enum PlayMode {
|
||||
PlayRealTime /*! Play in system real time */ ,
|
||||
PlayVariableSpeed /*! Play in software time with speed, set by \a setSpeed. Set by default */
|
||||
};
|
||||
|
||||
|
||||
//! Current \a PlayMode
|
||||
PlayMode playMode() const {return (PlayMode)(property("playMode").toInt());}
|
||||
|
||||
//! Current directory where billogs wiil be saved
|
||||
PIString logDir() const {return property("logDir").toString();}
|
||||
|
||||
//! Returns current file prefix
|
||||
PIString filePrefix() const {return property("filePrefix").toString();}
|
||||
|
||||
//! Current LogDir, returns directory where billogs wiil be saved
|
||||
int defaultID() const {return property("defaultID").toInt();}
|
||||
|
||||
//! Returns current play speed
|
||||
float playSpeed() const {return property("playSpeed").toFloat();}
|
||||
|
||||
//! Returns if rapid start enabled
|
||||
bool rapidStart() const {return property("rapidStart").toBool();}
|
||||
|
||||
|
||||
//! Set \a PlayMode
|
||||
void setPlayMode(PlayMode mode) {setProperty("playMode", (int)mode);}
|
||||
|
||||
//! Set path to directory where binlogs will be saved
|
||||
void setLogDir(const PIString & path) {setProperty("logDir", path);}
|
||||
|
||||
//! Set file prefix, used to
|
||||
void setFilePrefix(const PIString & prefix) {setProperty("filePrefix", prefix);}
|
||||
|
||||
//! Set defaultID, used in \a write function
|
||||
void setDefaultID(int id) {setProperty("defaultID", id);}
|
||||
|
||||
//! If enabled BinLog \a ThreadedRead starts without delay for first record, e.g. first record will be readed immediately
|
||||
void setRapidStart(bool enabled) {setProperty("rapidStart", enabled);}
|
||||
|
||||
// /** \brief Set play speed multiplyer, used only in \a PlayMode = \a PlayRealTime default value 1x.
|
||||
// * If "speedX" > 0 than it use as speed increase by X times, else as speed decrease by X times.
|
||||
// * While is running this function does nothing and returns false. If "speedX" is set, returns true.*/
|
||||
// bool setRealSpeedX(int speedX) {if (speedX == 0 || isRunning()) return false; real_speedX = speedX; return true;}
|
||||
// //! Returns current play speed multiplyer
|
||||
// float realSpeedX() const {return real_speedX;}
|
||||
//! Set play speed, used only if \a playMode = \a PlayVariableSpeed, default value 1.0
|
||||
void setPlaySpeed(float speed) {setProperty("playSpeed", speed);}
|
||||
|
||||
|
||||
//! Write one record to BinLog file, with ID = id, id must be greather than 0
|
||||
int writeBinLog(int id, PIByteArray data) {return writeBinLog(id, data.data(), data.size_s());}
|
||||
|
||||
int writeBinLog(int id, const void * data, int size);
|
||||
|
||||
//! Read one record from BinLog file, with ID = id, if id = 0 than any id will be readed
|
||||
PIByteArray readBinLog(int id = 0);
|
||||
|
||||
int readBinLog(int id, void * read_to, int max_size);
|
||||
|
||||
//! Return true, if position at the end of BinLog file
|
||||
bool isEnd() {if (!opened_) return true; return file.isEnd();}
|
||||
|
||||
//! Returns if BinLog file is empty
|
||||
bool isEmpty() {return (file.size() <= PIBINARYLOG_SIGNATURE_SIZE + 1);}
|
||||
|
||||
int lastReadedID() const {return lastrecord.id;}
|
||||
|
||||
//! Read one message from binlog file, with ID contains in "filterID" or any ID, if "filterID" is empty
|
||||
int read(void *read_to, int max_size);
|
||||
|
||||
//! Write one record to BinLog file, with ID = "defaultID"
|
||||
int write(const void * data, int size) {return writeBinLog(defaultID(), data, size);}
|
||||
|
||||
//! Array of ID, that BinLog can read from binlog file, when use \a read function, or in \a ThreadedRead
|
||||
PIVector<int> filterID;
|
||||
|
||||
//! Go to begin of BinLog file
|
||||
void restart();
|
||||
|
||||
PIString constructFullPath() const;
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn PIString createNewFile()
|
||||
//! \brief Open device
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void fileEnd()
|
||||
//! \brief Create new binlog file in \a logDir, if successful returns filename, else returns empty string.
|
||||
//! Filename is like \a filePrefix + "yyyy_MM_dd__hh_mm_ss.binlog"
|
||||
|
||||
//! \fn void fileError()
|
||||
//! \brief Raise on file creation error
|
||||
|
||||
//! \}
|
||||
|
||||
EVENT_HANDLER(PIString, createNewFile);
|
||||
EVENT(fileEnd)
|
||||
EVENT(fileError)
|
||||
|
||||
protected:
|
||||
PIString fullPathPrefix() const {return "binlog";}
|
||||
void configureFromFullPath(const PIString & full_path);
|
||||
bool openDevice();
|
||||
bool closeDevice();
|
||||
bool threadedRead(uchar *readed, int size);
|
||||
|
||||
private:
|
||||
struct BinLogRecord {
|
||||
int id;
|
||||
int size;
|
||||
PISystemTime timestamp;
|
||||
PIByteArray data;
|
||||
};
|
||||
|
||||
bool writeFileHeader();
|
||||
bool checkFileHeader();
|
||||
BinLogRecord readRecord();
|
||||
|
||||
PIFile file;
|
||||
BinLogRecord lastrecord;
|
||||
PISystemTime startlogtime;
|
||||
//BinLogRecord nextrecord;
|
||||
double play_time; //milliseconds
|
||||
//int real_speedX; // in X
|
||||
bool is_started, is_thread_ok;
|
||||
uchar binlog_sig[PIBINARYLOG_SIGNATURE_SIZE];
|
||||
|
||||
};
|
||||
|
||||
#endif // PIBINARYLOG_H
|
||||
104
pibitarray.h
104
pibitarray.h
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Bit array
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIBITARRAY_H
|
||||
#define PIBITARRAY_H
|
||||
|
||||
#include "picontainers.h"
|
||||
|
||||
class PIP_EXPORT PIBitArray {
|
||||
public:
|
||||
PIBitArray(const int & size = 0) {resize(size);}
|
||||
PIBitArray(uchar val) {resize(sizeof(val) * 8); data_[0] = val;}
|
||||
PIBitArray(ushort val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
PIBitArray(uint val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
PIBitArray(ulong val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
PIBitArray(ullong val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
PIBitArray(uchar * bytes, uint size) {resize(size * 8); memcpy(data(), bytes, size);}
|
||||
|
||||
uint bitSize() const {return size_;}
|
||||
uint byteSize() const {return bytesInBits(size_);}
|
||||
PIBitArray & resize(const uint & size) {size_ = size; data_.resize(bytesInBits(size_)); return *this;}
|
||||
|
||||
PIBitArray & clearBit(const uint & index) {data_[index / 8] &= ~(1 << (index % 8)); return *this;}
|
||||
PIBitArray & setBit(const uint & index) {data_[index / 8] |= (1 << (index % 8)); return *this;}
|
||||
PIBitArray & writeBit(const uint & index, const bool & value) {if (value) setBit(index); else clearBit(index); return *this;}
|
||||
PIBitArray & writeBit(const uint & index, const uchar & value) {return writeBit(index, value > 0);}
|
||||
|
||||
PIBitArray & push_back(const bool & value) {resize(size_ + 1); writeBit(size_ - 1, value); return *this;}
|
||||
PIBitArray & push_back(const uchar & value) {return push_back(value > 0);}
|
||||
PIBitArray & insert(const uint & index, const bool & value) {
|
||||
resize(size_ + 1);
|
||||
uint fi = byteSize() - 1, si = index / 8, ti = index % 8;
|
||||
uchar c = data_[si];
|
||||
for (uint i = fi; i > si; --i) {
|
||||
data_[i] <<= 1;
|
||||
if ((0x80 & data_[i - 1]) == 0x80) data_[i] |= 1;
|
||||
else data_[i] &= 0xFE;}
|
||||
data_[si] &= (0xFF >> (7 - ti));
|
||||
data_[si] |= ((c << 1) & (0xFF << (ti)));
|
||||
if (value) data_[si] |= (1 << ti);
|
||||
else data_[si] &= ~(1 << ti);
|
||||
return *this;}
|
||||
PIBitArray & insert(const uint & index, const uchar & value) {return insert(index, value > 0);}
|
||||
PIBitArray & push_front(const bool & value) {return insert(0, value);}
|
||||
PIBitArray & push_front(const uchar & value) {return push_front(value > 0);}
|
||||
PIBitArray & pop_back() {return resize(size_ - 1);}
|
||||
PIBitArray & pop_front() {
|
||||
if (size_ == 0) return *this;
|
||||
uint fi = byteSize() - 1;
|
||||
for (uint i = 0; i < fi; ++i) {
|
||||
data_[i] >>= 1;
|
||||
if ((1 & data_[i + 1]) == 1) data_[i] |= 0x80;
|
||||
else data_[i] &= 0x7F;}
|
||||
data_[fi] >>= 1;
|
||||
resize(size_ - 1);
|
||||
return *this;}
|
||||
PIBitArray & append(const PIBitArray & ba) {for (uint i = 0; i < ba.bitSize(); ++i) push_back(ba[i]); return *this;}
|
||||
|
||||
uchar * data() {return data_.data();}
|
||||
uchar toUChar() {if (size_ == 0) return 0; return data_[0];}
|
||||
ushort toUShort() {ushort t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
|
||||
uint toUInt() {uint t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
|
||||
ulong toULong() {ulong t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
|
||||
ullong toULLong() {ullong t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
|
||||
|
||||
bool at(const uint & index) const {return (1 & (data_[index / 8] >> (index % 8))) == 1 ? true : false;}
|
||||
bool operator [](const uint & index) const {return at(index);}
|
||||
void operator +=(const PIBitArray & ba) {append(ba);}
|
||||
bool operator ==(const PIBitArray & ba) const {if (bitSize() != ba.bitSize()) return false; for (uint i = 0; i < bitSize(); ++i) if (at(i) != ba[i]) return false; return true;}
|
||||
bool operator !=(const PIBitArray & ba) const {return !(*this == ba);}
|
||||
void operator =(const uchar & val) {resize(sizeof(val) * 8); data_[0] = val;}
|
||||
void operator =(const ushort & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
void operator =(const uint & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
void operator =(const ulong & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
void operator =(const ullong & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
|
||||
private:
|
||||
uint bytesInBits(const uint & bits) const {return (bits + 7) / 8;}
|
||||
|
||||
PIVector<uchar> data_;
|
||||
uint size_;
|
||||
|
||||
};
|
||||
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIBitArray & ba) {for (uint i = 0; i < ba.bitSize(); ++i) {s << ba[i]; if (i % 8 == 7) s << ' ';} return s;}
|
||||
inline PICout operator <<(PICout s, const PIBitArray & ba) {s.space(); s.setControl(0, true); for (uint i = 0; i < ba.bitSize(); ++i) {s << ba[i]; if (i % 8 == 7) s << ' ';} s.restoreControl(); return s;}
|
||||
|
||||
#endif // PIBITARRAY_H
|
||||
293
pibytearray.cpp
293
pibytearray.cpp
@@ -1,293 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Byte array
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pibytearray.h"
|
||||
#include "pistring.h"
|
||||
|
||||
/*! \class PIByteArray
|
||||
* \brief Byte array
|
||||
* \details This class based on PIDeque<uchar> and provide some handle function
|
||||
* to manipulate it.
|
||||
*
|
||||
* \section PIByteArray_sec0 Usage
|
||||
* %PIByteArray can be used to store custom data and manipulate it. There are many
|
||||
* stream operators to store/restore common types to byte array. Store operators
|
||||
* places data at the end of array, restore operators takes data from the beginning
|
||||
* of array.
|
||||
* In addition there are Base 64 convertions and checksums:
|
||||
* * plain 8-bit
|
||||
* * plain 32-bit
|
||||
*
|
||||
* One of the major usage of %PIByteArray is stream functions. You can form binary
|
||||
* packet from many types (also dynamic types, e.g. PIVector) with one line:
|
||||
* \snippet pibytearray.cpp 0
|
||||
*
|
||||
* Or you can descibe stream operator of your own type and store/restore vectors of
|
||||
* your type:
|
||||
* \snippet pibytearray.cpp 1
|
||||
*
|
||||
* For store/restore custom data blocks there is PIByteArray::RawData class. Stream
|
||||
* operators of this class simply store/restore data block to/from byte array.
|
||||
* \snippet pibytearray.cpp 2
|
||||
*
|
||||
* \section PIByteArray_sec1 Attention
|
||||
* Stream operator of %PIByteArray store byte array as vector, not simply append
|
||||
* content of byte array. This operators useful to transmit custom data as %PIByteArray
|
||||
* packed into parent byte array, e.g. to form packet from %PIByteArray.
|
||||
* To append one byte array to another use funtion \a append().
|
||||
* \snippet pibytearray.cpp 3
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
const char PIByteArray::base64Table[64] = {
|
||||
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
|
||||
0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
|
||||
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
||||
0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
|
||||
0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
|
||||
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
|
||||
0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f};
|
||||
|
||||
const char PIByteArray::base64InvTable[256] = {
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x3E, 0x0, 0x0, 0x0, 0x3F,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
|
||||
0x3C, 0x3D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6,
|
||||
0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE,
|
||||
0xF, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
0x17, 0x18, 0x19, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
|
||||
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
||||
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
|
||||
0x31, 0x32, 0x33, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
int PIHuffman::nodeCompare(const void * f, const void * s) {
|
||||
return (reinterpret_cast<node * >(const_cast<void * >(s))->freq -
|
||||
reinterpret_cast<node * >(const_cast<void * >(f))->freq);
|
||||
}
|
||||
|
||||
|
||||
PIDeque<uchar> PIHuffman::compress(const PIDeque<uchar> & src) {
|
||||
calcFrequencies(src);
|
||||
return src;
|
||||
}
|
||||
|
||||
|
||||
void PIHuffman::calcFrequencies(const PIDeque<uchar> & src) {
|
||||
nodes.resize(256);
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
nodes[i].parent = nodes[i].right = nodes[i].left = 0;
|
||||
nodes[i].freq = 0;
|
||||
nodes[i].word.resize(1);
|
||||
nodes[i].word[0] = static_cast<uchar>(i);
|
||||
}
|
||||
for (int i = 0; i < src.size_s(); ++i)
|
||||
nodes[src[i]].freq++;
|
||||
std::qsort(nodes.data(), 256, sizeof(node), nodeCompare);
|
||||
for (int i = 255; i >= 0; --i)
|
||||
if (nodes[i].freq > 0 && i < 255)
|
||||
{nodes.remove(i + 1, 255 - i); break;}
|
||||
for (int i = 0; i < nodes.size_s(); ++i)
|
||||
cout << string((char*)nodes[i].word.data(), 1) << ": " << nodes[i].freq << endl;
|
||||
}
|
||||
|
||||
|
||||
PIHuffman PIByteArray::huffman;
|
||||
|
||||
PIByteArray & PIByteArray::convertToBase64() {
|
||||
base64HelpStruct hs;
|
||||
PIByteArray t;
|
||||
if (size() == 0) return *this;
|
||||
int sz = (size_s() / 3) * 3;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
hs.byte.byte0 = hs.byte.byte1 = hs.byte.byte2 = 0;
|
||||
hs.byte.byte0 = at(i);
|
||||
hs.byte.byte1 = at(++i);
|
||||
hs.byte.byte2 = at(++i);
|
||||
t.push_back(base64Table[hs.ascii.ascii0]);
|
||||
t.push_back(base64Table[hs.ascii.ascii1]);
|
||||
t.push_back(base64Table[hs.ascii.ascii2]);
|
||||
t.push_back(base64Table[hs.ascii.ascii3]);
|
||||
}
|
||||
hs.byte.byte0 = hs.byte.byte1 = hs.byte.byte2 = 0; sz = size() % 3;
|
||||
switch (sz) {
|
||||
case 1:
|
||||
hs.byte.byte0 = back();
|
||||
t.push_back(base64Table[hs.ascii.ascii0]);
|
||||
t.push_back(base64Table[hs.ascii.ascii1]);
|
||||
t.push_back('=');
|
||||
t.push_back('=');
|
||||
break;
|
||||
case 2:
|
||||
hs.byte.byte0 = at(size() - 2); hs.byte.byte1 = back();
|
||||
t.push_back(base64Table[hs.ascii.ascii0]);
|
||||
t.push_back(base64Table[hs.ascii.ascii1]);
|
||||
t.push_back(base64Table[hs.ascii.ascii2]);
|
||||
t.push_back('=');
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
*this = t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray & PIByteArray::convertFromBase64() {
|
||||
base64HelpStruct hs;
|
||||
PIByteArray t;
|
||||
uint sz = size();
|
||||
if (sz == 0) return *this;
|
||||
for (uint i = 0; i < sz; ++i) {
|
||||
hs.byte.byte0 = hs.byte.byte1 = hs.byte.byte2 = 0;
|
||||
hs.ascii.ascii0 = base64InvTable[at(i)];
|
||||
hs.ascii.ascii1 = base64InvTable[at(++i)];
|
||||
hs.ascii.ascii2 = base64InvTable[at(++i)];
|
||||
hs.ascii.ascii3 = base64InvTable[at(++i)];
|
||||
t.push_back(hs.byte.byte0);
|
||||
t.push_back(hs.byte.byte1);
|
||||
t.push_back(hs.byte.byte2);
|
||||
}
|
||||
if (back() == '=') t.pop_back();
|
||||
if (sz > 1) if (at(sz - 2) == '=') t.pop_back();
|
||||
*this = t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray & PIByteArray::compressRLE(uchar threshold) {
|
||||
PIByteArray t;
|
||||
uchar fb, clen, mlen = 255 - threshold;
|
||||
for (uint i = 0; i < size();) {
|
||||
fb = at(i);
|
||||
clen = 1;
|
||||
while (at(++i) == fb) {
|
||||
++clen;
|
||||
if (clen == mlen)
|
||||
break;
|
||||
}
|
||||
if (clen > 1) {
|
||||
t.push_back(threshold + clen);
|
||||
t.push_back(fb);
|
||||
continue;
|
||||
}
|
||||
if (fb >= threshold) {
|
||||
t.push_back(threshold + 1);
|
||||
t.push_back(fb);
|
||||
} else
|
||||
t.push_back(fb);
|
||||
}
|
||||
*this = t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray & PIByteArray::decompressRLE(uchar threshold) {
|
||||
PIByteArray t;
|
||||
uchar fb, clen;
|
||||
for (uint i = 0; i < size(); ++i) {
|
||||
fb = at(i);
|
||||
if (fb >= threshold) {
|
||||
clen = fb - threshold;
|
||||
fb = at(++i);
|
||||
for (uint j = 0; j < clen; ++j)
|
||||
t.push_back(fb);
|
||||
continue;
|
||||
} else
|
||||
t.push_back(fb);
|
||||
}
|
||||
*this = t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
uchar PIByteArray::checksumPlain8() const {
|
||||
uchar c = 0;
|
||||
int sz = size_s();
|
||||
for (int i = 0; i < sz; ++i)
|
||||
c += at(i);
|
||||
c = ~(c + 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
uint PIByteArray::checksumPlain32() const {
|
||||
uint c = 0;
|
||||
int sz = size_s();
|
||||
for (int i = 0; i < sz; ++i)
|
||||
c += at(i) * (i + 1);
|
||||
c = ~(c + 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
PIString PIByteArray::toString(int base) const {
|
||||
PIString ret;
|
||||
int sz = size_s();
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
if (i > 0) ret += " ";
|
||||
if (base == 2) ret += "b";
|
||||
if (base == 8) ret += "0";
|
||||
if (base == 16) ret += "0x";
|
||||
ret += PIString::fromNumber(at(i), base);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIByteArray::fromString(PIString str) {
|
||||
PIByteArray ret;
|
||||
if (str.trim().isEmpty()) return ret;
|
||||
str.replaceAll("\n", " ").replaceAll("\t", " ").replaceAll(" ", " ");
|
||||
PIStringList bl(str.split(" "));
|
||||
bool ok(false);
|
||||
piForeachC (PIString & b, bl) {
|
||||
int bv = b.toInt(-1, &ok);
|
||||
if (ok) ret << uchar(bv);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
261
pibytearray.h
261
pibytearray.h
@@ -1,261 +0,0 @@
|
||||
/*! \file pibytearray.h
|
||||
* \brief Byte array
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Byte array
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIBYTEARRAY_H
|
||||
#define PIBYTEARRAY_H
|
||||
|
||||
#ifdef DOXYGEN
|
||||
//! This macro allow stream template operators for write and read any type from byte array. Use it with attention!
|
||||
# define PIP_BYTEARRAY_STREAM_ANY_TYPE
|
||||
#endif
|
||||
|
||||
#include "pibitarray.h"
|
||||
|
||||
class PIString;
|
||||
class PIByteArray;
|
||||
|
||||
class PIHuffman {
|
||||
public:
|
||||
PIDeque<uchar> compress(const PIDeque<uchar> & src);
|
||||
|
||||
private:
|
||||
struct node {
|
||||
int freq;
|
||||
PIDeque<uchar> word;
|
||||
PIBitArray path;
|
||||
node * parent;
|
||||
node * right;
|
||||
node * left;
|
||||
};
|
||||
static int nodeCompare(const void * f, const void * s);
|
||||
void calcFrequencies(const PIDeque<uchar> & src);
|
||||
PIVector<node> nodes;
|
||||
};
|
||||
|
||||
class PIP_EXPORT PIByteArray: public PIDeque<uchar>
|
||||
{
|
||||
public:
|
||||
|
||||
//! Constructs an empty byte array
|
||||
PIByteArray() {;}
|
||||
|
||||
//! Constructs 0-filled byte array with size "size"
|
||||
PIByteArray(const uint size) {resize(size);}
|
||||
|
||||
//! Constructs byte array from data "data" and size "size"
|
||||
PIByteArray(const void * data, const uint size): PIDeque<uchar>((const uchar*)data, size_t(size)) {/*for (uint i = 0; i < size; ++i) push_back(((uchar * )data)[i]);*/}
|
||||
|
||||
|
||||
//! Help struct to store/restore custom blocks of data to/from PIByteArray
|
||||
struct RawData {
|
||||
friend PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v);
|
||||
public:
|
||||
//! Constructs data block
|
||||
RawData(void * data = 0, int size = 0) {d = data; s = size;}
|
||||
//! Constructs data block
|
||||
RawData(const void * data, const int size) {d = const_cast<void * >(data); s = size;}
|
||||
RawData & operator =(const RawData & o) {d = o.d; s = o.s; return *this;}
|
||||
private:
|
||||
void * d;
|
||||
int s;
|
||||
};
|
||||
|
||||
//! Return resized byte array
|
||||
PIByteArray resized(int new_size) const {PIByteArray tv(*this); tv.resize(new_size); return tv;}
|
||||
|
||||
//! Convert data to Base 64 and return this byte array
|
||||
PIByteArray & convertToBase64();
|
||||
|
||||
//! Convert data from Base 64 and return this byte array
|
||||
PIByteArray & convertFromBase64();
|
||||
|
||||
//! Return converted to Base 64 data
|
||||
PIByteArray toBase64() const {PIByteArray ba(*this); ba.convertToBase64(); return ba;}
|
||||
|
||||
//! Return converted from Base 64 data
|
||||
PIByteArray fromBase64() const {PIByteArray ba(*this); ba.convertFromBase64(); return ba;}
|
||||
|
||||
PIByteArray & compressRLE(uchar threshold = 192);
|
||||
PIByteArray & decompressRLE(uchar threshold = 192);
|
||||
PIByteArray compressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.compressRLE(threshold); return ba;}
|
||||
PIByteArray decompressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.decompressRLE(threshold); return ba;}
|
||||
|
||||
PIByteArray & compressHuffman() {*this = huffman.compress(*this); return *this;}
|
||||
|
||||
PIString toString(int base = 16) const;
|
||||
|
||||
//! Add to the end data "data" with size "size"
|
||||
PIByteArray & append(const void * data_, int size_) {uint ps = size(); enlarge(size_); memcpy(data(ps), data_, size_); return *this;}
|
||||
|
||||
//! Add to the end byte array "data"
|
||||
PIByteArray & append(const PIByteArray & data_) {uint ps = size(); enlarge(data_.size_s()); memcpy(data(ps), data_.data(), data_.size()); return *this;}
|
||||
/*PIByteArray & operator <<(short v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;}
|
||||
PIByteArray & operator <<(ushort v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;}
|
||||
PIByteArray & operator <<(int v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;}
|
||||
PIByteArray & operator <<(uint v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;}
|
||||
PIByteArray & operator <<(llong v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;}
|
||||
PIByteArray & operator <<(ullong v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;}*/
|
||||
//PIByteArray & operator <<(const PIByteArray & v) {for (uint i = 0; i < v.size(); ++i) push_back(v[i]); return *this;}
|
||||
|
||||
//! Returns plain 8-bit checksum
|
||||
uchar checksumPlain8() const;
|
||||
|
||||
//! Returns plain 32-bit checksum
|
||||
uint checksumPlain32() const;
|
||||
|
||||
void operator =(const PIDeque<uchar> & d) {resize(d.size()); memcpy(data(), d.data(), d.size());}
|
||||
|
||||
static PIByteArray fromString(PIString str);
|
||||
|
||||
private:
|
||||
union base64HelpStruct {
|
||||
base64HelpStruct() {memset(this, 0, sizeof(base64HelpStruct));}
|
||||
struct {
|
||||
uchar ascii0: 6;
|
||||
uchar ascii1: 6;
|
||||
uchar ascii2: 6;
|
||||
uchar ascii3: 6;
|
||||
} ascii;
|
||||
struct {
|
||||
uchar byte0;
|
||||
uchar byte1;
|
||||
uchar byte2;
|
||||
} byte;
|
||||
};
|
||||
|
||||
static const char base64Table[64];
|
||||
static const char base64InvTable[256];
|
||||
static PIHuffman huffman;
|
||||
|
||||
};
|
||||
|
||||
inline bool operator <(const PIByteArray & v0, const PIByteArray & v1) {if (v0.size() == v1.size()) {for (uint i = 0; i < v0.size(); ++i) if (v0[i] != v1[i]) return v0[i] < v1[i]; return false;} return v0.size() < v1.size();}
|
||||
//! \relatesalso PIByteArray \brief Output to std::ostream operator
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIByteArray & ba) {s << "{"; for (uint i = 0; i < ba.size(); ++i) {s << ba[i]; if (i < ba.size() - 1) s << ", ";} s << "}"; return s;}
|
||||
|
||||
//! \relatesalso PIByteArray \brief Output to PICout operator
|
||||
inline PICout operator <<(PICout s, const PIByteArray & ba) {s.space(); s.setControl(0, true); s << "{"; for (uint i = 0; i < ba.size(); ++i) {s << ba[i]; if (i < ba.size() - 1) s << ", ";} s << "}"; s.restoreControl(); return s;}
|
||||
|
||||
#define PBA_OPERATOR_TO int os = s.size_s(); s.enlarge(sizeof(v)); memcpy(s.data(os), &v, sizeof(v));
|
||||
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, uchar v) {s.push_back(v); return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const short v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const int v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const long & v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const llong & v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const ushort v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const uint v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const ulong & v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const ullong & v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const float v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const double & v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator, see \ref PIByteArray_sec1 for details
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v) {s << v.size_s(); int os = s.size_s(); s.enlarge(v.size_s()); if (v.size_s() > 0) memcpy(s.data(os), v.data(), v.size()); return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator, see \ref PIByteArray_sec1 for details
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) {int os = s.size_s(); s.enlarge(v.s); if (v.s > 0) memcpy(s.data(os), v.d, v.s); return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
template<typename Type0, typename Type1>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIPair<Type0, Type1> & v) {s << v.first << v.second; return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
template<typename T>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {s << v.size_s(); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
template<typename T>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIList<T> & v) {s << v.size_s(); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
template<typename T>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {s << v.size_s(); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;}
|
||||
#ifdef PIP_BYTEARRAY_STREAM_ANY_TYPE
|
||||
template<typename T>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const T & v) {PBA_OPERATOR_TO return s;}
|
||||
#endif
|
||||
|
||||
#undef PBA_OPERATOR_TO
|
||||
#define PBA_OPERATOR_FROM memcpy(&v, s.data(), sizeof(v)); s.remove(0, sizeof(v));
|
||||
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, uchar & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, short & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, int & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, long & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, llong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, ushort & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, uint & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, ulong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, ullong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, float & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, double & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator, see \ref PIByteArray_sec1 for details
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIByteArray & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); if (sz > 0) memcpy(v.data(), s.data(), v.size()); s.remove(0, v.size()); return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator, see \ref PIByteArray_sec1 for details
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) {assert(s.size_s() >= v.s); if (v.s > 0) memcpy(v.d, s.data(), v.s); s.remove(0, v.s); return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
template<typename Type0, typename Type1>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIPair<Type0, Type1> & v) {s >> v.first >> v.second; return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
template<typename T>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
template<typename T>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIList<T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
template<typename T>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
|
||||
// //! \relatesalso PIByteArray \brief Restore operator
|
||||
//template <typename Key, typename T>
|
||||
//inline PIByteArray & operator >>(PIByteArray & s, PIMap<Key, T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
|
||||
#ifdef PIP_BYTEARRAY_STREAM_ANY_TYPE
|
||||
template<typename T>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, T & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
#endif
|
||||
|
||||
|
||||
#undef PBA_OPERATOR_FROM
|
||||
|
||||
//! \relatesalso PIByteArray \brief Byte arrays compare operator
|
||||
inline bool operator ==(PIByteArray & f, PIByteArray & s) {if (f.size_s() != s.size_s()) return false; for (int i = 0; i < f.size_s(); ++i) if (f[i] != s[i]) return false; return true;}
|
||||
//! \relatesalso PIByteArray \brief Byte arrays compare operator
|
||||
inline bool operator !=(PIByteArray & f, PIByteArray & s) {if (f.size_s() != s.size_s()) return true; for (int i = 0; i < f.size_s(); ++i) if (f[i] != s[i]) return true; return false;}
|
||||
|
||||
#endif // PIBYTEARRAY_H
|
||||
221
pichar.h
221
pichar.h
@@ -1,221 +0,0 @@
|
||||
/*! \file pichar.h
|
||||
* \brief Unicode char
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Unicode char
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PICHAR_H
|
||||
#define PICHAR_H
|
||||
|
||||
#include "pibytearray.h"
|
||||
/*! \brief Unicode char
|
||||
* \details This class is wrapper around \c "uint".
|
||||
* There are many contructors and information functions
|
||||
*/
|
||||
class PIP_EXPORT PIChar
|
||||
{
|
||||
friend class PIString;
|
||||
friend PIByteArray & operator <<(PIByteArray & s, const PIChar & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & s, PIChar & v);
|
||||
public:
|
||||
//! Contructs ascii symbol
|
||||
PIChar(const char c) {ch = c; ch &= 0xFF;}
|
||||
|
||||
//! Contructs 2-bytes symbol
|
||||
PIChar(const short c) {ch = c; ch &= 0xFFFF;}
|
||||
|
||||
//! Contructs 4-bytes symbol
|
||||
PIChar(const int c) {ch = c;}
|
||||
|
||||
//! Contructs ascii symbol
|
||||
PIChar(const uchar c) {ch = c; ch &= 0xFF;}
|
||||
|
||||
//! Contructs 2-bytes symbol
|
||||
PIChar(const ushort c) {ch = c; ch &= 0xFFFF;}
|
||||
|
||||
//! Default constructor. Contructs 4-bytes symbol
|
||||
PIChar(const uint c = 0) {ch = c;}
|
||||
|
||||
//! Contructs symbol from no more than 4 bytes of string
|
||||
PIChar(const char * c) {ch = *reinterpret_cast<const int * >(c);}
|
||||
|
||||
//inline operator const int() {return static_cast<const int>(ch);}
|
||||
//inline operator const char() {return toAscii();}
|
||||
|
||||
//! Copy operator
|
||||
PIChar & operator =(const char v) {ch = v; return *this;}
|
||||
/*inline PIChar & operator =(const short v) {ch = v; return *this;}
|
||||
inline PIChar & operator =(const int v) {ch = v; return *this;}
|
||||
inline PIChar & operator =(const uchar v) {ch = v; return *this;}
|
||||
inline PIChar & operator =(const ushort v) {ch = v; return *this;}
|
||||
inline PIChar & operator =(const uint v) {ch = v; return *this;}*/
|
||||
|
||||
//! Compare operator
|
||||
bool operator ==(const PIChar & o) const {return strcmp(o.toCharPtr(), toCharPtr()) == 0;}
|
||||
/*inline bool operator ==(const PIChar & o) const {if (o.isAscii() ^ isAscii()) return false;
|
||||
if (isAscii()) return (o.toAscii() == toAscii());
|
||||
return (o.toInt() == toInt());}
|
||||
inline bool operator ==(const char o) const {return (PIChar(o) == *this);}
|
||||
inline bool operator ==(const short o) const {return (PIChar(o) == *this);}
|
||||
inline bool operator ==(const int o) const {return (PIChar(o) == *this);}
|
||||
inline bool operator ==(const uchar o) const {return (PIChar(o) == *this);}
|
||||
inline bool operator ==(const ushort o) const {return (PIChar(o) == *this);}
|
||||
inline bool operator ==(const uint o) const {return (PIChar(o) == *this);}*/
|
||||
|
||||
//! Compare operator
|
||||
bool operator !=(const PIChar & o) const {return !(o == *this);}
|
||||
/*inline bool operator !=(const char o) const {return (PIChar(o) != *this);}
|
||||
inline bool operator !=(const short o) const {return (PIChar(o) != *this);}
|
||||
inline bool operator !=(const int o) const {return (PIChar(o) != *this);}
|
||||
inline bool operator !=(const uchar o) const {return (PIChar(o) != *this);}
|
||||
inline bool operator !=(const ushort o) const {return (PIChar(o) != *this);}
|
||||
inline bool operator !=(const uint o) const {return (PIChar(o) != *this);}*/
|
||||
|
||||
//! Compare operator
|
||||
bool operator >(const PIChar & o) const {return strcmp(o.toCharPtr(), toCharPtr()) < 0;}
|
||||
|
||||
//! Compare operator
|
||||
bool operator <(const PIChar & o) const {return strcmp(o.toCharPtr(), toCharPtr()) > 0;}
|
||||
|
||||
//! Compare operator
|
||||
bool operator >=(const PIChar & o) const {return strcmp(o.toCharPtr(), toCharPtr()) <= 0;}
|
||||
|
||||
//! Compare operator
|
||||
bool operator <=(const PIChar & o) const {return strcmp(o.toCharPtr(), toCharPtr()) >= 0;}
|
||||
|
||||
//! Return \b true if symbol is digit ('0' to '9')
|
||||
bool isDigit() const {return isdigit(ch) != 0;}
|
||||
|
||||
//! Return \b true if symbol is HEX digit ('0' to '9', 'a' to 'f', 'A' to 'F')
|
||||
bool isHex() const {return isxdigit(ch) != 0;}
|
||||
|
||||
//! Return \b true if symbol is drawable (without space)
|
||||
bool isGraphical() const {return isgraph(ch) != 0;}
|
||||
|
||||
//! Return \b true if symbol is control byte (< 32 or 127)
|
||||
bool isControl() const {return iscntrl(ch) != 0;}
|
||||
|
||||
//! Return \b true if symbol is in lower case
|
||||
bool isLower() const {return islower(ch) != 0;}
|
||||
|
||||
//! Return \b true if symbol is in upper case
|
||||
bool isUpper() const {return isupper(ch) != 0;}
|
||||
|
||||
//! Return \b true if symbol is printable (with space)
|
||||
bool isPrint() const {return isprint(ch) != 0;}
|
||||
|
||||
//! Return \b true if symbol is space or tab
|
||||
bool isSpace() const {return isspace(ch) != 0;}
|
||||
|
||||
//! Return \b true if symbol is alphabetical letter
|
||||
bool isAlpha() const {return isalpha(ch) != 0;}
|
||||
|
||||
//! Return \b true if symbol is ascii (< 128)
|
||||
bool isAscii() const {return isascii(ch) != 0;}
|
||||
|
||||
int toInt() const {return int(ch);}
|
||||
const wchar_t * toWCharPtr() const {return reinterpret_cast<const wchar_t * >(&ch);}
|
||||
|
||||
//! Return as <tt>"char * "</tt> string
|
||||
const char * toCharPtr() const {return reinterpret_cast<const char * >(&ch);}
|
||||
|
||||
wchar_t toWChar() const {return wchar_t(ch);}
|
||||
char toAscii() const {return ch % 256;}
|
||||
int unicode16Code() const {wchar_t wc; if (mbtowc(&wc, toCharPtr(), 4) > 0) return wc; return 0;}
|
||||
//#ifdef WINDOWS
|
||||
// inline PIChar toUpper() const __attribute__ ((optimize(0))) {return PIChar(toupper(ch));}
|
||||
// inline PIChar toLower() const __attribute__ ((optimize(0))) {return PIChar(tolower(ch));}
|
||||
//#else
|
||||
|
||||
//! Return symbol in upper case
|
||||
PIChar toUpper() const {return PIChar(toupper(ch));}
|
||||
|
||||
//! Return symbol in lower case
|
||||
PIChar toLower() const {return PIChar(tolower(ch));}
|
||||
//#endif
|
||||
|
||||
private:
|
||||
uint ch;
|
||||
|
||||
};
|
||||
|
||||
__PICONTAINERS_SIMPLE_TYPE__(PIChar)
|
||||
|
||||
//! Output operator to \c std::ostream
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIChar & v) {s << v.toCharPtr(); return s;}
|
||||
|
||||
//! Output operator to \a PICout
|
||||
inline PICout operator <<(PICout s, const PIChar & v) {s.space(); s.setControl(0, true); s << v.toCharPtr(); s.restoreControl(); return s;}
|
||||
|
||||
|
||||
//! Write operator to \c PIByteArray
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIChar & v) {s << uint(v.ch); return s;}
|
||||
|
||||
//! Read operator from \c PIByteArray
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIChar & v) {uint i; s >> i; v.ch = wchar_t(i); return s;}
|
||||
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator ==(const char v, const PIChar & c) {return (PIChar(v) == c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator >(const char v, const PIChar & c) {return (PIChar(v) > c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator <(const char v, const PIChar & c) {return (PIChar(v) < c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator >=(const char v, const PIChar & c) {return (PIChar(v) >= c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator <=(const char v, const PIChar & c) {return (PIChar(v) <= c);}
|
||||
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator ==(const char * v, const PIChar & c) {return (PIChar(v) == c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator >(const char * v, const PIChar & c) {return (PIChar(v) > c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator <(const char * v, const PIChar & c) {return (PIChar(v) < c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator >=(const char * v, const PIChar & c) {return (PIChar(v) >= c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator <=(const char * v, const PIChar & c) {return (PIChar(v) <= c);}
|
||||
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator ==(const int v, const PIChar & c) {return (PIChar(v) == c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator >(const int v, const PIChar & c) {return (PIChar(v) > c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator <(const int v, const PIChar & c) {return (PIChar(v) < c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator >=(const int v, const PIChar & c) {return (PIChar(v) >= c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator <=(const int v, const PIChar & c) {return (PIChar(v) <= c);}
|
||||
|
||||
#endif // PICHAR_H
|
||||
97
picli.cpp
97
picli.cpp
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Command-Line Parser
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picli.h"
|
||||
|
||||
|
||||
/*! \class PICLI
|
||||
* \brief Command-line arguments parser
|
||||
*
|
||||
* \section PICLI_sec0 Synopsis
|
||||
* 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();
|
||||
* \section PICLI_sec1 Example
|
||||
* \snippet picli.cpp main
|
||||
*/
|
||||
|
||||
|
||||
PICLI::PICLI(int argc, char * argv[]) {
|
||||
needParse = true;
|
||||
_prefix_short = "-";
|
||||
_prefix_full = "--";
|
||||
_count_opt = 0;
|
||||
_count_mand = 0;
|
||||
for (int i = 0; i < argc; ++i)
|
||||
_args_raw << argv[i];
|
||||
}
|
||||
|
||||
|
||||
void PICLI::parse() {
|
||||
if (!needParse) return;
|
||||
PIString cra, full;
|
||||
Argument * last = 0;
|
||||
for (int i = 1; i < _args_raw.size_s(); ++i) {
|
||||
cra = _args_raw[i];
|
||||
if (cra.left(2) == _prefix_full) {
|
||||
last = 0;
|
||||
full = cra.right(cra.length() - 2);
|
||||
piForeach (Argument & a, _args) {
|
||||
if (a.full_key == full) {
|
||||
a.found = true;
|
||||
last = &a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (cra.left(1) == _prefix_short) {
|
||||
last = 0;
|
||||
for (int j = 1; j < cra.length(); ++j) {
|
||||
bool found = false;
|
||||
piForeach (Argument & a, _args) {
|
||||
if (a.short_key == cra[j]) {
|
||||
a.found = true;
|
||||
last = &a;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) break;
|
||||
}
|
||||
} else {
|
||||
if (last == 0 ? true : !last->has_value) {
|
||||
if (_args_mand.size_s() < _count_mand) {
|
||||
_args_mand << cra;
|
||||
continue;
|
||||
}
|
||||
if (_args_opt.size_s() < _count_opt || _count_opt < 0) {
|
||||
_args_opt << cra;
|
||||
continue;
|
||||
}
|
||||
piCoutObj << "[PICli] Arguments overflow, \"" << cra << "\" ignored";
|
||||
}
|
||||
if (last == 0 ? false : last->has_value) {
|
||||
last->value = cra;
|
||||
last = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
needParse = false;
|
||||
}
|
||||
101
picli.h
101
picli.h
@@ -1,101 +0,0 @@
|
||||
/*! \file picli.h
|
||||
* \brief Command-Line parser
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Command-Line Parser
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PICLI_H
|
||||
#define PICLI_H
|
||||
|
||||
#include "piobject.h"
|
||||
|
||||
class PIP_EXPORT PICLI: public PIObject
|
||||
{
|
||||
PIOBJECT(PICLI)
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
PICLI(int argc, char * argv[]);
|
||||
|
||||
|
||||
//! Add argument with name "name", short key = name first letter, full key = name
|
||||
void addArgument(const PIString & name, bool value = false) {_args << Argument(name, name[0], name, value); needParse = true;}
|
||||
|
||||
//! Add argument with name "name", short key = "shortKey", full key = name
|
||||
void addArgument(const PIString & name, const PIChar & shortKey, bool value = false) {_args << Argument(name, shortKey, name, value); needParse = true;}
|
||||
|
||||
//! Add argument with name "name", short key = "shortKey", full key = name
|
||||
void addArgument(const PIString & name, const char * shortKey, bool value = false) {_args << Argument(name, PIChar(shortKey), name, value); needParse = true;}
|
||||
|
||||
//! Add argument with name "name", short key = "shortKey", full key = "fullKey"
|
||||
void addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value = false) {_args << Argument(name, shortKey, fullKey, value); needParse = true;}
|
||||
|
||||
//! Add argument with name "name", short key = "shortKey", full key = "fullKey"
|
||||
void addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value = false) {_args << Argument(name, PIChar(shortKey), fullKey, value); needParse = true;}
|
||||
|
||||
|
||||
//! Returns unparsed command-line argument by index "index". Index 0 is program execute command.
|
||||
PIString rawArgument(int index) {parse(); return _args_raw[index];}
|
||||
PIString mandatoryArgument(int index) {parse(); return _args_mand[index];}
|
||||
PIString optionalArgument(int index) {parse(); return _args_opt[index];}
|
||||
|
||||
//! Returns unparsed command-line arguments
|
||||
const PIStringList & rawArguments() {parse(); return _args_raw;}
|
||||
const PIStringList & mandatoryArguments() {parse(); return _args_mand;}
|
||||
const PIStringList & optionalArguments() {parse(); return _args_opt;}
|
||||
|
||||
//! Returns program execute command without arguments
|
||||
PIString programCommand() {parse(); return _args_raw.size() > 0 ? _args_raw.front() : PIString();}
|
||||
bool hasArgument(const PIString & name) {parse(); piForeach (Argument & i, _args) if (i.name == name && i.found) return true; return false;}
|
||||
PIString argumentValue(const PIString & name) {parse(); piForeach (Argument &i, _args) if (i.name == name && i.found) return i.value; return PIString();}
|
||||
PIString argumentShortKey(const PIString & name) {piForeach (Argument &i, _args) if (i.name == name) return i.short_key; return PIString();}
|
||||
PIString argumentFullKey(const PIString & name) {piForeach (Argument &i, _args) if (i.name == name) return i.full_key; return PIString();}
|
||||
|
||||
const PIString & shortKeyPrefix() const {return _prefix_short;}
|
||||
const PIString & fullKeyPrefix() const {return _prefix_full;}
|
||||
int mandatoryArgumentsCount() const {return _count_mand;}
|
||||
int optionalArgumentsCount() const {return _count_opt;}
|
||||
void setShortKeyPrefix(const PIString & prefix) {_prefix_short = prefix; needParse = true;}
|
||||
void setFullKeyPrefix(const PIString & prefix) {_prefix_full = prefix; needParse = true;}
|
||||
void setMandatoryArgumentsCount(const int count) {_count_mand = count; needParse = true;}
|
||||
void setOptionalArgumentsCount(const int count) {_count_opt = count; needParse = true;}
|
||||
|
||||
private:
|
||||
struct Argument {
|
||||
Argument() {has_value = found = false;}
|
||||
Argument(const PIString & n, const PIChar & s, const PIString & f, bool v) {name = n; short_key = s; full_key = f; has_value = v; found = false;}
|
||||
PIString name;
|
||||
PIChar short_key;
|
||||
PIString full_key;
|
||||
PIString value;
|
||||
bool has_value, found;
|
||||
};
|
||||
|
||||
void parse();
|
||||
|
||||
PIString _prefix_short, _prefix_full;
|
||||
PIStringList _args_raw, _args_mand, _args_opt;
|
||||
PISet<PIString> keys_full, keys_short;
|
||||
PIVector<Argument> _args;
|
||||
int _count_mand, _count_opt;
|
||||
bool needParse;
|
||||
|
||||
};
|
||||
|
||||
#endif // PICLI_H
|
||||
41
picodec.cpp
41
picodec.cpp
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Text codings coder, based on "iconv"
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picodec.h"
|
||||
|
||||
|
||||
PIStringList PICodec::availableCodecs() {
|
||||
exec("/usr/bin/iconv", "-l");
|
||||
waitForFinish();
|
||||
PIString str(readOutput());
|
||||
str.cutLeft(str.find("\n "));
|
||||
str.replaceAll("\n", "");
|
||||
return str.split("//");
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PICodec::exec_iconv(const PIString & from, const PIString & to, const PIByteArray & str) {
|
||||
tf.open();
|
||||
tf.clear();
|
||||
tf << str;
|
||||
tf.close();
|
||||
exec("/usr/bin/iconv", ("-f=" + from), ("-t=" + to), tf.path());
|
||||
waitForFinish();
|
||||
return readOutput();
|
||||
}
|
||||
50
picodec.h
50
picodec.h
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Text codings coder, based on "iconv"
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PICODEC_H
|
||||
#define PICODEC_H
|
||||
|
||||
#include "piprocess.h"
|
||||
|
||||
class PIP_EXPORT PICodec: private PIProcess
|
||||
{
|
||||
public:
|
||||
PICodec(): PIProcess() {setGrabOutput(true); tf = PIFile::openTemporary(PIIODevice::ReadWrite); tf.open();}
|
||||
PICodec(const PIString & from, const PIString & to): PIProcess() {setCodings(from, to); tf = PIFile::openTemporary(PIIODevice::ReadWrite);}
|
||||
~PICodec() {tf.remove();}
|
||||
|
||||
void setFromCoding(const PIString & from) {c_from = from;}
|
||||
void setToCoding(const PIString & to) {c_to = to;}
|
||||
void setCodings(const PIString & from, const PIString & to) {c_from = from; c_to = to;}
|
||||
|
||||
PIStringList availableCodecs();
|
||||
PIString encode(PIString & str) {return PIString(exec_iconv(c_from, c_to, str.toByteArray()));}
|
||||
PIString encode(const PIByteArray & str) {return PIString(exec_iconv(c_from, c_to, str));}
|
||||
PIString decode(PIString & str) {return PIString(exec_iconv(c_to, c_from, str.toByteArray()));}
|
||||
PIString decode(const PIByteArray & str) {return PIString(exec_iconv(c_to, c_from, str));}
|
||||
|
||||
private:
|
||||
PIByteArray exec_iconv(const PIString & from, const PIString & to, const PIByteArray & str);
|
||||
|
||||
PIString c_from, c_to;
|
||||
PIFile tf;
|
||||
|
||||
};
|
||||
|
||||
#endif // PICODEC_H
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
C++ code info structs
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picodeinfo.h"
|
||||
|
||||
|
||||
PIString PICodeInfo::EnumInfo::memberName(int value_) const {
|
||||
piForeachC (PICodeInfo::EnumeratorInfo & e, members)
|
||||
if (e.value == value_)
|
||||
return e.name;
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
int PICodeInfo::EnumInfo::memberValue(const PIString & name_) const {
|
||||
piForeachC (PICodeInfo::EnumeratorInfo & e, members)
|
||||
if (e.name == name_)
|
||||
return e.value;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
PIMap<PIString, PICodeInfo::ClassInfo * > * PICodeInfo::classesInfo;
|
||||
PIMap<PIString, PICodeInfo::EnumInfo * > * PICodeInfo::enumsInfo;
|
||||
|
||||
bool __PICodeInfoInitializer__::_inited_ = false;
|
||||
149
picodeinfo.h
149
picodeinfo.h
@@ -1,149 +0,0 @@
|
||||
/*! \file picodeinfo.h
|
||||
* \brief C++ code info structs
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
C++ code info structs
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PICODEINFO_H
|
||||
#define PICODEINFO_H
|
||||
|
||||
#include "pistring.h"
|
||||
|
||||
namespace PICodeInfo {
|
||||
|
||||
enum TypeFlag {NoFlag, Const = 0x01, Static = 0x02, Mutable = 0x04, Volatile = 0x08, Inline = 0x10, Virtual = 0x20};
|
||||
|
||||
typedef PIFlags<PICodeInfo::TypeFlag> TypeFlags;
|
||||
|
||||
struct TypeInfo {
|
||||
TypeInfo(const PIString & n = PIString(), const PIString & t = PIString(), PICodeInfo::TypeFlags f = 0) {name = n; type = t; flags = f;}
|
||||
PIString name;
|
||||
PIString type;
|
||||
PICodeInfo::TypeFlags flags;
|
||||
};
|
||||
|
||||
struct FunctionInfo {
|
||||
PIString name;
|
||||
TypeInfo return_type;
|
||||
PIVector<PICodeInfo::TypeInfo> arguments;
|
||||
};
|
||||
|
||||
struct ClassInfo {
|
||||
PIString name;
|
||||
PIStringList parents;
|
||||
PIVector<PICodeInfo::TypeInfo> variables;
|
||||
PIVector<PICodeInfo::FunctionInfo> functions;
|
||||
};
|
||||
|
||||
struct EnumeratorInfo {
|
||||
EnumeratorInfo(const PIString & n = PIString(), int v = 0) {name = n; value = v;}
|
||||
PIString name;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct EnumInfo {
|
||||
PIString memberName(int value) const;
|
||||
int memberValue(const PIString & name) const;
|
||||
PIString name;
|
||||
PIVector<PICodeInfo::EnumeratorInfo> members;
|
||||
};
|
||||
|
||||
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::TypeInfo & v) {
|
||||
if (v.flags[Inline]) s << "inline ";
|
||||
if (v.flags[Virtual]) s << "virtual ";
|
||||
if (v.flags[Mutable]) s << "mutable ";
|
||||
if (v.flags[Volatile]) s << "volatile ";
|
||||
if (v.flags[Static]) s << "static ";
|
||||
if (v.flags[Const]) s << "const ";
|
||||
s << v.type;
|
||||
if (!v.name.isEmpty())
|
||||
s << " " << v.name;
|
||||
return s;
|
||||
}
|
||||
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::EnumeratorInfo & v) {s << v.name << " = " << v.value; return s;}
|
||||
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::ClassInfo & v) {
|
||||
s.setControl(0, true);
|
||||
s << "class " << v.name;
|
||||
if (!v.parents.isEmpty()) {
|
||||
s << ": ";
|
||||
bool first = true;
|
||||
piForeachC (PIString & i, v.parents) {
|
||||
if (first) first = false;
|
||||
else s << ", ";
|
||||
s << i;
|
||||
}
|
||||
}
|
||||
s << " {\n";
|
||||
piForeachC (FunctionInfo & i, v.functions) {
|
||||
s << Tab << i.return_type << " " << i.name << "(";
|
||||
bool fa = true;
|
||||
piForeachC (TypeInfo & a, i.arguments) {
|
||||
if (fa) fa = false;
|
||||
else s << ", ";
|
||||
s << a;
|
||||
}
|
||||
s << ");\n";
|
||||
}
|
||||
if (!v.functions.isEmpty() && !v.variables.isEmpty())
|
||||
s << "\n";
|
||||
piForeachC (TypeInfo & i, v.variables) {
|
||||
s << Tab << i << ";\n";
|
||||
}
|
||||
s << "}\n";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::EnumInfo & v) {
|
||||
s.setControl(0, true);
|
||||
s << "enum " << v.name << " {\n";
|
||||
piForeachC (EnumeratorInfo & i, v.members) {
|
||||
bool f = true;
|
||||
if (f) f = false;
|
||||
else s << ", ";
|
||||
s << Tab << i << "\n";
|
||||
}
|
||||
s << "}\n";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
extern PIMap<PIString, PICodeInfo::ClassInfo * > * classesInfo;
|
||||
extern PIMap<PIString, PICodeInfo::EnumInfo * > * enumsInfo;
|
||||
|
||||
}
|
||||
|
||||
class __PICodeInfoInitializer__ {
|
||||
public:
|
||||
__PICodeInfoInitializer__() {
|
||||
if (_inited_) return;
|
||||
_inited_ = true;
|
||||
PICodeInfo::classesInfo = new PIMap<PIString, PICodeInfo::ClassInfo * >;
|
||||
PICodeInfo::enumsInfo = new PIMap<PIString, PICodeInfo::EnumInfo * >;
|
||||
}
|
||||
static bool _inited_;
|
||||
};
|
||||
|
||||
static __PICodeInfoInitializer__ __picodeinfoinitializer__;
|
||||
|
||||
#endif // PICODEINFO_H
|
||||
762
picodeparser.cpp
762
picodeparser.cpp
@@ -1,762 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
C++ code parser
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picodeparser.h"
|
||||
|
||||
|
||||
|
||||
PIString PICodeParser::Macro::expand(const PIStringList & arg_vals, bool * ok) const {
|
||||
if (args.size() != arg_vals.size()) {
|
||||
piCout << ("Error: in expansion of macro \"" + name + "(" + args.join(", ") + ")\": expect")
|
||||
<< args.size() << "arguments but takes" << arg_vals.size() << "!";
|
||||
if (ok != 0) *ok = false;
|
||||
return PIString();
|
||||
}
|
||||
PIString ret = value;
|
||||
for (int i = 0; i < args.size_s(); ++i) {
|
||||
const PIString & an(args[i]), av(arg_vals[i]);
|
||||
int ind(-1);
|
||||
while ((ind = ret.find(an, ind + 1)) >= 0) {
|
||||
PIChar ppc(0), pc(0), nc(0);
|
||||
if (ind > 1) ppc = ret[ind - 2];
|
||||
if (ind > 0) pc = ret[ind - 1];
|
||||
if (ind + an.size_s() < ret.size_s()) nc = ret[ind + an.size_s()];
|
||||
if (ppc != '#' && pc == '#' && !_isCChar(nc)) { // to chars
|
||||
ind--;
|
||||
ret.replace(ind, an.size_s() + 1, "\"" + av + "\"");
|
||||
ind -= an.size_s() - av.size_s() - 1;
|
||||
continue;
|
||||
}
|
||||
if (_isCChar(pc) || _isCChar(nc)) continue;
|
||||
ret.replace(ind, an.size_s(), av);
|
||||
ind -= an.size_s() - av.size_s();
|
||||
}
|
||||
}
|
||||
ret.replaceAll("##", "");
|
||||
if (ok != 0) *ok = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PICodeParser::PICodeParser() {
|
||||
macros_iter = 32;
|
||||
clear();
|
||||
includes << "";
|
||||
}
|
||||
|
||||
|
||||
void PICodeParser::parseFile(const PIString & file) {
|
||||
clear();
|
||||
parseFileInternal(file);
|
||||
/*piCout << "\n\nDefines:";
|
||||
piForeachC (Define & m, defines)
|
||||
piCout << "define" << m.first << m.second;
|
||||
piCout << "\n\nMacros:";
|
||||
piForeachC (Macro & m, macros)
|
||||
piCout << "Macro:" << m.name << m.args << m.value;
|
||||
piCout << "\n\nClasses:";
|
||||
piForeachC (Entity * c, entities)
|
||||
piCout << "class" << c->name << c->parents;
|
||||
piCout << "\n\nEnums:";
|
||||
piForeachC (Enum & c, enums)
|
||||
piCout << "enum" << c.name << c.members;
|
||||
piCout << "\n\nTypedefs:";
|
||||
piForeachC (Typedef & c, typedefs)
|
||||
piCout << "typedef" << c;*/
|
||||
}
|
||||
|
||||
|
||||
void PICodeParser::parseFiles(const PIStringList & files) {
|
||||
clear();
|
||||
piForeachC (PIString & f, files)
|
||||
parseFileInternal(f);
|
||||
/*piCout << "\n\nDefines:";
|
||||
piForeachC (Define & m, defines)
|
||||
piCout << "define" << m.first << m.second;
|
||||
piCout << "\n\nMacros:";
|
||||
piForeachC (Macro & m, macros)
|
||||
piCout << "Macro:" << m.name << m.args << m.value;
|
||||
piCout << "\n\nClasses:";
|
||||
piForeachC (Entity * c, entities)
|
||||
piCout << "class" << c->name << c->parents;
|
||||
piCout << "\n\nEnums:";
|
||||
piForeachC (Enum & c, enums)
|
||||
piCout << "enum" << c.name << c.members;
|
||||
piCout << "\n\nTypedefs:";
|
||||
piForeachC (Typedef & c, typedefs)
|
||||
piCout << "typedef" << c;*/
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::isEnum(const PIString & name) {
|
||||
piForeachC (Enum & e, enums)
|
||||
if (e.name == name)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::parseFileInternal(const PIString & file) {
|
||||
if (proc_files[file]) return true;
|
||||
proc_files << file;
|
||||
cur_file = file;
|
||||
PIFile f(file, PIIODevice::ReadOnly);
|
||||
int ii = 0;
|
||||
while (!f.isOpened() && ii < (includes.size_s() - 1)) {
|
||||
f.setPath(includes[++ii] + "/" + file);
|
||||
//piCout << "try" << f.path();
|
||||
f.open(PIIODevice::ReadOnly);
|
||||
}
|
||||
if (!f.isOpened()) {
|
||||
//piCout << ("Error: can`t open file \"" + file + "\"!");
|
||||
return false;
|
||||
}
|
||||
PIString fc = f.readAll();
|
||||
piCout << "parsing" << f.path() << "...";
|
||||
bool ret = parseFileContent(fc);
|
||||
piCout << "parsing" << f.path() << "done";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PICodeParser::clear() {
|
||||
piForeach (Entity * i, entities) delete i;
|
||||
defines.clear();
|
||||
macros.clear();
|
||||
enums.clear();
|
||||
typedefs.clear();
|
||||
entities.clear();
|
||||
proc_files.clear();
|
||||
cur_namespace.clear();
|
||||
evaluator.clearCustomVariables();
|
||||
defines << Define("PICODE", "") << custom_defines;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::parseFileContent(PIString & fc) {
|
||||
bool mlc = false, cc = false;
|
||||
int mls = 0, ole = -1, /*ccs = 0,*/ end = 0;
|
||||
char c = 0, pc = 0;
|
||||
PIString pfc, line, ccmn, tmp;
|
||||
PIMap<PIString, PIString> cchars;
|
||||
|
||||
/// Remove comments, join multiline "*" and replace "*" to $n (cchars)
|
||||
fc.replaceAll("\r\n", "\n");
|
||||
fc.replaceAll("\r", "\n");
|
||||
for (int i = 0; i < fc.size_s() - 1; ++i) {
|
||||
if (i > 0) pc = c;
|
||||
c = fc[i].toAscii();
|
||||
if (c == '"' && !mlc && pc != '\'') {
|
||||
if (i > 0) if (fc[i - 1] == '\\') continue;
|
||||
cc = !cc;
|
||||
/*if (cc) ccs = i;
|
||||
if (!cc) {
|
||||
ccmn = "$" + PIString::fromNumber(cchars.size());
|
||||
cchars[ccmn] = fc.mid(ccs, i - ccs + 1);
|
||||
fc.replace(ccs, i - ccs + 1, ccmn);
|
||||
i = ccs - 1 + ccmn.size_s();
|
||||
}*/
|
||||
continue;
|
||||
}
|
||||
if (i > 0)
|
||||
if (c == '\\' && fc[i - 1].toAscii() != '\\') {
|
||||
fc.cutMid(i, 2);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
if (cc) continue;
|
||||
if (fc.mid(i, 2) == "/*") {mlc = true; mls = i; ++i; continue;}
|
||||
if (fc.mid(i, 2) == "*/" && mlc) {mlc = false; fc.cutMid(mls, i - mls + 2); i = mls - 1; continue;}
|
||||
if (fc.mid(i, 2) == "//" && !mlc) {ole = fc.find('\n', i); fc.cutMid(i, ole < 0 ? -1 : ole - i); --i; continue;}
|
||||
}
|
||||
//piCout << fc;
|
||||
pfc = procMacros(fc);
|
||||
|
||||
bool replaced = true;
|
||||
int replaced_cnt = 0;
|
||||
while (replaced) {
|
||||
//piCout << "MACRO iter" << replaced_cnt;
|
||||
if (replaced_cnt >= macros_iter) {
|
||||
piCout << "Error: recursive macros detected!";
|
||||
break;//return false;
|
||||
}
|
||||
replaced_cnt++;
|
||||
replaced = false;
|
||||
piForeachC (Define & d, defines) {
|
||||
int ind(-1);
|
||||
while ((ind = pfc.find(d.first, ind + 1)) >= 0) {
|
||||
PIChar pc(0), nc(0);
|
||||
if (ind > 0) pc = pfc[ind - 1];
|
||||
if (ind + d.first.size_s() < pfc.size_s()) nc = pfc[ind + d.first.size_s()];
|
||||
if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue;
|
||||
pfc.replace(ind, d.first.size_s(), d.second);
|
||||
ind -= d.first.size_s() - d.second.size_s();
|
||||
replaced = true;
|
||||
}
|
||||
}
|
||||
piForeachC (Macro & m, macros) {
|
||||
int ind(-1);
|
||||
while ((ind = pfc.find(m.name, ind + 1)) >= 0) {
|
||||
PIChar pc(0), nc(0);
|
||||
if (ind > 0) pc = pfc[ind - 1];
|
||||
if (ind + m.name.size_s() < pfc.size_s()) nc = pfc[ind + m.name.size_s()];
|
||||
if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue;
|
||||
PIString ret, range; bool ok(false);
|
||||
range = pfc.mid(ind + m.name.size_s()).takeRange("(", ")");
|
||||
ret = m.expand(range.split(",").trim(), &ok);
|
||||
if (!ok) return false;
|
||||
int rlen = pfc.find(range, ind + m.name.size_s()) + range.size_s() + 1 - ind;
|
||||
pfc.replace(ind, rlen, ret);
|
||||
ind -= rlen - ret.size_s();
|
||||
replaced = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//piCout << NewLine << "file" << cur_file << pfc;
|
||||
for (int i = 0; i < pfc.size_s() - 5; ++i) {
|
||||
if (pfc.mid(i, 8) == "template") {
|
||||
pfc.cutLeft(i + 8);
|
||||
pfc.takeRange("<", ">");
|
||||
bool def = !isDeclaration(pfc, 0, &end);
|
||||
pfc.cutLeft(end);
|
||||
if (def) pfc.takeRange("{", "}");
|
||||
else pfc.takeSymbol();
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
if (pfc.mid(i, 5) == "class" || pfc.mid(i, 6) == "struct") {
|
||||
int dind = pfc.find("{", i), find = pfc.find(";", i);
|
||||
if (dind < 0 && find < 0) {pfc.cutLeft(i + 6); i = 0; continue;}
|
||||
if (dind < 0 || find < dind) {pfc.cutLeft(i + 6); i = 0; continue;}
|
||||
ccmn = pfc.mid(i, dind - i) + "{\n" + pfc.mid(dind).takeRange('{', '}') + "\n}\n";
|
||||
pfc.remove(i, ccmn.size());
|
||||
parseClass(ccmn);
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
if (pfc.mid(i, 4) == "enum") {
|
||||
pfc.cutLeft(i + 4);
|
||||
tmp = pfc.takeCWord();
|
||||
parseEnum(cur_namespace + tmp, pfc.takeRange("{", "}"));
|
||||
pfc.takeSymbol();
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
if (pfc.mid(i, 7) == "typedef") {
|
||||
pfc.cutLeft(i + 7);
|
||||
typedefs << parseTypedef(pfc.takeLeft(pfc.find(";")));
|
||||
if (typedefs.back().first.isEmpty()) typedefs.pop_back();
|
||||
pfc.takeSymbol();
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc) {
|
||||
PIString cd = fc.trimmed().removeAll('\n').replaceAll("\t", " ").replaceAll(" ", " "), pn;
|
||||
//piCout << "found class <****\n" << cd << "\n****>";
|
||||
int ind = cd.find(":");
|
||||
PIVector<Entity * > parents;
|
||||
if (ind > 0) {
|
||||
PIStringList pl = cd.takeMid(ind + 1).trim().split(",");
|
||||
cd.cutRight(1);
|
||||
Entity * pe = 0;
|
||||
piForeachC (PIString & p, pl) {
|
||||
if (p.contains(" ")) pn = p.mid(p.find(" ") + 1);
|
||||
else pn = p;
|
||||
pe = findEntityByName(pn);
|
||||
if (pe == 0) ;//{piCout << "Error: can`t find" << pn;}
|
||||
else parents << pe;
|
||||
}
|
||||
}
|
||||
bool is_class = cd.left(5) == "class";
|
||||
cur_def_vis = (is_class ? Private : Public);
|
||||
PIString cn = cd.mid(6).trim();
|
||||
if (cn.isEmpty()) return 0;
|
||||
Entity * e = new Entity();
|
||||
e->name = cur_namespace + cn;
|
||||
e->type = (is_class ? "class" : "struct");
|
||||
e->parents = parents;
|
||||
e->file = cur_file;
|
||||
entities << e;
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
PIString PICodeParser::parseClass(PIString & fc) {
|
||||
Visibility prev_vis = cur_def_vis;
|
||||
int dind = fc.find("{"), find = fc.find(";"), end = 0;
|
||||
if (dind < 0 && find < 0) return PIString();
|
||||
if (dind < 0 || find < dind) return fc.left(find);
|
||||
Entity * ce = parseClassDeclaration(fc.takeLeft(dind));
|
||||
fc.trim().cutLeft(1).cutRight(1).trim();
|
||||
//piCout << "found class <****\n" << fc << "\n****>";
|
||||
if (!ce) return PIString();
|
||||
int ps = -1;
|
||||
bool def = false;
|
||||
PIString prev_namespace = cur_namespace, stmp;
|
||||
cur_namespace = ce->name + "::";
|
||||
//piCout << "parse class" << ce->name << "namespace" << cur_namespace;
|
||||
//piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
|
||||
while (!fc.isEmpty()) {
|
||||
PIString cw = fc.takeCWord(), tmp;
|
||||
//piCout << "\ntaked word" << cw;
|
||||
if (cw == "public") {cur_def_vis = Public; fc.cutLeft(1); continue;}
|
||||
if (cw == "protected") {cur_def_vis = Protected; fc.cutLeft(1); continue;}
|
||||
if (cw == "private") {cur_def_vis = Private; fc.cutLeft(1); continue;}
|
||||
if (cw == "class") {if (isDeclaration(fc, 0, &end)) {fc.cutLeft(end); fc.takeSymbol(); continue;} tmp = fc.takeLeft(fc.find("{")); stmp = fc.takeRange("{", "}"); fc.takeSymbol(); stmp = "class " + tmp + "{" + stmp + "}"; parseClass(stmp); continue;}
|
||||
if (cw == "struct") {if (isDeclaration(fc, 0, &end)) {fc.cutLeft(end); fc.takeSymbol(); continue;} tmp = fc.takeLeft(fc.find("{")); stmp = fc.takeRange("{", "}"); fc.takeSymbol(); stmp = "struct " + tmp + "{" + stmp + "}"; parseClass(stmp); continue;}
|
||||
if (cw == "enum") {tmp = fc.takeCWord(); parseEnum(cur_namespace + tmp, fc.takeRange("{", "}")); fc.takeSymbol(); continue;}
|
||||
if (cw == "friend") {fc.cutLeft(fc.find(";") + 1); continue;}
|
||||
if (cw == "typedef") {ce->typedefs << parseTypedef(fc.takeLeft(fc.find(";"))); typedefs << ce->typedefs.back(); typedefs.back().first.insert(0, cur_namespace); if (ce->typedefs.back().first.isEmpty()) ce->typedefs.pop_back(); fc.takeSymbol(); continue;}
|
||||
if (cw == "template") {
|
||||
fc.takeRange("<", ">");
|
||||
def = !isDeclaration(fc, 0, &end);
|
||||
fc.cutLeft(end);
|
||||
if (def) fc.takeRange("{", "}");
|
||||
else fc.takeSymbol();
|
||||
continue;
|
||||
}
|
||||
def = !isDeclaration(fc, 0, &end);
|
||||
tmp = (cw + fc.takeLeft(end)).trim();
|
||||
if (!tmp.isEmpty())
|
||||
parseMember(ce, tmp);
|
||||
if (def) fc.takeRange("{", "}");
|
||||
else fc.takeSymbol();
|
||||
if (ps == fc.size_s()) {/*cur_namespace = prev_namespace;*/ fc.cutLeft(1);/*return false*/;}
|
||||
ps = fc.size_s();
|
||||
}
|
||||
cur_def_vis = prev_vis;
|
||||
cur_namespace = prev_namespace;
|
||||
return ce->name;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::parseEnum(const PIString & name, PIString fc) {
|
||||
//piCout << "enum" << name << fc;
|
||||
Enum e(name);
|
||||
PIStringList vl(fc.split(","));
|
||||
PIString vn;
|
||||
int cv = -1, ind = 0;
|
||||
piForeachC (PIString & v, vl) {
|
||||
vn = v; ind = v.find("=");
|
||||
if (ind > 0) {cv = v.right(v.size_s() - ind - 1).toInt(); vn = v.left(ind);}
|
||||
if (ind < 0) ++cv;
|
||||
e.members << Enumerator(vn.trim(), cv);
|
||||
}
|
||||
enums << e;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PICodeParser::Typedef PICodeParser::parseTypedef(PIString fc) {
|
||||
//piCout << "parse typedef" << fc;
|
||||
Typedef td;
|
||||
fc.replaceAll("\t", " ");
|
||||
|
||||
if (fc.contains("(")) {
|
||||
int start = fc.find("("), end = fc.find(")");
|
||||
td.first = fc.takeMid(start + 1, end - start - 1).trim();
|
||||
if (td.first.left(1) == "*") {td.first.cutLeft(1).trim(); fc.insert(start + 1, "*");}
|
||||
td.second = fc.trim();
|
||||
} else {
|
||||
td.first = fc.takeMid(fc.findLast(" ")).trim();
|
||||
td.second = fc.trim();
|
||||
}
|
||||
//piCout << "found typedef" << td;
|
||||
return td;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
|
||||
if (fc.trim().isEmpty()) return true;
|
||||
if (fc.find("operator") >= 0) return true;
|
||||
tmp_temp.clear();
|
||||
//piCout << "parse member" << fc;
|
||||
int ts = fc.find("<"), te = 0;
|
||||
PIString ctemp, crepl;
|
||||
while (ts >= 0) {
|
||||
ctemp = fc.mid(ts).takeRange("<", ">");
|
||||
if (ctemp.isEmpty()) {te = ts + 1; ts = fc.find("<", te); continue;}
|
||||
crepl = "$" + PIString::fromNumber(tmp_temp.size_s()).expandLeftTo(3, "0");
|
||||
fc.replace(ts, ctemp.size_s() + 2, crepl);
|
||||
tmp_temp[crepl] = "<" + ctemp + ">";
|
||||
ts = fc.find("<", te);
|
||||
}
|
||||
fc.replaceAll("\n", " ").replaceAll("\t", " ").replaceAll(" ", " ").replaceAll(", ", ",");
|
||||
PIStringList tl, al;
|
||||
Member me;
|
||||
//piCout << fc;
|
||||
if (fc.contains("(")) {
|
||||
fc.cutRight(fc.size_s() - fc.findLast(")") - 1);
|
||||
te = fc.find("(");
|
||||
//piCout << fc;
|
||||
for (ts = te - 1; ts >= 0; --ts)
|
||||
if (!_isCChar(fc[ts]) && !(fc[ts].isDigit())) break;
|
||||
//piCout << "takeMid" << ts + 1 << te - ts - 1;
|
||||
me.name = fc.takeMid(ts + 1, te - ts - 1);
|
||||
if (me.name == parent->name) return true;
|
||||
me.arguments_full = fc.takeMid(ts + 2).cutRight(1).split(",");
|
||||
me.type = fc.cutRight(1).trim();
|
||||
me.visibility = cur_def_vis;
|
||||
if (me.type.find("inline ") >= 0) {
|
||||
me.attributes |= Inline;
|
||||
me.type.removeAll("inline ");
|
||||
}
|
||||
if (me.type.find("static ") >= 0) {
|
||||
me.attributes |= Static;
|
||||
me.type.removeAll("static ");
|
||||
}
|
||||
if (me.type.find("virtual ") >= 0) {
|
||||
me.attributes |= Virtual;
|
||||
me.type.removeAll("virtual ");
|
||||
}
|
||||
normalizeEntityNamespace(me.type);
|
||||
int i = 0;
|
||||
piForeach (PIString & a, me.arguments_full)
|
||||
if ((i = a.find("=")) > 0)
|
||||
a.cutRight(a.size_s() - i).trim();
|
||||
me.arguments_type = me.arguments_full;
|
||||
piForeach (PIString & a, me.arguments_type) {
|
||||
crepl.clear();
|
||||
if (a.contains("["))
|
||||
crepl = a.takeMid(a.find("["), a.findLast("]") - a.find("[") + 1);
|
||||
for (ts = a.size_s() - 1; ts >= 0; --ts)
|
||||
if (!_isCChar(a[ts]) && !(a[ts].isDigit())) break;
|
||||
a.cutRight(a.size_s() - ts - 1);
|
||||
normalizeEntityNamespace(a);
|
||||
a += crepl;
|
||||
a.trim();
|
||||
}
|
||||
restoreTmpTemp(&me);
|
||||
//piCout << "func" << me.type << me.name << me.arguments_full << me.arguments_type;
|
||||
parent->functions << me;
|
||||
} else {
|
||||
tl = fc.split(",");
|
||||
bool vn = true;
|
||||
ctemp = tl.front();
|
||||
for (ts = ctemp.size_s() - 1; ts > 0; --ts) {
|
||||
if (vn) {if (!_isCChar(ctemp[ts]) && !ctemp[ts].isDigit() && ctemp[ts] != '[' && ctemp[ts] != ']') vn = false;}
|
||||
else {if (_isCChar(ctemp[ts]) || ctemp[ts].isDigit()) break;}
|
||||
}
|
||||
me.type = ctemp.takeLeft(ts + 1);
|
||||
me.visibility = cur_def_vis;
|
||||
restoreTmpTemp(&me);
|
||||
PIString type = " " + me.type;
|
||||
if (type.find(" const ") >= 0) {
|
||||
me.attributes |= Const;
|
||||
type.replaceAll(" const ", " ");
|
||||
}
|
||||
if (type.find(" static ") >= 0) {
|
||||
me.attributes |= Static;
|
||||
type.replaceAll(" static ", " ");
|
||||
}
|
||||
if (type.find(" mutable ") >= 0) {
|
||||
me.attributes |= Mutable;
|
||||
type.replaceAll(" mutable ", " ");
|
||||
}
|
||||
if (type.find(" volatile ") >= 0) {
|
||||
me.attributes |= Volatile;
|
||||
type.replaceAll(" volatile ", " ");
|
||||
}
|
||||
type.trim();
|
||||
normalizeEntityNamespace(type);
|
||||
tl[0] = ctemp.trim();
|
||||
piForeachC (PIString & v, tl) {
|
||||
crepl.clear();
|
||||
me.name = v.trimmed();
|
||||
me.type = type;
|
||||
if (me.name.isEmpty()) continue;
|
||||
if (me.name.contains("["))
|
||||
crepl = me.name.takeMid(me.name.find("["), me.name.findLast("]") - me.name.find("[") + 1);
|
||||
while (!me.name.isEmpty()) {
|
||||
if (me.name.front() == "*" || me.name.front() == "&") {
|
||||
me.type += me.name.takeLeft(1);
|
||||
me.name.trim();
|
||||
} else break;
|
||||
}
|
||||
me.is_type_ptr = (me.type.right(1) == "]" || me.type.right(1) == "*");
|
||||
me.type += crepl;
|
||||
//piCout << "var" << me.type << me.name << me.is_const << me.is_static;
|
||||
parent->members << me;
|
||||
}
|
||||
}
|
||||
//piCout << "parse member" << fc;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PICodeParser::normalizeEntityNamespace(PIString & n) {
|
||||
PIString suff, pref;
|
||||
for (int i = n.size_s() - 1; i > 0; --i)
|
||||
if (_isCChar(n[i]) || n[i].isDigit()) {
|
||||
suff = n.right(n.size_s() - i - 1);
|
||||
n.cutRight(suff.size_s());
|
||||
break;
|
||||
}
|
||||
n.push_front(" ");
|
||||
if (n.find(" static ") >= 0) {n.replaceAll(" static ", ""); pref += "static ";}
|
||||
if (n.find(" const ") >= 0) {n.replaceAll(" const ", ""); pref += "const ";}
|
||||
if (n.find(" mutable ") >= 0) {n.replaceAll(" mutable ", ""); pref += "mutable ";}
|
||||
if (n.find(" volatile ") >= 0) {n.replaceAll(" volatile ", ""); pref += "volatile ";}
|
||||
n.trim();
|
||||
int f = 0;
|
||||
piForeachC (Entity * e, entities) {
|
||||
if (e->name == n) {
|
||||
n = (pref + n + suff).trim();
|
||||
return;
|
||||
}
|
||||
if ((f = e->name.find(n)) >= 0)
|
||||
if (e->name.mid(f - 1, 1) == ":")
|
||||
if (e->name.find(cur_namespace) >= 0) {
|
||||
n = pref + e->name + suff;
|
||||
return;
|
||||
}
|
||||
}
|
||||
piForeachC (Enum & e, enums)
|
||||
if ((f = e.name.find(n)) >= 0)
|
||||
if (e.name.mid(f - 1, 1) == ":")
|
||||
if (e.name.find(cur_namespace) >= 0) {
|
||||
//piCout << "change" << n << "to" << e.name + suff;
|
||||
n = pref + e.name + suff;
|
||||
return;
|
||||
}
|
||||
piForeachC (Typedef & e, typedefs)
|
||||
if ((f = e.first.find(n)) >= 0)
|
||||
if (e.first.mid(f - 1, 1) == ":")
|
||||
if (e.first.find(cur_namespace) >= 0) {
|
||||
//piCout << "change" << n << "to" << e.name + suff;
|
||||
n = pref + e.first + suff;
|
||||
return;
|
||||
}
|
||||
n = (pref + n + suff).trim();
|
||||
}
|
||||
|
||||
|
||||
void PICodeParser::restoreTmpTemp(Member * e) {
|
||||
int i = 0;
|
||||
piForeach (PIString & a, e->arguments_full) {
|
||||
while ((i = a.find("$")) >= 0)
|
||||
a.replace(i, 4, tmp_temp[a.mid(i, 4)]);
|
||||
}
|
||||
piForeach (PIString & a, e->arguments_type) {
|
||||
while ((i = a.find("$")) >= 0)
|
||||
a.replace(i, 4, tmp_temp[a.mid(i, 4)]);
|
||||
}
|
||||
while ((i = e->type.find("$")) >= 0)
|
||||
e->type.replace(i, 4, tmp_temp[e->type.mid(i, 4)]);
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::macroCondition(const PIString & mif, PIString mifcond) {
|
||||
//piCout << "macroCondition" << mif << mifcond;
|
||||
if (mif == "ifdef") return isDefineExists(mifcond);
|
||||
if (mif == "ifndef") return !isDefineExists(mifcond);
|
||||
if (mif == "if" || mif == "elif") {
|
||||
mifcond.removeAll(" ").removeAll("\t");
|
||||
return procMacrosCond(mifcond) > 0.;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
double PICodeParser::procMacrosCond(PIString fc) {
|
||||
bool neg = false, first = true, br = false;
|
||||
double ret = 0., brv = 0.;
|
||||
int oper = 0, ps = -1;
|
||||
char cc, nc;
|
||||
PIString ce;
|
||||
fc.removeAll("defined");
|
||||
//piCout << "procMacrosCond" << fc;
|
||||
while (!fc.isEmpty()) {
|
||||
cc = fc[0].toAscii();
|
||||
nc = (fc.size() > 1 ? fc[1].toAscii() : 0);
|
||||
if (cc == '!') {neg = true; fc.pop_front(); continue;}
|
||||
if (cc == '(') {br = true; brv = procMacrosCond(fc.takeRange('(', ')'));}
|
||||
if (cc == '&' && nc == '&') {fc.remove(0, 2); oper = 1; continue;}
|
||||
if (cc == '|' && nc == '|') {fc.remove(0, 2); oper = 2; continue;}
|
||||
if (!br) {
|
||||
ce = fc.takeCWord();
|
||||
if (ce.isEmpty()) ce = fc.takeNumber();
|
||||
}
|
||||
if (first) {
|
||||
first = false;
|
||||
ret = br ? brv : defineValue(ce);
|
||||
if (neg) ret = -ret;
|
||||
} else {
|
||||
//piCout << "oper" << oper << "with" << ce;
|
||||
if (!br) brv = defineValue(ce);
|
||||
switch (oper) {
|
||||
case 1: ret = ret && (neg ? -brv : brv); break;
|
||||
case 2: ret = ret || (neg ? -brv : brv); break;
|
||||
}
|
||||
}
|
||||
if (ps == fc.size_s()) fc.cutLeft(1);
|
||||
ps = fc.size_s();
|
||||
br = neg = false;
|
||||
}
|
||||
//piCout << "return" << ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::isDefineExists(const PIString & dn) {
|
||||
piForeachC (Define & d, defines) {
|
||||
if (d.first == dn)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
double PICodeParser::defineValue(const PIString & dn) {
|
||||
piForeachC (Define & d, defines) {
|
||||
if (d.first == dn)
|
||||
return d.second.isEmpty() ? 1. : d.second.toDouble();
|
||||
}
|
||||
return dn.toDouble();
|
||||
}
|
||||
|
||||
|
||||
PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) {
|
||||
piForeach (Entity * e, entities)
|
||||
if (e->name == en)
|
||||
return e;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::isDeclaration(const PIString & fc, int start, int * end) {
|
||||
int dind = fc.find("{", start), find = fc.find(";", start);
|
||||
//piCout << "isDeclaration" << dind << find;
|
||||
if (dind < 0 && find < 0) {if (end) *end = -1; return true;}
|
||||
if (dind < 0 || find < dind) {if (end) *end = find; return true;}
|
||||
if (end) *end = dind;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PIString PICodeParser::procMacros(PIString fc) {
|
||||
if (fc.isEmpty()) return PIString();
|
||||
int ifcnt = 0;
|
||||
bool grab = false, skip = false, cond_ok = false;
|
||||
PIString pfc, nfc, line, mif, mifcond;
|
||||
//piCout << "procMacros\n<******" << fc << "\n******>";
|
||||
fc += "\n";
|
||||
while (!fc.isEmpty()) {
|
||||
line = fc.takeLine().trimmed();
|
||||
if (line.left(1) == "#") {
|
||||
mifcond = line.mid(1);
|
||||
mif = mifcond.takeCWord();
|
||||
//piCout << "mif mifcond" << mif << mifcond << ifcnt;
|
||||
if (skip || grab) {
|
||||
if (mif.left(2) == "if") ifcnt++;
|
||||
if (mif.left(5) == "endif") {
|
||||
if (ifcnt > 0) ifcnt--;
|
||||
else {
|
||||
//piCout << "main endif" << skip << grab;
|
||||
if (grab) pfc << procMacros(nfc);
|
||||
skip = grab = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (mif.left(4) == "elif" && ifcnt == 0) {
|
||||
//piCout << "main elif" << skip << grab << cond_ok;
|
||||
if (cond_ok) {
|
||||
if (grab) {
|
||||
pfc << procMacros(nfc);
|
||||
skip = true; grab = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (skip) {
|
||||
//piCout << "check elif" << skip << grab << cond_ok;
|
||||
if (!macroCondition(mif, mifcond.trimmed())) continue;
|
||||
//piCout << "check elif ok";
|
||||
skip = false; grab = cond_ok = true;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (mif.left(4) == "else" && ifcnt == 0) {
|
||||
//piCout << "main else" << skip << grab;
|
||||
if (grab) pfc << procMacros(nfc);
|
||||
if (skip && !cond_ok) {skip = false; grab = true;}
|
||||
else {skip = true; grab = false;}
|
||||
continue;
|
||||
}
|
||||
if (grab) nfc << line << "\n";
|
||||
continue;
|
||||
}
|
||||
if (mif.left(2) == "if") {
|
||||
//piCout << "main if";
|
||||
skip = grab = cond_ok = false;
|
||||
if (macroCondition(mif, mifcond.trimmed())) grab = cond_ok = true;
|
||||
else skip = true;
|
||||
ifcnt = 0;
|
||||
nfc.clear();
|
||||
} else {
|
||||
if (!parseDirective(line.cutLeft(1).trim()))
|
||||
;//return false; /// WARNING
|
||||
}
|
||||
} else {
|
||||
if (grab) nfc << line << "\n";
|
||||
else if (!skip) pfc << line << "\n";
|
||||
}
|
||||
}
|
||||
return pfc;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::parseDirective(PIString d) {
|
||||
if (d.isEmpty()) return true;
|
||||
PIString dname = d.takeCWord();
|
||||
//piCout << "parseDirective" << d;
|
||||
if (dname == "include") {
|
||||
d.replaceAll("<", "\"").replaceAll(">", "\"");
|
||||
PIString cf = cur_file;
|
||||
bool ret = parseFileInternal(d.takeRange("\"", "\""));
|
||||
cur_file = cf;
|
||||
return ret;
|
||||
}
|
||||
if (dname == "define") {
|
||||
PIString mname = d.takeCWord();
|
||||
if (d.left(1) == "(") { // macro
|
||||
PIStringList args = d.takeRange("(", ")").split(",").trim();
|
||||
macros << Macro(mname, d.trim(), args);
|
||||
} else { // define
|
||||
defines << Define(mname, d.trim());
|
||||
evaluator.setVariable(mname, complexd_1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (dname == "undef") {
|
||||
PIString mname = d.takeCWord();
|
||||
for (int i = 0; i < defines.size_s(); ++i)
|
||||
if (defines[i].first == mname) {defines.remove(i); --i;}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
148
picodeparser.h
148
picodeparser.h
@@ -1,148 +0,0 @@
|
||||
/*! \file picodeparser.h
|
||||
* \brief C++ code parser
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
C++ code parser
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PICODEPARSER_H
|
||||
#define PICODEPARSER_H
|
||||
|
||||
#include "pifile.h"
|
||||
#include "pievaluator.h"
|
||||
|
||||
inline bool _isCChar(const PIChar & c) {return (c.isAlpha() || (c.toAscii() == '_'));}
|
||||
inline bool _isCChar(const PIString & c) {if (c.isEmpty()) return false; return _isCChar(c[0]);}
|
||||
|
||||
class PIP_EXPORT PICodeParser {
|
||||
public:
|
||||
PICodeParser();
|
||||
|
||||
enum PIP_EXPORT Visibility {Global, Public, Protected, Private};
|
||||
enum PIP_EXPORT Attribute {NoAttributes = 0x0, Const = 0x01, Static = 0x02, Mutable = 0x04, Volatile = 0x08, Inline = 0x10, Virtual = 0x20};
|
||||
|
||||
typedef PIFlags<Attribute> Attributes;
|
||||
typedef PIPair<PIString, PIString> Define;
|
||||
typedef PIPair<PIString, PIString> Typedef;
|
||||
typedef PIPair<PIString, int> Enumerator;
|
||||
|
||||
struct PIP_EXPORT Macro {
|
||||
Macro(const PIString & n = PIString(), const PIString & v = PIString(), const PIStringList & a = PIStringList()) {
|
||||
name = n;
|
||||
value = v;
|
||||
args = a;
|
||||
}
|
||||
PIString expand(const PIStringList & arg_vals, bool * ok = 0) const;
|
||||
PIString name;
|
||||
PIString value;
|
||||
PIStringList args;
|
||||
};
|
||||
|
||||
struct PIP_EXPORT Member {
|
||||
Member() {
|
||||
visibility = Global;
|
||||
size = 0;
|
||||
is_type_ptr = false;
|
||||
attributes = NoAttributes;
|
||||
}
|
||||
PIString type;
|
||||
PIString name;
|
||||
PIStringList arguments_full;
|
||||
PIStringList arguments_type;
|
||||
Visibility visibility;
|
||||
Attributes attributes;
|
||||
bool is_type_ptr;
|
||||
int size;
|
||||
};
|
||||
|
||||
struct PIP_EXPORT Entity {
|
||||
Entity() {
|
||||
visibility = Global;
|
||||
size = 0;
|
||||
}
|
||||
PIString type;
|
||||
PIString name;
|
||||
PIString file;
|
||||
Visibility visibility;
|
||||
int size;
|
||||
PIVector<Entity * > parents;
|
||||
//PIVector<Entity * > children;
|
||||
PIVector<Member> functions;
|
||||
PIVector<Member> members;
|
||||
PIVector<Typedef> typedefs;
|
||||
};
|
||||
|
||||
struct PIP_EXPORT Enum {
|
||||
Enum(const PIString & n = PIString()) {
|
||||
name = n;
|
||||
}
|
||||
PIString name;
|
||||
PIVector<Enumerator> members;
|
||||
};
|
||||
|
||||
void parseFile(const PIString & file);
|
||||
void parseFiles(const PIStringList & files);
|
||||
|
||||
void includeDirectory(const PIString & dir) {includes << dir;}
|
||||
void addDefine(const PIString & def_name, const PIString & def_value) {custom_defines << Define(def_name, def_value);}
|
||||
bool isEnum(const PIString & name);
|
||||
Entity * findEntityByName(const PIString & en);
|
||||
|
||||
int macrosSubstitutionMaxIterations() const {return macros_iter;}
|
||||
void setMacrosSubstitutionMaxIterations(int value) {macros_iter = value;}
|
||||
|
||||
PIVector<Define> defines, custom_defines;
|
||||
PIVector<Macro> macros;
|
||||
PIVector<Enum> enums;
|
||||
PIVector<Typedef> typedefs;
|
||||
PIVector<Entity * > entities;
|
||||
|
||||
private:
|
||||
void clear();
|
||||
bool parseFileInternal(const PIString & file);
|
||||
bool parseFileContent(PIString & fc);
|
||||
bool parseDirective(PIString d);
|
||||
Entity * parseClassDeclaration(const PIString & fc);
|
||||
PIString parseClass(PIString & fc);
|
||||
bool parseEnum(const PIString & name, PIString fc);
|
||||
Typedef parseTypedef(PIString fc);
|
||||
bool parseMember(Entity * parent, PIString & fc);
|
||||
void restoreTmpTemp(Member * e);
|
||||
bool macroCondition(const PIString & mif, PIString mifcond);
|
||||
bool isDefineExists(const PIString & dn);
|
||||
double defineValue(const PIString & dn);
|
||||
PIString procMacros(PIString fc);
|
||||
double procMacrosCond(PIString fc);
|
||||
bool isDeclaration(const PIString & fc, int start, int * end);
|
||||
void normalizeEntityNamespace(PIString & n);
|
||||
|
||||
int macros_iter;
|
||||
PIEvaluator evaluator;
|
||||
//PIVector<Entity * > tree;
|
||||
PISet<PIString> proc_files;
|
||||
PIString cur_file;
|
||||
PIStringList includes;
|
||||
Entity root_;
|
||||
Visibility cur_def_vis;
|
||||
PIString cur_namespace;
|
||||
PIMap<PIString, PIString> tmp_temp;
|
||||
|
||||
};
|
||||
|
||||
#endif // PICODEPARSER_H
|
||||
@@ -1,49 +0,0 @@
|
||||
#include "picollection.h"
|
||||
|
||||
|
||||
/** \class PICollection
|
||||
* \brief Interface to discover element groups
|
||||
* \details
|
||||
* \section PICollection_sec0 Synopsis
|
||||
* This class has only static functions so no need to create instance of the
|
||||
* %PICollection. This class provide macros to add some classes or existing
|
||||
* objects to global collection and access to them from any place of the code.
|
||||
* \snippet picollection.cpp main
|
||||
* */
|
||||
|
||||
|
||||
PIStringList PICollection::groups() {
|
||||
PIStringList sl;
|
||||
piForeachC (Group & g, *_groups)
|
||||
sl << g.name;
|
||||
return sl;
|
||||
}
|
||||
|
||||
|
||||
PIVector<const PIObject * > PICollection::groupElements(const PIString & group) {
|
||||
piForeachC (Group & g, *_groups)
|
||||
if (g.name == group)
|
||||
return g.elements;
|
||||
return PIVector<const PIObject * >();
|
||||
}
|
||||
|
||||
|
||||
void PICollection::addToGroup(const PIString & group, const PIObject * element) {
|
||||
//piCout << "add to" << group << element;
|
||||
PIString n = element->className();
|
||||
piForeach (Group & g, *_groups)
|
||||
if (g.name == group) {
|
||||
for (int i = 0; i < g.elements.size_s(); ++i)
|
||||
if (PIString(g.elements[i]->className()) == n)
|
||||
return;
|
||||
g.elements << element;
|
||||
//piCout << "new group" << group << ", ok";
|
||||
return;
|
||||
}
|
||||
*_groups << Group(group);
|
||||
_groups->back().elements << element;
|
||||
//piCout << "new group" << group << ", ok";
|
||||
}
|
||||
|
||||
bool __PICollectionInitializer::_inited_(false);
|
||||
PIVector<PICollection::Group> * PICollection::_groups;
|
||||
@@ -1,94 +0,0 @@
|
||||
/*! \file picollection.h
|
||||
* \brief Custom elements collection
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Peer - named I/O ethernet node, forming self-organized peering network
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PICOLLECTION_H
|
||||
#define PICOLLECTION_H
|
||||
|
||||
#include "piobject.h"
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
/** \brief Add existing element "object" in group with name "group"
|
||||
* \relatesalso PICollection
|
||||
* \details If there is no group with name "group" it will be created.
|
||||
* Only one element of the class "object" can be in group "group". If
|
||||
* this is already exists nothing be happens. \n "object" should to
|
||||
* be pointer to object based on PIObject. */
|
||||
# define ADD_TO_COLLECTION(group, object)
|
||||
|
||||
/** \brief Add new element of class "class" in group with name "group"
|
||||
* \relatesalso PICollection
|
||||
* \details If there is no group with name "group" it will be created.
|
||||
* Only one element of the class "class" can be in group "group". If
|
||||
* this is already exists nothing be happens. \n "class" should to
|
||||
* be name of the any class based on PIObject. */
|
||||
# define ADD_NEW_TO_COLLECTION(group, class)
|
||||
|
||||
#else
|
||||
# define ADD_TO_COLLECTION(group, object) static PICollection::CollectionAdder __##group##_##__LINE__##_##adder##__(#group, object);
|
||||
# define ADD_NEW_TO_COLLECTION(group, class) static PICollection::CollectionAdder __##group##_##class##_##adder##__(#group, new class());
|
||||
#endif
|
||||
|
||||
class PIP_EXPORT PICollection
|
||||
{
|
||||
friend class __PICollectionInitializer;
|
||||
public:
|
||||
PICollection() {;}
|
||||
|
||||
//! \brief Returns all existing groups by their names
|
||||
static PIStringList groups();
|
||||
|
||||
//! \brief Returns all elements of group "group"
|
||||
static PIVector<const PIObject * > groupElements(const PIString & group);
|
||||
|
||||
static void addToGroup(const PIString & group, const PIObject * element);
|
||||
|
||||
class CollectionAdder {
|
||||
public:
|
||||
CollectionAdder(const PIString & group, const PIObject * element) {PICollection::addToGroup(group, element);}
|
||||
};
|
||||
|
||||
protected:
|
||||
struct Group {
|
||||
Group(const PIString & name_ = PIString()) {name = name_;}
|
||||
//~Group() {piCout << "delete group" << name << this; piForeach (const PIObject * o, elements) delete o; elements.clear();}
|
||||
PIString name;
|
||||
PIVector<const PIObject * > elements;
|
||||
};
|
||||
|
||||
static PIVector<Group> * _groups;
|
||||
|
||||
};
|
||||
|
||||
class PIP_EXPORT __PICollectionInitializer {
|
||||
public:
|
||||
__PICollectionInitializer() {
|
||||
if (_inited_) return;
|
||||
_inited_ = true;
|
||||
PICollection::_groups = new PIVector<PICollection::Group>();
|
||||
}
|
||||
static bool _inited_;
|
||||
};
|
||||
|
||||
static __PICollectionInitializer __picollectioninitializer;
|
||||
|
||||
#endif // PICOLLECTION_H
|
||||
601
piconfig.cpp
601
piconfig.cpp
@@ -1,601 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Config parser
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piconfig.h"
|
||||
|
||||
/*! \class PIConfig
|
||||
* \brief Configuration file
|
||||
* \details This class provide handle access to configuration file.
|
||||
*
|
||||
* \section PIConfig_sec0 Synopsis
|
||||
* PIConfig reads configuration file and create internal dendritic
|
||||
* representation of all entries of this file. You can easily read
|
||||
* some values and write new.
|
||||
* \image html piconfig.png
|
||||
*
|
||||
* %PIConfig supports also INI-style files with sections "[section]".
|
||||
* In this case line with section name interpret as prefix to the next
|
||||
* lines. For example, these configs are equal:
|
||||
* \code
|
||||
* ser.device = /dev/ttyS0
|
||||
* ser.speed = 115200
|
||||
* debug = true
|
||||
* \endcode
|
||||
* \code
|
||||
* [ser]
|
||||
* device = /dev/ttyS0
|
||||
* speed = 115200
|
||||
* []
|
||||
* debug = true
|
||||
* \endcode
|
||||
*
|
||||
* \section PIConfig_sec1 Concepts
|
||||
* Each node of internal tree has type PIConfig::Entry. %PIConfig
|
||||
* has one root element \a rootEntry(). Any entry of configuration file is a
|
||||
* child of this element.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \class PIConfig::Entry
|
||||
* \brief %Entry of configuration file
|
||||
* \details This class is node of internal PIConfig tree.
|
||||
* %Entry provide access to elements of PIConfig. Each entry has
|
||||
* children or next properties:
|
||||
* * name
|
||||
* * value
|
||||
* * type
|
||||
* * comment
|
||||
*
|
||||
* Each property is a PIString. These properties forms from text line with
|
||||
* format: \code{.cpp} <name> = <value> #<type> <comment> \endcode
|
||||
* Type and comment are optional fields. Type is a single letter immediately
|
||||
* after comment symbol "#". \n \n
|
||||
* %Entry has many implicit convertions to common types: boolean, integers,
|
||||
* float, double, PIString, PIStringList. \n \n
|
||||
* Generally there is no need to create instance of %PIConfig::Entry manually,
|
||||
* it returns by functions \a getValue() of \a PIConfig, \a PIConfig::Entry or
|
||||
* \a PIConfig::Branch. If there is no suitable entry to return, reference to
|
||||
* internal instance of %PIConfig::Entry with "default" value will be returned.
|
||||
* \snippet piconfig.cpp PIConfig::Entry
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \class PIConfig::Branch
|
||||
* \brief %Branch is a list of entries of configuration file
|
||||
* \details %Branch provides some features to get entries lists.
|
||||
* \snippet piconfig.cpp PIConfig::Branch
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
PIConfig::Entry PIConfig::Branch::_empty;
|
||||
PIConfig::Entry PIConfig::Entry::_empty;
|
||||
|
||||
|
||||
PIConfig::Branch PIConfig::Branch::allLeaves() {
|
||||
Branch b;
|
||||
b.delim = delim;
|
||||
piForeach (Entry * i, *this) {
|
||||
if (i->isLeaf()) b << i;
|
||||
else allLeaves(b, i);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
PIConfig::Entry & PIConfig::Branch::getValue(const PIString & vname, const PIString & def, bool * exist) {
|
||||
if (vname.isEmpty()) {
|
||||
_empty.clear();
|
||||
_empty.delim = delim;
|
||||
if (exist != 0) *exist = false;
|
||||
return _empty;
|
||||
}
|
||||
PIStringList tree = vname.split(delim);
|
||||
PIString name = tree.front();
|
||||
tree.pop_front();
|
||||
Entry * ce = 0;
|
||||
piForeach (Entry * i, *this)
|
||||
if (i->_name == name) {
|
||||
ce = i;
|
||||
break;
|
||||
}
|
||||
if (ce == 0) {
|
||||
_empty._name = vname;
|
||||
_empty._value = def;
|
||||
_empty.delim = delim;
|
||||
if (exist != 0) *exist = false;
|
||||
return _empty;
|
||||
}
|
||||
piForeach (PIString & i, tree) {
|
||||
ce = ce->findChild(i);
|
||||
if (ce == 0) {
|
||||
_empty._name = vname;
|
||||
_empty._value = def;
|
||||
_empty.delim = delim;
|
||||
if (exist != 0) *exist = false;
|
||||
return _empty;
|
||||
}
|
||||
}
|
||||
if (exist != 0) *exist = true;
|
||||
return *ce;
|
||||
}
|
||||
|
||||
|
||||
PIConfig::Branch PIConfig::Branch::getValues(const PIString & name) {
|
||||
Branch b;
|
||||
b.delim = delim;
|
||||
piForeach (Entry * i, *this) {
|
||||
if (i->isLeaf()) {
|
||||
if (i->_name.find(name) >= 0)
|
||||
b << i;
|
||||
} else {
|
||||
piForeach (Entry * j, i->_children)
|
||||
if (j->_name.find(name) >= 0)
|
||||
b << j;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
PIConfig::Branch PIConfig::Branch::getLeaves() {
|
||||
Branch b;
|
||||
b.delim = delim;
|
||||
piForeach (Entry * i, *this)
|
||||
if (i->isLeaf())
|
||||
b << i;
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
PIConfig::Branch PIConfig::Branch::getBranches() {
|
||||
Branch b;
|
||||
b.delim = delim;
|
||||
piForeach (Entry * i, *this)
|
||||
if (!i->isLeaf())
|
||||
b << i;
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
PIConfig::Branch & PIConfig::Branch::filter(const PIString & f) {
|
||||
for (int i = 0; i < size_s(); ++i) {
|
||||
if (at(i)->_name.find(f) < 0) {
|
||||
remove(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool PIConfig::Branch::entryExists(const Entry * e, const PIString & name) const {
|
||||
if (e->_children.isEmpty()) {
|
||||
if (e->_name == name) return true;
|
||||
else return false;
|
||||
}
|
||||
piForeachC (Entry * i, e->_children)
|
||||
if (entryExists(i, name)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PIConfig::Entry & PIConfig::Entry::getValue(const PIString & vname, const PIString & def, bool * exist) {
|
||||
PIStringList tree = vname.split(delim);
|
||||
Entry * ce = this;
|
||||
piForeach (PIString & i, tree) {
|
||||
ce = ce->findChild(i);
|
||||
if (ce == 0) {
|
||||
_empty._name = vname;
|
||||
_empty._value = def;
|
||||
_empty.delim = delim;
|
||||
if (exist != 0) *exist = false;
|
||||
return _empty;
|
||||
}
|
||||
}
|
||||
if (exist != 0) *exist = true;
|
||||
return *ce;
|
||||
}
|
||||
|
||||
|
||||
PIConfig::Branch PIConfig::Entry::getValues(const PIString & vname) {
|
||||
Branch b;
|
||||
b.delim = delim;
|
||||
piForeach (Entry * i, _children)
|
||||
if (i->_name.find(vname) >= 0)
|
||||
b << i;
|
||||
return b;
|
||||
};
|
||||
|
||||
|
||||
bool PIConfig::Entry::entryExists(const Entry * e, const PIString & name) const {
|
||||
if (e->_children.isEmpty()) {
|
||||
if (e->_name == name) return true;
|
||||
else return false;
|
||||
}
|
||||
piForeachC (Entry * i, e->_children)
|
||||
if (entryExists(i, name)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PIConfig::PIConfig(const PIString & path, PIIODevice::DeviceMode mode): PIFile(path, mode) {
|
||||
delim = ".";
|
||||
root.delim = delim;
|
||||
empty.delim = delim;
|
||||
empty._parent = 0;
|
||||
if (!isOpened())
|
||||
open(path, mode);
|
||||
parse();
|
||||
}
|
||||
|
||||
|
||||
PIConfig::Entry & PIConfig::getValue(const PIString & vname, const PIString & def, bool * exist) {
|
||||
PIStringList tree = vname.split(delim);
|
||||
Entry * ce = &root;
|
||||
piForeach (PIString & i, tree) {
|
||||
ce = ce->findChild(i);
|
||||
if (ce == 0) {
|
||||
if (exist != 0) *exist = false;
|
||||
empty._name = vname;
|
||||
empty._value = def;
|
||||
empty.delim = delim;
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
if (exist != 0) *exist = true;
|
||||
return *ce;
|
||||
}
|
||||
|
||||
|
||||
PIConfig::Branch PIConfig::getValues(const PIString & vname) {
|
||||
Branch b;
|
||||
b.delim = delim;
|
||||
piForeach (Entry * i, root._children)
|
||||
if (i->_name.find(vname) >= 0)
|
||||
b << i;
|
||||
return b;
|
||||
};
|
||||
|
||||
|
||||
void PIConfig::addEntry(const PIString & name, const PIString & value, const PIString & type, bool write) {
|
||||
if (getValue(name)._parent != 0)
|
||||
return;
|
||||
bool toRoot = false;
|
||||
PIStringList tree = name.split(delim);
|
||||
PIString ename = tree.back();
|
||||
tree.pop_back();
|
||||
Entry * te, * ce, * entry = &root;
|
||||
if (tree.isEmpty()) toRoot = true;
|
||||
piForeach (PIString & i, tree) {
|
||||
te = entry->findChild(i);
|
||||
if (te == 0) {
|
||||
ce = new Entry();
|
||||
ce->delim = delim;
|
||||
ce->_tab = entry->_tab;
|
||||
ce->_line = entry->_line;
|
||||
ce->_name = i;
|
||||
ce->_parent = entry;
|
||||
entry->_children << ce;
|
||||
entry = ce;
|
||||
} else entry = te;
|
||||
}
|
||||
PIConfig::Branch ch = entry->_children;
|
||||
ch.sort(PIConfig::Entry::compare);
|
||||
te = (entry->isLeaf() ? 0 : ch.back());
|
||||
ce = new Entry();
|
||||
ce->delim = delim;
|
||||
ce->_name = ename;
|
||||
ce->_value = value;
|
||||
ce->_type = type;
|
||||
if (te == 0) {
|
||||
ce->_tab = entry->_tab;
|
||||
if (toRoot) ce->_line = other.size_s() - 1;
|
||||
else ce->_line = entry->_line;
|
||||
} else {
|
||||
ce->_tab = te->_tab;
|
||||
if (toRoot) ce->_line = other.size_s() - 1;
|
||||
else {
|
||||
ch = entry->_parent->_children;
|
||||
ch.sort(PIConfig::Entry::compare);
|
||||
ce->_line = ch.back()->_line + 1;
|
||||
}
|
||||
}
|
||||
ce->_parent = entry;
|
||||
entry->_children << ce;
|
||||
other.insert(ce->_line, "");
|
||||
Branch b = allLeaves();
|
||||
bool found = false;
|
||||
for (int i = 0; i < b.size_s(); ++i) {
|
||||
if (found) {
|
||||
b[i]->_line++;
|
||||
continue;
|
||||
}
|
||||
if (b[i] == ce) {
|
||||
found = true;
|
||||
if (i > 0)
|
||||
if (b[i - 1]->_line == b[i]->_line)
|
||||
b[i - 1]->_line++;
|
||||
}
|
||||
}
|
||||
if (write) writeAll();
|
||||
}
|
||||
|
||||
|
||||
void PIConfig::setValue(const PIString & name, const PIString & value, const PIString & type, bool write) {
|
||||
Entry & e(getValue(name));
|
||||
if (&e == &empty) {
|
||||
addEntry(name, value, type, write);
|
||||
return;
|
||||
}
|
||||
e._value = value;
|
||||
e._type = type;
|
||||
if (write) writeAll();
|
||||
}
|
||||
|
||||
|
||||
int PIConfig::entryIndex(const PIString & name) {
|
||||
PIStringList tree = name.split(delim);
|
||||
Entry * ce = &root;
|
||||
piForeach (PIString & i, tree) {
|
||||
ce = ce->findChild(i);
|
||||
if (ce == 0)
|
||||
return -1;
|
||||
}
|
||||
Branch b = allLeaves();
|
||||
return allLeaves().indexOf(ce);
|
||||
}
|
||||
|
||||
|
||||
void PIConfig::setValue(uint number, const PIString & value, bool write) {
|
||||
Entry & e(entryByIndex(number));
|
||||
if (&e == &empty) return;
|
||||
e._value = value;
|
||||
if (write) writeAll();
|
||||
}
|
||||
|
||||
|
||||
void PIConfig::setName(uint number, const PIString & name, bool write) {
|
||||
Entry & e(entryByIndex(number));
|
||||
if (&e == &empty) return;
|
||||
e._name = name;
|
||||
if (write) writeAll();
|
||||
}
|
||||
|
||||
|
||||
void PIConfig::setType(uint number, const PIString & type, bool write) {
|
||||
Entry & e(entryByIndex(number));
|
||||
if (&e == &empty) return;
|
||||
e._type = type;
|
||||
if (write) writeAll();
|
||||
}
|
||||
|
||||
|
||||
void PIConfig::setComment(uint number, const PIString & comment, bool write) {
|
||||
Entry & e(entryByIndex(number));
|
||||
if (&e == &empty) return;
|
||||
e._comment = comment;
|
||||
if (write) writeAll();
|
||||
}
|
||||
|
||||
|
||||
void PIConfig::removeEntry(const PIString & name, bool write) {
|
||||
Entry & e(getValue(name));
|
||||
if (&e == &empty) return;
|
||||
Branch b = allLeaves();
|
||||
removeEntry(b, &e);
|
||||
if (write) writeAll();
|
||||
}
|
||||
|
||||
|
||||
void PIConfig::removeEntry(uint number, bool write) {
|
||||
Entry & e(entryByIndex(number));
|
||||
if (&e == &empty) return;
|
||||
Branch b = allLeaves();
|
||||
removeEntry(b, &e);
|
||||
if (write) writeAll();
|
||||
}
|
||||
|
||||
|
||||
void PIConfig::removeEntry(Branch & b, PIConfig::Entry * e) {
|
||||
bool leaf = true;
|
||||
if (e->isLeaf()) other.remove(e->_line);
|
||||
if (!e->isLeaf() && !e->_value.isEmpty()) {
|
||||
e->_value.clear();
|
||||
leaf = false;
|
||||
} else {
|
||||
int cc = e->_children.size_s();
|
||||
piForTimes (cc)
|
||||
removeEntry(b, e->_children.back());
|
||||
}
|
||||
bool found = false;
|
||||
for (int i = 0; i < b.size_s(); ++i) {
|
||||
if (found) {
|
||||
b[i]->_line--;
|
||||
continue;
|
||||
}
|
||||
if (b[i] == e) found = true;
|
||||
}
|
||||
if (!leaf) return;
|
||||
e->_parent->_children.removeOne(e);
|
||||
b.removeOne(e);
|
||||
delete e;
|
||||
}
|
||||
|
||||
|
||||
PIString PIConfig::getPrefixFromLine(PIString line, bool * exists) {
|
||||
line.trim();
|
||||
if (line.left(1) == "#") {if (exists) *exists = false; return PIString();}
|
||||
int ci = line.find("#");
|
||||
if (ci >= 0) line.cutRight(line.size() - ci);
|
||||
if (line.find("=") >= 0) {if (exists) *exists = false; return PIString();}
|
||||
if (line.find("[") >= 0 && line.find("]") >= 0) {
|
||||
if (exists) *exists = true;
|
||||
return line.takeRange('[', ']').trim();
|
||||
}
|
||||
if (exists) *exists = false;
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
void PIConfig::writeAll() {
|
||||
//cout << this << " write < " << size() << endl;
|
||||
PIFile::clear();
|
||||
//*this << "1234567894132456798\n"; return;
|
||||
//writeEntry(&root);
|
||||
buildFullNames(&root);
|
||||
Branch b = allLeaves();
|
||||
PIString prefix, tprefix;
|
||||
bool isPrefix;
|
||||
//for (int i = 0; i < b.size_s(); ++i)
|
||||
// cout << b[i]->_name << " = " << b[i]->_value << endl;
|
||||
int j = 0;
|
||||
for (int i = 0; i < other.size_s(); ++i) {
|
||||
//cout << j << endl;
|
||||
if (j >= 0 && j < b.size_s()) {
|
||||
if (b[j]->_line == i) {
|
||||
b[j]->buildLine();
|
||||
*this << (b[j]->_all).cutLeft(prefix.size()) << '\n';
|
||||
//cout << this << " " << b[j]->_all << endl;
|
||||
++j;
|
||||
} else {
|
||||
*this << other[i];
|
||||
tprefix = getPrefixFromLine(other[i], &isPrefix);
|
||||
if (isPrefix) {
|
||||
prefix = tprefix;
|
||||
if (!prefix.isEmpty())
|
||||
prefix += delim;
|
||||
}
|
||||
if (i < other.size_s() - 1) *this << '\n';
|
||||
//cout << this << " " << other[i] << endl;
|
||||
}
|
||||
} else {
|
||||
*this << other[i];
|
||||
tprefix = getPrefixFromLine(other[i], &isPrefix);
|
||||
if (isPrefix) {
|
||||
prefix = tprefix;
|
||||
if (!prefix.isEmpty())
|
||||
prefix += delim;
|
||||
}
|
||||
if (i < other.size_s() - 1) *this << '\n';
|
||||
//cout << this << " " << other[i] << endl;
|
||||
}
|
||||
}
|
||||
flush();
|
||||
readAll();
|
||||
//cout << this << " write > " << size() << endl;
|
||||
}
|
||||
|
||||
|
||||
void PIConfig::readAll() {
|
||||
root.deleteBranch();
|
||||
root.clear();
|
||||
parse();
|
||||
}
|
||||
|
||||
|
||||
bool PIConfig::entryExists(const Entry * e, const PIString & name) const {
|
||||
if (e->_children.isEmpty()) {
|
||||
if (e->_name == name) return true;
|
||||
else return false;
|
||||
}
|
||||
piForeachC (Entry * i, e->_children)
|
||||
if (entryExists(i, name)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void PIConfig::parse() {
|
||||
PIString src, str, tab, comm, all, name, type, prefix, tprefix;
|
||||
PIStringList tree;
|
||||
Entry * entry, * te, * ce;
|
||||
int ind, sind;
|
||||
bool isNew, isPrefix;
|
||||
if (!isOpened()) return;
|
||||
seekToBegin();
|
||||
other.clear();
|
||||
lines = centry = 0;
|
||||
while (!isEnd()) {
|
||||
other.push_back(PIString());
|
||||
src = str = readLine();
|
||||
tprefix = getPrefixFromLine(src, &isPrefix);
|
||||
if (isPrefix) {
|
||||
prefix = tprefix;
|
||||
if (!prefix.isEmpty())
|
||||
prefix += delim;
|
||||
}
|
||||
tab = str.left(str.find(str.trimmed().left(1)));
|
||||
str.trim();
|
||||
//cout << endl << str << endl << endl;
|
||||
all = str;
|
||||
ind = str.find('=');
|
||||
if ((ind > 0) && !(str[0] == '#')) {
|
||||
sind = str.find('#');
|
||||
if (sind > 0) {
|
||||
comm = str.right(str.length() - sind - 1).trimmed();
|
||||
if (comm.length() > 0) type = comm[0];
|
||||
else type = "s";
|
||||
comm = comm.right(comm.length() - 1).trimmed();
|
||||
str = str.left(sind);
|
||||
} else {
|
||||
type = "s";
|
||||
comm = "";
|
||||
}
|
||||
//name = str.left(ind).trimmed();
|
||||
tree = (prefix + str.left(ind).trimmed()).split(delim);
|
||||
name = tree.back();
|
||||
tree.pop_back();
|
||||
entry = &root;
|
||||
piForeachC (PIString & i, tree) {
|
||||
te = entry->findChild(i);
|
||||
if (te == 0) {
|
||||
ce = new Entry();
|
||||
ce->delim = delim;
|
||||
ce->_tab = tab;
|
||||
ce->_line = lines;
|
||||
ce->_name = i;
|
||||
ce->_parent = entry;
|
||||
entry->_children << ce;
|
||||
entry = ce;
|
||||
} else entry = te;
|
||||
}
|
||||
isNew = false;
|
||||
ce = entry->findChild(name);
|
||||
if (ce == 0) {
|
||||
ce = new Entry();
|
||||
isNew = true;
|
||||
}
|
||||
ce->delim = delim;
|
||||
ce->_tab = tab;
|
||||
ce->_name = name;
|
||||
ce->_value = str.right(str.length() - ind - 1).trimmed();
|
||||
ce->_type = type;
|
||||
ce->_comment = comm;
|
||||
ce->_line = lines;
|
||||
ce->_all = all;
|
||||
if (isNew) {
|
||||
ce->_parent = entry;
|
||||
entry->_children << ce;
|
||||
}
|
||||
} else other.back() = src;
|
||||
lines++;
|
||||
}
|
||||
setEntryDelim(&root, delim);
|
||||
buildFullNames(&root);
|
||||
}
|
||||
502
piconfig.h
502
piconfig.h
@@ -1,502 +0,0 @@
|
||||
/*! \file piconfig.h
|
||||
* \brief Configuration file
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Config parser
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PICONFIG_H
|
||||
#define PICONFIG_H
|
||||
|
||||
#include "pifile.h"
|
||||
|
||||
#define PICONFIG_GET_VALUE \
|
||||
Entry & getValue(const PIString & vname, const char * def, bool * exists = 0) {return getValue(vname, PIString(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const PIStringList & def, bool * exists = 0) {return getValue(vname, def.join("%|%"), exists);} \
|
||||
Entry & getValue(const PIString & vname, const bool def, bool * exists = 0) {return getValue(vname, PIString::fromBool(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const short def, bool * exists = 0) {return getValue(vname, itos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const int def, bool * exists = 0) {return getValue(vname, itos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const long def, bool * exists = 0) {return getValue(vname, ltos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const uchar def, bool * exists = 0) {return getValue(vname, uitos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const ushort def, bool * exists = 0) {return getValue(vname, uitos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const uint def, bool * exists = 0) {return getValue(vname, uitos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const ulong def, bool * exists = 0) {return getValue(vname, ultos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const float def, bool * exists = 0) {return getValue(vname, ftos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const double def, bool * exists = 0) {return getValue(vname, dtos(def), exists);} \
|
||||
\
|
||||
Entry & getValue(const PIString & vname, const char * def, bool * exists = 0) const {return getValue(vname, PIString(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const PIStringList & def, bool * exists = 0) const {return getValue(vname, def.join("%|%"), exists);} \
|
||||
Entry & getValue(const PIString & vname, const bool def, bool * exists = 0) const {return getValue(vname, PIString::fromBool(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const short def, bool * exists = 0) const {return getValue(vname, itos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const int def, bool * exists = 0) const {return getValue(vname, itos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const long def, bool * exists = 0) const {return getValue(vname, ltos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const uchar def, bool * exists = 0) const {return getValue(vname, uitos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const ushort def, bool * exists = 0) const {return getValue(vname, uitos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const uint def, bool * exists = 0) const {return getValue(vname, uitos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const ulong def, bool * exists = 0) const {return getValue(vname, ultos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const float def, bool * exists = 0) const {return getValue(vname, ftos(def), exists);} \
|
||||
Entry & getValue(const PIString & vname, const double def, bool * exists = 0) const {return getValue(vname, dtos(def), exists);}
|
||||
|
||||
class PIP_EXPORT PIConfig: public PIFile
|
||||
{
|
||||
friend class Entry;
|
||||
friend class Branch;
|
||||
public:
|
||||
|
||||
//! Contructs and read configuration file at path "path" in mode "mode"
|
||||
PIConfig(const PIString & path, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
|
||||
|
||||
~PIConfig() {root.deleteBranch(); close();}
|
||||
|
||||
class Entry;
|
||||
|
||||
|
||||
class PIP_EXPORT Branch: public PIVector<Entry * > {
|
||||
friend class PIConfig;
|
||||
friend class Entry;
|
||||
friend std::ostream & operator <<(std::ostream & s, const Branch & v);
|
||||
friend PICout operator <<(PICout s, const Branch & v);
|
||||
public:
|
||||
Branch() {;}
|
||||
|
||||
Entry & getValue(const PIString & vname, const PIString & def = PIString(), bool * exists = 0);
|
||||
Entry & getValue(const PIString & vname, const PIString & def = PIString(), bool * exists = 0) const {return const_cast<Branch * >(this)->getValue(vname, def, exists);}
|
||||
PICONFIG_GET_VALUE
|
||||
|
||||
Branch allLeaves();
|
||||
Branch getValues(const PIString & name);
|
||||
Branch getLeaves();
|
||||
Branch getBranches();
|
||||
Branch & filter(const PIString & f);
|
||||
bool isEntryExists(const PIString & name) const {piForeachC (Entry * i, *this) if (entryExists(i, name)) return true; return false;}
|
||||
int indexOf(const Entry * e) {for (int i = 0; i < size_s(); ++i) if (at(i) == e) return i; return -1;}
|
||||
|
||||
//void clear() {piForeach (Entry * i, *this) delete i; PIVector<Entry * >::clear();}
|
||||
|
||||
private:
|
||||
bool entryExists(const Entry * e, const PIString & name) const;
|
||||
void allLeaves(Branch & b, Entry * e) {piForeach (Entry * i, e->_children) {if (i->isLeaf()) b << i; else allLeaves(b, i);}}
|
||||
void coutt(std::ostream & s, const PIString & p) const {piForeachC (Entry * i, *this) i->coutt(s, p);}
|
||||
void piCoutt(PICout s, const PIString & p) const {piForeachC (Entry * i, *this) i->piCoutt(s, p);}
|
||||
|
||||
static Entry _empty;
|
||||
PIString delim;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class PIP_EXPORT Entry {
|
||||
friend class PIConfig;
|
||||
friend class Branch;
|
||||
public:
|
||||
Entry() {_parent = 0;}
|
||||
|
||||
//! Returns parent entry, or 0 if there is no parent (root of default value)
|
||||
Entry * parent() const {return _parent;}
|
||||
|
||||
//! Returns children count
|
||||
int childCount() const {return _children.size_s();}
|
||||
|
||||
//! Returns children as \a PIConfig::Branch
|
||||
Branch & children() const {_children.delim = delim; return _children;}
|
||||
|
||||
//! Returns child at index "index"
|
||||
Entry * child(const int index) const {return _children[index];}
|
||||
|
||||
//! Returns first child with name "name"
|
||||
Entry * findChild(const PIString & name) {piForeach (Entry * i, _children) if (i->_name == name) return i; return 0;}
|
||||
|
||||
//! Returns first child with name "name"
|
||||
const Entry * findChild(const PIString & name) const {piForeachC (Entry * i, _children) if (i->_name == name) return i; return 0;}
|
||||
|
||||
//! Returns \b true if there is no children
|
||||
bool isLeaf() const {return _children.isEmpty();}
|
||||
|
||||
|
||||
//! Returns name
|
||||
const PIString & name() const {return _name;}
|
||||
|
||||
//! Returns value
|
||||
const PIString & value() const {return _value;}
|
||||
|
||||
//! Returns type
|
||||
const PIString & type() const {return _type;}
|
||||
|
||||
//! Returns comment
|
||||
const PIString & comment() const {return _comment;}
|
||||
|
||||
/** \brief Returns full name, i.e. name as it looks in file
|
||||
* \details In case of default entry full name always is empty
|
||||
* \snippet piconfig.cpp fullName */
|
||||
const PIString & fullName() const {return _full_name;}
|
||||
|
||||
//! Set name to "value" and returns this
|
||||
Entry & setName(const PIString & value) {_name = value; return *this;}
|
||||
|
||||
//! Set type to "value" and returns this
|
||||
Entry & setType(const PIString & value) {_type = value; return *this;}
|
||||
|
||||
//! Set comment to "value" and returns this
|
||||
Entry & setComment(const PIString & value) {_comment = value; return *this;}
|
||||
|
||||
//! Set value to "value" and returns this
|
||||
Entry & setValue(const PIString & value) {_value = value; return *this;}
|
||||
|
||||
//! Set value to "value" and returns this. Type is set to "l"
|
||||
Entry & setValue(const PIStringList & value) {setValue(value.join("%|%")); setType("l"); return *this;}
|
||||
|
||||
//! Set value to "value" and returns this. Type is set to "s"
|
||||
Entry & setValue(const char * value) {setValue(PIString(value)); setType("s"); return *this;}
|
||||
|
||||
//! Set value to "value" and returns this. Type is set to "b"
|
||||
Entry & setValue(const bool value) {setValue(btos(value)); setType("b"); return *this;}
|
||||
|
||||
//! Set value to "value" and returns this. Type is set to "s"
|
||||
Entry & setValue(const char value) {setValue(PIString(1, value)); setType("s"); return *this;}
|
||||
|
||||
//! Set value to "value" and returns this. Type is set to "n"
|
||||
Entry & setValue(const short value) {setValue(itos(value)); setType("n"); return *this;}
|
||||
|
||||
//! Set value to "value" and returns this. Type is set to "n"
|
||||
Entry & setValue(const int value) {setValue(itos(value)); setType("n"); return *this;}
|
||||
|
||||
//! Set value to "value" and returns this. Type is set to "n"
|
||||
Entry & setValue(const long value) {setValue(ltos(value)); setType("n"); return *this;}
|
||||
|
||||
//! Set value to "value" and returns this. Type is set to "n"
|
||||
Entry & setValue(const uchar value) {setValue(uitos(value)); setType("n"); return *this;}
|
||||
|
||||
//! Set value to "value" and returns this. Type is set to "n"
|
||||
Entry & setValue(const ushort value) {setValue(uitos(value)); setType("n"); return *this;}
|
||||
|
||||
//! Set value to "value" and returns this. Type is set to "n"
|
||||
Entry & setValue(const uint value) {setValue(uitos(value)); setType("n"); return *this;}
|
||||
|
||||
//! Set value to "value" and returns this. Type is set to "n"
|
||||
Entry & setValue(const ulong value) {setValue(ultos(value)); setType("n"); return *this;}
|
||||
|
||||
//! Set value to "value" and returns this. Type is set to "f"
|
||||
Entry & setValue(const float value) {setValue(ftos(value)); setType("f"); return *this;}
|
||||
|
||||
//! Set value to "value" and returns this. Type is set to "f"
|
||||
Entry & setValue(const double value) {setValue(dtos(value)); setType("f"); return *this;}
|
||||
|
||||
|
||||
/** \brief Returns entry with name "vname" and default value "def"
|
||||
* \details If there is no suitable entry found, reference to default internal entry with
|
||||
* value = "def" will be returned, and if "exists" not null it will be set to \b false */
|
||||
Entry & getValue(const PIString & vname, const PIString & def = PIString(), bool * exists = 0);
|
||||
Entry & getValue(const PIString & vname, const PIString & def = PIString(), bool * exists = 0) const {return const_cast<Entry * >(this)->getValue(vname, def, exists);}
|
||||
PICONFIG_GET_VALUE
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const char * def, bool * exists = 0)
|
||||
//! \brief Returns entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const char * def, bool * exists = 0)
|
||||
//! \brief Returns entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const PIStringList & def, bool * exists = 0)
|
||||
//! \brief Returns entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const bool def, bool * exists = 0)
|
||||
//! \brief Returns entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const short def, bool * exists = 0)
|
||||
//! \brief Returns entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const int def, bool * exists = 0)
|
||||
//! \brief Returns entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const long def, bool * exists = 0)
|
||||
//! \brief Returns entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const uchar def, bool * exists = 0)
|
||||
//! \brief Returns entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const ushort def, bool * exists = 0)
|
||||
//! \brief Returns entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const uint def, bool * exists = 0)
|
||||
//! \brief Returns entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const ulong def, bool * exists = 0)
|
||||
//! \brief Returns entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const float def, bool * exists = 0)
|
||||
//! \brief Returns entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const double def, bool * exists = 0)
|
||||
//! \brief Returns entry with name "vname" and default value "def"
|
||||
|
||||
|
||||
//! Find all entries with names with substrings "vname" and returns them as \a PIConfig::Branch
|
||||
Branch getValues(const PIString & vname);
|
||||
|
||||
|
||||
//! If there is no children returns if name == "name". Else returns if any child has name == "name"
|
||||
bool isEntryExists(const PIString & name) const {return entryExists(this, name);}
|
||||
|
||||
|
||||
//! Convertion to boolean
|
||||
operator bool() {return _value.toBool();}
|
||||
|
||||
//! Convertion to char
|
||||
operator char() {return (_value.isEmpty() ? 0 : _value[0].toAscii());}
|
||||
|
||||
//! Convertion to short
|
||||
operator short() {return _value.toShort();}
|
||||
|
||||
//! Convertion to int
|
||||
operator int() {return _value.toInt();}
|
||||
|
||||
//! Convertion to long
|
||||
operator long() {return _value.toLong();}
|
||||
|
||||
//! Convertion to uchar
|
||||
operator uchar() {return _value.toInt();}
|
||||
|
||||
//! Convertion to ushort
|
||||
operator ushort() {return _value.toShort();}
|
||||
|
||||
//! Convertion to uint
|
||||
operator uint() {return _value.toInt();}
|
||||
|
||||
//! Convertion to ulong
|
||||
operator ulong() {return _value.toLong();}
|
||||
|
||||
//! Convertion to float
|
||||
operator float() {return _value.toFloat();}
|
||||
|
||||
//! Convertion to double
|
||||
operator double() {return _value.toDouble();}
|
||||
|
||||
//! Convertion to PIString
|
||||
operator PIString() {return _value;}
|
||||
|
||||
//! Convertion to PIStringList
|
||||
operator PIStringList() {return _value.split("%|%");}
|
||||
|
||||
private:
|
||||
typedef PIConfig::Entry * EntryPtr;
|
||||
static int compare(const EntryPtr * f, const EntryPtr * s) {return (*f)->_line == (*s)->_line ? 0 : (*f)->_line < (*s)->_line ? -1 : 1;}
|
||||
bool entryExists(const Entry * e, const PIString & name) const;
|
||||
void buildLine() {_all = _tab + _full_name + " = " + _value + " #" + _type + " " + _comment;}
|
||||
void clear() {_children.clear(); _name = _value = _type = _comment = _all = PIString(); _line = 0; _parent = 0;}
|
||||
void coutt(std::ostream & s, const PIString & p) const {PIString nl = p + " "; if (!_value.isEmpty()) s << p << _name << " = " << _value << endl; else cout << p << _name << endl; piForeachC (Entry * i, _children) i->coutt(s, nl);}
|
||||
void piCoutt(PICout s, const PIString & p) const {PIString nl = p + " "; if (!_value.isEmpty()) s << p << _name << " = " << _value << NewLine; else cout << p << _name << endl; piForeachC (Entry * i, _children) i->piCoutt(s, nl);}
|
||||
void deleteBranch() {piForeach (Entry * i, _children) {i->deleteBranch(); delete i;}}
|
||||
|
||||
static Entry _empty;
|
||||
Entry * _parent;
|
||||
mutable Branch _children;
|
||||
PIString _tab;
|
||||
PIString _name;
|
||||
PIString _value;
|
||||
PIString _type;
|
||||
PIString _comment;
|
||||
PIString _all;
|
||||
PIString _full_name;
|
||||
PIString delim;
|
||||
int _line;
|
||||
};
|
||||
|
||||
|
||||
//! Returns top-level entry with name "vname", if doesn`t exists return entry with value "def" and set *exist to false
|
||||
Entry & getValue(const PIString & vname, const PIString & def = PIString(), bool * exists = 0);
|
||||
Entry & getValue(const PIString & vname, const PIString & def = PIString(), bool * exists = 0) const {return const_cast<PIConfig * >(this)->getValue(vname, def, exists);}
|
||||
|
||||
PICONFIG_GET_VALUE
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const char * def, bool * exists = 0)
|
||||
//! \brief Returns top-level entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const char * def, bool * exists = 0)
|
||||
//! \brief Returns top-level entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const PIStringList & def, bool * exists = 0)
|
||||
//! \brief Returns top-level entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const bool def, bool * exists = 0)
|
||||
//! \brief Returns top-level entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const short def, bool * exists = 0)
|
||||
//! \brief Returns top-level entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const int def, bool * exists = 0)
|
||||
//! \brief Returns top-level entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const long def, bool * exists = 0)
|
||||
//! \brief Returns top-level entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const uchar def, bool * exists = 0)
|
||||
//! \brief Returns top-level entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const ushort def, bool * exists = 0)
|
||||
//! \brief Returns top-level entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const uint def, bool * exists = 0)
|
||||
//! \brief Returns top-level entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const ulong def, bool * exists = 0)
|
||||
//! \brief Returns top-level entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const float def, bool * exists = 0)
|
||||
//! \brief Returns top-level entry with name "vname" and default value "def"
|
||||
|
||||
//! \fn Entry & getValue(const PIString & vname, const double def, bool * exists = 0)
|
||||
//! \brief Returns top-level entry with name "vname" and default value "def"
|
||||
|
||||
|
||||
//! Returns top-level entries with names with substrings "vname"
|
||||
Branch getValues(const PIString & vname);
|
||||
|
||||
|
||||
//! Set top-level entry with name "name" value to "value", type to "type" and if "write" immediate write to file. Add new entry if there is no suitable exists
|
||||
void setValue(const PIString & name, const PIString & value, const PIString & type = "s", bool write = true);
|
||||
|
||||
//! Set top-level entry with name "name" value to "value", type to "l" and if "write" immediate write to file. Add new entry if there is no suitable exists
|
||||
void setValue(const PIString & name, const PIStringList & value, bool write = true) {setValue(name, value.join("%|%"), "l", write);}
|
||||
|
||||
//! Set top-level entry with name "name" value to "value", type to "s" and if "write" immediate write to file. Add new entry if there is no suitable exists
|
||||
void setValue(const PIString & name, const char * value, bool write = true) {setValue(name, PIString(value), "s", write);}
|
||||
|
||||
//! Set top-level entry with name "name" value to "value", type to "b" and if "write" immediate write to file. Add new entry if there is no suitable exists
|
||||
void setValue(const PIString & name, const bool value, bool write = true) {setValue(name, btos(value), "b", write);}
|
||||
|
||||
//! Set top-level entry with name "name" value to "value", type to "n" and if "write" immediate write to file. Add new entry if there is no suitable exists
|
||||
void setValue(const PIString & name, const short value, bool write = true) {setValue(name, itos(value), "n", write);}
|
||||
|
||||
//! Set top-level entry with name "name" value to "value", type to "n" and if "write" immediate write to file. Add new entry if there is no suitable exists
|
||||
void setValue(const PIString & name, const int value, bool write = true) {setValue(name, itos(value), "n", write);}
|
||||
|
||||
//! Set top-level entry with name "name" value to "value", type to "n" and if "write" immediate write to file. Add new entry if there is no suitable exists
|
||||
void setValue(const PIString & name, const long value, bool write = true) {setValue(name, ltos(value), "n", write);}
|
||||
|
||||
//! Set top-level entry with name "name" value to "value", type to "n" and if "write" immediate write to file. Add new entry if there is no suitable exists
|
||||
void setValue(const PIString & name, const uchar value, bool write = true) {setValue(name, uitos(value), "n", write);}
|
||||
|
||||
//! Set top-level entry with name "name" value to "value", type to "n" and if "write" immediate write to file. Add new entry if there is no suitable exists
|
||||
void setValue(const PIString & name, const ushort value, bool write = true) {setValue(name, uitos(value), "n", write);}
|
||||
|
||||
//! Set top-level entry with name "name" value to "value", type to "n" and if "write" immediate write to file. Add new entry if there is no suitable exists
|
||||
void setValue(const PIString & name, const uint value, bool write = true) {setValue(name, uitos(value), "n", write);}
|
||||
|
||||
//! Set top-level entry with name "name" value to "value", type to "n" and if "write" immediate write to file. Add new entry if there is no suitable exists
|
||||
void setValue(const PIString & name, const ulong value, bool write = true) {setValue(name, ultos(value), "n", write);}
|
||||
|
||||
//! Set top-level entry with name "name" value to "value", type to "f" and if "write" immediate write to file. Add new entry if there is no suitable exists
|
||||
void setValue(const PIString & name, const float value, bool write = true) {setValue(name, ftos(value), "f", write);}
|
||||
|
||||
//! Set top-level entry with name "name" value to "value", type to "f" and if "write" immediate write to file. Add new entry if there is no suitable exists
|
||||
void setValue(const PIString & name, const double value, bool write = true) {setValue(name, dtos(value), "f", write);}
|
||||
|
||||
//! Returns root entry
|
||||
Entry & rootEntry() {return root;}
|
||||
|
||||
//! Returns top-level entries count
|
||||
int entriesCount() const {return childCount(&root);}
|
||||
|
||||
//! Returns if top-level entry with name "name" exists
|
||||
bool isEntryExists(const PIString & name) const {return entryExists(&root, name);}
|
||||
|
||||
//! Returns all top-level entries
|
||||
Branch allTree() {Branch b; piForeach (Entry * i, root._children) b << i; b.delim = delim; return b;}
|
||||
|
||||
//! Returns all entries without children
|
||||
Branch allLeaves() {Branch b; allLeaves(b, &root); b.sort(Entry::compare); b.delim = delim; return b;}
|
||||
|
||||
int entryIndex(const PIString & name);
|
||||
|
||||
PIString getName(uint number) {return entryByIndex(number)._name;}
|
||||
PIString getValue(uint number) {return entryByIndex(number)._value;}
|
||||
PIChar getType(uint number) {return entryByIndex(number)._type[0];}
|
||||
PIString getComment(uint number) {return entryByIndex(number)._comment;}
|
||||
|
||||
void addEntry(const PIString & name, const PIString & value, const PIString & type = "s", bool write = true);
|
||||
void setName(uint number, const PIString & name, bool write = true);
|
||||
void setValue(uint number, const PIString & value, bool write = true);
|
||||
void setType(uint number, const PIString & type, bool write = true);
|
||||
void setComment(uint number, const PIString & comment, bool write = true);
|
||||
|
||||
void removeEntry(const PIString & name, bool write = true);
|
||||
void removeEntry(uint number, bool write = true);
|
||||
|
||||
//! Remove all tree and file content
|
||||
void clear() {PIFile::clear(); parse();}
|
||||
|
||||
//! Parse file and build internal tree
|
||||
void readAll();
|
||||
|
||||
//! Write all internal tree to file
|
||||
void writeAll();
|
||||
|
||||
//! Returns current tree delimiter, default "."
|
||||
const PIString & delimiter() const {return delim;}
|
||||
|
||||
//! Set current tree delimiter
|
||||
void setDelimiter(const PIString & d) {delim = d; setEntryDelim(&root, d); readAll();}
|
||||
|
||||
private:
|
||||
int childCount(const Entry * e) const {int c = 0; piForeachC (Entry * i, e->_children) c += childCount(i); c += e->_children.size_s(); return c;}
|
||||
bool entryExists(const Entry * e, const PIString & name) const;
|
||||
void buildFullNames(Entry * e) {piForeach (Entry * i, e->_children) {if (e != &root) i->_full_name = e->_full_name + delim + i->_name; else i->_full_name = i->_name; buildFullNames(i);}}
|
||||
void allLeaves(Branch & b, Entry * e) {piForeach (Entry * i, e->_children) {if ((!i->_value.isEmpty() && !i->isLeaf()) || i->isLeaf()) b << i; allLeaves(b, i);}}
|
||||
void setEntryDelim(Entry * e, const PIString & d) {piForeach (Entry * i, e->_children) setEntryDelim(i, d); e->delim = d;}
|
||||
Entry & entryByIndex(const int index) {Branch b = allLeaves(); if (index < 0 || index >= b.size_s()) return empty; return *(b[index]);}
|
||||
void removeEntry(Branch & b, Entry * e);
|
||||
void deleteEntry(Entry * e) {piForeach (Entry * i, e->_children) deleteEntry(i); delete e;}
|
||||
PIString getPrefixFromLine(PIString line, bool * exists);
|
||||
void parse();
|
||||
|
||||
int centry;
|
||||
PIString delim;
|
||||
Entry root, empty;
|
||||
uint lines;
|
||||
PIStringList other;
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIConfig::Branch & v) {v.coutt(s, ""); return s;}
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIConfig::Entry & v) {s << v.value(); return s;}
|
||||
inline PICout operator <<(PICout s, const PIConfig::Branch & v) {s.setControl(0, true); v.piCoutt(s, ""); s.restoreControl(); return s;}
|
||||
inline PICout operator <<(PICout s, const PIConfig::Entry & v) {s << v.value(); return s;}
|
||||
|
||||
|
||||
/** \relatesalso PIConfig \relatesalso PIIODevice
|
||||
* \brief Service function. useful for configuring devices
|
||||
* \details Function takes entry name "name", default value "def" and two
|
||||
* \a PIConfig::Entry sections: "em" and their parent "ep". If there is no
|
||||
* parent ep = 0. If "ep" is not null and entry "name" exists in "ep" function
|
||||
* returns this value. Else returns value of entry "name" in section "em" or
|
||||
* "def" if entry doesn`t exists. \n This function useful to read settings
|
||||
* from configuration file in implementation \a PIIODevice::configureDevice() function */
|
||||
template<typename T>
|
||||
T readDeviceSetting(const PIString & name, const T & def, const PIConfig::Entry * em, const PIConfig::Entry * ep) {
|
||||
if (ep != 0) {
|
||||
T ret;
|
||||
bool ex;
|
||||
ret = ep->getValue(name, def, &ex);
|
||||
if (!ex) ret = em->getValue(name, def);
|
||||
return ret;
|
||||
}
|
||||
return em->getValue(name, def);
|
||||
|
||||
}
|
||||
|
||||
#endif // PICONFIG_H
|
||||
764
piconnection.cpp
764
piconnection.cpp
@@ -1,764 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Complex I/O point
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piconnection.h"
|
||||
#include "piconfig.h"
|
||||
|
||||
/** \class PIConnection
|
||||
* \brief Complex Input/Output point
|
||||
*
|
||||
* \section PIConnection_synopsis Synopsis
|
||||
* %PIConnection provides abstract layer over physical devices,
|
||||
* filtering and connecting data streams. Each %PIConnection
|
||||
* works through Device Pool, so several %PIConnections can
|
||||
* read from single physical device. General scheme:
|
||||
* \image html piconnection.png
|
||||
*
|
||||
* \section PIConnection_pool Device pool concept
|
||||
* Device pool is static object, single for each application, which
|
||||
* contains unique devices. Each %PIConnection works with real devices
|
||||
* through Device pool. Each device has assosiated thread for read
|
||||
* and it can be started or stopped with %PIConnection functions
|
||||
* \a startThreadedRead() and \a stopThreadedRead().
|
||||
*
|
||||
* \section PIConnection_config Configuration
|
||||
* You can create %PIConnection from config file section or configure
|
||||
* it later with function \a configureFromConfig(). Devices describes
|
||||
* with its full pathes, for details see \ref PIIODevice_sec7. Example:
|
||||
* \image html piconnection_conf.png
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
PIVector<PIConnection * > PIConnection::_connections;
|
||||
|
||||
|
||||
PIConnection::PIConnection(): PIObject() {
|
||||
_connections << this;
|
||||
}
|
||||
|
||||
|
||||
PIConnection::PIConnection(const PIString & config, const PIString & name_): PIObject(name_) {
|
||||
_connections << this;
|
||||
configureFromConfig(config, name_);
|
||||
}
|
||||
|
||||
|
||||
PIConnection::~PIConnection() {
|
||||
__device_pool__->unboundConnection(this);
|
||||
removeAllFilters();
|
||||
_connections.removeAll(this);
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::configureFromConfig(const PIString & conf_path, const PIString & name_) {
|
||||
PIConfig conf(conf_path, PIIODevice::ReadOnly);
|
||||
if (!conf.isOpened()) return false;
|
||||
__device_pool__->unboundConnection(this);
|
||||
removeAllChannels();
|
||||
removeAllFilters();
|
||||
removeAllDevices();
|
||||
setName(name_);
|
||||
PIConfig::Entry ce(conf.getValue(name_));
|
||||
PIConfig::Branch db(ce.getValue("device").children()), fb(ce.getValue("filter").children()), cb(ce.getValue("channel").children());
|
||||
PIStringList dev_list(ce.getValue("device").value());
|
||||
piForeachC (PIConfig::Entry * e, db)
|
||||
dev_list << e->value();
|
||||
dev_list.removeStrings("");
|
||||
piForeachC (PIString & s, dev_list) {
|
||||
PIString fn(s);
|
||||
PIIODevice::DeviceMode dm = PIIODevice::ReadWrite;
|
||||
if (fn.find("(") > 0 && fn.find(")") > 0) {
|
||||
PIString dms(fn.right(fn.length() - fn.find("(")).takeRange("(", ")").trim().toLowerCase().removeAll(" "));
|
||||
//piCout << dms;
|
||||
if (dms == "r" || dms == "ro" || dms == "read" || dms == "readonly")
|
||||
dm = PIIODevice::ReadOnly;
|
||||
if (dms == "w" || dms == "wo" || dms == "write" || dms == "writeonly")
|
||||
dm = PIIODevice::WriteOnly;
|
||||
fn.cutRight(fn.length() - fn.find("(") + 1).trim();
|
||||
}
|
||||
//piCout << fn;
|
||||
PIIODevice * dev = addDevice(fn, dm);
|
||||
if (dev) dev->setName(name_ + ".device." + s);
|
||||
}
|
||||
piForeachC (PIConfig::Entry * e, fb) {
|
||||
PIPacketExtractor::SplitMode sm = PIPacketExtractor::None;
|
||||
PIString sms(e->getValue("splitMode").value());
|
||||
int smi = sms.toInt();
|
||||
if (smi >= 1 && smi <= 5) sm = (PIPacketExtractor::SplitMode)smi;
|
||||
else {
|
||||
sms = sms.trim().toLowerCase();
|
||||
if (sms.find("header") >= 0 && sms.find("footer") >= 0)
|
||||
sm = PIPacketExtractor::HeaderAndFooter;
|
||||
else {
|
||||
if (sms.find("header") >= 0)
|
||||
sm = PIPacketExtractor::Header;
|
||||
else {
|
||||
if (sms.find("footer") >= 0)
|
||||
sm = PIPacketExtractor::Footer;
|
||||
else {
|
||||
if (sms.find("time") >= 0)
|
||||
sm = PIPacketExtractor::Timeout;
|
||||
else {
|
||||
if (sms.find("size") >= 0)
|
||||
sm = PIPacketExtractor::Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PIStringList devs(e->value());
|
||||
PIConfig::Branch db(e->getValue("device").children());
|
||||
piForeachC (PIConfig::Entry * e2, db)
|
||||
devs << e2->value();
|
||||
devs.removeStrings("");
|
||||
if (devs.isEmpty()) continue;
|
||||
PIPacketExtractor * pe = addFilter(e->name(), devs.front(), sm);
|
||||
if (pe == 0) continue;
|
||||
for (int i = 1; i < devs.size_s(); ++i)
|
||||
addFilter(e->name(), devs[i], sm);
|
||||
pe->setPayloadSize(e->getValue("payloadSize", pe->payloadSize()));
|
||||
pe->setPacketSize(e->getValue("packetSize", pe->packetSize()));
|
||||
pe->setTimeout(e->getValue("timeout", pe->timeout()));
|
||||
pe->setHeader(PIByteArray::fromString(e->getValue("header", "").value()));
|
||||
pe->setFooter(PIByteArray::fromString(e->getValue("footer", "").value()));
|
||||
}
|
||||
piForeachC (PIConfig::Entry * e, cb) {
|
||||
PIString f(e->getValue("from").value()), t(e->getValue("to").value());
|
||||
addChannel(f, t);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PIString PIConnection::makeConfig() const {
|
||||
PIString ret;
|
||||
ret << "[" << name() << "]\n";
|
||||
PIVector<PIIODevice * > devs(boundedDevices());
|
||||
int dn(0);
|
||||
piForeachC (PIIODevice * d, devs) {
|
||||
ret << "device." << dn << " = " << d->constructFullPath(); ++dn;
|
||||
if (d->mode() == PIIODevice::ReadOnly) ret << " (ro)";
|
||||
if (d->mode() == PIIODevice::WriteOnly) ret << " (wo)";
|
||||
ret << "\n";
|
||||
}
|
||||
piForeachC (PEPair & f, extractors) {
|
||||
if (f.second == 0) continue;
|
||||
if (f.second->extractor == 0) continue;
|
||||
PIString prefix = "filter." + f.first;
|
||||
for (int i = 0; i < f.second->devices.size_s(); ++i)
|
||||
ret << prefix << ".device." << i << " = " << f.second->devices[i]->constructFullPath() << "\n";
|
||||
ret << prefix << ".splitMode = ";
|
||||
switch (f.second->extractor->splitMode()) {
|
||||
case PIPacketExtractor::None: ret << "none"; break;
|
||||
case PIPacketExtractor::Header: ret << "header"; break;
|
||||
case PIPacketExtractor::Footer: ret << "footer"; break;
|
||||
case PIPacketExtractor::HeaderAndFooter: ret << "header & footer"; break;
|
||||
case PIPacketExtractor::Size: ret << "size"; break;
|
||||
case PIPacketExtractor::Timeout: ret << "timeout"; break;
|
||||
}
|
||||
ret << "\n";
|
||||
ret << prefix << ".payloadSize = " << f.second->extractor->payloadSize() << "\n";
|
||||
ret << prefix << ".packetSize = " << f.second->extractor->packetSize() << "\n";
|
||||
ret << prefix << ".timeout = " << f.second->extractor->timeout() << "\n";
|
||||
ret << prefix << ".header = " << f.second->extractor->header().toString() << "\n";
|
||||
ret << prefix << ".footer = " << f.second->extractor->footer().toString() << "\n";
|
||||
}
|
||||
dn = 0;
|
||||
piForeachC (CPair & c, channels_) {
|
||||
piForeachC (PIIODevice * d, c.second) {
|
||||
PIString prefix = "channel." + PIString::fromNumber(dn); ++dn;
|
||||
ret << prefix << ".from = " << devPath(c.first) << "\n";
|
||||
ret << prefix << ".to = " << devPath(d) << "\n";
|
||||
}
|
||||
}
|
||||
ret << "[]\n";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIIODevice * PIConnection::addDevice(const PIString & full_path, PIIODevice::DeviceMode mode, bool start) {
|
||||
PIIODevice * dev = __device_pool__->addDevice(this, full_path, mode, start);
|
||||
if (dev) {
|
||||
dev->setName(name() + ".device." + full_path);
|
||||
device_modes[dev] = mode;
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::removeDevice(const PIString & full_path) {
|
||||
PIIODevice * dev = __device_pool__->device(full_path);
|
||||
if (dev == 0) return false;
|
||||
device_modes.remove(dev);
|
||||
piForeachC (PEPair & i, extractors) {
|
||||
if (i.second == 0) continue;
|
||||
i.second->devices.removeAll(dev);
|
||||
}
|
||||
bounded_extractors.remove(dev);
|
||||
channels_.remove(dev);
|
||||
for (PIMap<PIIODevice * , PIVector<PIIODevice * > >::iterator it = channels_.begin(); it != channels_.end(); ++it)
|
||||
it.value().removeAll(dev);
|
||||
return __device_pool__->removeDevice(this, full_path);
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::removeAllDevices() {
|
||||
PIVector<PIIODevice * > bdevs(__device_pool__->boundedDevices(this));
|
||||
piForeach (PIIODevice * d, bdevs) {
|
||||
channels_.remove(d);
|
||||
for (PIMap<PIIODevice * , PIVector<PIIODevice * > >::iterator it = channels_.begin(); it != channels_.end(); ++it)
|
||||
it.value().removeAll(d);
|
||||
}
|
||||
__device_pool__->unboundConnection(this);
|
||||
device_modes.clear();
|
||||
bounded_extractors.clear();
|
||||
piForeachC (PEPair & i, extractors) {
|
||||
if (i.second == 0) continue;
|
||||
i.second->devices.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIIODevice * PIConnection::device(const PIString & full_path) const {
|
||||
DevicePool::DeviceData * dd = __device_pool__->devices.value(full_path);
|
||||
if (dd == 0) return 0;
|
||||
if (dd->dev == 0) return 0;
|
||||
if (!dd->listeners.contains(const_cast<PIConnection * >(this))) return 0;
|
||||
return dd->dev;
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIIODevice * > PIConnection::boundedDevices() const {
|
||||
return __device_pool__->boundedDevices(this);
|
||||
}
|
||||
|
||||
|
||||
PIPacketExtractor * PIConnection::addFilter(const PIString & name_, const PIString & full_path, PIPacketExtractor::SplitMode mode) {
|
||||
Extractor * e = extractors.value(name_);
|
||||
PIIODevice * dev = __device_pool__->device(full_path);
|
||||
if (dev == 0) {
|
||||
piCoutObj << "\"addPacketExtractor\" error: no such device \"" << full_path << "\"!";
|
||||
return 0;
|
||||
}
|
||||
if (e == 0) {
|
||||
e = new Extractor();
|
||||
extractors[name_] = e;
|
||||
}
|
||||
if (e->extractor == 0) {
|
||||
e->extractor = new PIPacketExtractor(0, mode);
|
||||
e->extractor->setName(name_);
|
||||
e->extractor->setThreadedReadData(new PIPair<PIConnection * , PIString>(this, name_));
|
||||
e->extractor->setHeaderCheckSlot(filterValidateHeaderS);
|
||||
e->extractor->setFooterCheckSlot(filterValidateFooterS);
|
||||
e->extractor->setPayloadCheckSlot(filterValidatePayloadS);
|
||||
CONNECT2(void, uchar * , int, e->extractor, packetReceived, this, packetExtractorReceived)
|
||||
}
|
||||
if (!e->devices.contains(dev)) {
|
||||
bounded_extractors[dev] << e->extractor;
|
||||
e->devices << dev;
|
||||
}
|
||||
return e->extractor;
|
||||
}
|
||||
|
||||
|
||||
PIPacketExtractor * PIConnection::addFilter(const PIString & name_, const PIIODevice * dev, PIPacketExtractor::SplitMode mode) {
|
||||
if (dev == 0) return 0;
|
||||
PIString fp;
|
||||
if (dev->isPropertyExists("__fullPath__")) fp = dev->property("__fullPath__").toString();
|
||||
fp = dev->constructFullPath();
|
||||
return addFilter(name_, fp, mode);
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::removeFilter(const PIString & name_, const PIString & full_path) {
|
||||
Extractor * p = extractors.value(name_);
|
||||
if (p == 0) return false;
|
||||
bool ret = false;
|
||||
for (int i = 0; i < p->devices.size_s(); ++i) {
|
||||
if (p->devices[i]->property("__fullPath__").toString() == full_path) {
|
||||
bounded_extractors[p->devices[i]].removeAll(p->extractor);
|
||||
p->devices.remove(i);
|
||||
--i;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
if (p->devices.isEmpty()) {
|
||||
unboundExtractor(p->extractor);
|
||||
delete p;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::removeFilter(const PIString & name, const PIIODevice * dev) {
|
||||
if (dev == 0) return false;
|
||||
return removeFilter(name, dev->property("__fullPath__").toString());
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::removeFilter(const PIString & name_) {
|
||||
Extractor * p = extractors.value(name_);
|
||||
if (p == 0) return false;
|
||||
unboundExtractor(p->extractor);
|
||||
delete p;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::removeAllFilters() {
|
||||
piForeachC (PEPair & i, extractors) {
|
||||
if (i.second == 0) continue;
|
||||
channels_.remove(i.second->extractor);
|
||||
for (PIMap<PIIODevice * , PIVector<PIIODevice * > >::iterator it = channels_.begin(); it != channels_.end(); ++it)
|
||||
it.value().removeAll(i.second->extractor);
|
||||
delete i.second;
|
||||
}
|
||||
extractors.clear();
|
||||
bounded_extractors.clear();
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIPacketExtractor * > PIConnection::filters() const {
|
||||
PIVector<PIPacketExtractor * > ret;
|
||||
piForeachC (PEPair & i, extractors)
|
||||
if (i.second != 0)
|
||||
if (i.second->extractor != 0) ret << i.second->extractor;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIStringList PIConnection::filterNames() const {
|
||||
PIStringList ret;
|
||||
piForeachC (PEPair & i, extractors)
|
||||
if (i.second != 0)
|
||||
if (i.second->extractor != 0) ret << i.first;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIPacketExtractor * PIConnection::filter(const PIString & name) const {
|
||||
piForeachC (PEPair & i, extractors)
|
||||
if (i.second != 0)
|
||||
if (i.second->extractor != 0 && i.first == name)
|
||||
return i.second->extractor;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIIODevice * > PIConnection::filterBoundedDevices(const PIString & name_) const {
|
||||
PIVector<PIIODevice * > ret;
|
||||
Extractor * p = extractors.value(name_);
|
||||
if (p == 0) return ret;
|
||||
return p->devices;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::addChannel(const PIString & name0, const PIString & name1) {
|
||||
//piCout << "addChannel" << name0 << name1;
|
||||
if (name0.isEmpty() || name1.isEmpty()) return false;
|
||||
PIIODevice * dev0 = device(name0), * dev1 = device(name1);
|
||||
PIPacketExtractor * pe0(0), * pe1(0);
|
||||
if (extractors.value(name0) != 0) pe0 = extractors.value(name0)->extractor;
|
||||
if (extractors.value(name1) != 0) pe1 = extractors.value(name1)->extractor;
|
||||
if (pe0 != 0) dev0 = pe0;
|
||||
if (pe1 != 0) dev1 = pe1;
|
||||
if (dev0 == 0 || dev1 == 0) {
|
||||
if (dev0 == 0) piCoutObj << "\"addChannel\" error: no such device \"" << name0 << "\"!";
|
||||
if (dev1 == 0) piCoutObj << "\"addChannel\" error: no such device \"" << name1 << "\"!";
|
||||
return false;
|
||||
}
|
||||
if (!channels_[dev0].contains(dev1))
|
||||
channels_[dev0] << dev1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::removeChannel(const PIString & name0, const PIString & name1) {
|
||||
PIIODevice * dev0 = device(name0), * dev1 = device(name1);
|
||||
PIPacketExtractor * pe0(0), * pe1(0);
|
||||
if (extractors.value(name0) != 0) pe0 = extractors.value(name0)->extractor;
|
||||
if (extractors.value(name1) != 0) pe1 = extractors.value(name1)->extractor;
|
||||
if (pe0 != 0) dev0 = pe0;
|
||||
if (pe1 != 0) dev1 = pe1;
|
||||
if (dev0 == 0 || dev1 == 0) return false;
|
||||
channels_[dev0].removeAll(dev1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::removeChannel(const PIString & name0) {
|
||||
PIIODevice * dev0 = device(name0);
|
||||
PIPacketExtractor * pe0(0);
|
||||
if (extractors.value(name0) != 0) pe0 = extractors.value(name0)->extractor;
|
||||
if (pe0 != 0) dev0 = pe0;
|
||||
if (dev0 == 0) return false;
|
||||
channels_.remove(dev0);
|
||||
for (PIMap<PIIODevice * , PIVector<PIIODevice * > >::iterator it = channels_.begin(); it != channels_.end(); ++it)
|
||||
it.value().removeAll(dev0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::removeAllChannels() {
|
||||
channels_.clear();
|
||||
}
|
||||
|
||||
|
||||
PIString PIConnection::devPath(const PIIODevice * d) const {
|
||||
if (d == 0) return PIString();
|
||||
if (strcmp(d->className(), "PIPacketExtractor") == 0) return d->name();
|
||||
return d->constructFullPath();
|
||||
}
|
||||
|
||||
|
||||
PIString PIConnection::devFPath(const PIIODevice * d) const {
|
||||
if (d == 0) return PIString();
|
||||
if (d->isPropertyExists("__fullPath__")) return d->property("__fullPath__").toString();
|
||||
return d->name();
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIPair<PIString, PIString > > PIConnection::channels() const {
|
||||
PIVector<PIPair<PIString, PIString > > ret;
|
||||
piForeachC (CPair & i, channels_) {
|
||||
PIString fp0(devFPath(i.first));
|
||||
piForeachC (PIIODevice * d, i.second)
|
||||
ret << PIPair<PIString, PIString>(fp0, devFPath(d));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::startThreadedRead(const PIString & full_path) {
|
||||
DevicePool::DeviceData * dd = __device_pool__->devices.value(full_path, 0);
|
||||
if (dd == 0) return;
|
||||
if (dd->dev == 0) return;
|
||||
if (dd->started || dd->dev->mode() == PIIODevice::WriteOnly) return;
|
||||
dd->rthread->start();
|
||||
dd->started = true;
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::startAllThreadedReads() {
|
||||
piForeachC (DevicePool::DDPair & d, __device_pool__->devices)
|
||||
startThreadedRead(d.first);
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::stopThreadedRead(const PIString & full_path) {
|
||||
DevicePool::DeviceData * dd = __device_pool__->devices.value(full_path, 0);
|
||||
if (dd == 0) return;
|
||||
if (dd->dev == 0) return;
|
||||
if (!dd->started || dd->dev->mode() == PIIODevice::WriteOnly) return;
|
||||
dd->rthread->stop();
|
||||
dd->started = false;
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::stopAllThreadedReads() {
|
||||
piForeachC (DevicePool::DDPair & d, __device_pool__->devices)
|
||||
stopThreadedRead(d.first);
|
||||
}
|
||||
|
||||
|
||||
int PIConnection::write(const PIString & full_path, const PIByteArray & data) {
|
||||
PIIODevice * dev = __device_pool__->device(full_path);
|
||||
if (dev == 0) {
|
||||
piCoutObj << "Null Device!";
|
||||
return -1;
|
||||
}
|
||||
if (!dev->canWrite()) {
|
||||
piCoutObj << "Device \"" << full_path << "\" can`t write!";
|
||||
return -1;
|
||||
}
|
||||
return dev->write(data);
|
||||
}
|
||||
|
||||
|
||||
PIVector< PIConnection * > PIConnection::allConnections() {
|
||||
return _connections;
|
||||
}
|
||||
|
||||
|
||||
PIVector< PIIODevice * > PIConnection::allDevices() {
|
||||
return __device_pool__->boundedDevices();
|
||||
}
|
||||
|
||||
|
||||
|
||||
PIIODevice * PIConnection::DevicePool::addDevice(PIConnection * parent, const PIString & fp, PIIODevice::DeviceMode mode, bool start) {
|
||||
DeviceData * dd = devices[fp];
|
||||
int pmode(0);
|
||||
bool need_start = false;
|
||||
if (dd == 0) {
|
||||
dd = new DeviceData();
|
||||
devices[fp] = dd;
|
||||
}
|
||||
if (dd->dev == 0) {
|
||||
//piCout << "new device" << fp;
|
||||
dd->dev = PIIODevice::createFromFullPath(fp);
|
||||
if (dd->dev == 0) {
|
||||
piCoutObj << "Error: can`t create device \"" << fp << "\"!"; //:" << errorString();
|
||||
return 0;
|
||||
}
|
||||
dd->dev->setProperty("__fullPath__", fp);
|
||||
} else
|
||||
pmode = dd->dev->mode();
|
||||
if (!dd->listeners.contains(parent))
|
||||
dd->listeners << parent;
|
||||
if (pmode == mode || pmode == PIIODevice::ReadWrite)
|
||||
return dd->dev;
|
||||
if ((mode & PIIODevice::ReadOnly) > 0) {
|
||||
if (dd->rthread != 0) {
|
||||
delete dd->rthread;
|
||||
dd->rthread = 0;
|
||||
dd->started = false;
|
||||
}
|
||||
dd->rthread = new PIThread(dd, threadReadDP);
|
||||
need_start = true;
|
||||
pmode |= PIIODevice::ReadOnly;
|
||||
}
|
||||
if ((mode & PIIODevice::WriteOnly) > 0)
|
||||
pmode |= PIIODevice::WriteOnly;
|
||||
dd->dev->close();
|
||||
dd->dev->open((PIIODevice::DeviceMode)pmode);
|
||||
if (need_start && start) {
|
||||
dd->rthread->start();
|
||||
dd->started = true;
|
||||
}
|
||||
return dd->dev;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::DevicePool::removeDevice(PIConnection * parent, const PIString & fp) {
|
||||
DeviceData * dd = devices.value(fp);
|
||||
if (dd == 0)
|
||||
return false;
|
||||
if (dd->dev == 0)
|
||||
return false;
|
||||
bool ok = dd->listeners.contains(parent);
|
||||
dd->listeners.removeAll(parent);
|
||||
if (dd->listeners.isEmpty()) {
|
||||
delete dd;
|
||||
devices.remove(fp);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::DevicePool::unboundConnection(PIConnection * parent) {
|
||||
PIStringList rem;
|
||||
piForeachC (DDPair & i, devices) {
|
||||
if (i.second == 0) {
|
||||
rem << i.first;
|
||||
continue;
|
||||
}
|
||||
i.second->listeners.removeAll(parent);
|
||||
if (i.second->listeners.isEmpty())
|
||||
rem << i.first;
|
||||
}
|
||||
piForeachC (PIString & i, rem) {
|
||||
DeviceData * dd = devices.value(i);
|
||||
if (dd == 0)
|
||||
continue;
|
||||
delete dd;
|
||||
devices.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIIODevice * PIConnection::DevicePool::device(const PIString & fp) const {
|
||||
DeviceData * dd = devices.value(fp);
|
||||
if (dd == 0) return 0;
|
||||
return dd->dev;
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIConnection * > PIConnection::DevicePool::boundedConnections() const {
|
||||
PIVector<PIConnection * > ret;
|
||||
piForeachC (DDPair & i, devices) {
|
||||
if (i.second == 0)
|
||||
continue;
|
||||
ret << i.second->listeners;
|
||||
}
|
||||
for (int i = 0; i < ret.size_s(); ++i)
|
||||
for (int j = i + 1; j < ret.size_s(); ++j)
|
||||
if (ret[i] == ret[j]) {
|
||||
ret.remove(j);
|
||||
--j;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIVector< PIIODevice * > PIConnection::DevicePool::boundedDevices() const {
|
||||
PIVector<PIIODevice * > ret;
|
||||
piForeachC (DDPair & i, devices) {
|
||||
if (i.second == 0) continue;
|
||||
if (i.second->dev == 0) continue;
|
||||
ret << i.second->dev;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIIODevice * > PIConnection::DevicePool::boundedDevices(const PIConnection * parent) const {
|
||||
PIVector<PIIODevice * > ret;
|
||||
piForeachC (DDPair & i, devices) {
|
||||
if (i.second == 0) continue;
|
||||
if (i.second->dev == 0) continue;
|
||||
if (i.second->listeners.contains(const_cast<PIConnection*>(parent)))
|
||||
ret << i.second->dev;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIConnection::DevicePool::DeviceData::~DeviceData() {
|
||||
if (rthread != 0) {
|
||||
rthread->stop();
|
||||
delete rthread;
|
||||
rthread = 0;
|
||||
}
|
||||
if (dev != 0) {
|
||||
delete dev;
|
||||
dev = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::DevicePool::threadReadDP(void * ddp) {
|
||||
DeviceData * dd((DeviceData * )ddp);
|
||||
if (dd->dev == 0) {piMSleep(100); return;}
|
||||
PIByteArray ba;
|
||||
ba = dd->dev->read(dd->dev->threadedReadBufferSize());
|
||||
if (ba.isEmpty()) {piMSleep(10); return;}
|
||||
//piCout << "Readed from" << dd->dev->path() << Hex << ba;
|
||||
__device_pool__->deviceReaded(dd, ba);
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::DevicePool::deviceReaded(PIConnection::DevicePool::DeviceData * dd, const PIByteArray & data) {
|
||||
PIString from = dd->dev->property("__fullPath__").toString();
|
||||
piForeach (PIConnection * ld, dd->listeners)
|
||||
ld->rawReceived(dd->dev, from, data);
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::filterValidateHeaderS(void * c, uchar * src, uchar * rec, int size) {
|
||||
PIPair<PIConnection * , PIString> * p((PIPair<PIConnection * , PIString> * )c);
|
||||
return p->first->filterValidateHeader(p->second, src, rec, size);
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::filterValidateFooterS(void * c, uchar * src, uchar * rec, int size) {
|
||||
PIPair<PIConnection * , PIString> * p((PIPair<PIConnection * , PIString> * )c);
|
||||
return p->first->filterValidateFooter(p->second, src, rec, size);
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::filterValidatePayloadS(void * c, uchar * rec, int size) {
|
||||
PIPair<PIConnection * , PIString> * p((PIPair<PIConnection * , PIString> * )c);
|
||||
return p->first->filterValidatePayload(p->second, rec, size);
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::rawReceived(PIIODevice * dev, const PIString & from, const PIByteArray & data) {
|
||||
dataReceived(from, data);
|
||||
dataReceivedEvent(from, data);
|
||||
PIVector<PIPacketExtractor * > be(bounded_extractors.value(dev));
|
||||
//piCout << be;
|
||||
piForeach (PIPacketExtractor * i, be)
|
||||
i->threadedRead(const_cast<uchar * >(data.data()), data.size_s());
|
||||
PIVector<PIIODevice * > chd(channels_.value(dev));
|
||||
piForeach (PIIODevice * d, chd)
|
||||
d->write(data);
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::filterValidateHeader(const PIString & filter_name, uchar * src, uchar * rec, int size) {
|
||||
for (int i = 0; i < size; ++i)
|
||||
if (src[i] != rec[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::filterValidateFooter(const PIString & filter_name, uchar * src, uchar * rec, int size) {
|
||||
for (int i = 0; i < size; ++i)
|
||||
if (src[i] != rec[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIConnection::filterValidatePayload(const PIString & filter_name, uchar * rec, int size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PIConnection::Extractor::~Extractor() {
|
||||
if (extractor != 0) {
|
||||
if (extractor->threadedReadData() != 0)
|
||||
delete (PIPair<PIConnection * , PIString> * )(extractor->threadedReadData());
|
||||
delete extractor;
|
||||
extractor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::unboundExtractor(PIPacketExtractor * pe) {
|
||||
if (pe == 0) return;
|
||||
channels_.remove(pe);
|
||||
for (PIMap<PIIODevice * , PIVector<PIIODevice * > >::iterator it = channels_.begin(); it != channels_.end(); ++it)
|
||||
it.value().removeAll(pe);
|
||||
PIVector<PIIODevice * > k = bounded_extractors.keys();
|
||||
piForeach (PIIODevice * i, k) {
|
||||
PIVector<PIPacketExtractor*> & be(bounded_extractors[i]);
|
||||
be.removeAll(pe);
|
||||
if (be.isEmpty())
|
||||
bounded_extractors.remove(i);
|
||||
}
|
||||
extractors.remove(pe->name());
|
||||
}
|
||||
|
||||
|
||||
void PIConnection::packetExtractorReceived(uchar * data, int size) {
|
||||
PIString from(emitter() == 0 ? "" : emitter()->name());
|
||||
packetReceived(from, PIByteArray(data, size));
|
||||
packetReceivedEvent(from, PIByteArray(data, size));
|
||||
PIIODevice * cd = (PIIODevice * )emitter();
|
||||
if (cd == 0) return;
|
||||
PIVector<PIIODevice * > chd(channels_.value(cd));
|
||||
piForeach (PIIODevice * d, chd)
|
||||
d->write(data, size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
PIConnection::DevicePool * __device_pool__;
|
||||
|
||||
bool __DevicePoolContainer__::inited_(false);
|
||||
|
||||
__DevicePoolContainer__::__DevicePoolContainer__() {
|
||||
if (inited_) return;
|
||||
inited_ = true;
|
||||
__device_pool__ = new PIConnection::DevicePool();
|
||||
}
|
||||
291
piconnection.h
291
piconnection.h
@@ -1,291 +0,0 @@
|
||||
/*! \file piconnection.h
|
||||
* \brief Complex I/O point
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Complex I/O point
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PICONNECTION_H
|
||||
#define PICONNECTION_H
|
||||
|
||||
#include "pipacketextractor.h"
|
||||
|
||||
|
||||
class PIP_EXPORT PIConnection: public PIObject
|
||||
{
|
||||
PIOBJECT(PIConnection)
|
||||
public:
|
||||
|
||||
//! Constructs an empty connection
|
||||
PIConnection();
|
||||
|
||||
//! Constructs connection and configure it from config file "config" from section "name"
|
||||
PIConnection(const PIString & config, const PIString & name);
|
||||
|
||||
~PIConnection();
|
||||
|
||||
|
||||
/*! \brief Configure connection from config file "config" from section "name". Returns if configuration was successful
|
||||
* \details \b Warning: all devices, filters and channels removed before configure! */
|
||||
bool configureFromConfig(const PIString & config, const PIString & name);
|
||||
|
||||
//! Returns config file section of current connection configuration
|
||||
PIString makeConfig() const;
|
||||
|
||||
|
||||
/*! \brief Add device with full path "full_path", open mode "mode" to Device pool and connection
|
||||
* \details Returns pointer to device or null if device can not be created. If "start" is true,
|
||||
* read thread is started immediately. Else, you can start read thread with functions \a startThreadedRead()
|
||||
* or \a startAllThreadedReads(). By default, read thread doesn`t start */
|
||||
PIIODevice * addDevice(const PIString & full_path, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite, bool start = false);
|
||||
|
||||
/*! \brief Remove device with full path "full_path" from connection
|
||||
* \details Returns if device was removed. If there is no connection bounded to this device,
|
||||
* it will be removed from Device pool */
|
||||
bool removeDevice(const PIString & full_path);
|
||||
|
||||
/*! \brief Remove all device from connection
|
||||
* \details If there is no connection bounded to there devices, they removed from Device pool */
|
||||
void removeAllDevices();
|
||||
|
||||
//! Returns device with full path "full_path" or null if there is no such device
|
||||
PIIODevice * device(const PIString & full_path) const;
|
||||
|
||||
//! Returns all devices bounded to this connection
|
||||
PIVector<PIIODevice * > boundedDevices() const;
|
||||
|
||||
|
||||
/*! \brief Add filter with name "name" to device with full path "full_path"
|
||||
* \details If there is no filter with name "name", connection create new with split mode "mode" and bound
|
||||
* to it device "full_path". If filter with name "name" already exists, device "full_path" add to this filter.
|
||||
* \b Attention! "mode" is altual olny if new filter was created!
|
||||
* This function returns PIPacketExtractor * assosiated with this filter */
|
||||
PIPacketExtractor * addFilter(const PIString & name, const PIString & full_path, PIPacketExtractor::SplitMode mode = PIPacketExtractor::None);
|
||||
|
||||
//! Add filter with name "name" to device "dev"
|
||||
PIPacketExtractor * addFilter(const PIString & name, const PIIODevice * dev, PIPacketExtractor::SplitMode mode = PIPacketExtractor::None);
|
||||
|
||||
/*! \brief Remove from filter with name "name" device with full path "full_path"
|
||||
* \details If there is no devices bounded to this filter, it will be removed. Returns
|
||||
* if device was removed */
|
||||
bool removeFilter(const PIString & name, const PIString & full_path);
|
||||
|
||||
//! Remove from filter with name "name" device "dev"
|
||||
bool removeFilter(const PIString & name, const PIIODevice * dev);
|
||||
|
||||
//! Remove filter with name "name". Returns if filter was removed
|
||||
bool removeFilter(const PIString & name);
|
||||
|
||||
//! Remove all filters from connection
|
||||
void removeAllFilters();
|
||||
|
||||
|
||||
//! Returns all filters of connection
|
||||
PIVector<PIPacketExtractor * > filters() const;
|
||||
|
||||
//! Returns all filter names of connection
|
||||
PIStringList filterNames() const;
|
||||
|
||||
//! Returns PIPacketExtractor * assosiated with filter "name" or null if there is no such filter
|
||||
PIPacketExtractor * filter(const PIString & name) const;
|
||||
|
||||
//! Returns all devices bounded to filter "name"
|
||||
PIVector<PIIODevice * > filterBoundedDevices(const PIString & name) const;
|
||||
|
||||
|
||||
/*! \brief Add to connection channel from "name_from" to "name_to"
|
||||
* \details "name_from" and "name_to" can be full pathes of devices or filter names.
|
||||
* Returns \b false if there if no such device or filter, else create channel and returns \b true */
|
||||
bool addChannel(const PIString & name_from, const PIString & name_to);
|
||||
|
||||
//! Add to connection channel from "name_from" to "dev_to"
|
||||
bool addChannel(const PIString & name_from, const PIIODevice * dev_to) {return addChannel(name_from, devFPath(dev_to));}
|
||||
|
||||
//! Add to connection channel from "dev_from" to "name_to"
|
||||
bool addChannel(const PIIODevice * dev_from, const PIString & name_to) {return addChannel(devFPath(dev_from), name_to);}
|
||||
|
||||
//! Add to connection channel from "dev_from" to "dev_to"
|
||||
bool addChannel(const PIIODevice * dev_from, const PIIODevice * dev_to) {return addChannel(devFPath(dev_from), devFPath(dev_to));}
|
||||
|
||||
/*! \brief Remove from connection channel from "name_from" to "name_to"
|
||||
* \details "name_from" and "name_to" can be full pathes of devices or filter names.
|
||||
* Returns \b false if there if no such device or filter, else remove channel and returns \b true */
|
||||
bool removeChannel(const PIString & name_from, const PIString & name_to);
|
||||
|
||||
//! Remove from connection channel from "name_from" to "dev_to"
|
||||
bool removeChannel(const PIString & name_from, const PIIODevice * dev_to) {return removeChannel(name_from, devFPath(dev_to));}
|
||||
|
||||
//! Remove from connection channel from "dev_from" to "name_to"
|
||||
bool removeChannel(const PIIODevice * dev_from, const PIString & name_to) {return removeChannel(devFPath(dev_from), name_to);}
|
||||
|
||||
//! Remove from connection channel from "dev_from" to "dev_to"
|
||||
bool removeChannel(const PIIODevice * dev_from, const PIIODevice * dev_to) {return removeChannel(devFPath(dev_from), devFPath(dev_to));}
|
||||
|
||||
/*! \brief Remove from connection all channels from "name_from"
|
||||
* \details "name_from" can be full path of device or filter name.
|
||||
* Returns \b false if there if no such device or filter, else remove channels and returns \b true */
|
||||
bool removeChannel(const PIString & name_from);
|
||||
|
||||
//! Remove from connection all channels from "dev_from"
|
||||
bool removeChannel(const PIIODevice * dev_from) {return removeChannel(devFPath(dev_from));}
|
||||
|
||||
//! Remove from connection all channels
|
||||
void removeAllChannels();
|
||||
|
||||
//! Returns all channels of this connection as full pathes or filter names pair array (from, to)
|
||||
PIVector<PIPair<PIString, PIString> > channels() const;
|
||||
|
||||
|
||||
//! Start read thread of device with full path "full_path"
|
||||
void startThreadedRead(const PIString & full_path);
|
||||
|
||||
//! Start read thread of device "dev"
|
||||
void startThreadedRead(const PIIODevice * dev) {startThreadedRead(devFPath(dev));}
|
||||
|
||||
//! Start read threads of all Device pool device
|
||||
void startAllThreadedReads();
|
||||
|
||||
//! Stop read thread of device with full path "full_path"
|
||||
void stopThreadedRead(const PIString & full_path);
|
||||
|
||||
//! Stop read thread of device "dev"
|
||||
void stopThreadedRead(const PIIODevice * dev) {stopThreadedRead(devFPath(dev));}
|
||||
|
||||
//! Stop read threads of all Device pool device
|
||||
void stopAllThreadedReads();
|
||||
|
||||
|
||||
//! Returns if there is no devices in this connection
|
||||
bool isEmpty() const {return device_modes.isEmpty();}
|
||||
|
||||
|
||||
//! Write data "data" to device with full path "full_path" and returns result of \a write() function of device
|
||||
int write(const PIString & full_path, const PIByteArray & data);
|
||||
|
||||
|
||||
//! Returns all connections in application
|
||||
static PIVector<PIConnection * > allConnections();
|
||||
|
||||
//! Returns all devices in Device pool
|
||||
static PIVector<PIIODevice * > allDevices();
|
||||
|
||||
class DevicePool: public PIObject {
|
||||
PIOBJECT(DevicePool)
|
||||
friend class PIConnection;
|
||||
public:
|
||||
DevicePool(): PIObject("PIConnection::DevicePool") {}
|
||||
|
||||
PIIODevice * addDevice(PIConnection * parent, const PIString & fp, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite, bool start = true);
|
||||
bool removeDevice(PIConnection * parent, const PIString & fp);
|
||||
void unboundConnection(PIConnection * parent);
|
||||
PIIODevice * device(const PIString & fp) const;
|
||||
PIVector<PIConnection * > boundedConnections() const;
|
||||
PIVector<PIIODevice * > boundedDevices() const;
|
||||
PIVector<PIIODevice * > boundedDevices(const PIConnection * parent) const;
|
||||
|
||||
protected:
|
||||
struct DeviceData {
|
||||
DeviceData(): dev(0), rthread(0), started(false) {}
|
||||
~DeviceData();
|
||||
PIIODevice * dev;
|
||||
PIThread * rthread;
|
||||
bool started;
|
||||
PIVector<PIConnection * > listeners;
|
||||
};
|
||||
|
||||
static void threadReadDP(void * ddp);
|
||||
void deviceReaded(DeviceData * dd, const PIByteArray & data);
|
||||
|
||||
typedef PIMap<PIString, DeviceData * >::value_type DDPair;
|
||||
PIMap<PIString, DeviceData * > devices;
|
||||
};
|
||||
|
||||
EVENT2(dataReceivedEvent, const PIString &, from, const PIByteArray &, data)
|
||||
EVENT2(packetReceivedEvent, const PIString &, from, const PIByteArray &, data)
|
||||
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void dataReceivedEvent(const PIString & from, const PIByteArray & data)
|
||||
//! \brief Raise on data received from device with full path "from"
|
||||
|
||||
//! \fn void packetReceivedEvent(const PIString & from, const PIByteArray & data)
|
||||
//! \brief Raise on packet received from filter with name "from"
|
||||
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
|
||||
//! Executes on data received from device with full path "from"
|
||||
virtual void dataReceived(const PIString & from, const PIByteArray & data) {}
|
||||
|
||||
//! Executes on packet received from filter with name "from"
|
||||
virtual void packetReceived(const PIString & from, const PIByteArray & data) {}
|
||||
|
||||
//! Validate header "rec" with source header "src" and size "size", executes from filter "filter_name"
|
||||
virtual bool filterValidateHeader(const PIString & filter_name, uchar * src, uchar * rec, int size);
|
||||
|
||||
//! Validate footer "rec" with source footer "src" and size "size", executes from filter "filter_name"
|
||||
virtual bool filterValidateFooter(const PIString & filter_name, uchar * src, uchar * rec, int size);
|
||||
|
||||
//! Validate payload "rec" with size "size", executes from filter "filter_name"
|
||||
virtual bool filterValidatePayload(const PIString & filter_name, uchar * rec, int size);
|
||||
|
||||
private:
|
||||
static bool filterValidateHeaderS(void * c, uchar * src, uchar * rec, int size);
|
||||
static bool filterValidateFooterS(void * c, uchar * src, uchar * rec, int size);
|
||||
static bool filterValidatePayloadS(void * c, uchar * rec, int size);
|
||||
void rawReceived(PIIODevice * dev, const PIString & from, const PIByteArray & data);
|
||||
void unboundExtractor(PIPacketExtractor * pe);
|
||||
EVENT_HANDLER2(void, packetExtractorReceived, uchar * , data, int, size);
|
||||
|
||||
PIString devPath(const PIIODevice * d) const;
|
||||
PIString devFPath(const PIIODevice * d) const;
|
||||
|
||||
struct Extractor {
|
||||
Extractor(): extractor(0) {}
|
||||
~Extractor();
|
||||
PIPacketExtractor * extractor;
|
||||
PIVector<PIIODevice * > devices;
|
||||
};
|
||||
|
||||
typedef PIMap<PIString, Extractor * >::value_type PEPair;
|
||||
typedef PIMap<PIIODevice * , PIVector<PIPacketExtractor * > >::value_type BEPair;
|
||||
typedef PIMap<PIIODevice * , PIVector<PIIODevice * > >::value_type CPair;
|
||||
PIMap<PIString, Extractor * > extractors;
|
||||
PIMap<PIIODevice * , PIIODevice::DeviceMode> device_modes;
|
||||
PIMap<PIIODevice * , PIVector<PIPacketExtractor * > > bounded_extractors;
|
||||
PIMap<PIIODevice * , PIVector<PIIODevice * > > channels_;
|
||||
|
||||
static PIVector<PIConnection * > _connections;
|
||||
|
||||
};
|
||||
|
||||
|
||||
extern PIConnection::DevicePool * __device_pool__;
|
||||
|
||||
class __DevicePoolContainer__ {
|
||||
public:
|
||||
__DevicePoolContainer__();
|
||||
static bool inited_;
|
||||
};
|
||||
|
||||
static __DevicePoolContainer__ __device_pool_container__;
|
||||
|
||||
|
||||
#endif // PICONNECTION_H
|
||||
1011
piconsole.cpp
1011
piconsole.cpp
@@ -1,1011 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Console output/input
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piconsole.h"
|
||||
#include "pipeer.h"
|
||||
|
||||
|
||||
/** \class PIConsole
|
||||
* \brief Console output class
|
||||
* \details
|
||||
* \section PIConsole_sec0 Synopsis
|
||||
* This class provides output to console with automatic alignment and update.
|
||||
* It supports tabs, keyboard listening, formats and colors.
|
||||
*
|
||||
* \section PIConsole_sec1 Layout
|
||||
* %PIConsole works with variable pointers. You should add your variables with
|
||||
* functions \a addVariable() which receives label name, pointer to variable
|
||||
* and optional column and format. Columns count is dynamically increased if
|
||||
* new column used. E.g. if you add variable to empty tab to column 3, columns
|
||||
* count will be increased to 3, but two firsts columns will be empty. Each column
|
||||
* filled from top to bottom, but you can add just string with function
|
||||
* \a addString() or add empty line with function \a addEmptyLine(). Layout scheme:
|
||||
* \image html piconsole_layout.png
|
||||
*
|
||||
* \section PIConsole_sec2 Keyboard usage
|
||||
* %PIConsole should to be single in application. %PIConsole aggregate PIKbdListener
|
||||
* which grab keyboard and automatic switch tabs by theirs bind keys. If there is no
|
||||
* tab binded to pressed key external function "slot" will be called
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
extern PIMutex __PICout_mutex__;
|
||||
|
||||
|
||||
PIConsole::PIConsole(bool startNow, KBFunc slot): PIThread() {
|
||||
setPriority(piLow);
|
||||
needLockRun(true);
|
||||
ret_func = slot;
|
||||
num_format = systime_format = 0;
|
||||
vid = 0;
|
||||
cur_tab = width = height = pwidth = pheight = max_y = 0;
|
||||
def_align = Nothing;
|
||||
#ifdef WINDOWS
|
||||
ulcoord.X = 0;
|
||||
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
GetConsoleScreenBufferInfo(hOut, &sbi);
|
||||
dattr = sbi.wAttributes;
|
||||
width = sbi.srWindow.Right - sbi.srWindow.Left;
|
||||
height = sbi.srWindow.Bottom - sbi.srWindow.Top;
|
||||
ulcoord.Y = sbi.srWindow.Top;
|
||||
GetConsoleMode(hOut, &smode);
|
||||
GetConsoleCursorInfo(hOut, &curinfo);
|
||||
#endif
|
||||
tabs.reserve(16);
|
||||
addTab("main");
|
||||
listener = new PIKbdListener(key_event, this);
|
||||
peer = 0;
|
||||
server_mode = false;
|
||||
state = Disconnected;
|
||||
peer_timer.addDelimiter(20);
|
||||
CONNECT2(void, void * , int, &peer_timer, timeout, this, peerTimer);
|
||||
if (startNow) start();
|
||||
}
|
||||
|
||||
|
||||
PIConsole::~PIConsole() {
|
||||
stopPeer();
|
||||
if (isRunning())
|
||||
stop();
|
||||
clearTabs(false);
|
||||
delete listener;
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(hOut, smode);
|
||||
SetConsoleTextAttribute(hOut, dattr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int PIConsole::addTab(const PIString & name, char bind_key) {
|
||||
if (isRunning()) lock();
|
||||
tabs.push_back(Tab(name, bind_key));
|
||||
cur_tab = tabs.size() - 1;
|
||||
if (isRunning()) unlock();
|
||||
return tabs.size();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::removeTab(uint index) {
|
||||
if (index >= tabs.size()) return;
|
||||
if (isRunning()) lock();
|
||||
tabs.remove(index);
|
||||
if (cur_tab >= tabs.size()) cur_tab = tabs.size() - 1;
|
||||
if (isRunning()) unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::removeTab(const PIString & name) {
|
||||
uint index = tabs.size() + 1;
|
||||
for (uint i = 0; i < tabs.size(); ++i) {
|
||||
if (tabs[i].name == name) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
removeTab(index);
|
||||
}
|
||||
|
||||
|
||||
bool PIConsole::setTab(uint index) {
|
||||
if (index >= tabs.size())
|
||||
return false;
|
||||
if (!isRunning()) {
|
||||
cur_tab = index;
|
||||
return true;
|
||||
}
|
||||
lock();
|
||||
__PICout_mutex__.lock();
|
||||
cur_tab = index;
|
||||
clearScreen();
|
||||
fillLabels();
|
||||
__PICout_mutex__.unlock();
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIConsole::setTab(const PIString & name) {
|
||||
uint index = tabs.size() + 1;
|
||||
for (uint i = 0; i < tabs.size(); ++i) {
|
||||
if (tabs[i].name == name) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return setTab(index);
|
||||
}
|
||||
|
||||
|
||||
bool PIConsole::setTabBindKey(uint index, char bind_key) {
|
||||
if (index >= tabs.size())
|
||||
return false;
|
||||
tabs[index].key = bind_key;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIConsole::setTabBindKey(const PIString & name, char bind_key) {
|
||||
uint index =tabs.size() + 1;
|
||||
for (uint i = 0; i < tabs.size(); ++i) {
|
||||
if (tabs[i].name == name) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return setTabBindKey(index, bind_key);
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::key_event(char key, void * t) {
|
||||
PIConsole * p = (PIConsole * )t;
|
||||
int ct = p->cur_tab;
|
||||
if (key == char(PIKbdListener::LeftArrow)) {
|
||||
do {
|
||||
ct--;
|
||||
if (ct < 0) return;
|
||||
} while (p->tabs[ct].key == 0);
|
||||
p->setTab(ct);
|
||||
return;
|
||||
}
|
||||
if (key == char(PIKbdListener::RightArrow)) {
|
||||
do {
|
||||
ct++;
|
||||
if (ct >= p->tabs.size_s()) return;
|
||||
} while (p->tabs[ct].key == 0);
|
||||
p->setTab(ct);
|
||||
return;
|
||||
}
|
||||
for (uint i = 0; i < p->tabsCount(); ++i) {
|
||||
if (p->tabs[i].key == key) {
|
||||
p->setTab(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (p->ret_func != 0) p->ret_func(key, t);
|
||||
p->keyPressed(key, t);
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::stop(bool clear) {
|
||||
PIThread::stop(true);
|
||||
if (clear) clearScreen();
|
||||
moveTo(0, max_y + 4);
|
||||
showCursor();
|
||||
couts(fstr(Normal));
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(hOut, smode);
|
||||
SetConsoleTextAttribute(hOut, dattr);
|
||||
#endif
|
||||
fflush(0);
|
||||
}
|
||||
|
||||
|
||||
PIString PIConsole::fstr(PIFlags<PIConsole::Format> f) {
|
||||
num_format = systime_format = 0;
|
||||
if (f[PIConsole::Dec]) num_format = 0;
|
||||
if (f[PIConsole::Hex]) num_format = 1;
|
||||
if (f[PIConsole::Oct]) num_format = 2;
|
||||
if (f[PIConsole::Bin]) num_format = 4;
|
||||
if (f[PIConsole::Scientific]) num_format = 3;
|
||||
if (f[PIConsole::SystemTimeSplit]) systime_format = 0;
|
||||
if (f[PIConsole::SystemTimeSeconds]) systime_format = 1;
|
||||
|
||||
#ifdef WINDOWS
|
||||
WORD attr = 0;
|
||||
|
||||
if (f[PIConsole::Inverse]) {
|
||||
if (f[PIConsole::Red]) attr |= BACKGROUND_RED;
|
||||
if (f[PIConsole::Green]) attr |= BACKGROUND_GREEN;
|
||||
if (f[PIConsole::Blue]) attr |= BACKGROUND_BLUE;
|
||||
if (f[PIConsole::Yellow]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN);
|
||||
if (f[PIConsole::Magenta]) attr |= (BACKGROUND_RED | BACKGROUND_BLUE);
|
||||
if (f[PIConsole::Cyan]) attr |= (BACKGROUND_GREEN | BACKGROUND_BLUE);
|
||||
if (f[PIConsole::White]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
|
||||
if (f[PIConsole::BackRed]) attr |= FOREGROUND_RED;
|
||||
if (f[PIConsole::BackGreen]) attr |= FOREGROUND_GREEN;
|
||||
if (f[PIConsole::BackBlue]) attr |= FOREGROUND_BLUE;
|
||||
if (f[PIConsole::BackYellow]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN);
|
||||
if (f[PIConsole::BackMagenta]) attr |= (FOREGROUND_RED | FOREGROUND_BLUE);
|
||||
if (f[PIConsole::BackCyan]) attr |= (FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
if (f[PIConsole::BackWhite]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
if ((attr & BACKGROUND_RED) + (attr & BACKGROUND_GREEN) + (attr & BACKGROUND_BLUE) == 0)
|
||||
attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
||||
} else {
|
||||
if (f[PIConsole::Red]) attr |= FOREGROUND_RED;
|
||||
if (f[PIConsole::Green]) attr |= FOREGROUND_GREEN;
|
||||
if (f[PIConsole::Blue]) attr |= FOREGROUND_BLUE;
|
||||
if (f[PIConsole::Yellow]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN);
|
||||
if (f[PIConsole::Magenta]) attr |= (FOREGROUND_RED | FOREGROUND_BLUE);
|
||||
if (f[PIConsole::Cyan]) attr |= (FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
if (f[PIConsole::White]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
if (f[PIConsole::BackRed]) attr |= BACKGROUND_RED;
|
||||
if (f[PIConsole::BackGreen]) attr |= BACKGROUND_GREEN;
|
||||
if (f[PIConsole::BackBlue]) attr |= BACKGROUND_BLUE;
|
||||
if (f[PIConsole::BackYellow]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN);
|
||||
if (f[PIConsole::BackMagenta]) attr |= (BACKGROUND_RED | BACKGROUND_BLUE);
|
||||
if (f[PIConsole::BackCyan]) attr |= (BACKGROUND_GREEN | BACKGROUND_BLUE);
|
||||
if (f[PIConsole::BackWhite]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
|
||||
if ((attr & FOREGROUND_RED) + (attr & FOREGROUND_GREEN) + (attr & FOREGROUND_BLUE) == 0)
|
||||
attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
||||
}
|
||||
if (f[PIConsole::Bold]) attr |= FOREGROUND_INTENSITY;
|
||||
if (f[PIConsole::Underline]) attr |= COMMON_LVB_UNDERSCORE;
|
||||
|
||||
SetConsoleTextAttribute(hOut, attr);
|
||||
return PIString();
|
||||
#else
|
||||
PIString ts("\e[0");
|
||||
|
||||
if (f[PIConsole::Bold]) ts += ";1";
|
||||
if (f[PIConsole::Faint]) ts += ";2";
|
||||
if (f[PIConsole::Italic]) ts += ";3";
|
||||
if (f[PIConsole::Underline]) ts += ";4";
|
||||
if (f[PIConsole::Blink]) ts += ";5";
|
||||
if (f[PIConsole::Inverse]) ts += ";7";
|
||||
|
||||
if (f[PIConsole::Black]) ts += ";30";
|
||||
if (f[PIConsole::Red]) ts += ";31";
|
||||
if (f[PIConsole::Green]) ts += ";32";
|
||||
if (f[PIConsole::Yellow]) ts += ";33";
|
||||
if (f[PIConsole::Blue]) ts += ";34";
|
||||
if (f[PIConsole::Magenta]) ts += ";35";
|
||||
if (f[PIConsole::Cyan]) ts += ";36";
|
||||
if (f[PIConsole::White]) ts += ";37";
|
||||
|
||||
if (f[PIConsole::BackBlack]) ts += ";40";
|
||||
if (f[PIConsole::BackRed]) ts += ";41";
|
||||
if (f[PIConsole::BackGreen]) ts += ";42";
|
||||
if (f[PIConsole::BackYellow]) ts += ";43";
|
||||
if (f[PIConsole::BackBlue]) ts += ";44";
|
||||
if (f[PIConsole::BackMagenta]) ts += ";45";
|
||||
if (f[PIConsole::BackCyan]) ts += ";46";
|
||||
if (f[PIConsole::BackWhite]) ts += ";47";
|
||||
|
||||
return ts + "m";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
inline int PIConsole::couts(const PIString & v) {return printf("%s", v.data());}
|
||||
inline int PIConsole::couts(const char * v) {return printf("%s", v);}
|
||||
inline int PIConsole::couts(const bool v) {return (v ? printf("true") : printf("false"));}
|
||||
inline int PIConsole::couts(const char v) {return printf("%c", v);}
|
||||
inline int PIConsole::couts(const short v) {
|
||||
switch (num_format) {case (1): return printf("0x%.4hX", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 2)); break; default: return printf("%hd", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const int v) {
|
||||
switch (num_format) {case (1): return printf("0x%.8X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 4)); break; default: return printf("%d", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const long v) {
|
||||
switch (num_format) {case (1): return printf("0x%.16lX", v); break; case (2): return printf("%lo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%ld", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const llong v) {
|
||||
switch (num_format) {case (1): return printf("0x%.16llX", v); break; case (2): return printf("%llo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%lld", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const uchar v) {
|
||||
switch (num_format) {case (1): return printf("0x%.2X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 1)); break; default: return printf("%u", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const ushort v) {
|
||||
switch (num_format) {case (1): return printf("0x%.4hX", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 2)); break; default: return printf("%hu", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const uint v) {
|
||||
switch (num_format) {case (1): return printf("0x%.8X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 4)); break; default: return printf("%u", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const ulong v) {
|
||||
switch (num_format) {case (1): return printf("0x%.16lX", v); break; case (2): return printf("%lo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%lu", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const ullong v) {
|
||||
switch (num_format) {case (1): return printf("0x%.16llX", v); break; case (2): return printf("%llo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%llu", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const float v) {
|
||||
switch (num_format) {case (3): return printf("%e", v); break; default: return printf("%.5g", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const double v) {
|
||||
switch (num_format) {case (3): return printf("%le", v); break; default: return printf("%.5lg", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const PISystemTime & v) {
|
||||
switch (systime_format) {case (1): return printf("%.6lg", v.toSeconds()); break;
|
||||
default: return couts(v.seconds) + printf(" s, ") + couts(v.nanoseconds) + printf(" ns"); break;}
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::begin() {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(hOut, ENABLE_WRAP_AT_EOL_OUTPUT);
|
||||
#endif
|
||||
max_y = 0;
|
||||
__PICout_mutex__.lock();
|
||||
clearScreen();
|
||||
hideCursor();
|
||||
fillLabels();
|
||||
__PICout_mutex__.unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::run() {
|
||||
uint cx, clen = 0;
|
||||
int j;
|
||||
#ifdef WINDOWS
|
||||
GetConsoleScreenBufferInfo(hOut, &sbi);
|
||||
width = sbi.srWindow.Right - sbi.srWindow.Left;
|
||||
height = sbi.srWindow.Bottom - sbi.srWindow.Top;
|
||||
#else
|
||||
winsize ws;
|
||||
ioctl(0, TIOCGWINSZ, &ws);
|
||||
width = ws.ws_col;
|
||||
height = ws.ws_row;
|
||||
#endif
|
||||
//fflush(0); return;
|
||||
__PICout_mutex__.lock();
|
||||
if (pwidth != width || pheight != height) {
|
||||
clearScreen();
|
||||
fillLabels();
|
||||
}
|
||||
pwidth = width;
|
||||
pheight = height;
|
||||
col_cnt = columns().size();
|
||||
col_wid = (col_cnt > 0) ? width / col_cnt : width;
|
||||
for (uint i = 0; i < col_cnt; ++i) {
|
||||
PIVector<Variable> & cvars(tabs[cur_tab].columns[i].variables);
|
||||
cx = col_wid * i;
|
||||
toUpperLeft();
|
||||
if (max_y < cvars.size()) max_y = cvars.size();
|
||||
j = 0;
|
||||
piForeachC (Variable & tv, cvars) {
|
||||
if (j > height - 3) continue;
|
||||
j++;
|
||||
moveRight(cx);
|
||||
if (tv.type == 15) {
|
||||
newLine();
|
||||
continue;
|
||||
}
|
||||
moveRight(tv.offset);
|
||||
const void * ptr = 0;
|
||||
if (tv.remote) {
|
||||
if (tv.type == 0) {
|
||||
rstr.clear();
|
||||
rba = tv.rdata;
|
||||
rba >> rstr;
|
||||
rstr.trim();
|
||||
ptr = &rstr;
|
||||
} else
|
||||
ptr = tv.rdata.data();
|
||||
} else
|
||||
ptr = tv.ptr;
|
||||
switch (tv.type) {
|
||||
case 0: clen = printValue(ptr != 0 ? *(const PIString*)ptr : PIString(), tv.format); break;
|
||||
case 1: clen = printValue(ptr != 0 ? *(const bool*)ptr : false, tv.format); break;
|
||||
case 2: clen = printValue(ptr != 0 ? *(const int*)ptr : 0, tv.format); break;
|
||||
case 3: clen = printValue(ptr != 0 ? *(const long*)ptr : 0l, tv.format); break;
|
||||
case 4: clen = printValue(ptr != 0 ? *(const char*)ptr : char(0), tv.format); break;
|
||||
case 5: clen = printValue(ptr != 0 ? *(const float*)ptr : 0.f, tv.format); break;
|
||||
case 6: clen = printValue(ptr != 0 ? *(const double*)ptr : 0., tv.format); break;
|
||||
case 7: clen = printValue(ptr != 0 ? *(const short*)ptr : short(0), tv.format); break;
|
||||
case 8: clen = printValue(ptr != 0 ? *(const uint*)ptr : 0u, tv.format); break;
|
||||
case 9: clen = printValue(ptr != 0 ? *(const ulong*)ptr : 0ul, tv.format); break;
|
||||
case 10: clen = printValue(ptr != 0 ? *(const ushort*)ptr : ushort(0), tv.format); break;
|
||||
case 11: clen = printValue(ptr != 0 ? *(const uchar*)ptr : uchar(0), tv.format); break;
|
||||
case 12: clen = printValue(ptr != 0 ? *(const llong*)ptr : 0l, tv.format); break;
|
||||
case 13: clen = printValue(ptr != 0 ? *(const ullong*)ptr: 0ull, tv.format); break;
|
||||
case 20: clen = printValue(ptr != 0 ? *(const PISystemTime*)ptr: PISystemTime(), tv.format); break;
|
||||
case 14: clen = printValue(bitsValue(ptr, tv.bitFrom, tv.bitCount), tv.format); break;
|
||||
}
|
||||
if (clen + tv.offset < (uint)col_wid) {
|
||||
PIString ts = PIString(
|
||||
#if defined(QNX) || defined(FREE_BSD)
|
||||
col_wid - clen - tv.offset - 1, ' ');
|
||||
#else
|
||||
col_wid - clen - tv.offset, ' ');
|
||||
#endif
|
||||
printf("%s", ts.data());
|
||||
}
|
||||
newLine();
|
||||
}
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
moveTo(0, max_y + 1);
|
||||
#else
|
||||
moveTo(0, max_y + 2);
|
||||
#endif
|
||||
fflush(0);
|
||||
__PICout_mutex__.unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::fillLabels() {
|
||||
if (!isRunning()) return;
|
||||
uint cx, cy, mx = 0, dx;
|
||||
#ifdef WINDOWS
|
||||
GetConsoleScreenBufferInfo(hOut, &sbi);
|
||||
width = sbi.srWindow.Right - sbi.srWindow.Left;
|
||||
height = sbi.srWindow.Bottom - sbi.srWindow.Top;
|
||||
#else
|
||||
winsize ws;
|
||||
ioctl(0, TIOCGWINSZ, &ws);
|
||||
width = ws.ws_col;
|
||||
height = ws.ws_row;
|
||||
#endif
|
||||
max_y = 0;
|
||||
col_cnt = columns().size();
|
||||
col_wid = (col_cnt > 0) ? width / col_cnt : width;
|
||||
for (uint i = 0; i < col_cnt; ++i) {
|
||||
Column & ccol(tabs[cur_tab].columns[i]);
|
||||
PIVector<Variable> & cvars(ccol.variables);
|
||||
if (ccol.alignment != Nothing) {
|
||||
mx = 0;
|
||||
piForeachC (Variable & j, cvars)
|
||||
if (!j.isEmpty())
|
||||
if (mx < j.name.size())
|
||||
mx = j.name.size();
|
||||
mx += 2;
|
||||
}
|
||||
cx = col_wid * i;
|
||||
cy = 1;
|
||||
toUpperLeft();
|
||||
for (uint j = 0; j < cvars.size(); ++j) {
|
||||
if (int(j) > height - 3) continue;
|
||||
if (max_y < j) max_y = j;
|
||||
moveRight(cx);
|
||||
Variable & tv(cvars[j]);
|
||||
cvars[j].nx = cx;
|
||||
cvars[j].ny = cy;
|
||||
if (tv.name.isEmpty()) {
|
||||
cvars[j].offset = 0;
|
||||
clearLine();
|
||||
newLine();
|
||||
cy++;
|
||||
continue;
|
||||
}
|
||||
clearLine();
|
||||
//piCout << tv.name << tv.type << tv.ptr;
|
||||
if (tv.type == 15) {
|
||||
cvars[j].offset = cvars[j].name.length();
|
||||
cvars[j].nx += cvars[j].offset;
|
||||
printLine(tv.name, cx, tv.format);
|
||||
newLine();
|
||||
cy++;
|
||||
continue;
|
||||
}
|
||||
if (!tv.isEmpty()) {
|
||||
switch (ccol.alignment) {
|
||||
case Nothing:
|
||||
cvars[j].offset = (tv.name + ": ").length();
|
||||
cvars[j].nx += cvars[j].offset;
|
||||
printValue(tv.name + ": ", tv.format);
|
||||
break;
|
||||
case Left:
|
||||
cvars[j].offset = mx;
|
||||
cvars[j].nx += cvars[j].offset;
|
||||
printValue(tv.name + ": ", tv.format);
|
||||
break;
|
||||
case Right:
|
||||
cvars[j].offset = mx;
|
||||
cvars[j].nx += cvars[j].offset;
|
||||
dx = mx - (tv.name + ": ").length();
|
||||
moveRight(dx);
|
||||
printValue(tv.name + ": ", tv.format);
|
||||
moveLeft(dx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
newLine();
|
||||
cy++;
|
||||
}
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
moveTo(0, max_y + 1);
|
||||
#else
|
||||
moveTo(0, max_y + 2);
|
||||
#endif
|
||||
if (!tabs[cur_tab].status.isEmpty()) {
|
||||
printValue(tabs[cur_tab].status);
|
||||
newLine();
|
||||
}
|
||||
status();
|
||||
//fflush(0);
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::status() {
|
||||
Tab * ctab;
|
||||
//clearLine();
|
||||
for (uint i = 0; i < tabsCount(); ++i) {
|
||||
ctab = &tabs[i];
|
||||
if (ctab->key == 0) continue;
|
||||
printValue(ctab->key, PIConsole::White | PIConsole::Bold);
|
||||
if (i == cur_tab)
|
||||
printValue(ctab->name + " ", PIConsole::BackYellow | PIConsole::Black);
|
||||
else
|
||||
printValue(ctab->name + " ", PIConsole::Cyan | PIConsole::Inverse);
|
||||
printValue(" ");
|
||||
}
|
||||
newLine();
|
||||
}
|
||||
|
||||
|
||||
int PIConsole::bitsValue(const void * src, int offset, int count) const {
|
||||
int ret = 0, stbyte = offset / 8, cbit = offset - stbyte * 8;
|
||||
char cbyte = reinterpret_cast<const char * >(src)[stbyte];
|
||||
for (int i = 0; i < count; i++) {
|
||||
ret |= ((cbyte >> cbit & 1) << i);
|
||||
cbit++;
|
||||
if (cbit == 8) {
|
||||
cbit = 0;
|
||||
stbyte++;
|
||||
cbyte = reinterpret_cast<const char * >(src)[stbyte];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
const char * PIConsole::toBin(const void * d, int s) {
|
||||
binstr.clear();
|
||||
uchar cc, b;
|
||||
for (int i = 0; i < s; ++i) {
|
||||
cc = ((const uchar *)d)[i];
|
||||
b = 1;
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
binstr << (cc & b ? "1" : "0");
|
||||
b <<= 1;
|
||||
}
|
||||
if (i < s - 1) binstr << " ";
|
||||
}
|
||||
binstr.reverse();
|
||||
return binstr.data();
|
||||
}
|
||||
|
||||
|
||||
#define ADD_VAR_BODY vid++; tv.id = vid; tv.name = name; tv.bitFrom = tv.bitCount = 0; tv.format = format; tv.remote = false; checkColumn(col);
|
||||
|
||||
void PIConsole::addString(const PIString & name, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 15; tv.size = 0; tv.ptr = 0; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const PIString * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 0; tv.size = 0; tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const bool * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 1; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const int * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 2; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const long * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 3; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const char * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 4; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const float * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 5; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const double * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 6; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const short * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 7; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const uint * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 8; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const ulong * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 9; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const ushort * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 10; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const uchar * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 11; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const llong * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 12; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const ullong * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 13; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const PISystemTime * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
ADD_VAR_BODY tv.type = 20; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
/** \brief Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
* \details This function add to column "column" next lines:
|
||||
* * "protocol <name>"
|
||||
* * "Rec - receiverDeviceName": \a PIProtocol::receiverDeviceState
|
||||
* * "Send - senderDeviceName": \a PIProtocol::senderDeviceState
|
||||
* * "Received count": \a PIProtocol::receiveCount
|
||||
* * "Invalid count": \a PIProtocol::wrongCount
|
||||
* * "Missed count": \a PIProtocol::missedCount
|
||||
* * "Sended count": \a PIProtocol::sendCount
|
||||
* * "Immediate Frequency, Hz": \a PIProtocol::immediateFrequency
|
||||
* * "Integral Frequency, Hz": \a PIProtocol::integralFrequency
|
||||
* * "Receive speed": \a PIProtocol::receiveSpeed
|
||||
* * "Send speed": \a PIProtocol::sendSpeed
|
||||
* * "Receiver history size": \a PIProtocol::receiverHistorySize
|
||||
* * "Sender history size": \a PIProtocol::senderHistorySize
|
||||
* * "Disconnect Timeout, s": \a PIProtocol::disconnectTimeout
|
||||
* * "Quality": \a PIProtocol::quality
|
||||
* */
|
||||
void PIConsole::addVariable(const PIString & name, const PIProtocol * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
addString("protocol " + name, col, format | PIConsole::Bold);
|
||||
addVariable("Rec - " + ptr->receiverDeviceName(), ptr->receiverDeviceState_ptr(), col, format);
|
||||
addVariable("Send - " + ptr->senderDeviceName(), ptr->senderDeviceState_ptr(), col, format);
|
||||
addVariable("Received count", ptr->receiveCount_ptr(), col, format);
|
||||
addVariable("Invalid count", ptr->wrongCount_ptr(), col, format);
|
||||
addVariable("Missed count", ptr->missedCount_ptr(), col, format);
|
||||
addVariable("Sended count", ptr->sendCount_ptr(), col, format);
|
||||
addVariable("Immediate Frequency, Hz", ptr->immediateFrequency_ptr(), col, format);
|
||||
addVariable("Integral Frequency, Hz", ptr->integralFrequency_ptr(), col, format);
|
||||
addVariable("Receive speed", ptr->receiveSpeed_ptr(), col, format);
|
||||
addVariable("Send speed", ptr->sendSpeed_ptr(), col, format);
|
||||
addVariable("Receiver history size", ptr->receiverHistorySize_ptr(), col, format);
|
||||
addVariable("Sender history size", ptr->senderHistorySize_ptr(), col, format);
|
||||
addVariable("Disconnect Timeout, s", ptr->disconnectTimeout_ptr(), col, format);
|
||||
addVariable("Quality", ptr->quality_ptr(), col, format);
|
||||
}
|
||||
/** \brief Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
* \details This function add to column "column" next lines:
|
||||
* * "<name> diagnostics"
|
||||
* * "Received count": \a PIDiagnostics::receiveCount
|
||||
* * "Invalid count": \a PIDiagnostics::wrongCount
|
||||
* * "Sended count": \a PIDiagnostics::sendCount
|
||||
* * "Immediate Frequency, Hz": \a PIDiagnostics::immediateFrequency
|
||||
* * "Integral Frequency, Hz": \a PIDiagnostics::integralFrequency
|
||||
* * "Receive speed": \a PIDiagnostics::receiveSpeed
|
||||
* * "Send speed": \a PIDiagnostics::sendSpeed
|
||||
* * "Quality": \a PIDiagnostics::quality
|
||||
* */
|
||||
void PIConsole::addVariable(const PIString & name, const PIDiagnostics * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
addString(name + " diagnostics", col, format | PIConsole::Bold);
|
||||
addVariable("Received count", ptr->receiveCount_ptr(), col, format);
|
||||
addVariable("Invalid count", ptr->wrongCount_ptr(), col, format);
|
||||
addVariable("Sended count", ptr->sendCount_ptr(), col, format);
|
||||
addVariable("Immediate Frequency, Hz", ptr->immediateFrequency_ptr(), col, format);
|
||||
addVariable("Integral Frequency, Hz", ptr->integralFrequency_ptr(), col, format);
|
||||
addVariable("Receive speed", ptr->receiveSpeed_ptr(), col, format);
|
||||
addVariable("Send speed", ptr->sendSpeed_ptr(), col, format);
|
||||
addVariable("Quality", ptr->quality_ptr(), col, format);
|
||||
}
|
||||
void PIConsole::addVariable(const PIString & name, const PISystemMonitor * ptr, int col, PIFlags<PIConsole::Format> format) {
|
||||
addString("monitor " + name, col, format | PIConsole::Bold);
|
||||
addVariable("state", &(ptr->statistic().state), col, format);
|
||||
addVariable("threads", &(ptr->statistic().threads), col, format);
|
||||
addVariable("priority", &(ptr->statistic().priority), col, format);
|
||||
addVariable("memory physical", &(ptr->statistic().physical_memsize_readable), col, format);
|
||||
addVariable("memory shared", &(ptr->statistic().share_memsize_readable), col, format);
|
||||
addVariable("cpu load", &(ptr->statistic().cpu_load_user), col, format);
|
||||
}
|
||||
void PIConsole::addBitVariable(const PIString & name, const void * ptr, int fromBit, int bitCount, int col, PIFlags<PIConsole::Format> format) {
|
||||
vid++; tv.id = vid; tv.size = sizeof(ullong); tv.name = name; tv.bitFrom = fromBit; tv.bitCount = bitCount; tv.type = 14; tv.ptr = ptr; tv.format = format;
|
||||
checkColumn(col); column(col).push_back(tv);}
|
||||
void PIConsole::addEmptyLine(int col, uint count) {
|
||||
tv.id = 0; tv.size = 0; tv.name = ""; tv.type = 0; tv.ptr = 0; tv.format = Normal;
|
||||
for (uint i = 0; i < count; ++i) {
|
||||
checkColumn(col);
|
||||
column(col).push_back(tv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIString PIConsole::getString(int x, int y) {
|
||||
bool run = isRunning();
|
||||
if (run) PIThread::stop(true);
|
||||
listener->setActive(false);
|
||||
msleep(50);
|
||||
#ifdef WINDOWS
|
||||
moveTo(x - 1, y - 1);
|
||||
#else
|
||||
moveTo(x, y);
|
||||
#endif
|
||||
showCursor();
|
||||
PIByteArray ba(4096);
|
||||
#ifdef CC_VC
|
||||
int ret = scanf_s(" %s", ba.data());
|
||||
#else
|
||||
int ret = scanf(" %s", ba.data());
|
||||
#endif
|
||||
listener->setActive(true);
|
||||
if (run) start();
|
||||
if (ret >= 1) return PIString(ba);
|
||||
else return PIString();
|
||||
}
|
||||
|
||||
|
||||
PIString PIConsole::getString(const PIString & name) {
|
||||
piForeachC (Column & i, tabs[cur_tab].columns)
|
||||
piForeachC (Variable & j, i.variables)
|
||||
if (j.name == name)
|
||||
return getString(j.nx + 1, j.ny);
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
#define PRINT_VAR_BODY couts(fstr(format)); int ret = couts(value); couts(fstr(PIConsole::Dec)); return ret;
|
||||
|
||||
inline void PIConsole::printLine(const PIString & value, int dx, PIFlags<PIConsole::Format> format) {
|
||||
int i = width - value.length() - dx;
|
||||
#if defined(QNX) || defined(FREE_BSD)
|
||||
--i;
|
||||
#endif
|
||||
PIString ts = fstr(format);
|
||||
couts(ts);
|
||||
if (i >= 0) ts = value + PIString(i, ' ');
|
||||
else ts = value.left(value.size() + i);
|
||||
couts(ts);
|
||||
couts(fstr(Dec));
|
||||
}
|
||||
inline int PIConsole::printValue(const PIString & value, PIFlags<PIConsole::Format> format) {
|
||||
couts(fstr(format));
|
||||
int ret = couts(value);
|
||||
fstr(PIConsole::Dec);
|
||||
return ret;
|
||||
}
|
||||
inline int PIConsole::printValue(const char * value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const bool value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const int value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const long value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const llong value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const float value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const double value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const char value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const short value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const uchar value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const ushort value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const uint value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const ulong value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const ullong value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const PISystemTime & value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
|
||||
|
||||
|
||||
|
||||
void PIConsole::startServer(const PIString & name) {
|
||||
stopPeer();
|
||||
server_mode = true;
|
||||
peer = new PIPeer("_rcs_:" + name);
|
||||
CONNECT2(void, const PIString & , const PIByteArray &, peer, dataReceivedEvent, this, peerReceived);
|
||||
CONNECT1(void, const PIString & , peer, peerDisconnectedEvent, this, peerDisconnectedEvent);
|
||||
peer_timer.start(50.);
|
||||
serverSendInfo();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::stopPeer() {
|
||||
remote_clients.clear();
|
||||
peer_timer.stop();
|
||||
if (peer != 0) delete peer;
|
||||
peer = 0;
|
||||
state = Disconnected;
|
||||
}
|
||||
|
||||
|
||||
PIStringList PIConsole::clients() const {
|
||||
PIStringList sl;
|
||||
if (peer == 0) return sl;
|
||||
piForeachC (PIPeer::PeerInfo & i, peer->allPeers()) {
|
||||
if (i.name.left(6) != "_rcc_:") continue;
|
||||
sl << i.name.right(i.name.length() - 6);
|
||||
}
|
||||
return sl;
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::listenServers() {
|
||||
stopPeer();
|
||||
server_mode = false;
|
||||
server_name.clear();
|
||||
srand(PISystemTime::current().nanoseconds);
|
||||
peer = new PIPeer("_rcc_:" + PIDateTime::current().toString("hhmmssddMMyy_") + PIString::fromNumber(rand()));
|
||||
CONNECT2(void, const PIString & , const PIByteArray &, peer, dataReceivedEvent, this, peerReceived);
|
||||
peer_timer.start(100.);
|
||||
}
|
||||
|
||||
|
||||
PIStringList PIConsole::availableServers() const {
|
||||
PIStringList sl;
|
||||
if (peer == 0) return sl;
|
||||
piForeachC (PIPeer::PeerInfo & i, peer->allPeers()) {
|
||||
if (i.name.left(6) != "_rcs_:") continue;
|
||||
sl << i.name.right(i.name.length() - 6);
|
||||
}
|
||||
return sl;
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::connectToServer(const PIString & name) {
|
||||
if (peer == 0) listenServers();
|
||||
server_name = name;
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::disconnect() {
|
||||
stopPeer();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::serverSendInfo() {
|
||||
if (peer == 0) return;
|
||||
PIByteArray ba;
|
||||
ba << int(0xAA);
|
||||
peer->sendToAll(ba);
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::serverSendData() {
|
||||
if (peer == 0) return;
|
||||
PIByteArray ba;
|
||||
PIVector<VariableContent> content;
|
||||
piForeach (Tab & t, tabs)
|
||||
piForeach (Column & c, t.columns)
|
||||
piForeach (Variable & v, c.variables)
|
||||
if (!v.isEmpty() && v.id > 0) {
|
||||
VariableContent vc;
|
||||
vc.id = v.id;
|
||||
v.writeData(vc.rdata);
|
||||
content << vc;
|
||||
}
|
||||
piForeach (RemoteClient & rc, remote_clients) {
|
||||
ba.clear();
|
||||
switch (rc.state) {
|
||||
case FetchingData:
|
||||
ba << int(0xCC) << tabs;
|
||||
//piCout << "server send const data" << rc.name << ba.size_s();
|
||||
break;
|
||||
case Committing:
|
||||
ba << int(0xDD);
|
||||
break;
|
||||
case Connected:
|
||||
ba << int(0xEE) << content;
|
||||
//piCout << "send data" << ba.size();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
if (!ba.isEmpty())
|
||||
peer->send(rc.name, ba);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIConsole::RemoteClient & PIConsole::remoteClient(const PIString & fname) {
|
||||
piForeach (RemoteClient & i, remote_clients)
|
||||
if (i.name == fname)
|
||||
return i;
|
||||
remote_clients << RemoteClient(fname);
|
||||
return remote_clients.back();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::peerReceived(const PIString & from, const PIByteArray & data) {
|
||||
int type;
|
||||
PIByteArray ba(data);
|
||||
ba >> type;
|
||||
//piCout << "rec packet from" << from << "type" << PICoutManipulators::Hex << type;
|
||||
if (server_mode) {
|
||||
if (from.left(5) != "_rcc_") return;
|
||||
//PIString rcn = from.right(from.length() - 6);
|
||||
RemoteClient & rc(remoteClient(from));
|
||||
switch (type) {
|
||||
case 0xBB: // fetch const data request
|
||||
//piCout << "fetch data request from" << from << rc.state;
|
||||
if (rc.state != Connected)
|
||||
rc.state = FetchingData;
|
||||
break;
|
||||
case 0xCC: // const data commit
|
||||
//piCout << "commit from" << from;
|
||||
if (rc.state != Connected)
|
||||
rc.state = Connected;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
} else {
|
||||
PIVector<VariableContent> content;
|
||||
PIMap<int, Variable * > vids;
|
||||
if (from.left(5) != "_rcs_") return;
|
||||
PIString rcn = from.right(from.length() - 6);
|
||||
switch (type) {
|
||||
case 0xAA: // new server
|
||||
//piCout << "new server" << rcn;
|
||||
break;
|
||||
case 0xCC: // const data
|
||||
//piCout << "received const data";
|
||||
state = Committing;
|
||||
ba >> tabs;
|
||||
cur_tab = tabs.isEmpty() ? -1 : 0;
|
||||
piForeach (Tab & t, tabs)
|
||||
piForeach (Column & c, t.columns)
|
||||
piForeach (Variable & v, c.variables)
|
||||
v.remote = true;
|
||||
break;
|
||||
case 0xDD: // const data commit
|
||||
//piCout << "received commit";
|
||||
state = Connected;
|
||||
break;
|
||||
case 0xEE: // dynamic data
|
||||
//piCout << "received data" << ba.size_s();
|
||||
piForeach (Tab & t, tabs)
|
||||
piForeach (Column & c, t.columns)
|
||||
piForeach (Variable & v, c.variables)
|
||||
if (!v.isEmpty() && v.id > 0)
|
||||
vids[v.id] = &v;
|
||||
ba >> content;
|
||||
piForeach (VariableContent & vc, content) {
|
||||
if (vc.id <= 0) continue;
|
||||
Variable * v = vids.at(vc.id);
|
||||
if (v == 0) continue;
|
||||
//piCout << "read" << v->name << vc.rdata.size_s();
|
||||
v->rdata = vc.rdata;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::peerTimer(void * data, int delim) {
|
||||
if (peer == 0) return;
|
||||
//piCout << "timer" << delim;
|
||||
if (server_mode) {
|
||||
if (delim == 20)
|
||||
serverSendInfo();
|
||||
else
|
||||
serverSendData();
|
||||
} else {
|
||||
if (delim != 1 || server_name.isEmpty()) return;
|
||||
const PIPeer::PeerInfo * p = peer->getPeerByName("_rcs_:" + server_name);
|
||||
if (p == 0) return;
|
||||
PIByteArray ba;
|
||||
switch (state) {
|
||||
case Disconnected:
|
||||
peer_timer.reset();
|
||||
ba << int(0xBB);
|
||||
//piCout << "send to" << server_name << "fetch request disc";
|
||||
peer->send(p, ba);
|
||||
state = FetchingData;
|
||||
break;
|
||||
case FetchingData:
|
||||
if (peer_timer.elapsed_s() < 3.)
|
||||
return;
|
||||
peer_timer.reset();
|
||||
ba << int(0xBB);
|
||||
//piCout << "send to" << server_name << "fetch request fd";
|
||||
peer->send(p, ba);
|
||||
break;
|
||||
case Committing:
|
||||
peer_timer.reset();
|
||||
ba << int(0xCC);
|
||||
//piCout << "send to" << server_name << "committing";
|
||||
state = Connected;
|
||||
peer->send(p, ba);
|
||||
break;
|
||||
default: break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::peerDisconnectedEvent(const PIString & name) {
|
||||
for (int i = 0; i < remote_clients.size_s(); ++i)
|
||||
if (remote_clients[i].name == name) {
|
||||
remote_clients.remove(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
489
piconsole.h
489
piconsole.h
@@ -1,489 +0,0 @@
|
||||
/*! \file piconsole.h
|
||||
* \brief Console output class
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Console output/input
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PICONSOLE_H
|
||||
#define PICONSOLE_H
|
||||
|
||||
#include "pikbdlistener.h"
|
||||
#include "piprotocol.h"
|
||||
#include "pidiagnostics.h"
|
||||
#include "pisystemmonitor.h"
|
||||
#ifndef WINDOWS
|
||||
# include <sys/ioctl.h>
|
||||
# include <fcntl.h>
|
||||
#else
|
||||
# define COMMON_LVB_UNDERSCORE 0x8000
|
||||
#endif
|
||||
|
||||
class PIPeer;
|
||||
|
||||
class PIP_EXPORT PIConsole: public PIThread
|
||||
{
|
||||
PIOBJECT(PIConsole)
|
||||
public:
|
||||
|
||||
//! Constructs %PIConsole with key handler "slot" and if "startNow" start it
|
||||
PIConsole(bool startNow = true, KBFunc slot = 0);
|
||||
|
||||
~PIConsole();
|
||||
|
||||
|
||||
//! Variables output format
|
||||
enum Format {
|
||||
Normal /** Default console format */ = 0x01,
|
||||
Bold /** Bold text */ = 0x02,
|
||||
Faint = 0x04,
|
||||
Italic = 0x08,
|
||||
Underline /** Underlined text */ = 0x10,
|
||||
Blink /** Blinked text */ = 0x20,
|
||||
Inverse /** Swap text and background colors */ = 0x40,
|
||||
Black /** Black text */ = 0x100,
|
||||
Red /** Red text */ = 0x200,
|
||||
Green /** Green text */ = 0x400,
|
||||
Yellow /** Yellow text */ = 0x800,
|
||||
Blue /** Blue text */ = 0x1000,
|
||||
Magenta /** Magenta text */ = 0x2000,
|
||||
Cyan /** Cyan text */ = 0x4000,
|
||||
White /** White text */ = 0x8000,
|
||||
BackBlack /** Black background */ = 0x10000,
|
||||
BackRed /** Red background */ = 0x20000,
|
||||
BackGreen /** Green background */ = 0x40000,
|
||||
BackYellow /** Yellow background */ = 0x80000,
|
||||
BackBlue /** Blue background */ = 0x100000,
|
||||
BackMagenta /** Magenta background */ = 0x200000,
|
||||
BackCyan /** Cyan background */ = 0x400000,
|
||||
BackWhite /** White background */ = 0x800000,
|
||||
Dec /** Decimal base for integers */ = 0x1000000,
|
||||
Hex /** Hexadecimal base for integers */ = 0x2000000,
|
||||
Oct /** Octal base for integers */ = 0x4000000,
|
||||
Bin /** Binary base for integers */ = 0x8000000,
|
||||
Scientific /** Scientific representation of floats */ = 0x10000000,
|
||||
SystemTimeSplit /** PISystemTime split representation (* s, * ns) */ = 0x20000000,
|
||||
SystemTimeSeconds /** PISystemTime seconds representation (*.* s) */ = 0x40000000
|
||||
};
|
||||
|
||||
//! Column labels alignment
|
||||
enum Alignment {
|
||||
Nothing /** No alignment */ ,
|
||||
Left /** Labels align left and variables align left */ ,
|
||||
Right /** Labels align right and variables align left */
|
||||
};
|
||||
|
||||
//! Add to current tab to column "column" string "name" with format "format"
|
||||
void addString(const PIString & name, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const PIString * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const char * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const bool * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const short * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const int * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const long * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const llong * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const uchar * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const ushort * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const uint * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const ulong * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const ullong * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const float * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const double * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const PISystemTime * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
void addVariable(const PIString & name, const PIProtocol * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
void addVariable(const PIString & name, const PIDiagnostics * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
void addVariable(const PIString & name, const PISystemMonitor * ptr, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" bits field with label "name", pointer "ptr" and format "format"
|
||||
void addBitVariable(const PIString & name, const void * ptr, int fromBit, int bitsCount, int column = 1, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" "count" empty lines
|
||||
void addEmptyLine(int column = 1, uint count = 1);
|
||||
|
||||
PIString getString(int x, int y);
|
||||
short getShort(int x, int y) {return getString(x, y).toShort();}
|
||||
int getInt(int x, int y) {return getString(x, y).toInt();}
|
||||
float getFloat(int x, int y) {return getString(x, y).toFloat();}
|
||||
double getDouble(int x, int y) {return getString(x, y).toDouble();}
|
||||
PIString getString(const PIString & name);
|
||||
short getShort(const PIString & name) {return getString(name).toShort();}
|
||||
int getInt(const PIString & name) {return getString(name).toInt();}
|
||||
float getFloat(const PIString & name) {return getString(name).toFloat();}
|
||||
double getDouble(const PIString & name) {return getString(name).toDouble();}
|
||||
|
||||
|
||||
//! Returns tabs count
|
||||
uint tabsCount() const {return tabs.size();}
|
||||
|
||||
//! Returns current tab name
|
||||
PIString currentTab() const {return tabs[cur_tab].name;}
|
||||
|
||||
//! Add new tab with name "name", bind key "bind_key" and returns this tab index
|
||||
int addTab(const PIString & name, char bind_key = 0);
|
||||
|
||||
//! Remove tab with index "index"
|
||||
void removeTab(uint index);
|
||||
|
||||
//! Remove tab with name "name"
|
||||
void removeTab(const PIString & name);
|
||||
|
||||
//! Set current tab to tab with index "index", returns if tab exists
|
||||
bool setTab(uint index);
|
||||
|
||||
//! Set current tab to tab with name "name", returns if tab exists
|
||||
bool setTab(const PIString & name);
|
||||
|
||||
//! Set tab with index "index" bind key to "bind_key", returns if tab exists
|
||||
bool setTabBindKey(uint index, char bind_key);
|
||||
|
||||
//! Set tab with name "name" bind key to "bind_key", returns if tab exists
|
||||
bool setTabBindKey(const PIString & name, char bind_key);
|
||||
|
||||
//! Remove all tabs and if "clearScreen" clear the screen
|
||||
void clearTabs(bool clearScreen = true) {if (clearScreen && isRunning()) {toUpperLeft(); clearScreenLower();} tabs.clear();}
|
||||
|
||||
|
||||
//! Set custom status text of current tab to "str"
|
||||
void addCustomStatus(const PIString & str) {tabs[cur_tab].status = str;}
|
||||
|
||||
//! Clear custom status text of current tab
|
||||
void clearCustomStatus() {tabs[cur_tab].status.clear();}
|
||||
|
||||
//! Returns default alignment
|
||||
Alignment defaultAlignment() const {return def_align;}
|
||||
|
||||
//! Set default alignment to "align"
|
||||
void setDefaultAlignment(Alignment align) {def_align = align;}
|
||||
|
||||
//! Set column "col" alignment to "align"
|
||||
void setColumnAlignment(int col, Alignment align) {if (col < 0 || col >= columns().size_s()) return; column(col).alignment = align;}
|
||||
|
||||
//! Set all columns of all tabs alignment to "align"
|
||||
void setColumnAlignmentToAll(Alignment align) {piForeach (Tab & i, tabs) piForeach (Column & j, i.columns) j.alignment = align; fillLabels();}
|
||||
PIString fstr(PIFlags<PIConsole::Format> f);
|
||||
|
||||
|
||||
//! Directly call function from \a PIKbdListener
|
||||
void enableExitCapture(char key = 'Q') {listener->enableExitCapture(key);}
|
||||
|
||||
//! Directly call function from \a PIKbdListener
|
||||
void disableExitCapture() {listener->disableExitCapture();}
|
||||
|
||||
//! Directly call function from \a PIKbdListener
|
||||
bool exitCaptured() const {return listener->exitCaptured();}
|
||||
|
||||
//! Directly call function from \a PIKbdListener
|
||||
char exitKey() const {return listener->exitKey();}
|
||||
|
||||
// Server functions
|
||||
void startServer(const PIString & name);
|
||||
void stopPeer();
|
||||
bool isServerStarted() const {return peer != 0;}
|
||||
PIStringList clients() const;
|
||||
|
||||
// Client functions
|
||||
void listenServers();
|
||||
PIStringList availableServers() const;
|
||||
PIString selectedServer() const {return server_name;}
|
||||
void connectToServer(const PIString & name);
|
||||
void disconnect();
|
||||
bool isConnected() const {return state == Connected;}
|
||||
|
||||
#ifdef WINDOWS
|
||||
void toUpperLeft() {SetConsoleCursorPosition(hOut, ulcoord);}
|
||||
void moveRight(int n = 1) {SetConsoleCursorPosition(hOut, getWinCoord(n));}
|
||||
void moveLeft(int n = 1) {SetConsoleCursorPosition(hOut, getWinCoord(-n));}
|
||||
void moveTo(int x = 0, int y = 0) {ccoord.X = x; ccoord.Y = ulcoord.Y + y; SetConsoleCursorPosition(hOut, ccoord);}
|
||||
void clearScreen() {toUpperLeft(); FillConsoleOutputAttribute(hOut, dattr, width * (height + 1), ulcoord, &written);
|
||||
FillConsoleOutputCharacter(hOut, ' ', width * (height + 1), ulcoord, &written);}
|
||||
void clearScreenLower() {getWinCurCoord(); FillConsoleOutputAttribute(hOut, dattr, width * height - width * ccoord.Y + ccoord.X, ccoord, &written);
|
||||
FillConsoleOutputCharacter(hOut, ' ', width * height - width * ccoord.Y + ccoord.X, ccoord, &written);}
|
||||
void clearLine() {getWinCurCoord(); FillConsoleOutputAttribute(hOut, dattr, width - ccoord.X, ccoord, &written);
|
||||
FillConsoleOutputCharacter(hOut, ' ', width - ccoord.X, ccoord, &written);}
|
||||
void newLine() {getWinCurCoord(); ccoord.X = 0; ccoord.Y++; SetConsoleCursorPosition(hOut, ccoord);}
|
||||
void hideCursor() {curinfo.bVisible = false; SetConsoleCursorInfo(hOut, &curinfo);}
|
||||
void showCursor() {curinfo.bVisible = true; SetConsoleCursorInfo(hOut, &curinfo);}
|
||||
#else
|
||||
void toUpperLeft() {printf("\e[H");}
|
||||
void moveRight(int n = 1) {if (n > 0) printf("\e[%dC", n);}
|
||||
void moveLeft(int n = 1) {if (n > 0) printf("\e[%dD", n);}
|
||||
void moveTo(int x = 0, int y = 0) {printf("\e[%d;%dH", y, x);}
|
||||
void clearScreen() {printf("\e[H\e[J");}
|
||||
void clearScreenLower() {printf("\e[J");}
|
||||
void clearLine() {printf("\e[K");}
|
||||
void newLine() {printf("\eE");}
|
||||
void hideCursor() {printf("\e[?25l");}
|
||||
void showCursor() {printf("\e[?25h");}
|
||||
#endif
|
||||
|
||||
EVENT_HANDLER0(void, clearVariables) {clearVariables(true);}
|
||||
EVENT_HANDLER1(void, clearVariables, bool, clearScreen) {if (clearScreen && isRunning()) {toUpperLeft(); clearScreenLower();} columns().clear();}
|
||||
|
||||
EVENT_HANDLER0(void, waitForFinish) {WAIT_FOR_EXIT}
|
||||
EVENT_HANDLER0(void, start) {start(false);}
|
||||
EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();}
|
||||
EVENT_HANDLER0(void, stop) {stop(false);}
|
||||
EVENT_HANDLER1(void, stop, bool, clear);
|
||||
|
||||
EVENT2(keyPressed, char, key, void * , data)
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void waitForFinish()
|
||||
//! \brief block until finished (exit key will be pressed)
|
||||
|
||||
//! \fn void clearVariables(bool clearScreen = true)
|
||||
//! \brief Remove all columns at current tab and if "clearScreen" clear the screen
|
||||
|
||||
//! \fn void start(bool wait = false)
|
||||
//! \brief Start console output and if "wait" block until finished (exit key will be pressed)
|
||||
|
||||
//! \fn void stop(bool clear = false)
|
||||
//! \brief Stop console output and if "clear" clear the screen
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void keyPressed(char key, void * data)
|
||||
//! \brief Raise on key "key" pressed, "data" is pointer to %PIConsole object
|
||||
|
||||
//! \}
|
||||
|
||||
private:
|
||||
#ifdef WINDOWS
|
||||
void getWinCurCoord() {GetConsoleScreenBufferInfo(hOut, &csbi); ccoord = csbi.dwCursorPosition;}
|
||||
COORD & getWinCoord(int dx = 0, int dy = 0) {getWinCurCoord(); ccoord.X += dx; ccoord.Y += dy; return ccoord;}
|
||||
#endif
|
||||
|
||||
void begin();
|
||||
void run();
|
||||
void fillLabels();
|
||||
void status();
|
||||
void checkColumn(uint col) {while (columns().size() < col) columns().push_back(Column(def_align));}
|
||||
int bitsValue(const void * src, int offset, int count) const;
|
||||
const char * toBin(const void * d, int s);
|
||||
inline void printLine(const PIString & str, int dx = 0, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const PIString & str, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const char * str, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const bool value, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const int value, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const long value, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const llong value, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const float value, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const double value, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const char value, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const short value, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const uchar value, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const ushort value, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const uint value, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const ulong value, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const ullong value, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
inline int printValue(const PISystemTime & value, PIFlags<PIConsole::Format> format = PIConsole::Normal);
|
||||
static void key_event(char key, void * t);
|
||||
|
||||
struct Variable {
|
||||
Variable() {nx = ny = type = offset = bitFrom = bitCount = size = 0; format = Normal; remote = false; ptr = 0; id = 1;}
|
||||
bool isEmpty() const {return (remote ? false : ptr == 0);}
|
||||
const void * data() {return (remote ? rdata.data() : ptr);}
|
||||
void writeData(PIByteArray & ba) {
|
||||
if (remote) ba << rdata;
|
||||
else {
|
||||
if (type == 0) ba << (*(PIString * )ptr);
|
||||
else ba << PIByteArray::RawData(ptr, size);
|
||||
}
|
||||
}
|
||||
PIString name;
|
||||
PIFlags<PIConsole::Format> format;
|
||||
int nx;
|
||||
int ny;
|
||||
int type;
|
||||
int offset;
|
||||
int bitFrom;
|
||||
int bitCount;
|
||||
int size;
|
||||
int id;
|
||||
bool remote;
|
||||
const void * ptr;
|
||||
PIByteArray rdata;
|
||||
void operator =(const Variable & src) {remote = src.remote; name = src.name; format = src.format; type = src.type; offset = src.offset; size = src.size;
|
||||
bitFrom = src.bitFrom; bitCount = src.bitCount; ptr = src.ptr; nx = src.nx; ny = src.ny; rdata = src.rdata; id = src.id;}
|
||||
};
|
||||
|
||||
struct VariableContent {
|
||||
int id;
|
||||
PIByteArray rdata;
|
||||
};
|
||||
|
||||
struct Column {
|
||||
Column(Alignment align = PIConsole::Right) {variables.reserve(16); alignment = align;}
|
||||
PIVector<Variable> variables;
|
||||
Alignment alignment;
|
||||
uint size() const {return variables.size();}
|
||||
Variable & operator [](int index) {return variables[index];}
|
||||
const Variable & operator [](int index) const {return variables[index];}
|
||||
void push_back(const Variable & v) {variables.push_back(v);}
|
||||
void operator =(const Column & src) {variables = src.variables; alignment = src.alignment;}
|
||||
};
|
||||
|
||||
struct Tab {
|
||||
Tab(PIString n = "", char k = 0) {columns.reserve(16); name = n; key = k;}
|
||||
PIVector<Column> columns;
|
||||
PIString name;
|
||||
PIString status;
|
||||
char key;
|
||||
};
|
||||
|
||||
enum ConnectedState {Disconnected, FetchingData, Committing, Connected};
|
||||
|
||||
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::VariableContent & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::VariableContent & v);
|
||||
|
||||
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Variable & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Variable & v);
|
||||
|
||||
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Column & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Column & v);
|
||||
|
||||
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Tab & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Tab & v);
|
||||
|
||||
PIVector<Column> & columns() {return tabs[cur_tab].columns;}
|
||||
Column & column(int index) {return tabs[cur_tab].columns[index - 1];}
|
||||
inline int couts(const PIString & v);
|
||||
inline int couts(const char * v);
|
||||
inline int couts(const bool v);
|
||||
inline int couts(const char v);
|
||||
inline int couts(const short v);
|
||||
inline int couts(const int v);
|
||||
inline int couts(const long v);
|
||||
inline int couts(const llong v);
|
||||
inline int couts(const uchar v);
|
||||
inline int couts(const ushort v);
|
||||
inline int couts(const uint v);
|
||||
inline int couts(const ulong v);
|
||||
inline int couts(const ullong v);
|
||||
inline int couts(const float v);
|
||||
inline int couts(const double v);
|
||||
inline int couts(const PISystemTime & v);
|
||||
|
||||
struct RemoteClient;
|
||||
|
||||
void serverSendInfo();
|
||||
void serverSendData();
|
||||
RemoteClient & remoteClient(const PIString & fname);
|
||||
EVENT_HANDLER2(void, peerReceived, const PIString &, from, const PIByteArray &, data);
|
||||
EVENT_HANDLER2(void, peerTimer, void * , data, int, delim);
|
||||
EVENT_HANDLER1(void, peerDisconnectedEvent, const PIString &, name);
|
||||
|
||||
#ifdef WINDOWS
|
||||
void * hOut;
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi, csbi;
|
||||
CONSOLE_CURSOR_INFO curinfo;
|
||||
COORD ccoord, ulcoord;
|
||||
WORD dattr;
|
||||
DWORD smode, written;
|
||||
#else
|
||||
struct termios sterm, vterm;
|
||||
#endif
|
||||
PIVector<Tab> tabs;
|
||||
PIString binstr, rstr;
|
||||
PIByteArray rba;
|
||||
Variable tv;
|
||||
PIKbdListener * listener;
|
||||
Alignment def_align;
|
||||
KBFunc ret_func;
|
||||
int width, height, pwidth, pheight, ret, col_wid, num_format, systime_format;
|
||||
uint max_y;
|
||||
int vid;
|
||||
uint cur_tab, col_cnt;
|
||||
|
||||
PIPeer * peer;
|
||||
PITimer peer_timer;
|
||||
PIString server_name;
|
||||
bool server_mode;
|
||||
ConnectedState state;
|
||||
|
||||
/*struct RemoteData {
|
||||
RemoteData() {msg_count = msg_rec = msg_send = 0;}
|
||||
void clear() {msg_count = msg_rec = msg_send = 0; data.clear();}
|
||||
bool isEmpty() const {return msg_count == 0;}
|
||||
bool isReadyRec() const {return msg_count == msg_rec;}
|
||||
bool isReadySend() const {return msg_count == msg_send;}
|
||||
void setData(const PIByteArray & ba) {data = ba; msg_rec = msg_send = 0; msg_count = (data.size_s() - 1) / 4096 + 1;}
|
||||
PIByteArray data;
|
||||
int msg_count;
|
||||
int msg_rec;
|
||||
int msg_send;
|
||||
};*/
|
||||
|
||||
struct RemoteClient {
|
||||
RemoteClient(const PIString & n = "") {name = n; state = Disconnected;}
|
||||
PIString name;
|
||||
ConnectedState state;
|
||||
};
|
||||
|
||||
PIVector<RemoteClient> remote_clients;
|
||||
|
||||
};
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::VariableContent & v) {ba << v.id << v.rdata; return ba;}
|
||||
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::VariableContent & v) {ba >> v.id; ba >> v.rdata; return ba;}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Variable & v) {ba << v.name << v.id << (int)v.format << v.type << v.size << v.bitFrom << v.bitCount; return ba;}
|
||||
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Variable & v) {ba >> v.name >> v.id >> (int & )v.format >> v.type >> v.size >> v.bitFrom >> v.bitCount; return ba;}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Column & v) {ba << (int)v.alignment << v.variables; return ba;}
|
||||
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Column & v) {ba >> (int & )v.alignment >> v.variables; return ba;}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Tab & v) {ba << v.name << v.status << (uchar)v.key << v.columns; return ba;}
|
||||
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Tab & v) {ba >> v.name >> v.status >> (uchar&)v.key >> v.columns; return ba;}
|
||||
|
||||
#endif // PICONSOLE_H
|
||||
177
picontainers.cpp
177
picontainers.cpp
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Generic containers
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// * This class based on std::vector, expanding his functionality
|
||||
|
||||
#include "pivector.h"
|
||||
|
||||
/** \class PIVector
|
||||
* \brief Dynamic array of any type
|
||||
* \details This class used to store dynamic array of any
|
||||
* type of data. In memory data stored linear. You can insert
|
||||
* item in any place of remove some items from any place.
|
||||
* For quick add elements this is stream operator <<.
|
||||
|
||||
* \fn PIVector::PIVector();
|
||||
* Contructs an empty vector
|
||||
|
||||
* \fn PIVector::PIVector(ullong size, const Type & value = Type());
|
||||
* \brief Contructs vector with size "size" filled elements "value"
|
||||
* \details Example: \snippet picontainers.cpp PIVector::PIVector
|
||||
|
||||
* \fn const Type & PIVector::at(ullong index) const;
|
||||
* \brief Read-only access to element by index "index"
|
||||
* \details Example: \snippet picontainers.cpp PIVector::at_c
|
||||
* \sa \a operator[]
|
||||
|
||||
* \fn Type & PIVector::at(ullong index);
|
||||
* \brief Full access to element by index "index"
|
||||
* \details Example: \snippet picontainers.cpp PIVector::at
|
||||
* \sa \a operator[]
|
||||
|
||||
* \fn const Type * PIVector::data(ullong index = 0) const;
|
||||
* \brief Read-only pointer to element by index "index"
|
||||
* \details Example: \snippet picontainers.cpp PIVector::data_c
|
||||
|
||||
* \fn Type * PIVector::data(ullong index = 0);
|
||||
* \brief Pointer to element by index "index"
|
||||
* \details Example: \snippet picontainers.cpp PIVector::data
|
||||
|
||||
* \fn ullong PIVector::size() const;
|
||||
* \brief Elements count
|
||||
|
||||
* \fn int PIVector::size_s() const;
|
||||
* \brief Elements count
|
||||
|
||||
* \fn bool PIVector::isEmpty() const;
|
||||
* \brief Return \c "true" if vector is empty, i.e. size = 0
|
||||
|
||||
* \fn bool PIVector::has(const Type & t) const;
|
||||
|
||||
* \fn bool PIVector::contains(const Type & v) const;
|
||||
* \brief Return \c "true" if vector has at least one element equal "t"
|
||||
|
||||
* \fn int PIVector::etries(const Type & t) const;
|
||||
* \brief Return how many times element "t" appears in vector
|
||||
|
||||
* \fn static int PIVector::compare_func(const Type * t0, const Type * t1);
|
||||
* \brief Standard compare function for type "Type". Return 0 if t0 = t1, -1 if t0 < t1 and 1 if t0 > t1.
|
||||
|
||||
* \fn void PIVector::resize(ullong size, const Type & new_type = Type());
|
||||
* \brief Resize vector to size "size"
|
||||
* \details Elements removed from end of vector if new size < old size, or added new elements = "new_type" if new size > old size.\n
|
||||
* Example: \snippet picontainers.cpp PIVector::resize
|
||||
* \sa \a size(), \a clear()
|
||||
|
||||
* \fn PIVector<T> & PIVector::enlarge(ullong size);
|
||||
* \brief Increase vector size with "size" elements
|
||||
|
||||
* \fn void PIVector::clear();
|
||||
* \brief Clear vector. Equivalent to call <tt>"resize(0)"</tt>
|
||||
|
||||
* \fn PIVector<T> & PIVector::sort(CompareFunc compare = compare_func);
|
||||
* \brief Sort vector using quick sort algorithm and standard compare function
|
||||
* \details Example: \snippet picontainers.cpp PIVector::sort_0
|
||||
* With custom compare function: \snippet picontainers.cpp PIVector::sort_1
|
||||
|
||||
* \fn PIVector<T> & PIVector::fill(const Type & t);
|
||||
* \brief Fill vector with elements "t" leave size is unchanged and return reference to vector
|
||||
* \details Example: \snippet picontainers.cpp PIVector::fill
|
||||
|
||||
* \fn Type & PIVector::back();
|
||||
* \brief Last element of the vector
|
||||
|
||||
* \fn const Type & PIVector::back() const;
|
||||
* \brief Last element of the vector
|
||||
|
||||
* \fn Type & PIVector::front();
|
||||
* \brief First element of the vector
|
||||
|
||||
* \fn const Type & PIVector::front() const;
|
||||
* \brief First element of the vector
|
||||
|
||||
* \fn PIVector<T> & PIVector::push_back(const Type & t);
|
||||
* \brief Add new element "t" at the end of vector and return reference to vector
|
||||
|
||||
* \fn PIVector<T> & PIVector::push_front(const Type & t);
|
||||
* \brief Add new element "t" at the beginning of vector and return reference to vector
|
||||
|
||||
* \fn PIVector<T> & PIVector::pop_back();
|
||||
* \brief Remove one element from the end of vector and return reference to vector
|
||||
|
||||
* \fn PIVector<T> & PIVector::pop_front();
|
||||
* \brief Remove one element from the beginning of vector and return reference to vector
|
||||
|
||||
* \fn Type PIVector::take_back();
|
||||
* \brief Remove one element from the end of vector and return it
|
||||
|
||||
* \fn Type PIVector::take_front();
|
||||
* \brief Remove one element from the beginning of vector and return it
|
||||
|
||||
* \fn PIVector<T> & PIVector::remove(uint index);
|
||||
* \brief Remove one element by index "index" and return reference to vector
|
||||
* \details Example: \snippet picontainers.cpp PIVector::remove_0
|
||||
* \sa \a removeOne(), \a removeAll()
|
||||
|
||||
* \fn PIVector<T> & PIVector::remove(uint index, uint count);
|
||||
* \brief Remove "count" elements by first index "index" and return reference to vector
|
||||
* \details Example: \snippet picontainers.cpp PIVector::remove_1
|
||||
* \sa \a removeOne(), \a removeAll()
|
||||
|
||||
* \fn PIVector<T> & PIVector::removeOne(const Type & v);
|
||||
* \brief Remove no more than one element equal "v" and return reference to vector
|
||||
* \details Example: \snippet picontainers.cpp PIVector::removeOne
|
||||
* \sa \a remove(), \a removeAll()
|
||||
|
||||
* \fn PIVector<T> & PIVector::removeAll(const Type & v);
|
||||
* \brief Remove all elements equal "v" and return reference to vector
|
||||
* \details Example: \snippet picontainers.cpp PIVector::removeAll
|
||||
* \sa \a remove(), \a removeOne()
|
||||
|
||||
* \fn PIVector<T> & PIVector::insert(uint pos, const Type & t);
|
||||
* \brief Insert element "t" after index "pos" and return reference to vector
|
||||
* \details Example: \snippet picontainers.cpp PIVector::insert_0
|
||||
|
||||
* \fn PIVector<T> & PIVector::insert(uint pos, const PIVector<T> & t);
|
||||
* \brief Insert other vector "t" after index "pos" and return reference to vector
|
||||
* \details Example: \snippet picontainers.cpp PIVector::insert_1
|
||||
|
||||
* \fn Type & PIVector::operator [](uint index);
|
||||
* \brief Full access to element by index "index"
|
||||
* \details Example: \snippet picontainers.cpp PIVector::()
|
||||
* \sa \a at()
|
||||
|
||||
* \fn const Type & PIVector::operator [](uint index) const;
|
||||
* \brief Read-only access to element by index "index"
|
||||
* \details Example: \snippet picontainers.cpp PIVector::()_c
|
||||
* \sa \a at()
|
||||
|
||||
* \fn PIVector<T> & PIVector::operator <<(const Type & t);
|
||||
* \brief Add new element "t" at the end of vector and return reference to vector
|
||||
|
||||
* \fn PIVector<T> & PIVector::operator <<(const PIVector<T> & t);
|
||||
* \brief Add vector "t" at the end of vector and return reference to vector
|
||||
|
||||
* \fn bool PIVector::operator ==(const PIVector<T> & t);
|
||||
* \brief Compare with vector "t"
|
||||
|
||||
* \fn bool PIVector::operator !=(const PIVector<T> & t);
|
||||
* \brief Compare with vector "t"
|
||||
|
||||
* */
|
||||
324
picontainers.h
324
picontainers.h
@@ -1,324 +0,0 @@
|
||||
/*! \file picontainers.h
|
||||
* \brief Generic containers
|
||||
*
|
||||
* This file declare all containers and useful macros
|
||||
* to use them
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Generic containers
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PICONTAINERS_H
|
||||
#define PICONTAINERS_H
|
||||
|
||||
#include "piincludes.h"
|
||||
|
||||
template<typename Type0, typename Type1>
|
||||
class PIP_EXPORT PIPair {
|
||||
public:
|
||||
PIPair() {first = Type0(); second = Type1();}
|
||||
PIPair(const Type0 & value0, const Type1 & value1) {first = value0; second = value1;}
|
||||
Type0 first;
|
||||
Type1 second;
|
||||
};
|
||||
template<typename Type0, typename Type1>
|
||||
inline bool operator <(const PIPair<Type0, Type1> & value0, const PIPair<Type0, Type1> & value1) {return value0.first < value1.first;}
|
||||
template<typename Type0, typename Type1>
|
||||
inline bool operator ==(const PIPair<Type0, Type1> & value0, const PIPair<Type0, Type1> & value1) {return (value0.first == value1.first) && (value0.second == value1.second);}
|
||||
template<typename Type0, typename Type1>
|
||||
inline bool operator !=(const PIPair<Type0, Type1> & value0, const PIPair<Type0, Type1> & value1) {return (value0.first != value1.first) || (value0.second != value1.second);}
|
||||
template<typename Type0, typename Type1>
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIPair<Type0, Type1> & v) {s << "(" << v.first << ", " << v.second << ")"; return s;}
|
||||
template<typename Type0, typename Type1>
|
||||
inline PICout operator <<(PICout s, const PIPair<Type0, Type1> & v) {s.space(); s.setControl(0, true); s << "(" << v.first << ", " << v.second << ")"; s.restoreControl(); return s;}
|
||||
|
||||
#include "pivector.h"
|
||||
#include "pistack.h"
|
||||
#include "piqueue.h"
|
||||
#include "pideque.h"
|
||||
#include "pimap.h"
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/*! \def piForeach(i,c)
|
||||
* \brief Macro for iterate any container
|
||||
* \details Use this macros instead of standard "for"
|
||||
* to get read/write access to each element of container.
|
||||
* Pass direction is direct \n
|
||||
* Example: \snippet picontainers.cpp foreach
|
||||
*/
|
||||
/*! \def piForeachC(i,c)
|
||||
* \brief Macro for iterate any container only for read
|
||||
* \details Use this macros instead of standard "for"
|
||||
* to get read access to each element of container.
|
||||
* Pass direction is direct \n
|
||||
* Example: \snippet picontainers.cpp foreachC
|
||||
*/
|
||||
/*! \def piForeachR(i,c)
|
||||
* \brief Macro for iterate any container with reverse direction
|
||||
* \details Use this macros instead of standard "for"
|
||||
* to get read/write access to each element of container.
|
||||
* Pass direction is reverse \n
|
||||
* Example: \snippet picontainers.cpp foreachR
|
||||
*/
|
||||
/*! \def piForeachCR(i,c)
|
||||
* \brief Macro for iterate any container only for read with reverse direction
|
||||
* \details Use this macros instead of standard "for"
|
||||
* to get read access to each element of container.
|
||||
* Pass direction is reverse \n
|
||||
* Example: \snippet picontainers.cpp foreachCR
|
||||
*/
|
||||
#endif
|
||||
|
||||
#ifdef CC_GCC
|
||||
|
||||
template<typename Type>
|
||||
class _PIForeach {
|
||||
public:
|
||||
_PIForeach(Type & t): _t(t) {_it = _t.begin(); _break = false;}
|
||||
typename Type::value_type _var;
|
||||
typename Type::iterator _it;
|
||||
Type & _t;
|
||||
bool _break;
|
||||
inline bool isEnd() {return _it == _t.end();}
|
||||
inline void operator ++() {_it++; _break = false;}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
class _PIForeachR {
|
||||
public:
|
||||
_PIForeachR(Type & t): _t(t) {_rit = _t.rbegin(); _break = false;}
|
||||
typename Type::value_type _var;
|
||||
typename Type::reverse_iterator _rit;
|
||||
Type & _t;
|
||||
bool _break;
|
||||
inline bool isEnd() {return _rit == _t.rend();}
|
||||
inline void operator ++() {_rit++; _break = false;}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
class _PIForeachC {
|
||||
public:
|
||||
_PIForeachC(const Type & t): _t(t) {_it = _t.begin(); _break = false;}
|
||||
typename Type::value_type _var;
|
||||
typename Type::const_iterator _it;
|
||||
const Type & _t;
|
||||
bool _break;
|
||||
inline bool isEnd() {return _it == _t.end();}
|
||||
inline void operator ++() {_it++; _break = false;}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
class _PIForeachCR {
|
||||
public:
|
||||
_PIForeachCR(const Type & t): _t(t) {_rit = _t.rbegin(); _break = false;}
|
||||
typename Type::value_type _var;
|
||||
typename Type::const_reverse_iterator _rit;
|
||||
const Type & _t;
|
||||
bool _break;
|
||||
inline bool isEnd() {return _rit == _t.rend();}
|
||||
inline void operator ++() {_rit++; _break = false;}
|
||||
};
|
||||
|
||||
#define piForeach(i,c) for(_PIForeach<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(i(*_for._it); !_for._break; _for._break = true)
|
||||
#define piForeachR(i,c) for(_PIForeachR<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(i(*_for._rit); !_for._break; _for._break = true)
|
||||
#define piForeachA(i,c) for(_PIForeach<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(typeof(_for._var) & i(*_for._it); !_for._break; _for._break = true)
|
||||
#define piForeachAR(i,c) for(_PIForeachR<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(typeof(_for._var) & i(*_for._rit); !_for._break; _for._break = true)
|
||||
#define piForeachC(i,c) for(_PIForeachC<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(const i(*_for._it); !_for._break; _for._break = true)
|
||||
#define piForeachCR(i,c) for(_PIForeachCR<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(const i(*_for._rit); !_for._break; _for._break = true)
|
||||
#define piForeachCA(i,c) for(_PIForeachC<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(const typeof(_for._var) & i(*_for._it); !_for._break; _for._break = true)
|
||||
#define piForeachCAR(i,c) for(_PIForeachCR<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(const typeof(_for._var) & i(*_for._rit); !_for._break; _for._break = true)
|
||||
|
||||
#define piForeachRA piForeachAR
|
||||
#define piForeachAC piForeachCA
|
||||
#define piForeachCRA piForeachCAR
|
||||
#define piForeachARC piForeachCAR
|
||||
#define piForeachACR piForeachCAR
|
||||
#define piForeachRCA piForeachCAR
|
||||
#define piForeachRAC piForeachCAR
|
||||
|
||||
#else
|
||||
|
||||
struct _PIForeachBase {mutable bool _break;};
|
||||
|
||||
template<typename Type>
|
||||
class _PIForeach: public _PIForeachBase {
|
||||
public:
|
||||
_PIForeach(Type & t, bool i = false): _t(t), _inv(i) {if (_inv) _rit = _t.rbegin(); else _it = _t.begin(); _break = false;}
|
||||
mutable typename Type::value_type _var;
|
||||
mutable typename Type::iterator _it;
|
||||
mutable typename Type::reverse_iterator _rit;
|
||||
Type & _t;
|
||||
bool _inv;
|
||||
bool isEnd() {if (_inv) return _rit == _t.rend(); else return _it == _t.end();}
|
||||
void operator ++() {if (_inv) _rit++; else _it++; _break = false;}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
class _PIForeachC: public _PIForeachBase {
|
||||
public:
|
||||
_PIForeachC(const Type & t, bool i = false): _t(t), _inv(i) {if (_inv) _rit = _t.rbegin(); else _it = _t.begin(); _break = false;}
|
||||
mutable typename Type::value_type _var;
|
||||
mutable typename Type::const_iterator _it;
|
||||
mutable typename Type::const_reverse_iterator _rit;
|
||||
const Type & _t;
|
||||
bool _inv;
|
||||
bool isEnd() {if (_inv) return _rit == _t.rend(); else return _it == _t.end();}
|
||||
void operator ++() {if (_inv) _rit++; else _it++; _break = false;}
|
||||
};
|
||||
|
||||
template <typename T> inline _PIForeach<T> _PIForeachNew(T & t, bool i = false) {return _PIForeach<T>(t, i);}
|
||||
template <typename T> inline _PIForeach<T> * _PIForeachCast(_PIForeachBase & c, T & ) {return static_cast<_PIForeach<T> * >(&c);}
|
||||
|
||||
template <typename T> inline _PIForeachC<T> _PIForeachNewC(const T & t, bool i = false) {return _PIForeachC<T>(t, i);}
|
||||
template <typename T> inline _PIForeachC<T> * _PIForeachCastC(_PIForeachBase & c, const T & ) {return static_cast<_PIForeachC<T> * >(&c);}
|
||||
|
||||
#define piForeach(i,c) for(_PIForeachBase & _for = _PIForeachNew(c); !_PIForeachCast(_for, c)->isEnd(); ++(*_PIForeachCast(_for, c))) \
|
||||
for(i = *(_PIForeachCast(_for, c)->_it); !_for._break; _for._break = true)
|
||||
#define piForeachR(i,c) for(_PIForeachBase & _for = _PIForeachNew(c, true); !_PIForeachCast(_for, c)->isEnd(); ++(*_PIForeachCast(_for, c))) \
|
||||
for(i = *(_PIForeachCast(_for, c)->_rit); !_for._break; _for._break = true)
|
||||
#define piForeachC(i,c) for(_PIForeachBase & _for = _PIForeachNewC(c); !_PIForeachCastC(_for, c)->isEnd(); ++(*_PIForeachCastC(_for, c))) \
|
||||
for(const i = *(_PIForeachCastC(_for, c)->_it); !_for._break; _for._break = true)
|
||||
#define piForeachCR(i,c) for(_PIForeachBase & _for = _PIForeachNewC(c, false); !_PIForeachCastC(_for, c)->isEnd(); ++(*_PIForeachCastC(_for, c))) \
|
||||
for(const i = *(_PIForeachCastC(_for, c)->_rit); !_for._break; _for._break = true)
|
||||
|
||||
#endif
|
||||
|
||||
#define piForeachRC piForeachCR
|
||||
|
||||
#define piForTimes(c) for(int _i##c = 0; _i##c < c; ++_i##c)
|
||||
|
||||
|
||||
template<typename Type, typename Allocator = std::allocator<Type> >
|
||||
class PIP_EXPORT PIList: public list<Type, Allocator> {
|
||||
typedef PIList<Type, Allocator> _CList;
|
||||
typedef list<Type, Allocator> _stlc;
|
||||
public:
|
||||
PIList() {piMonitor.containers++;}
|
||||
PIList(const Type & value) {piMonitor.containers++; _stlc::resize(1, value);}
|
||||
PIList(const Type & v0, const Type & v1) {piMonitor.containers++; _stlc::push_back(v0); _stlc::push_back(v1);}
|
||||
PIList(const Type & v0, const Type & v1, const Type & v2) {piMonitor.containers++; _stlc::push_back(v0); _stlc::push_back(v1); _stlc::push_back(v2);}
|
||||
PIList(const Type & v0, const Type & v1, const Type & v2, const Type & v3) {piMonitor.containers++; _stlc::push_back(v0); _stlc::push_back(v1); _stlc::push_back(v2); _stlc::push_back(v3);}
|
||||
PIList(uint size, const Type & value = Type()) {piMonitor.containers++; _stlc::resize(size, value);}
|
||||
~PIList() {piMonitor.containers--;}
|
||||
Type & operator [](uint index) {return (*this)[index];}
|
||||
Type & operator [](uint index) const {return (*this)[index];}
|
||||
const Type * data(uint index = 0) const {return &(*this)[index];}
|
||||
Type * data(uint index = 0) {return &(*this)[index];}
|
||||
int size_s() const {return static_cast<int>(_stlc::size());}
|
||||
bool isEmpty() const {return _stlc::empty();}
|
||||
bool has(const Type & t) const {for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (t == *i) return true; return false;}
|
||||
int etries(const Type & t) const {int ec = 0; for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (t == *i) ++ec; return ec;}
|
||||
_CList & fill(const Type & t) {_stlc::assign(_stlc::size(), t); return *this;}
|
||||
_CList & remove(uint index) {_stlc::erase(_stlc::begin() + index); return *this;}
|
||||
_CList & remove(uint index, uint count) {_stlc::erase(_stlc::begin() + index, _stlc::begin() + index + count); return *this;}
|
||||
_CList & insert(uint pos, const Type & t) {_stlc::insert(_stlc::begin() + pos, t); return *this;}
|
||||
_CList & operator <<(const Type & t) {_stlc::push_back(t); return *this;}
|
||||
PIVector<Type> toVector() {PIVector<Type> v; for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) v << *i; return v;}
|
||||
};
|
||||
|
||||
/*! \brief Set of any type
|
||||
* \details This class used to store collection of unique elements
|
||||
* of any type. You can only add values to set with \a operator<< or
|
||||
* with function \a insert(). You can discover if value already in
|
||||
* set with \a operator[] or with function \a find(). These function
|
||||
* has logarithmic complexity.
|
||||
*/
|
||||
template<typename Type, typename Compare = std::less<Type>, typename Allocator = std::allocator<Type> >
|
||||
class PIP_EXPORT PISet: public set<Type, Compare, Allocator> {
|
||||
typedef PISet<Type, Compare, Allocator> _CSet;
|
||||
typedef set<Type, Compare, Allocator> _stlc;
|
||||
public:
|
||||
|
||||
//! Contructs an empty set
|
||||
PISet() {piMonitor.containers++;}
|
||||
|
||||
//! Contructs set with one element "value"
|
||||
PISet(const Type & value) {piMonitor.containers++; _stlc::resize(1, value);}
|
||||
|
||||
//! Contructs set with elements "v0" and "v1"
|
||||
PISet(const Type & v0, const Type & v1) {piMonitor.containers++; _stlc::insert(v0); _stlc::insert(v1);}
|
||||
|
||||
//! Contructs set with elements "v0", "v1" and "v2"
|
||||
PISet(const Type & v0, const Type & v1, const Type & v2) {piMonitor.containers++; _stlc::insert(v0); _stlc::insert(v1); _stlc::insert(v2);}
|
||||
|
||||
//! Contructs set with elements "v0", "v1", "v2" and "v3"
|
||||
PISet(const Type & v0, const Type & v1, const Type & v2, const Type & v3) {piMonitor.containers++; _stlc::insert(v0); _stlc::insert(v1); _stlc::insert(v2); _stlc::insert(v3);}
|
||||
|
||||
~PISet() {piMonitor.containers--;}
|
||||
|
||||
//! Returns elements count
|
||||
int size_s() const {return static_cast<int>(_stlc::size());}
|
||||
|
||||
//! Returns if set is empty
|
||||
bool isEmpty() const {return _stlc::empty();}
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
//! Clear th set
|
||||
void clear();
|
||||
|
||||
//! Insert element "t" if it doesn`t exists in this set
|
||||
void insert(const Type & t);
|
||||
|
||||
#endif
|
||||
|
||||
_CSet & remove(uint index) {_stlc::erase(_stlc::begin() + index); return *this;}
|
||||
_CSet & remove(uint index, uint count) {_stlc::erase(_stlc::begin() + index, _stlc::begin() + index + count); return *this;}
|
||||
_CSet & operator <<(const Type & t) {_stlc::insert(t); return *this;}
|
||||
|
||||
//! Returns if element "t" exists in this set
|
||||
bool operator [](const Type & t) {return _stlc::find(t) != _stlc::end();}
|
||||
|
||||
//! Returns content of set as PIVector
|
||||
PIVector<Type> toVector() {PIVector<Type> v; for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) v << *i; return v;}
|
||||
};
|
||||
|
||||
|
||||
#ifndef PIP_CONTAINERS_STL
|
||||
|
||||
# define __PICONTAINERS_SIMPLE_TYPE__(T) \
|
||||
__PIDEQUE_SIMPLE_TYPE__(T)\
|
||||
__PIVECTOR_SIMPLE_TYPE__(T)
|
||||
|
||||
__PICONTAINERS_SIMPLE_TYPE__(bool)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(char)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(uchar)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(short)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(ushort)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(int)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(uint)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(long)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(ulong)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(llong)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(ullong)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(float)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(double)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(ldouble)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // PICONTAINERS_H
|
||||
234
picrc.h
234
picrc.h
@@ -1,234 +0,0 @@
|
||||
/*! \file picrc.h
|
||||
* \brief CRC checksum calculator
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Abstract input/output device
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PICRC_H
|
||||
#define PICRC_H
|
||||
|
||||
#include "pistring.h"
|
||||
|
||||
template <int L>
|
||||
class PIP_EXPORT uint_cl {
|
||||
public:
|
||||
uint_cl() {for (int i = 0; i < L / 8; ++i) data_[i] = 0;}
|
||||
uint_cl(const uint_cl<L> & v) {for (int i = 0; i < L / 8; ++i) data_[i] = v.data_[i];}
|
||||
uint_cl(uchar v) {for (int i = 0; i < L / 8; ++i) data_[i] = (i == 0 ? v : 0);}
|
||||
uint_cl(char v) {for (int i = 0; i < L / 8; ++i) data_[i] = (i == 0 ? v : 0);}
|
||||
uint_cl(ushort v) {int l = piMin<uint>(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0;}
|
||||
uint_cl(short v) {int l = piMin<uint>(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0;}
|
||||
uint_cl(uint v) {int l = piMin<uint>(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0;}
|
||||
uint_cl(int v) {int l = piMin<uint>(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0;}
|
||||
uint_cl(ulong v) {int l = piMin<uint>(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0;}
|
||||
uint_cl(long v) {int l = piMin<uint>(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0;}
|
||||
uint_cl(ullong v) {int l = piMin<uint>(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0;}
|
||||
uint_cl(llong v) {int l = piMin<uint>(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0;}
|
||||
|
||||
operator bool() {for (int i = 0; i < L / 8; ++i) if (data_[i] > 0) return true; return false;}
|
||||
operator char() {return (char)data_[0];}
|
||||
operator short() {short t(0); int l = piMin<uint>(L / 8, sizeof(t)); memcpy(&t, data_, l); return t;}
|
||||
operator int() {int t(0); int l = piMin<uint>(L / 8, sizeof(t)); memcpy(&t, data_, l); return t;}
|
||||
operator long() {long t(0); int l = piMin<uint>(L / 8, sizeof(t)); memcpy(&t, data_, l); return t;}
|
||||
operator llong() {llong t(0); int l = piMin<uint>(L / 8, sizeof(t)); memcpy(&t, data_, l); return t;}
|
||||
operator uchar() {return data_[0];}
|
||||
operator ushort() {ushort t(0); int l = piMin<uint>(L / 8, sizeof(t)); memcpy(&t, data_, l); return t;}
|
||||
operator uint() {uint t(0); int l = piMin<uint>(L / 8, sizeof(t)); memcpy(&t, data_, l); return t;}
|
||||
operator ulong() {ulong t(0); int l = piMin<uint>(L / 8, sizeof(t)); memcpy(&t, data_, l); return t;}
|
||||
operator ullong() {ullong t(0); int l = piMin<uint>(L / 8, sizeof(t)); memcpy(&t, data_, l); return t;}
|
||||
|
||||
uint_cl<L> operator +(const uint_cl<L> & v) {
|
||||
uint_cl<L> t;
|
||||
uint cv;
|
||||
bool ov = false;
|
||||
for (int i = 0; i < L / 8; ++i) {
|
||||
cv = v.data_[i] + data_[i];
|
||||
if (ov) ++cv;
|
||||
ov = cv > 255;
|
||||
t.data_[i] = ov ? cv - 256 : cv;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
uint_cl<L> operator &(const uint_cl<L> & v) const {uint_cl<L> t; for (int i = 0; i < L / 8; ++i) t.data_[i] = v.data_[i] & data_[i]; return t;}
|
||||
uint_cl<L> operator &(const uchar & v) const {return *this & uint_cl<L>(v);}
|
||||
uint_cl<L> operator &(const ushort & v) const {return *this & uint_cl<L>(v);}
|
||||
uint_cl<L> operator &(const uint & v) const {return *this & uint_cl<L>(v);}
|
||||
uint_cl<L> operator &(const ulong & v) const {return *this & uint_cl<L>(v);}
|
||||
uint_cl<L> operator &(const ullong & v) const {return *this & uint_cl<L>(v);}
|
||||
uint_cl<L> operator &(const char & v) const {return *this & uint_cl<L>(v);}
|
||||
uint_cl<L> operator &(const short & v) const {return *this & uint_cl<L>(v);}
|
||||
uint_cl<L> operator &(const int & v) const {return *this & uint_cl<L>(v);}
|
||||
uint_cl<L> operator &(const long & v) const {return *this & uint_cl<L>(v);}
|
||||
uint_cl<L> operator &(const llong & v) const {return *this & uint_cl<L>(v);}
|
||||
|
||||
uint_cl<L> operator |(const uint_cl<L> & v) const {uint_cl<L> t; for (int i = 0; i < L / 8; ++i) t.data_[i] = v.data_[i] | data_[i]; return t;}
|
||||
uint_cl<L> operator |(const uchar & v) const {return *this | uint_cl<L>(v);}
|
||||
uint_cl<L> operator |(const ushort & v) const {return *this | uint_cl<L>(v);}
|
||||
uint_cl<L> operator |(const uint & v) const {return *this | uint_cl<L>(v);}
|
||||
uint_cl<L> operator |(const ulong & v) const {return *this | uint_cl<L>(v);}
|
||||
uint_cl<L> operator |(const ullong & v) const {return *this | uint_cl<L>(v);}
|
||||
uint_cl<L> operator |(const char & v) const {return *this | uint_cl<L>(v);}
|
||||
uint_cl<L> operator |(const short & v) const {return *this | uint_cl<L>(v);}
|
||||
uint_cl<L> operator |(const int & v) const {return *this | uint_cl<L>(v);}
|
||||
uint_cl<L> operator |(const long & v) const {return *this | uint_cl<L>(v);}
|
||||
uint_cl<L> operator |(const llong & v) const {return *this | uint_cl<L>(v);}
|
||||
|
||||
uint_cl<L> operator ^(const uint_cl<L> & v) const {uint_cl<L> t; for (int i = 0; i < L / 8; ++i) t.data_[i] = v.data_[i] ^ data_[i]; return t;}
|
||||
uint_cl<L> operator ^(const uchar & v) const {return *this ^ uint_cl<L>(v);}
|
||||
uint_cl<L> operator ^(const ushort & v) const {return *this ^ uint_cl<L>(v);}
|
||||
uint_cl<L> operator ^(const uint & v) const {return *this ^ uint_cl<L>(v);}
|
||||
uint_cl<L> operator ^(const ulong & v) const {return *this ^ uint_cl<L>(v);}
|
||||
uint_cl<L> operator ^(const ullong & v) const {return *this ^ uint_cl<L>(v);}
|
||||
uint_cl<L> operator ^(const char & v) const {return *this ^ uint_cl<L>(v);}
|
||||
uint_cl<L> operator ^(const short & v) const {return *this ^ uint_cl<L>(v);}
|
||||
uint_cl<L> operator ^(const int & v) const {return *this ^ uint_cl<L>(v);}
|
||||
uint_cl<L> operator ^(const long & v) const {return *this ^ uint_cl<L>(v);}
|
||||
uint_cl<L> operator ^(const llong & v) const {return *this ^ uint_cl<L>(v);}
|
||||
|
||||
bool operator <(const uint_cl<L> & v) const {for (int i = 0; i < L / 8; ++i) {if (v.data_[i] > data_[i]) return true; if (v.data_[i] < data_[i]) return false;} return false;}
|
||||
bool operator <=(const uint_cl<L> & v) const {for (int i = 0; i < L / 8; ++i) {if (v.data_[i] > data_[i]) return true; if (v.data_[i] < data_[i]) return false;} return true;}
|
||||
bool operator >(const uint_cl<L> & v) const {for (int i = 0; i < L / 8; ++i) {if (v.data_[i] < data_[i]) return true; if (v.data_[i] > data_[i]) return false;} return false;}
|
||||
bool operator >=(const uint_cl<L> & v) const {for (int i = 0; i < L / 8; ++i) {if (v.data_[i] < data_[i]) return true; if (v.data_[i] > data_[i]) return false;} return true;}
|
||||
bool operator ==(const uint_cl<L> & v) const {for (int i = 0; i < L / 8; ++i) if (v.data_[i] != data_[i]) return false; return true;}
|
||||
bool operator !=(const uint_cl<L> & v) const {for (int i = 0; i < L / 8; ++i) if (v.data_[i] != data_[i]) return true; return false;}
|
||||
|
||||
uint_cl<L> operator >>(const int & c) const {
|
||||
uint_cl<L> t;
|
||||
int l = L - c;
|
||||
bool bit;
|
||||
if (l <= 0) return t;
|
||||
for (int i = 0; i < l; ++i) {
|
||||
bit = 1 & (data_[(i + c) / 8] >> ((i + c) % 8));
|
||||
if (bit) t.data_[i / 8] |= (1 << (i % 8));
|
||||
else t.data_[i / 8] &= ~(1 << (i % 8));
|
||||
}
|
||||
return t;
|
||||
}
|
||||
uint_cl<L> operator >>(const uint & c) const {return (*this << (int)c);}
|
||||
uint_cl<L> operator <<(const int & c) const {
|
||||
uint_cl<L> t;
|
||||
int l = L - c;
|
||||
bool bit;
|
||||
if (l <= 0) return t;
|
||||
for (int i = c; i < L; ++i) {
|
||||
bit = 1 & (data_[(i - c) / 8] >> ((i - c) % 8));
|
||||
if (bit) t.data_[i / 8] |= (1 << (i % 8));
|
||||
else t.data_[i / 8] &= ~(1 << (i % 8));
|
||||
}
|
||||
return t;
|
||||
}
|
||||
uint_cl<L> operator <<(const uint & c) const {return (*this >> (int)c);}
|
||||
|
||||
uint_cl<L> & inverse() const {for (int i = 0; i < L / 8; ++i) data_[i] = ~data_[i]; return *this;}
|
||||
uint_cl<L> inversed() const {uint_cl<L> t(*this); for (int i = 0; i < L / 8; ++i) t.data_[i] = ~t.data_[i]; return t;}
|
||||
uint_cl<L> reversed() const {
|
||||
uint_cl<L> t;
|
||||
bool bit;
|
||||
for (int i = 0; i < L; ++i) {
|
||||
bit = 1 & (data_[(L - i - 1) / 8] >> ((L - i - 1) % 8));
|
||||
if (bit) t.data_[i / 8] |= (1 << (i % 8));
|
||||
else t.data_[i / 8] &= ~(1 << (i % 8));
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
const uchar * data() const {return data_;}
|
||||
uchar * data() {return data_;}
|
||||
uint length() const {return L / 8;}
|
||||
|
||||
private:
|
||||
uchar data_[L / 8];
|
||||
|
||||
};
|
||||
|
||||
template <uint L>
|
||||
inline std::ostream & operator <<(std::ostream & s, const uint_cl<L> & v) {std::ios::fmtflags f = s.flags(); s << std::hex; for (uint i = 0; i < v.length(); ++i) {s << int(v.data()[i]); if (v.data()[i] < 0x10) s << '0'; s << ' ';} s.flags(f); return s;}
|
||||
|
||||
|
||||
template <uint L>
|
||||
class PIP_EXPORT PICRC {
|
||||
public:
|
||||
PICRC(const uint_cl<L> & poly) {poly_ = poly; reverse_poly = true; init_ = uint_cl<L>(0).inversed(); out_ = uint_cl<L>(0).inversed(); reverse_before_xor = reverse_data = false; initTable();}
|
||||
PICRC(const uint_cl<L> & poly, bool reverse_poly_, const uint_cl<L> & initial, const uint_cl<L> & out_xor) {poly_ = poly; reverse_poly = reverse_poly_; init_ = initial; out_ = out_xor; reverse_before_xor = reverse_data = false; initTable();}
|
||||
|
||||
void setInitial(const uint_cl<L> & v) {init_ = v;}
|
||||
void setOutXor(const uint_cl<L> & v) {out_ = v;}
|
||||
void setReversePolynome(bool yes) {reverse_poly = yes; initTable();}
|
||||
void setReverseOutBeforeXOR(bool yes) {reverse_before_xor = yes;}
|
||||
void setReverseDataBytes(bool yes) {reverse_data = yes;}
|
||||
|
||||
void initTable() {
|
||||
uint_cl<L> tmp, pol = reverse_poly ? poly_.reversed() : poly_;
|
||||
//cout << std::hex << "poly " << (uint)uint_cl<L>(poly_) << " -> " << (uint)uint_cl<L>(pol) << endl;
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
tmp = uchar(i);
|
||||
for (int j = 0; j < 8; ++j)
|
||||
tmp = ((tmp & 1) ? ((tmp >> 1) ^ pol) : (tmp >> 1));
|
||||
table[i] = tmp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint_cl<L> calculate(const void * data, int size) {
|
||||
uint_cl<L> crc = init_;
|
||||
uchar * data_ = (uchar * )data, cb;
|
||||
//cout << "process " << size << endl;
|
||||
uchar nTemp;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
cb = data_[i];
|
||||
if (reverse_data) cb = reverseByte(cb);
|
||||
nTemp = cb ^ uchar(crc);
|
||||
crc = crc >> 8;
|
||||
crc = crc ^ table[nTemp];
|
||||
}
|
||||
if (reverse_before_xor) crc = crc.reversed();
|
||||
return crc ^ out_;
|
||||
|
||||
}
|
||||
uint_cl<L> calculate(const PIByteArray & d) {return calculate(d.data(), d.size());}
|
||||
uint_cl<L> calculate(const char * str) {string s(str); return calculate((void * )s.data(), s.size());}
|
||||
|
||||
private:
|
||||
uchar reverseByte(uchar b) {
|
||||
uchar ret = 0;
|
||||
bool bit;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
bit = 1 & (b >> (7 - i));
|
||||
if (bit) ret |= (1 << i);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint_cl<L> table[256];
|
||||
uint_cl<L> poly_, init_, out_;
|
||||
bool reverse_poly, reverse_before_xor, reverse_data;
|
||||
|
||||
};
|
||||
|
||||
typedef PICRC<32> CRC_32;
|
||||
typedef PICRC<24> CRC_24;
|
||||
typedef PICRC<16> CRC_16;
|
||||
typedef PICRC<8> CRC_8;
|
||||
|
||||
inline CRC_32 standardCRC_32() {return CRC_32(0x04C11DB7, true, 0xFFFFFFFF, 0xFFFFFFFF);}
|
||||
inline CRC_16 standardCRC_16() {return CRC_16(0x8005, true, 0x0, 0x0);}
|
||||
inline CRC_8 standardCRC_8() {return CRC_8(0xD5, true, 0x0, 0x0);}
|
||||
|
||||
#endif // CRC_H
|
||||
477
pideque.h
477
pideque.h
@@ -1,477 +0,0 @@
|
||||
/*! \file pideque.h
|
||||
* \brief Dynamic array of any type
|
||||
*
|
||||
* This file declares PIDeque
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Dynamic array of any type
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIDEQUE_H
|
||||
#define PIDEQUE_H
|
||||
|
||||
#include "piincludes.h"
|
||||
|
||||
|
||||
#if !defined(PIP_CONTAINERS_STL) || defined(DOXYGEN)
|
||||
|
||||
|
||||
template <typename T>
|
||||
class PIDeque {
|
||||
public:
|
||||
PIDeque(): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
|
||||
//printf("new vector 1 %p (%s) ... !{\n", this, typeid(T).name());
|
||||
//printf("(s=%d, d=%p) }!\n", int(pid_size), pid_data);
|
||||
}
|
||||
PIDeque(const PIDeque<T> & other): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
|
||||
//printf("new vector 2 %p (%s) ... !{\n", this, typeid(T).name());
|
||||
alloc(other.pid_size, true);
|
||||
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
|
||||
//printf("(s=%d, d=%p) }!\n", int(pid_size), pid_data);
|
||||
}
|
||||
PIDeque(const T * data, size_t size): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
|
||||
//printf("new vector 2 %p (%s) ... !{\n", this, typeid(T).name());
|
||||
alloc(size, true);
|
||||
newT(pid_data + pid_start, data, pid_size);
|
||||
//printf("(s=%d, d=%p) }!\n", int(pid_size), pid_data);
|
||||
}
|
||||
PIDeque(size_t pid_size, const T & f = T()): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
|
||||
//printf("new vector 3 %p (%s) ... !{\n", this, typeid(T).name());
|
||||
resize(pid_size, f);
|
||||
//printf("(s=%d, d=%p) }!\n", int(pid_size), pid_data);
|
||||
}
|
||||
~PIDeque() {
|
||||
//printf("delete deque %p (%s) (s=%d, rs=%d, st=%d, d=%p) ... ~{\n", this, typeid(T).name(), int(pid_size), int(pid_rsize), int(pid_start), pid_data);
|
||||
deleteT(pid_data + pid_start, pid_size);
|
||||
dealloc();
|
||||
//deleteRaw(pid_tdata);
|
||||
_reset();
|
||||
//printf("}~\n");
|
||||
}
|
||||
|
||||
PIDeque<T> & operator =(const PIDeque<T> & other) {
|
||||
if (this == &other) return *this;
|
||||
deleteT(pid_data + pid_start, pid_size);
|
||||
alloc(other.pid_size, true);
|
||||
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
class iterator {
|
||||
friend class PIDeque<T>;
|
||||
private:
|
||||
iterator(PIDeque<T> * v, size_t p): parent(v), pos(p) {}
|
||||
PIDeque<T> * parent;
|
||||
size_t pos;
|
||||
public:
|
||||
iterator(): parent(0) {}
|
||||
T & operator *() {return (*parent)[pos];}
|
||||
const T & operator *() const {return (*parent)[pos];}
|
||||
void operator ++() {++pos;}
|
||||
void operator ++(int) {++pos;}
|
||||
void operator --() {--pos;}
|
||||
void operator --(int) {--pos;}
|
||||
bool operator ==(const iterator & it) const {return (pos == it.pos);}
|
||||
bool operator !=(const iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
class const_iterator {
|
||||
friend class PIDeque<T>;
|
||||
private:
|
||||
const_iterator(const PIDeque<T> * v, size_t p): parent(v), pos(p) {}
|
||||
const PIDeque<T> * parent;
|
||||
size_t pos;
|
||||
public:
|
||||
const_iterator(): parent(0) {}
|
||||
//T & operator *() {return (*parent)[pos];}
|
||||
const T & operator *() const {return (*parent)[pos];}
|
||||
void operator ++() {++pos;}
|
||||
void operator ++(int) {++pos;}
|
||||
void operator --() {--pos;}
|
||||
void operator --(int) {--pos;}
|
||||
bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
|
||||
bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
class reverse_iterator {
|
||||
friend class PIDeque<T>;
|
||||
private:
|
||||
reverse_iterator(PIDeque<T> * v, size_t p): parent(v), pos(p) {}
|
||||
PIDeque<T> * parent;
|
||||
size_t pos;
|
||||
public:
|
||||
reverse_iterator(): parent(0) {}
|
||||
T & operator *() {return (*parent)[pos];}
|
||||
const T & operator *() const {return (*parent)[pos];}
|
||||
void operator ++() {--pos;}
|
||||
void operator ++(int) {--pos;}
|
||||
void operator --() {++pos;}
|
||||
void operator --(int) {++pos;}
|
||||
bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);}
|
||||
bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
class const_reverse_iterator {
|
||||
friend class PIDeque<T>;
|
||||
private:
|
||||
const_reverse_iterator(const PIDeque<T> * v, size_t p): parent(v), pos(p) {}
|
||||
const PIDeque<T> * parent;
|
||||
size_t pos;
|
||||
public:
|
||||
const_reverse_iterator(): parent(0) {}
|
||||
//T & operator *() {return (*parent)[pos];}
|
||||
const T & operator *() const {return (*parent)[pos];}
|
||||
void operator ++() {--pos;}
|
||||
void operator ++(int) {--pos;}
|
||||
void operator --() {++pos;}
|
||||
void operator --(int) {++pos;}
|
||||
bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
|
||||
bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
iterator begin() {return iterator(this, 0);}
|
||||
iterator end() {return iterator(this, pid_size);}
|
||||
const_iterator begin() const {return const_iterator(this, 0);}
|
||||
const_iterator end() const {return const_iterator(this, pid_size);}
|
||||
reverse_iterator rbegin() {return reverse_iterator(this, pid_size - 1);}
|
||||
reverse_iterator rend() {return reverse_iterator(this, -1);}
|
||||
const_reverse_iterator rbegin() const {return const_reverse_iterator(this, pid_size - 1);}
|
||||
const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
|
||||
|
||||
size_t size() const {return pid_size;}
|
||||
ssize_t size_s() const {return pid_size;}
|
||||
size_t length() const {return pid_size;}
|
||||
size_t capacity() const {return pid_rsize;}
|
||||
bool isEmpty() const {return (pid_size == 0);}
|
||||
|
||||
T & operator [](size_t index) {return pid_data[pid_start + index];}
|
||||
T & at(size_t index) {return pid_data[pid_start + index];}
|
||||
const T & operator [](size_t index) const {return pid_data[pid_start + index];}
|
||||
const T & at(size_t index) const {return pid_data[pid_start + index];}
|
||||
T & back() {return pid_data[pid_start + pid_size - 1];}
|
||||
const T & back() const {return pid_data[pid_start + pid_size - 1];}
|
||||
T & front() {return pid_data[pid_start];}
|
||||
const T & front() const {return pid_data[pid_start];}
|
||||
bool operator ==(const PIDeque<T> & t) const {if (pid_size != t.pid_size) return false; for (size_t i = 0; i < pid_size; ++i) if (t[i] != pid_data[pid_start + i]) return false; return true;}
|
||||
bool operator !=(const PIDeque<T> & t) const {if (pid_size != t.pid_size) return true; for (size_t i = 0; i < pid_size; ++i) if (t[i] != pid_data[pid_start + i]) return true; return false;}
|
||||
bool contains(const T & v) const {for (size_t i = pid_start; i < pid_start + pid_size; ++i) if (v == pid_data[i]) return true; return false;}
|
||||
int etries(const T & v) const {int ec = 0; for (size_t i = pid_start; i < pid_start + pid_size; ++i) if (v == pid_data[i]) ++ec; return ec;}
|
||||
|
||||
T * data(size_t index = 0) {return &(pid_data[pid_start + index]);}
|
||||
const T * data(size_t index = 0) const {return &(pid_data[pid_start + index]);}
|
||||
PIDeque<T> & clear() {resize(0); return *this;}
|
||||
PIDeque<T> & fill(const T & f = T()) {
|
||||
//if (sizeof(T) == 1) memset(pid_data, f, pid_size);
|
||||
deleteT(pid_data + pid_start, pid_size);
|
||||
//zeroRaw(pid_data, pid_size);
|
||||
for (size_t i = pid_start; i < pid_start + pid_size; ++i)
|
||||
elementNew(pid_data + i, f);
|
||||
return *this;
|
||||
}
|
||||
PIDeque<T> & assign(const T & f = T()) {return fill(f);}
|
||||
PIDeque<T> & assign(size_t new_size, const T & f) {resize(new_size); return fill(f);}
|
||||
PIDeque<T> & resize(size_t new_size, const T & f = T()) {
|
||||
if (new_size < pid_size) {
|
||||
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
|
||||
pid_size = new_size;
|
||||
}
|
||||
if (new_size > pid_size) {
|
||||
size_t os = pid_size;
|
||||
alloc(new_size, true);
|
||||
//if (sizeof(T) == 1) memset(&(pid_data[os]), f, ds);
|
||||
//zeroRaw(&(pid_data[os]), new_size - os);
|
||||
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) elementNew(pid_data + i, f);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
PIDeque<T> & reserve(size_t new_size) {if (new_size <= pid_rsize) return *this; size_t os = pid_size; alloc(new_size, true); pid_size = os; return *this;}
|
||||
|
||||
PIDeque<T> & insert(size_t index, const T & v = T()) {
|
||||
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
|
||||
//piCout << "insert" << dir << index << pid_size << pid_rsize << pid_start << "!<";
|
||||
if (dir) {
|
||||
alloc(pid_size + 1, true);
|
||||
if (index < pid_size - 1) {
|
||||
size_t os = pid_size - index - 1;
|
||||
memmove(&(pid_data[index + pid_start + 1]), &(pid_data[index + pid_start]), os * sizeof(T));
|
||||
}
|
||||
} else {
|
||||
pid_start--;
|
||||
alloc(pid_size + 1, false);
|
||||
//piCout << "insert front" << pid_size << pid_rsize << pid_start << "!<";
|
||||
if (index > 0)
|
||||
memmove(&(pid_data[pid_start]), &(pid_data[pid_start + 1]), index * sizeof(T));
|
||||
}
|
||||
//piCout << "insert" << pid_start << index << (pid_start + ssize_t(index)) << pid_size << ">!";
|
||||
elementNew(pid_data + pid_start + index, v);
|
||||
return *this;
|
||||
}
|
||||
PIDeque<T> & insert(size_t index, const PIDeque<T> & other) {
|
||||
if (other.isEmpty()) return *this;
|
||||
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
|
||||
//piCout << "insert" << dir << index << pid_size << pid_rsize << pid_start << "!<";
|
||||
if (dir) {
|
||||
ssize_t os = pid_size - index;
|
||||
alloc(pid_size + other.pid_size, true);
|
||||
if (os > 0)
|
||||
memmove(&(pid_data[index + pid_start + other.pid_size]), &(pid_data[index + pid_start]), os * sizeof(T));
|
||||
} else {
|
||||
pid_start -= other.pid_size;
|
||||
alloc(pid_size + other.pid_size, false);
|
||||
//piCout << "insert front" << pid_size << pid_rsize << pid_start << "!<";
|
||||
if (index > 0)
|
||||
memmove(&(pid_data[pid_start]), &(pid_data[pid_start + other.pid_size]), index * sizeof(T));
|
||||
}
|
||||
//piCout << "insert" << pid_start << index << (pid_start + ssize_t(index)) << pid_size << ">!";
|
||||
newT(pid_data + pid_start + index, other.pid_data + other.pid_start, other.pid_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PIDeque<T> & remove(size_t index, size_t count = 1) {
|
||||
if (count == 0) return *this;
|
||||
if (index + count >= pid_size) {
|
||||
resize(index);
|
||||
return *this;
|
||||
}
|
||||
size_t os = pid_size - index - count;
|
||||
deleteT(&(pid_data[index + pid_start]), count);
|
||||
if (os <= index) {
|
||||
//if (true) {
|
||||
if (os > 0) memmove(&(pid_data[index + pid_start]), &(pid_data[index + pid_start + count]), os * sizeof(T));
|
||||
} else {
|
||||
if (index > 0) memmove(&(pid_data[pid_start + count]), &(pid_data[pid_start]), index * sizeof(T));
|
||||
pid_start += count;
|
||||
}
|
||||
pid_size -= count;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(PIDeque<T> & other) {
|
||||
piSwap<T*>(pid_data, other.pid_data);
|
||||
piSwap<size_t>(pid_size, other.pid_size);
|
||||
piSwap<size_t>(pid_rsize, other.pid_rsize);
|
||||
piSwap<size_t>(pid_start, other.pid_start);
|
||||
}
|
||||
|
||||
typedef int (*CompareFunc)(const T * , const T * );
|
||||
static int compare_func(const T * t0, const T * t1) {return (*t0) < (*t1) ? -1 : ((*t0) == (*t1) ? 0 : 1);}
|
||||
PIDeque<T> & sort(CompareFunc compare = compare_func) {qsort(pid_data + pid_start, pid_size, sizeof(T), (int(*)(const void * , const void * ))compare); return *this;}
|
||||
|
||||
PIDeque<T> & enlarge(llong pid_size) {llong ns = size_s() + pid_size; if (ns <= 0) clear(); else resize(size_t(ns)); return *this;}
|
||||
|
||||
PIDeque<T> & removeOne(const T & v) {for (size_t i = 0; i < pid_size; ++i) if (pid_data[i + pid_start] == v) {remove(i); return *this;} return *this;}
|
||||
PIDeque<T> & removeAll(const T & v) {for (llong i = 0; i < pid_size; ++i) if (pid_data[i + pid_start] == v) {remove(i); --i;} return *this;}
|
||||
|
||||
PIDeque<T> & push_back(const T & v) {alloc(pid_size + 1, true); elementNew(pid_data + pid_start + pid_size - 1, v); return *this;}
|
||||
PIDeque<T> & append(const T & v) {return push_back(v);}
|
||||
PIDeque<T> & operator <<(const T & v) {return push_back(v);}
|
||||
PIDeque<T> & operator <<(const PIDeque<T> & t) {
|
||||
size_t ps = pid_size;
|
||||
alloc(pid_size + t.pid_size, true);
|
||||
newT(pid_data + ps + pid_start, t.pid_data + t.pid_start, t.pid_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PIDeque<T> & push_front(const T & v) {insert(0, v); return *this;}
|
||||
PIDeque<T> & prepend(const T & v) {return push_front(v);}
|
||||
|
||||
PIDeque<T> & pop_back() {if (pid_size == 0) return *this; resize(pid_size - 1); return *this;}
|
||||
PIDeque<T> & pop_front() {if (pid_size == 0) return *this; remove(0); return *this;}
|
||||
|
||||
T take_back() {T t(back()); pop_back(); return t;}
|
||||
T take_front() {T t(front()); pop_front(); return t;}
|
||||
|
||||
private:
|
||||
void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;}
|
||||
/*void * qmemmove(void * dst, void * src, size_t size) {
|
||||
if (piAbs<ssize_t>(ssize_t(dst) - ssize_t(src)) >= size)
|
||||
memcpy(dst, src, size);
|
||||
else {
|
||||
char * tb = new char[size];
|
||||
memcpy(tb, src, size);
|
||||
memcpy(dst, tb, size);
|
||||
delete tb;
|
||||
}
|
||||
return dst;
|
||||
}*/
|
||||
inline size_t asize(ssize_t s) {
|
||||
if (s <= 0) return 0;
|
||||
if (pid_rsize + pid_rsize >= size_t(s) && pid_rsize < size_t(s))
|
||||
return pid_rsize + pid_rsize;
|
||||
size_t t = 0, s_ = size_t(s) - 1;
|
||||
while (s_ >> t) ++t;
|
||||
return (1 << t);
|
||||
}
|
||||
inline void newT(T * dst, const T * src, size_t s) {
|
||||
for (size_t i = 0; i < s; ++i)
|
||||
elementNew(dst + i, src[i]);
|
||||
}
|
||||
inline T * newRaw(size_t s) {
|
||||
//cout << std::dec << " ![("<<this<<")newRaw " << s << " elements ... <\n" << endl;
|
||||
//uchar * ret = new uchar[s * sizeof(T)];
|
||||
uchar * ret = (uchar*)(malloc(s * sizeof(T)));//new uchar[];
|
||||
//zeroRaw((T*)ret, s);
|
||||
//cout << std::hex << " > (new 0x" << (llong)ret << ") ok]!" << endl;
|
||||
return (T*)ret;
|
||||
}
|
||||
/*void reallocRawTemp(size_t s) {
|
||||
if (pid_tdata == 0) pid_tdata = (T*)(malloc(s * sizeof(T)));
|
||||
else pid_tdata = (T*)(realloc(pid_tdata, s * sizeof(T)));
|
||||
}*/
|
||||
inline void deleteT(T * d, size_t sz) {
|
||||
//cout << " ~[("<<this<<")deleteT " << std::dec << sz << " elements " << std::hex << "0x" << (llong)d << " ... <\n" << endl;
|
||||
if ((uchar*)d != 0) {
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
elementDelete(d[i]);
|
||||
//zeroRaw(d, sz);
|
||||
}
|
||||
//cout << " > ok]~" << endl;
|
||||
}
|
||||
inline void deleteRaw(T *& d) {
|
||||
//cout << " ~[("<<this<<")deleteRaw " << std::dec << pid_rsize << " elements " << std::hex << "0x" << (llong)d << " ... <\n" << endl;
|
||||
if ((uchar*)d != 0) free((uchar*)d);
|
||||
d = 0;
|
||||
//cout << " > ok]~" << endl;
|
||||
}
|
||||
void zeroRaw(T * d, size_t s) {
|
||||
//cout << " ~[("<<this<<")zeroRaw " << std::dec << s << " elements " << std::hex << "0x" << (llong)d << " ... <\n" << endl;
|
||||
if ((uchar*)d != 0) memset(d, 0, s*sizeof(T));
|
||||
//cout << " > ok]~" << endl;
|
||||
}
|
||||
inline void elementNew(T * to, const T & from) {new(to)T(from);}
|
||||
inline void elementDelete(T & from) {from.~T();}
|
||||
void dealloc() {deleteRaw(pid_data);}
|
||||
inline void checkMove(bool direction) {
|
||||
if (pid_size >= 4 && pid_size < pid_rsize / 4) {
|
||||
/*if (direction) {
|
||||
if (pid_start >= 4 && pid_start > pid_size + pid_size && pid_start > pid_rsize / 2) {
|
||||
piCout << (int)this << "checkMove" << direction << pid_start << (int)pid_data << pid_rsize << pid_size;
|
||||
piCout << (int)this << "move from" << pid_start << "to" << pid_size << "," << (int)pid_data << pid_rsize << pid_size;
|
||||
memmove(pid_data + pid_size, pid_data + pid_start, pid_size * sizeof(T));
|
||||
pid_start = pid_size;
|
||||
}
|
||||
} else {
|
||||
if (ssize_t(pid_start) < ssize_t(pid_rsize) - pid_size - pid_size && ssize_t(pid_start) < ssize_t(pid_rsize / 2) - pid_size) {
|
||||
piCout << (int)this << "checkMove" << direction << pid_start << (int)pid_data << pid_rsize << pid_size;
|
||||
piCout << (int)this << "move from" << pid_start << "to" << (ssize_t(pid_rsize) - pid_size) << "," << (int)pid_data << pid_rsize << pid_size;
|
||||
memmove(pid_data + ssize_t(pid_rsize) - pid_size - pid_size, pid_data + pid_start, pid_size * sizeof(T));
|
||||
pid_start = ssize_t(pid_rsize) - pid_size - pid_size;
|
||||
}
|
||||
}*/
|
||||
if (pid_start < pid_size + pid_size || pid_start > pid_rsize - pid_size - pid_size) {
|
||||
size_t ns = (pid_rsize - pid_size) / 2;
|
||||
if (pid_start != ns) {
|
||||
memmove(pid_data + ns, pid_data + pid_start, pid_size * sizeof(T));
|
||||
pid_start = ns;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void alloc(size_t new_size, bool direction) { // direction == true -> alloc forward
|
||||
if (direction) {
|
||||
if (pid_start + new_size <= pid_rsize) {
|
||||
pid_size = new_size;
|
||||
checkMove(direction);
|
||||
return;
|
||||
}
|
||||
pid_size = new_size;
|
||||
size_t as = asize(pid_start + new_size);
|
||||
if (as != pid_rsize) {
|
||||
pid_data = (T*)(realloc(pid_data, as*sizeof(T)));
|
||||
pid_rsize = as;
|
||||
}
|
||||
} else {
|
||||
size_t as = asize(piMax<ssize_t>(new_size, pid_rsize) - pid_start);
|
||||
//piCout << "alloc" << new_size << pid_size << pid_rsize << as << pid_start;
|
||||
if (pid_start >= 0 && as <= pid_rsize) {
|
||||
pid_size = new_size;
|
||||
checkMove(direction);
|
||||
return;
|
||||
}
|
||||
size_t os = pid_size;
|
||||
pid_size = new_size;
|
||||
if (as > pid_rsize) {
|
||||
//piCout << "alloc new size" << as;
|
||||
//cout << std::hex << " ![("<<this<<")realloc " << pid_data << " data ... <\n" << endl;
|
||||
T * td = newRaw(as);
|
||||
//piCout << "pid_start" << pid_start << (pid_start + ssize_t(as) - os);
|
||||
ssize_t ost = pid_start, ns = 0;
|
||||
if (ost < 0) {ns -= ost; ost = 0;}
|
||||
pid_start += ssize_t(as) - os;
|
||||
if (os > 0 && pid_data != 0) {
|
||||
memcpy(td + pid_start + ns, pid_data + ost, os * sizeof(T));
|
||||
deleteRaw(pid_data);
|
||||
}
|
||||
pid_data = td;
|
||||
pid_rsize = as;
|
||||
}
|
||||
}
|
||||
//checkMove(direction);
|
||||
//piCout << "alloc new start" << pid_start;
|
||||
}
|
||||
|
||||
T * pid_data;
|
||||
size_t pid_size, pid_rsize;
|
||||
size_t pid_start;
|
||||
};
|
||||
|
||||
#define __PIDEQUE_SIMPLE_TYPE__(T) \
|
||||
template<> inline void PIDeque<T>::newT(T * dst, const T * src, size_t s) {memcpy(dst, src, s * sizeof(T));} \
|
||||
template<> inline void PIDeque<T>::deleteT(T * d, size_t sz) {;} \
|
||||
template<> inline void PIDeque<T>::elementNew(T * to, const T & from) {(*to) = from;} \
|
||||
template<> inline void PIDeque<T>::elementDelete(T & from) {;}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
template<typename Type, typename Allocator = std::allocator<Type> >
|
||||
class PIP_EXPORT PIDeque: public deque<Type, Allocator> {
|
||||
typedef PIDeque<Type, Allocator> _CDeque;
|
||||
typedef deque<Type, Allocator> _stlc;
|
||||
public:
|
||||
PIDeque() {piMonitor.containers++;}
|
||||
PIDeque(const Type & value) {piMonitor.containers++; _stlc::resize(1, value);}
|
||||
PIDeque(const Type & v0, const Type & v1) {piMonitor.containers++; _stlc::push_back(v0); _stlc::push_back(v1);}
|
||||
PIDeque(const Type & v0, const Type & v1, const Type & v2) {piMonitor.containers++; _stlc::push_back(v0); _stlc::push_back(v1); _stlc::push_back(v2);}
|
||||
PIDeque(const Type & v0, const Type & v1, const Type & v2, const Type & v3) {piMonitor.containers++; _stlc::push_back(v0); _stlc::push_back(v1); _stlc::push_back(v2); _stlc::push_back(v3);}
|
||||
~PIDeque() {piMonitor.containers--;}
|
||||
int size_s() const {return static_cast<int>(_stlc::size());}
|
||||
bool isEmpty() const {return _stlc::empty();}
|
||||
bool has(const Type & t) const {for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (t == *i) return true; return false;}
|
||||
int etries(const Type & t) const {int ec = 0; for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (t == *i) ++ec; return ec;}
|
||||
_CDeque & operator <<(const Type & t) {_CDeque::push_back(t); return *this;}
|
||||
PIDeque<Type> toVector() {PIDeque<Type> v; for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) v << *i; return v;}
|
||||
};
|
||||
|
||||
|
||||
#define __PIDEQUE_SIMPLE_FUNCTIONS__(T)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIDeque<T> & v) {s << "{"; for (size_t i = 0; i < v.size(); ++i) {s << v[i]; if (i < v.size() - 1) s << ", ";} s << "}"; return s;}
|
||||
|
||||
template<typename T>
|
||||
inline PICout operator <<(PICout s, const PIDeque<T> & v) {s.space(); s.setControl(0, true); s << "{"; for (size_t i = 0; i < v.size(); ++i) {s << v[i]; if (i < v.size() - 1) s << ", ";} s << "}"; s.restoreControl(); return s;}
|
||||
|
||||
|
||||
#endif // PIDEQUE_H
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Single collection of devices
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pidevicepool.h"
|
||||
|
||||
|
||||
/*! \class PIDevicePool
|
||||
* \brief Single collection of devices
|
||||
*
|
||||
* \section PIDevicePool_sec0 Synopsis
|
||||
*
|
||||
* \section PIDevicePool_ex0 Example
|
||||
* \snippet pidevicepool.cpp 0
|
||||
*/
|
||||
|
||||
|
||||
PIDevicePool::PIDevicePool(): PIObject() {
|
||||
}
|
||||
|
||||
|
||||
PIDevicePool::~PIDevicePool() {
|
||||
/*stop();
|
||||
if (opened_) {
|
||||
closeDevice();
|
||||
if (!opened_)
|
||||
closed();
|
||||
}*/
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*! \file pidevicepool.h
|
||||
* \brief Single collection of devices
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Single collection of devices
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIDEVICEPOOL_H
|
||||
#define PIDEVICEPOOL_H
|
||||
|
||||
#include "piiodevice.h"
|
||||
|
||||
class PIP_EXPORT PIDevicePool: public PIObject
|
||||
{
|
||||
PIOBJECT(PIDevicePool)
|
||||
public:
|
||||
|
||||
PIDevicePool();
|
||||
~PIDevicePool();
|
||||
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn bool initialize()
|
||||
//! \brief Initialize device
|
||||
|
||||
//! \}
|
||||
//! \vhandlers
|
||||
//! \{
|
||||
|
||||
//! \fn void flush()
|
||||
//! \brief Immediate write all buffers
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void threadedWriteEvent(ullong id, int written_size)
|
||||
//! \brief Raise if write thread succesfull write some data of task with ID "id"
|
||||
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif // PIDEVICEPOOL_H
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Speed and quality in/out diagnostics
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pidiagnostics.h"
|
||||
|
||||
|
||||
/** \class PIDiagnostics
|
||||
* \brief Connection quality diagnostics
|
||||
* \details
|
||||
* \section PIDiagnostics_sec0 Synopsis
|
||||
* This class provide abstract connection quality diagnostics and
|
||||
* counting. You should create instance of %PIDiagnostics and on
|
||||
* packet receive call function \a received(), on packet send call
|
||||
* function \a sended(). %PIDiagnostics calculates correct, wrong
|
||||
* and sended counters, packets per second, bytes per seconds,
|
||||
* immediate and integral receive frequencies and receive/send speeds
|
||||
* in human readable representation. There statistics are calculates
|
||||
* one time per period, by default 1 second. To calculate them you
|
||||
* should start %PIDiagnostics with function \a start() or pass \b true
|
||||
* to constructor.
|
||||
* */
|
||||
|
||||
|
||||
PIDiagnostics::PIDiagnostics(bool start_): PITimer() {
|
||||
PITimer::reset();
|
||||
reset();
|
||||
if (start_) start();
|
||||
}
|
||||
|
||||
|
||||
void PIDiagnostics::reset() {
|
||||
lock();
|
||||
qual = PIDiagnostics::Unknown;
|
||||
speedIn = speedOut = PIString::readableSize(0) + "/s";
|
||||
ifreq = immediate_freq = integral_freq = 0.f;
|
||||
packets[0] = packets[1] = 0;
|
||||
cur_pckt = rec_once = 0;
|
||||
wrong_count = receive_count = send_count = 0;
|
||||
packets_in_sec = packets_out_sec = bytes_in_sec = bytes_out_sec = 0;
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIDiagnostics::received(int size, bool correct) {
|
||||
lock();
|
||||
packets[correct ? 1 : 0]++;
|
||||
rec_once = 1;
|
||||
if (correct) {
|
||||
float el = elapsed_s();
|
||||
PITimer::reset();
|
||||
if (el > 0.f) immediate_freq = ifreq = 1.f / el;
|
||||
else immediate_freq = ifreq = 0.f;
|
||||
receive_count++;
|
||||
packets_in_sec++;
|
||||
bytes_in_sec += size;
|
||||
} else {
|
||||
immediate_freq = ifreq = 0.f;
|
||||
wrong_count++;
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIDiagnostics::sended(int size) {
|
||||
lock();
|
||||
send_count++;
|
||||
packets_out_sec++;
|
||||
bytes_out_sec += size;
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIDiagnostics::tick(void * data, int delimiter) {
|
||||
lock();
|
||||
PIDiagnostics::Quality diag;
|
||||
float fdel = 1. / (interval() / 1000.);
|
||||
immediate_freq = ifreq;
|
||||
ifreq = 0.f;
|
||||
speedIn = PIString::readableSize(bytes_in_sec * fdel) + "/s";
|
||||
speedOut = PIString::readableSize(bytes_out_sec * fdel) + "/s";
|
||||
bytes_in_sec = bytes_out_sec = packets_in_sec = packets_out_sec = 0;
|
||||
int arc = packets[0] + packets[1];
|
||||
float good_percents = 0.f;
|
||||
if (arc > 0) good_percents = (float)packets[1] / arc * 100.f;
|
||||
integral_freq = packets[1] * fdel;
|
||||
if (rec_once == 0) {
|
||||
diag = PIDiagnostics::Unknown;
|
||||
} else {
|
||||
if (good_percents == 0.f) diag = PIDiagnostics::Failure;
|
||||
else if (good_percents <= 20.f) diag = PIDiagnostics::Bad;
|
||||
else if (good_percents > 20.f && good_percents <= 80.f) diag = PIDiagnostics::Average;
|
||||
else diag = PIDiagnostics::Good;
|
||||
if (diag != qual) {
|
||||
qualityChanged(diag, qual);
|
||||
qual = diag;
|
||||
}
|
||||
}
|
||||
packets[0] = packets[1] = 0;
|
||||
unlock();
|
||||
}
|
||||
170
pidiagnostics.h
170
pidiagnostics.h
@@ -1,170 +0,0 @@
|
||||
/*! \file pidiagnostics.h
|
||||
* \brief Connection quality diagnostics
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Speed and quality in/out diagnostics
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com, Bychkov Andrey wapmobil@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIDIAGNOSTICS_H
|
||||
#define PIDIAGNOSTICS_H
|
||||
|
||||
#include "pitimer.h"
|
||||
|
||||
|
||||
class PIP_EXPORT PIDiagnostics: private PITimer
|
||||
{
|
||||
PIOBJECT(PIDiagnostics)
|
||||
public:
|
||||
|
||||
//! Constructs an empty diagnostics and if "strat_" start it
|
||||
PIDiagnostics(bool start_ = true);
|
||||
|
||||
virtual ~PIDiagnostics() {;}
|
||||
|
||||
//! Connection quality
|
||||
enum Quality {
|
||||
Unknown /** Unknown, no one packet received yet */ = 1,
|
||||
Failure /** No connection, no one correct packet received for last period */ = 2,
|
||||
Bad /** Bad connection, correct packets received <= 20% */ = 3,
|
||||
Average /** Average connection, correct packets received > 20% and <= 80% */ = 4,
|
||||
Good /** Good connection, correct packets received > 80% */ = 5
|
||||
};
|
||||
|
||||
|
||||
//! Returns immediate receive frequency, packets/s
|
||||
float immediateFrequency() const {return immediate_freq;}
|
||||
|
||||
//! Returns integral receive frequency for period, packets/s
|
||||
float integralFrequency() const {return integral_freq;}
|
||||
|
||||
//! Returns correct received packets per second
|
||||
ullong receiveCountPerSec() const {return packets_in_sec;}
|
||||
|
||||
//! Returns sended packets per second
|
||||
ullong sendCountPerSec() const {return packets_out_sec;}
|
||||
|
||||
//! Returns correct received bytes per second
|
||||
ullong receiveBytesPerSec() const {return bytes_in_sec;}
|
||||
|
||||
//! Returns sended bytes per second
|
||||
ullong sendBytesPerSec() const {return bytes_out_sec;}
|
||||
|
||||
//! Returns overall correct received packets count
|
||||
ullong receiveCount() const {return receive_count;}
|
||||
|
||||
//! Returns overall wrong received packets count
|
||||
ullong wrongCount() const {return wrong_count;}
|
||||
|
||||
//! Returns overall sended packets count
|
||||
ullong sendCount() const {return send_count;}
|
||||
|
||||
//! Returns connection quality
|
||||
PIDiagnostics::Quality quality() const {return qual;}
|
||||
|
||||
//! Returns receive speed in format "n {B|kB|MB|GB|TB}/s"
|
||||
PIString receiveSpeed() const {return speedIn;}
|
||||
|
||||
//! Returns send speed in format "n {B|kB|MB|GB|TB}/s"
|
||||
PIString sendSpeed() const {return speedOut;}
|
||||
|
||||
|
||||
//! Returns immediate receive frequency pointer, packets/s. Useful for output to PIConsole
|
||||
const float * immediateFrequency_ptr() const {return &immediate_freq;}
|
||||
|
||||
//! Returns integral receive frequency pointer for period, packets/s. Useful for output to PIConsole
|
||||
const float * integralFrequency_ptr() const {return &integral_freq;}
|
||||
|
||||
//! Returns correct received packets per second pointer. Useful for output to PIConsole
|
||||
const ullong * receiveCountPerSec_ptr() const {return &packets_in_sec;}
|
||||
|
||||
//! Returns sended packets per second pointer. Useful for output to PIConsole
|
||||
const ullong * sendCountPerSec_ptr() const {return &packets_out_sec;}
|
||||
|
||||
//! Returns correct received bytes per second pointer. Useful for output to PIConsole
|
||||
const ullong * receiveBytesPerSec_ptr() const {return &bytes_in_sec;}
|
||||
|
||||
//! Returns sended bytes per second pointer. Useful for output to PIConsole
|
||||
const ullong * sendBytesPerSec_ptr() const {return &bytes_out_sec;}
|
||||
|
||||
//! Returns overall correct received packets count pointer. Useful for output to PIConsole
|
||||
const ullong * receiveCount_ptr() const {return &receive_count;}
|
||||
|
||||
//! Returns overall wrong received packets count pointer. Useful for output to PIConsole
|
||||
const ullong * wrongCount_ptr() const {return &wrong_count;}
|
||||
|
||||
//! Returns overall sended packets count pointer. Useful for output to PIConsole
|
||||
const ullong * sendCount_ptr() const {return &send_count;}
|
||||
|
||||
//! Returns connection quality pointer. Useful for output to PIConsole
|
||||
const int * quality_ptr() const {return (int * )&qual;}
|
||||
|
||||
//! Returns receive speed pointer in format "n {B|kB|MB|GB|TB}/s". Useful for output to PIConsole
|
||||
const PIString * receiveSpeed_ptr() const {return &speedIn;}
|
||||
|
||||
//! Returns send speed pointer in format "n {B|kB|MB|GB|TB}/s". Useful for output to PIConsole
|
||||
const PIString * sendSpeed_ptr() const {return &speedOut;}
|
||||
|
||||
EVENT_HANDLER0(void, start) {start(1000.);}
|
||||
EVENT_HANDLER1(void, start, double, msecs) {if (msecs > 0.) PITimer::start(msecs);}
|
||||
EVENT_HANDLER0(void, reset);
|
||||
|
||||
EVENT_HANDLER1(void, received, int, size) {received(size, true);}
|
||||
EVENT_HANDLER2(void, received, int, size, bool, correct);
|
||||
EVENT_HANDLER1(void, sended, int, size);
|
||||
|
||||
EVENT2(qualityChanged, PIDiagnostics::Quality, new_quality, PIDiagnostics::Quality, old_quality)
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void start(double msecs = 1000.)
|
||||
//! \brief Start diagnostics evaluations with period "msecs" milliseconds
|
||||
|
||||
//! \fn void reset()
|
||||
//! \brief Reset diagnostics counters
|
||||
|
||||
//! \fn void received(int size, bool correct = true)
|
||||
//! \brief Notify diagnostics about "correct" corected received packet
|
||||
|
||||
//! \fn void sended(int size)
|
||||
//! \brief Notify diagnostics about sended packet
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void qualityChanged(PIDiagnostics::Quality new_quality, PIDiagnostics::Quality old_quality)
|
||||
//! \brief Raise on change receive quality from "old_quality" to "new_quality"
|
||||
|
||||
//! \}
|
||||
|
||||
private:
|
||||
void tick(void * data, int delimiter);
|
||||
void changeDisconnectTimeout();
|
||||
|
||||
PIDiagnostics::Quality qual;
|
||||
PIString speedIn, speedOut;
|
||||
float ifreq, immediate_freq, integral_freq;
|
||||
int packets[2];
|
||||
char cur_pckt, rec_once;
|
||||
ullong wrong_count, receive_count, send_count;
|
||||
ullong packets_in_sec, packets_out_sec, bytes_in_sec, bytes_out_sec;
|
||||
|
||||
};
|
||||
|
||||
#endif // PIDIAGNOSTICS_H
|
||||
313
pidir.cpp
313
pidir.cpp
@@ -1,313 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Directory
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pidir.h"
|
||||
|
||||
#if !defined(ANDROID)
|
||||
#ifdef WINDOWS
|
||||
const PIChar PIDir::separator = '\\';
|
||||
#else
|
||||
const PIChar PIDir::separator = '/';
|
||||
#endif
|
||||
|
||||
|
||||
PIDir::PIDir(const PIString & dir) {
|
||||
path_ = dir;
|
||||
}
|
||||
|
||||
|
||||
PIDir::PIDir(const PIFile & file) {
|
||||
path_ = file.path();
|
||||
if (isExists()) return;
|
||||
int pos = path_.findLast(separator);
|
||||
path_.cutRight(path_.size_s() - pos);
|
||||
}
|
||||
|
||||
|
||||
bool PIDir::operator ==(const PIDir & d) const {
|
||||
return d.absolutePath() == absolutePath();
|
||||
}
|
||||
|
||||
|
||||
bool PIDir::isAbsolute() const {
|
||||
if (path_.size() == 0) return false;
|
||||
#ifdef WINDOWS
|
||||
if (path_.size() < 3) return false;
|
||||
return (path_[1] == ":");
|
||||
#else
|
||||
return (path_[0] == separator);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PIString PIDir::absolutePath() const {
|
||||
if (isAbsolute()) return path_;
|
||||
PIDir d(path_);
|
||||
d.setDir(PIDir::current().path_ + separator + path_);
|
||||
return d.path_;
|
||||
}
|
||||
|
||||
|
||||
PIDir & PIDir::cleanPath() {
|
||||
PIString p(path_);
|
||||
if (p.size() == 0) {
|
||||
path_ = ".";
|
||||
return *this;
|
||||
}
|
||||
path_.replaceAll(PIString(separator) + PIString(separator), PIString(separator));
|
||||
bool is_abs = isAbsolute();
|
||||
PIStringList l = PIString(p).split(separator);
|
||||
#ifdef WINDOWS
|
||||
PIString letter;
|
||||
if (is_abs) letter = l.take_front();
|
||||
#endif
|
||||
l.removeAll(".");
|
||||
l.removeAll("");
|
||||
bool found = true;
|
||||
while (found) {
|
||||
found = false;
|
||||
for (uint i = 0; i < l.size() - 1; ++i) {
|
||||
if (l.size() < 2) break;
|
||||
if (l[i] != ".." && l[i + 1] == "..") {
|
||||
if (l.size() + i > 2) l.remove(i, 2);
|
||||
else l.remove(i, 1);
|
||||
--i;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
found = true;
|
||||
while (found) {
|
||||
found = false;
|
||||
if (l.size() > 0) if (l[0] == "..")
|
||||
{l.pop_front(); found = true;}
|
||||
}
|
||||
path_ = separator + l.join(separator); /// TODO think about windows
|
||||
if (!is_abs) path_.prepend(".");
|
||||
#ifdef WINDOWS
|
||||
else path_.prepend(letter);
|
||||
#endif
|
||||
if (path_.size() == 0) path_ = ".";
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIDir & PIDir::setDir(const PIString & path) {
|
||||
path_ = path;
|
||||
cleanPath();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIDir & PIDir::cd(const PIString & path) {
|
||||
if (path_.size() == 0) return *this;
|
||||
if (path_[path_.size() - 1] != separator) path_ += separator;
|
||||
path_ += path;
|
||||
return cleanPath();
|
||||
}
|
||||
|
||||
|
||||
bool PIDir::make(bool withParents) {
|
||||
PIDir d = cleanedPath();
|
||||
PIString tp;
|
||||
bool is_abs = isAbsolute();
|
||||
if (withParents) {
|
||||
PIStringList l = d.path_.split(separator);
|
||||
for (int i = l.size_s() - 1; i >= 0; --i) {
|
||||
if (i > 1) tp = PIStringList(l).remove(i, l.size_s() - i).join(separator);
|
||||
else {
|
||||
tp = separator;
|
||||
if (!is_abs) tp.push_front('.');
|
||||
}
|
||||
//cout << tp << endl;
|
||||
if (isExists(tp)) {
|
||||
for (int j = i + 1; j <= l.size_s(); ++j) {
|
||||
tp = PIStringList(l).remove(j, l.size_s() - j).join(separator);
|
||||
//cout << tp << endl;
|
||||
if (makeDir(tp)) continue;
|
||||
else return false;
|
||||
}
|
||||
break;
|
||||
};
|
||||
}
|
||||
} else
|
||||
if (makeDir(d.path_)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIDir::DirEntry> PIDir::entries() {
|
||||
PIVector<DirEntry> l;
|
||||
PIString p(cleanedPath().path_);
|
||||
#ifdef WINDOWS
|
||||
WIN32_FIND_DATA fd; memset(&fd, 0, sizeof(fd));
|
||||
p += "\\*";
|
||||
void * hf = FindFirstFile((LPCTSTR)(p.data()), &fd);
|
||||
if (!hf) return l;
|
||||
LARGE_INTEGER filesize;
|
||||
do {
|
||||
int m = 0;
|
||||
filesize.LowPart = filesize.HighPart = 0;
|
||||
if (fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) m |= S_IFHDN;
|
||||
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) m |= S_IFBLK;
|
||||
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) m |= S_IFDIR;
|
||||
else {
|
||||
m |= S_IFREG;
|
||||
filesize.LowPart = fd.nFileSizeLow;
|
||||
filesize.HighPart = fd.nFileSizeHigh;
|
||||
}
|
||||
l << DirEntry(fd.cFileName, m, filesize.QuadPart);
|
||||
memset(&fd, 0, sizeof(fd));
|
||||
} while (FindNextFile(hf, &fd) != 0);
|
||||
FindClose(hf);
|
||||
#else
|
||||
dirent ** list;
|
||||
# ifndef QNX
|
||||
int cnt = scandir(p.data(), &list, 0, versionsort);
|
||||
# else
|
||||
int cnt = scandir(const_cast<char*>(p.data()), 0, 0, versionsort);
|
||||
# endif
|
||||
struct stat fs;
|
||||
for (int i = 0; i < cnt; ++i) {
|
||||
stat((p + separator + PIString(list[i]->d_name)).data(), &fs);
|
||||
l << DirEntry(list[i]->d_name, fs.st_mode, fs.st_size);
|
||||
if (list[i]->d_name[0] == '.') l.back().mode |= S_IFHDN;
|
||||
delete list[i];
|
||||
}
|
||||
delete list;
|
||||
#endif
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool PIDir::isExists(const PIString & path) {
|
||||
#ifdef WINDOWS
|
||||
return (GetFileAttributes((LPCTSTR)(path.data())) & FILE_ATTRIBUTE_DIRECTORY);
|
||||
#else
|
||||
DIR * dir_ = opendir(path.data());
|
||||
if (dir_ == 0) return false;
|
||||
closedir(dir_);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PIDir PIDir::current() {
|
||||
char rc[1024];
|
||||
#ifdef WINDOWS
|
||||
memset(rc, 0, 1024);
|
||||
if (GetCurrentDirectory(1024, (LPTSTR)rc) == 0) return PIString();
|
||||
#else
|
||||
if (getcwd(rc, 1024) == 0) return PIString();
|
||||
#endif
|
||||
return PIDir(rc);
|
||||
}
|
||||
|
||||
|
||||
PIDir PIDir::home() {
|
||||
char * rc = 0;
|
||||
#ifdef WINDOWS
|
||||
rc = new char[1024];
|
||||
memset(rc, 0, 1024);
|
||||
if (ExpandEnvironmentStrings((LPCTSTR)"%HOMEPATH%", (LPTSTR)rc, 1024) == 0) {
|
||||
delete[] rc;
|
||||
return PIDir();
|
||||
}
|
||||
PIString s(rc);
|
||||
delete[] rc;
|
||||
return PIDir(s);
|
||||
#else
|
||||
rc = getenv("HOME");
|
||||
if (rc == 0) return PIDir();
|
||||
return PIDir(rc);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PIDir PIDir::temporary() {
|
||||
char * rc = 0;
|
||||
#ifdef WINDOWS
|
||||
rc = new char[1024];
|
||||
memset(rc, 0, 1024);
|
||||
int ret = GetTempPath(1024, (LPTSTR)rc);
|
||||
if (ret == 0) {
|
||||
delete[] rc;
|
||||
return PIDir();
|
||||
}
|
||||
PIString s(rc);
|
||||
delete[] rc;
|
||||
return PIDir(s);
|
||||
#else
|
||||
rc = tmpnam(0);
|
||||
if (rc == 0) return PIDir();
|
||||
PIString s(rc);
|
||||
return PIDir(s.left(s.findLast(PIDir::separator)));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PIDir::make(const PIString & path, bool withParents) {
|
||||
PIDir d(path);
|
||||
if (d.isExists()) return true;
|
||||
return d.make(withParents);
|
||||
}
|
||||
|
||||
|
||||
bool PIDir::setCurrent(const PIString & path) {
|
||||
#ifdef WINDOWS
|
||||
if (SetCurrentDirectory((LPCTSTR)(path.data())) != 0) return true;
|
||||
#else
|
||||
if (chdir(path.data()) == 0) return true;
|
||||
#endif
|
||||
printf("[PIDir] setCurrent(\"%s\") error: %s\n", path.data(), errorString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PIDir::makeDir(const PIString & path) {
|
||||
#ifdef WINDOWS
|
||||
if (CreateDirectory((LPCTSTR)(path.data()), NULL) != 0) return true;
|
||||
#else
|
||||
if (mkdir(path.data(), 16877) == 0) return true;
|
||||
#endif
|
||||
printf("[PIDir] makeDir(\"%s\") error: %s\n", path.data(), errorString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PIDir::removeDir(const PIString & path) {
|
||||
#ifdef WINDOWS
|
||||
if (RemoveDirectory((LPCTSTR)(path.data())) != 0) return true;
|
||||
#else
|
||||
if (rmdir(path.data()) == 0) return true;
|
||||
#endif
|
||||
printf("[PIDir] removeDir(\"%s\") error: %s\n", path.data(), errorString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PIDir::renameDir(const PIString & path, const PIString & new_name) {
|
||||
if (::rename(path.data(), new_name.data()) == 0) return true;
|
||||
printf("[PIDir] renameDir(\"%s\", \"%s\") error: %s\n", path.data(), new_name.data(), errorString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
127
pidir.h
127
pidir.h
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Directory
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIDIR_H
|
||||
#define PIDIR_H
|
||||
|
||||
#include "pifile.h"
|
||||
#if !defined(ANDROID)
|
||||
#ifdef WINDOWS
|
||||
# undef S_IFDIR
|
||||
# undef S_IFREG
|
||||
# undef S_IFLNK
|
||||
# undef S_IFBLK
|
||||
# undef S_IFCHR
|
||||
# undef S_IFSOCK
|
||||
# define S_IFDIR 0x01
|
||||
# define S_IFREG 0x02
|
||||
# define S_IFLNK 0x04
|
||||
# define S_IFBLK 0x08
|
||||
# define S_IFCHR 0x10
|
||||
# define S_IFSOCK 0x20
|
||||
#else
|
||||
# ifdef ANDROID
|
||||
# include <sys/dirent.h>
|
||||
# else
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
#define S_IFHDN 0x40
|
||||
|
||||
class PIP_EXPORT PIDir
|
||||
{
|
||||
public:
|
||||
PIDir(const PIString & dir = PIString());
|
||||
PIDir(const PIFile & file);
|
||||
|
||||
struct DirEntry {
|
||||
DirEntry(const PIString & name_ = PIString(), int mode_ = 0, int size_ = 0) {
|
||||
name = name_; mode = mode_; size = size_;
|
||||
}
|
||||
|
||||
PIString name;
|
||||
int mode;
|
||||
int size;
|
||||
|
||||
bool isDir() const {return (mode & S_IFDIR);}
|
||||
bool isFile() const {return (mode & S_IFREG);}
|
||||
bool isSymbolicLink() const {return (mode & S_IFLNK);}
|
||||
bool isBlockDevice() const {return (mode & S_IFBLK);}
|
||||
bool isCharacterDevice() const {return (mode & S_IFCHR);}
|
||||
bool isSocket() const {return (mode & S_IFSOCK);}
|
||||
bool isHidden() const {return (mode & S_IFHDN);}
|
||||
};
|
||||
|
||||
bool isExists() const {return PIDir::isExists(path_);}
|
||||
bool isAbsolute() const;
|
||||
bool isRelative() const {return !isAbsolute();}
|
||||
|
||||
const PIString & path() const {return path_;}
|
||||
PIString absolutePath() const;
|
||||
PIDir & cleanPath();
|
||||
PIDir cleanedPath() const {PIDir d(path_); d.cleanPath(); return d;}
|
||||
PIDir & setDir(const PIString & path);
|
||||
bool setCurrent() {return PIDir::setCurrent(path_);}
|
||||
|
||||
PIVector<DirEntry> entries();
|
||||
|
||||
bool make(bool withParents = true);
|
||||
bool remove() {return PIDir::remove(path_);}
|
||||
bool rename(const PIString & new_name) {if (!PIDir::rename(path_, new_name)) return false; path_ = new_name; return true;}
|
||||
PIDir & cd(const PIString & path);
|
||||
PIDir & up() {return cd("..");}
|
||||
|
||||
bool operator ==(const PIDir & d) const;
|
||||
bool operator !=(const PIDir & d) const {return !((*this) == d);}
|
||||
|
||||
|
||||
static const PIChar separator;
|
||||
|
||||
static PIDir current();
|
||||
static PIDir home();
|
||||
static PIDir temporary();
|
||||
static bool isExists(const PIString & path);
|
||||
static bool make(const PIString & path, bool withParents = true);
|
||||
static bool remove(const PIString & path) {return removeDir(path);}
|
||||
static bool rename(const PIString & path, const PIString & new_name) {return PIDir::renameDir(path, new_name);}
|
||||
static bool setCurrent(const PIString & path);
|
||||
static bool setCurrent(const PIDir & dir) {return setCurrent(dir.path_);}
|
||||
|
||||
private:
|
||||
static bool makeDir(const PIString & path);
|
||||
static bool removeDir(const PIString & path);
|
||||
static bool renameDir(const PIString & path, const PIString & new_name);
|
||||
|
||||
PIString path_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline bool operator <(const PIDir::DirEntry & v0, const PIDir::DirEntry & v1) {return (v0.name < v1.name);}
|
||||
inline bool operator >(const PIDir::DirEntry & v0, const PIDir::DirEntry & v1) {return (v0.name > v1.name);}
|
||||
inline bool operator ==(const PIDir::DirEntry & v0, const PIDir::DirEntry & v1) {return (v0.name == v1.name);}
|
||||
inline bool operator !=(const PIDir::DirEntry & v0, const PIDir::DirEntry & v1) {return (v0.name != v1.name);}
|
||||
|
||||
inline PICout operator <<(PICout s, const PIDir & v) {s.setControl(0, true); s << "PIDir(\"" << v.path() << "\")"; s.restoreControl(); return s;}
|
||||
inline PICout operator <<(PICout s, const PIDir::DirEntry & v) {s.setControl(0, true); s << "DirEntry(\"" << v.name << "\", " << v.size << " b, " << PIString::fromNumber(v.mode, 16) << ")"; s.restoreControl(); return s;}
|
||||
|
||||
|
||||
#endif
|
||||
#endif // PIDIR_H
|
||||
877
piethernet.cpp
877
piethernet.cpp
@@ -1,877 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Ethernet, UDP/TCP Broadcast/Multicast
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piethernet.h"
|
||||
#include "piconfig.h"
|
||||
#ifdef QNX
|
||||
# include <net/if_dl.h>
|
||||
# include <hw/nicinfo.h>
|
||||
# include <sys/dcmd_io-net.h>
|
||||
#endif
|
||||
|
||||
|
||||
/** \class PIEthernet
|
||||
* \brief Ethernet device
|
||||
* \details
|
||||
* \section PIEthernet_sec0 Synopsis
|
||||
* %PIEthernet designed to work with IPv4 network by two protocols:
|
||||
* UDP and TCP. This class allow you send and receive packets to/from
|
||||
* another computer through network.
|
||||
*
|
||||
* \section PIEthernet_sec1 IPv4
|
||||
*
|
||||
*
|
||||
* \section PIEthernet_sec2 UDP
|
||||
* User Datagram Protocol
|
||||
*
|
||||
* \section PIEthernet_sec3 TCP
|
||||
* Transmission Control Protocol
|
||||
*
|
||||
* */
|
||||
|
||||
REGISTER_DEVICE(PIEthernet);
|
||||
|
||||
|
||||
PIEthernet::PIEthernet(): PIIODevice("", ReadWrite) {
|
||||
piMonitor.ethernets++;
|
||||
ip_ = ip_s = "";
|
||||
port_ = port_s = 0;
|
||||
sock = sock_s = -1;
|
||||
connected_ = connecting_ = listen_threaded = server_bounded = false;
|
||||
server_thread_.setData(this);
|
||||
setThreadedReadBufferSize(65536);
|
||||
setPriority(piHigh);
|
||||
setType(UDP);
|
||||
setParameters(PIEthernet::ReuseAddress);
|
||||
//if (type_ != UDP) init();
|
||||
}
|
||||
|
||||
|
||||
PIEthernet::PIEthernet(PIEthernet::Type type_, const PIString & ip_port, const PIFlags<PIEthernet::Parameters> params_): PIIODevice(ip_port, ReadWrite) {
|
||||
piMonitor.ethernets++;
|
||||
parseAddress(ip_port, &ip_, &port_);
|
||||
ip_s = "";
|
||||
port_s = 0;
|
||||
sock = sock_s = -1;
|
||||
connected_ = connecting_ = listen_threaded = server_bounded = false;
|
||||
server_thread_.setData(this);
|
||||
setThreadedReadBufferSize(65536);
|
||||
setPriority(piHigh);
|
||||
setType(type_);
|
||||
setParameters(params_);
|
||||
if (type_ != UDP) init();
|
||||
}
|
||||
|
||||
|
||||
PIEthernet::PIEthernet(int sock_, PIString ip_port): PIIODevice("", ReadWrite) {
|
||||
piMonitor.ethernets++;
|
||||
parseAddress(ip_port, &ip_s, &port_s);
|
||||
sock = sock_;
|
||||
sock_s = -1;
|
||||
init_ = opened_ = connected_ = true;
|
||||
connecting_ = listen_threaded = server_bounded = false;
|
||||
server_thread_.setData(this);
|
||||
setParameters(PIEthernet::ReuseAddress);
|
||||
setThreadedReadBufferSize(65536);
|
||||
setPriority(piHigh);
|
||||
setType(TCP_Client, false);
|
||||
setPath(ip_port);
|
||||
}
|
||||
|
||||
|
||||
PIEthernet::~PIEthernet() {
|
||||
piMonitor.ethernets--;
|
||||
stop();
|
||||
closeDevice();
|
||||
//if (buffer_ != 0) delete buffer_;
|
||||
//buffer_ = 0;
|
||||
}
|
||||
|
||||
|
||||
bool PIEthernet::init() {
|
||||
//cout << "init " << type_ << endl;
|
||||
closeSocket(sock);
|
||||
closeSocket(sock_s);
|
||||
int st = 0, pr = 0;
|
||||
#ifdef WINDOWS
|
||||
int flags = WSA_FLAG_OVERLAPPED;
|
||||
#else
|
||||
int so = 1;
|
||||
#endif
|
||||
if (type() == UDP) {
|
||||
st = SOCK_DGRAM;
|
||||
pr = IPPROTO_UDP;
|
||||
} else {
|
||||
st = SOCK_STREAM;
|
||||
pr = IPPROTO_TCP;
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
if (type() == UDP) flags = WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF;
|
||||
sock = WSASocket(AF_INET, st, pr, NULL, 0, flags);
|
||||
sock_s = WSASocket(AF_INET, st, pr, NULL, 0, WSA_FLAG_OVERLAPPED);
|
||||
#else
|
||||
sock = socket(AF_INET, st, pr);
|
||||
sock_s = socket(AF_INET, st, pr);
|
||||
#endif
|
||||
if (sock == -1 || sock_s == -1) {
|
||||
piCoutObj << "Can`t create socket, " << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
PIFlags<Parameters> params = parameters();
|
||||
#ifndef WINDOWS
|
||||
timeval to;
|
||||
to.tv_sec = 10;
|
||||
to.tv_usec = 0;
|
||||
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to));
|
||||
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &to, sizeof(to));
|
||||
if (params[PIEthernet::ReuseAddress]) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &so, sizeof(so));
|
||||
if (params[PIEthernet::Broadcast]) setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &so, sizeof(so));
|
||||
#else
|
||||
BOOL bv = TRUE;
|
||||
if (params[PIEthernet::ReuseAddress]) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char * )&bv, sizeof(bv));
|
||||
#endif
|
||||
//cout << "inited " << sock << ": bc = " << params << endl;
|
||||
//fcntl(sock, F_SETFL, 0/*O_NONBLOCK*/);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIEthernet::parseAddress(const PIString & ipp, PIString * ip, int * port) {
|
||||
if (ip != 0) *ip = ipp.left(ipp.find(":"));
|
||||
if (port != 0) *port = ipp.right(ipp.length() - ipp.find(":") - 1).toInt();
|
||||
}
|
||||
|
||||
|
||||
bool PIEthernet::openDevice() {
|
||||
if (connected_) return true;
|
||||
init();
|
||||
if (sock == -1 || path().isEmpty()) return false;
|
||||
parseAddress(path(), &ip_, &port_);
|
||||
if (type() != UDP || mode() == PIIODevice::WriteOnly)
|
||||
return true;
|
||||
//piCout << "bind to" << (params[PIEthernet::Broadcast] ? "bc" : ip_) << ":" << port_ << " ...";
|
||||
memset(&addr_, 0, sizeof(addr_));
|
||||
addr_.sin_family = AF_INET;
|
||||
addr_.sin_port = htons(port_);
|
||||
PIFlags<Parameters> params = parameters();
|
||||
if (params[PIEthernet::Broadcast]) addr_.sin_addr.s_addr = INADDR_ANY;
|
||||
else addr_.sin_addr.s_addr = inet_addr(ip_.data());
|
||||
#ifdef QNX
|
||||
addr_.sin_len = sizeof(addr_);
|
||||
#endif
|
||||
int tries = 0;
|
||||
while ((bind(sock, (sockaddr * )&addr_, sizeof(addr_)) == -1) && (tries < 10)) {
|
||||
init();
|
||||
tries++;
|
||||
}
|
||||
if (tries == 10) {
|
||||
piCoutObj << "Can`t bind to " << ip_ << ":" << port_ << ", " << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
opened_ = true;
|
||||
while (!mcast_queue.isEmpty())
|
||||
joinMulticastGroup(mcast_queue.dequeue());
|
||||
//cout << "!" << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIEthernet::closeDevice() {
|
||||
//cout << "close\n";
|
||||
if (server_thread_.isRunning()) {
|
||||
server_thread_.stop();
|
||||
if (!server_thread_.waitForFinish(100))
|
||||
server_thread_.terminate();
|
||||
}
|
||||
closeSocket(sock);
|
||||
closeSocket(sock_s);
|
||||
piForeach (PIEthernet * i, clients_)
|
||||
delete i;
|
||||
clients_.clear();
|
||||
if (connected_) disconnected(false);
|
||||
connected_ = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIEthernet::closeSocket(int & sd) {
|
||||
if (sd != -1) {
|
||||
#ifdef WINDOWS
|
||||
shutdown(sd, SD_BOTH);
|
||||
closesocket(sd);
|
||||
#else
|
||||
shutdown(sd, SHUT_RDWR);
|
||||
::close(sd);
|
||||
#endif
|
||||
}
|
||||
sd = -1;
|
||||
}
|
||||
|
||||
|
||||
void PIEthernet::setParameter(PIEthernet::Parameters parameter, bool on) {
|
||||
PIFlags<Parameters> cp = (PIFlags<Parameters>)(property("parameters").toInt());
|
||||
cp.setFlag(parameter, on);
|
||||
setParameters(cp);
|
||||
}
|
||||
|
||||
|
||||
bool PIEthernet::joinMulticastGroup(const PIString & group) {
|
||||
if (sock == -1) init();
|
||||
if (sock == -1) return false;
|
||||
if (type() != UDP) {
|
||||
piCoutObj << "Only UDP sockets can join multicast groups";
|
||||
return false;
|
||||
}
|
||||
if (!opened_) {
|
||||
if (mcast_queue.contains(group))
|
||||
return false;
|
||||
mcast_queue.enqueue(group);
|
||||
if (!mcast_groups.contains(group)) mcast_groups << group;
|
||||
return true;
|
||||
}
|
||||
PIFlags<Parameters> params = parameters();
|
||||
#ifdef WINDOWS
|
||||
parseAddress(path(), &ip_, &port_);
|
||||
memset(&addr_, 0, sizeof(addr_));
|
||||
addr_.sin_family = AF_INET;
|
||||
addr_.sin_addr.s_addr = inet_addr(group.data());
|
||||
//int so = 1;
|
||||
//setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char * )&so, sizeof(so));
|
||||
SOCKET ret = WSAJoinLeaf(sock, (sockaddr *)&addr_, sizeof(addr_), NULL, NULL, NULL, NULL, JL_BOTH);
|
||||
if (ret == INVALID_SOCKET) {
|
||||
piCoutObj << "Can`t join multicast group " << group << ", " << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
if (ret != sock) {
|
||||
leafs.insert(group, ret);
|
||||
if (!mcast_groups.contains(group)) mcast_groups << group;
|
||||
}
|
||||
#else
|
||||
# ifndef QNX
|
||||
if (!params[Broadcast])
|
||||
piCoutObj << "Warning: \"Broadcast\" parameter not set, \"joinMulticastGroup(\"" << group << "\")\" may be useless!";
|
||||
parseAddress(path(), &ip_, &port_);
|
||||
struct ip_mreqn mreq;
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
mreq.imr_ifindex = 0;
|
||||
if (params[PIEthernet::Broadcast]) mreq.imr_address.s_addr = INADDR_ANY;
|
||||
else mreq.imr_address.s_addr = inet_addr(ip_.data());
|
||||
PIEthernet::InterfaceList il = interfaces();
|
||||
const PIEthernet::Interface * ci = il.getByAddress(ip_);
|
||||
if (ci != 0) mreq.imr_ifindex = ci->index;
|
||||
//piCout << "join group" << group << "ip" << ip_ << "with index" << mreq.imr_ifindex;
|
||||
mreq.imr_multiaddr.s_addr = inet_addr(group.data());
|
||||
int so = 1;
|
||||
//setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &so, sizeof(so));
|
||||
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &so, sizeof(so));
|
||||
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq));
|
||||
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != 0) {
|
||||
piCoutObj << "Can`t join multicast group " << group << ", " << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
if (!mcast_groups.contains(group)) mcast_groups << group;
|
||||
# endif
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIEthernet::leaveMulticastGroup(const PIString & group) {
|
||||
if (sock == -1) init();
|
||||
if (sock == -1) return false;
|
||||
if (type() != UDP) {
|
||||
piCoutObj << "Only UDP sockets can leave multicast groups";
|
||||
return false;
|
||||
}
|
||||
PIFlags<Parameters> params = parameters();
|
||||
#ifdef WINDOWS
|
||||
SOCKET s = leafs[group];
|
||||
if (s != SOCKET()) {
|
||||
leafs.erase(group);
|
||||
closesocket(s);
|
||||
mcast_groups.removeAll(group);
|
||||
}
|
||||
#else
|
||||
# ifndef QNX
|
||||
parseAddress(path(), &ip_, &port_);
|
||||
struct ip_mreqn mreq;
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
if (params[PIEthernet::Broadcast]) mreq.imr_address.s_addr = INADDR_ANY;
|
||||
else mreq.imr_address.s_addr = inet_addr(ip_.data());
|
||||
mreq.imr_multiaddr.s_addr = inet_addr(group.data());
|
||||
mreq.imr_ifindex = 0;
|
||||
if (setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
|
||||
piCoutObj << "Can`t leave multicast group " << group << ", " << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
mcast_groups.removeAll(group);
|
||||
#endif
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIEthernet::connect() {
|
||||
connecting_ = true;
|
||||
return true;
|
||||
/*if (sock == -1) return false;
|
||||
memset(&addr_, 0, sizeof(addr_));
|
||||
parseAddress(path_, &ip_, &port_);
|
||||
addr_.sin_port = htons(port_);
|
||||
addr_.sin_addr.s_addr = inet_addr(ip_.data());
|
||||
addr_.sin_family = AF_INET;
|
||||
#ifdef QNX
|
||||
addr_.sin_len = sizeof(addr_);
|
||||
#endif
|
||||
//piCoutObj << "connect to " << ip << ":" << port_;
|
||||
connected_ = (::connect(sock, (sockaddr * )&addr_, sizeof(addr_)) == 0);
|
||||
if (!connected_)
|
||||
piCoutObj << "Can`t connect to " << ip_ << ":" << port_ << ", " << ethErrorString();
|
||||
opened_ = connected_;
|
||||
if (connected_) connected();
|
||||
return connected_;*/
|
||||
}
|
||||
|
||||
|
||||
bool PIEthernet::listen(bool threaded) {
|
||||
if (sock == -1) init();
|
||||
if (sock == -1) return false;
|
||||
if (threaded) {
|
||||
if (server_thread_.isRunning()) {
|
||||
if (!server_bounded) return true;
|
||||
server_thread_.stop();
|
||||
if (!server_thread_.waitForFinish(100))
|
||||
server_thread_.terminate();
|
||||
}
|
||||
listen_threaded = true;
|
||||
server_bounded = false;
|
||||
server_thread_.start(server_func);
|
||||
return true;
|
||||
}
|
||||
listen_threaded = server_bounded = false;
|
||||
parseAddress(path(), &ip_, &port_);
|
||||
memset(&addr_, 0, sizeof(addr_));
|
||||
addr_.sin_port = htons(port_);
|
||||
addr_.sin_addr.s_addr = inet_addr(ip_.data());
|
||||
addr_.sin_family = AF_INET;
|
||||
#ifdef QNX
|
||||
addr_.sin_len = sizeof(addr_);
|
||||
#endif
|
||||
opened_ = false;
|
||||
int tries = 0;
|
||||
while ((bind(sock, (sockaddr * )&addr_, sizeof(addr_)) == -1) && (tries < 10)) {
|
||||
init();
|
||||
tries++;
|
||||
}
|
||||
if (tries == 10) {
|
||||
piCoutObj << "Can`t bind to " << ip_ << ":" << port_ << ", " << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
if (::listen(sock, 64) == -1) {
|
||||
piCoutObj << "Can`t listen on "<< ip_ << ":" << port_ << ", " << ethErrorString();
|
||||
return false;
|
||||
}
|
||||
opened_ = server_bounded = true;
|
||||
//piCoutObj << "listen on " << ip_ << ":" << port_;
|
||||
server_thread_.start(server_func);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int PIEthernet::read(void * read_to, int max_size) {
|
||||
//cout << "read " << sock << endl;
|
||||
if (sock == -1) init();
|
||||
if (sock == -1 || read_to == 0) return -1;
|
||||
int rs = 0, s = 0, lerr = 0;
|
||||
sockaddr_in client_addr;
|
||||
socklen_t slen = sizeof(client_addr);
|
||||
//piCoutObj << "read from " << ip_ << ":" << port_ << endl;
|
||||
switch (type()) {
|
||||
case TCP_SingleTCP:
|
||||
::listen(sock, 64);
|
||||
s = accept(sock, (sockaddr * )&client_addr, &slen);
|
||||
if (s == -1) {
|
||||
//piCoutObj << "Can`t accept new connection, " << ethErrorString();
|
||||
msleep(1);
|
||||
return -1;
|
||||
}
|
||||
rs = recv(s, (char * )read_to, max_size, 0);
|
||||
closeSocket(s);
|
||||
return rs;
|
||||
case TCP_Client:
|
||||
if (connecting_) {
|
||||
memset(&addr_, 0, sizeof(addr_));
|
||||
parseAddress(path(), &ip_, &port_);
|
||||
addr_.sin_port = htons(port_);
|
||||
addr_.sin_addr.s_addr = inet_addr(ip_.data());
|
||||
addr_.sin_family = AF_INET;
|
||||
#ifdef QNX
|
||||
addr_.sin_len = sizeof(addr_);
|
||||
#endif
|
||||
//piCoutObj << "connect to " << ip_ << ":" << port_ << "...";
|
||||
connected_ = (::connect(sock, (sockaddr * )&addr_, sizeof(addr_)) == 0);
|
||||
//piCoutObj << "connect to " << ip_ << ":" << port_ << connected_;
|
||||
if (!connected_)
|
||||
piCoutObj << "Can`t connect to " << ip_ << ":" << port_ << ", " << ethErrorString();
|
||||
opened_ = connected_;
|
||||
if (connected_) {
|
||||
connecting_ = false;
|
||||
connected();
|
||||
} else
|
||||
piMSleep(10);
|
||||
//piCout << "connected to" << path();
|
||||
}
|
||||
if (!connected_) return -1;
|
||||
errorClear();
|
||||
#ifdef WINDOWS
|
||||
rs = recv(sock, (char * )read_to, max_size, 0);
|
||||
#else
|
||||
rs = recv(sock, read_to, max_size, MSG_DONTWAIT);
|
||||
#endif
|
||||
//piCoutObj << "readed" << rs;
|
||||
if (rs <= 0) {
|
||||
#ifdef WINDOWS
|
||||
lerr = WSAGetLastError();
|
||||
if (lerr == WSAEWOULDBLOCK) {
|
||||
piMSleep(10);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
lerr = errno;
|
||||
//piCoutObj << errorString();
|
||||
if (lerr == EAGAIN || lerr == EWOULDBLOCK) {
|
||||
piMSleep(10);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
if (connected_) {
|
||||
init();
|
||||
disconnected(rs < 0);
|
||||
}
|
||||
connected_ = false;
|
||||
//piCoutObj << "eth" << ip_ << "disconnected";
|
||||
}
|
||||
if (rs > 0) received(read_to, rs);
|
||||
return rs;
|
||||
case UDP:
|
||||
#ifdef WINDOWS
|
||||
rs = recv(sock, (char * )read_to, max_size, 0);
|
||||
#else
|
||||
rs = recv(sock, read_to, max_size, 0);
|
||||
#endif
|
||||
//piCout << "eth" << path() << "read return" << rs << errno;
|
||||
if (rs > 0) received(read_to, rs);
|
||||
return rs;
|
||||
//return ::read(sock, read_to, max_size);
|
||||
default: break;
|
||||
//return ::read(sock, (char * )read_to, max_size);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int PIEthernet::write(const void * data, int max_size) {
|
||||
if (sock == -1) init();
|
||||
if (sock == -1 || !isWriteable()) {
|
||||
//piCoutObj << "Can`t send to uninitialized socket";
|
||||
return -1;
|
||||
}
|
||||
//piCoutObj << "sending to " << ip_s << ":" << port_s << " " << max_size << " bytes";
|
||||
int ret = 0;
|
||||
switch (type()) {
|
||||
case TCP_SingleTCP:
|
||||
memset(&addr_, 0, sizeof(addr_));
|
||||
addr_.sin_port = htons(port_s);
|
||||
addr_.sin_addr.s_addr = inet_addr(ip_s.data());
|
||||
addr_.sin_family = AF_INET;
|
||||
#ifdef QNX
|
||||
addr_.sin_len = sizeof(addr_);
|
||||
#endif
|
||||
//piCoutObj << "connect SingleTCP" << ip_s << ":" << port_s << "...";
|
||||
if (::connect(sock, (sockaddr * )&addr_, sizeof(addr_)) != 0) {
|
||||
//piCoutObj << "Can`t connect to " << ip_s << ":" << port_s << ", " << ethErrorString();
|
||||
msleep(1);
|
||||
return -1;
|
||||
}
|
||||
//piCoutObj << "ok, write SingleTCP" << int(data) << max_size << "bytes ...";
|
||||
ret = ::send(sock, (const char *)data, max_size, 0);
|
||||
//piCoutObj << "ok, ret" << ret;
|
||||
closeSocket(sock);
|
||||
init();
|
||||
return ret;
|
||||
case UDP:
|
||||
saddr_.sin_port = htons(port_s);
|
||||
/*if (params[PIEthernet::Broadcast]) saddr_.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
else*/ saddr_.sin_addr.s_addr = inet_addr(ip_s.data());
|
||||
saddr_.sin_family = AF_INET;
|
||||
//piCout << "[PIEth] write to" << ip_s << ":" << port_s << max_size << "bytes ...";
|
||||
#ifdef WINDOWS
|
||||
return sendto(sock_s, (const char * )data, max_size, 0, (sockaddr * )&saddr_, sizeof(saddr_));
|
||||
#else
|
||||
return sendto(sock_s, data, max_size, 0, (sockaddr * )&saddr_, sizeof(saddr_));
|
||||
#endif
|
||||
//piCout << "[PIEth] write to" << ip_s << ":" << port_s << "ok";
|
||||
case TCP_Client:
|
||||
if (connecting_) {
|
||||
memset(&addr_, 0, sizeof(addr_));
|
||||
parseAddress(path(), &ip_, &port_);
|
||||
addr_.sin_port = htons(port_);
|
||||
addr_.sin_addr.s_addr = inet_addr(ip_.data());
|
||||
addr_.sin_family = AF_INET;
|
||||
#ifdef QNX
|
||||
addr_.sin_len = sizeof(addr_);
|
||||
#endif
|
||||
//piCoutObj << "connect to " << ip << ":" << port_;
|
||||
connected_ = (::connect(sock, (sockaddr * )&addr_, sizeof(addr_)) == 0);
|
||||
if (!connected_)
|
||||
piCoutObj << "Can`t connect to " << ip_ << ":" << port_ << ", " << ethErrorString();
|
||||
opened_ = connected_;
|
||||
if (connected_) {
|
||||
connecting_ = false;
|
||||
connected();
|
||||
}
|
||||
}
|
||||
if (!connected_) return -1;
|
||||
ret = ::send(sock, (const char *)data, max_size, 0);
|
||||
if (ret < 0) {
|
||||
connected_ = false; {
|
||||
init();
|
||||
disconnected(true);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
default: break;
|
||||
//return ::read(sock, read_to, max_size);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void PIEthernet::server_func(void * eth) {
|
||||
PIEthernet * ce = (PIEthernet * )eth;
|
||||
if (ce->listen_threaded) {
|
||||
if (!ce->server_bounded) {
|
||||
if (!ce->listen(false)) {
|
||||
ce->listen_threaded = true;
|
||||
piMSleep(100);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
sockaddr_in client_addr;
|
||||
socklen_t slen = sizeof(client_addr);
|
||||
int s = accept(ce->sock, (sockaddr * )&client_addr, &slen);
|
||||
if (s == -1) {
|
||||
if (ce->debug()) piCout << "[PIEthernet] Can`t accept new connection, " << ethErrorString();
|
||||
piMSleep(10);
|
||||
return;
|
||||
}
|
||||
PIString ip(inet_ntoa(client_addr.sin_addr));
|
||||
ip += ":" + PIString::fromNumber(htons(client_addr.sin_port));
|
||||
ce->clients_ << new PIEthernet(s, ip);
|
||||
ce->newConnection(ce->clients_.back());
|
||||
//cout << "connected " << ip << endl;
|
||||
//char d[256];
|
||||
//cout << " recv " << recv(s, d, 256, 0) << endl;
|
||||
//cout << recv(ce->clients_.back()->sock, d, 256, 0) << endl;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool PIEthernet::configureDevice(const void * e_main, const void * e_parent) {
|
||||
PIConfig::Entry * em = (PIConfig::Entry * )e_main;
|
||||
PIConfig::Entry * ep = (PIConfig::Entry * )e_parent;
|
||||
setReadIP(readDeviceSetting<PIString>("ip", readIP(), em, ep));
|
||||
setReadPort(readDeviceSetting<int>("port", readPort(), em, ep));
|
||||
setParameter(PIEthernet::Broadcast, readDeviceSetting<bool>("broadcast", isParameterSet(PIEthernet::Broadcast), em, ep));
|
||||
setParameter(PIEthernet::ReuseAddress, readDeviceSetting<bool>("reuseAddress", isParameterSet(PIEthernet::ReuseAddress), em, ep));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PIString PIEthernet::constructFullPath() const {
|
||||
PIString ret(fullPathPrefix() + "://");
|
||||
ret << (type() == PIEthernet::UDP ? "UDP" : "TCP") << ":" << readIP() << ":" << readPort();
|
||||
if (type() == PIEthernet::UDP) {
|
||||
piForeachC (PIString & m, multicastGroups())
|
||||
ret << ":mcast:" << m;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PIEthernet::configureFromFullPath(const PIString & full_path) {
|
||||
PIStringList pl = full_path.split(":");
|
||||
bool mcast = false;
|
||||
for (int i = 0; i < pl.size_s(); ++i) {
|
||||
PIString p(pl[i]);
|
||||
switch (i) {
|
||||
case 0:
|
||||
p = p.toLowerCase();
|
||||
if (p == "udp") setType(UDP);
|
||||
if (p == "tcp") setType(TCP_Client);
|
||||
break;
|
||||
case 1: setReadIP(p); setSendIP(p); break;
|
||||
case 2: setReadPort(p.toInt()); setSendPort(p.toInt()); break;
|
||||
}
|
||||
if (i <= 2) continue;
|
||||
if (i % 2 == 1) {if (p.toLowerCase() == "mcast") mcast = true;}
|
||||
else {if (mcast) {joinMulticastGroup(p); mcast = false;}}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
PIEthernet::InterfaceList il;
|
||||
Interface ci;
|
||||
#ifdef WINDOWS
|
||||
PIP_ADAPTER_INFO pAdapterInfo, pAdapter = 0;
|
||||
int ret = 0;
|
||||
ulong ulOutBufLen = sizeof(IP_ADAPTER_INFO);
|
||||
pAdapterInfo = (IP_ADAPTER_INFO * ) HeapAlloc(GetProcessHeap(), 0, (sizeof (IP_ADAPTER_INFO)));
|
||||
if (pAdapterInfo == 0) {
|
||||
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo";
|
||||
return il;
|
||||
}
|
||||
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
|
||||
HeapFree(GetProcessHeap(), 0, (pAdapterInfo));
|
||||
pAdapterInfo = (IP_ADAPTER_INFO *) HeapAlloc(GetProcessHeap(), 0, (ulOutBufLen));
|
||||
if (pAdapterInfo == 0) {
|
||||
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo";
|
||||
return il;
|
||||
}
|
||||
}
|
||||
if ((ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
|
||||
pAdapter = pAdapterInfo;
|
||||
while (pAdapter) {
|
||||
ci.name = PIString(pAdapter->AdapterName);
|
||||
ci.index = pAdapter->Index;
|
||||
ci.address = PIString(pAdapter->IpAddressList.IpAddress.String);
|
||||
if (ci.address == "0.0.0.0") {
|
||||
pAdapter = pAdapter->Next;
|
||||
continue;
|
||||
}
|
||||
ci.mac = macFromBytes(PIByteArray(pAdapter->Address, pAdapter->AddressLength));
|
||||
ci.netmask = PIString(pAdapter->IpAddressList.IpMask.String);
|
||||
ci.flags = PIEthernet::ifActive | PIEthernet::ifRunning;
|
||||
//if (ret->ifa_flags & IFF_BROADCAST) ci.flags |= PIEthernet::ifBroadcast;
|
||||
//if (ret->ifa_flags & IFF_MULTICAST) ci.flags |= PIEthernet::ifMulticast;
|
||||
if (pAdapter->Type == MIB_IF_TYPE_PPP) ci.flags |= PIEthernet::ifPTP;
|
||||
if (pAdapter->Type == MIB_IF_TYPE_LOOPBACK) ci.flags |= PIEthernet::ifLoopback;
|
||||
ci.broadcast.clear();
|
||||
ci.ptp.clear();
|
||||
/*if (ci.flags[PIEthernet::ifBroadcast])
|
||||
ci.broadcast = getSockAddr(ret->ifa_broadaddr);
|
||||
if (ci.flags[PIEthernet::ifPTP])
|
||||
ci.ptp = getSockAddr(ret->ifa_dstaddr);*/
|
||||
il << ci;
|
||||
pAdapter = pAdapter->Next;
|
||||
}
|
||||
} else
|
||||
piCout << "[PIEthernet] GetAdaptersInfo failed with error: " << ret;
|
||||
if (pAdapterInfo)
|
||||
HeapFree(GetProcessHeap(), 0, (pAdapterInfo));
|
||||
#else
|
||||
/*# ifdef QNX
|
||||
PIStringList il, sl;
|
||||
PIProcess proc;
|
||||
proc.setGrabOutput(true);
|
||||
proc.exec(ifconfigPath.c_str(), "-l");
|
||||
if (!proc.waitForFinish(1000)) return sl;
|
||||
PIString out(proc.readOutput());
|
||||
il = out.split(" ");
|
||||
il.removeAll("");
|
||||
piForeachC (PIString & i, il) {
|
||||
proc.exec(ifconfigPath.c_str(), i);
|
||||
if (!proc.waitForFinish(1000)) return il;
|
||||
sl << i.trimmed();
|
||||
out = proc.readOutput();
|
||||
int al = out.length();
|
||||
al = (al - out.replaceAll("alias", "").length()) / 5;
|
||||
for (int j = 0; j < al; ++j)
|
||||
sl << i.trimmed() + ":" + PIString::fromNumber(j);
|
||||
}
|
||||
return sl;
|
||||
# else
|
||||
PIStringList sl;
|
||||
PIProcess proc;
|
||||
proc.setGrabOutput(true);
|
||||
proc.exec(ifconfigPath.c_str(), "-s");
|
||||
if (!proc.waitForFinish(1000)) return sl;
|
||||
PIString out(proc.readOutput());
|
||||
out.cutLeft(out.find('\n') + 1);
|
||||
while (!out.isEmpty()) {
|
||||
sl << out.left(out.find(' '));
|
||||
out.cutLeft(out.find('\n') + 1);
|
||||
}
|
||||
return sl;
|
||||
# endif*/
|
||||
# ifdef ANDROID
|
||||
struct ifconf ifc;
|
||||
int s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
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();
|
||||
delete ifc.ifc_buf;
|
||||
return il;
|
||||
}
|
||||
int icnt = ifc.ifc_len / sizeof(ifreq);
|
||||
PIStringList inl;
|
||||
struct ifreq ir;
|
||||
for (int i = 0; i < icnt; ++i) {
|
||||
PIString in(ifc.ifc_req[i].ifr_name);
|
||||
if (in.isEmpty()) continue;
|
||||
ci.name = in;
|
||||
strcpy(ir.ifr_name, in.data());
|
||||
if (ioctl(s, SIOCGIFHWADDR, &ir) == 0)
|
||||
ci.mac = macFromBytes(PIByteArray(ir.ifr_hwaddr.sa_data, 6));
|
||||
if (ioctl(s, SIOCGIFADDR, &ir) >= 0)
|
||||
ci.address = getSockAddr(&ir.ifr_addr);
|
||||
if (ioctl(s, SIOCGIFNETMASK, &ir) >= 0)
|
||||
ci.netmask = getSockAddr(&ir.ifr_addr);
|
||||
il << ci;
|
||||
}
|
||||
delete ifc.ifc_buf;
|
||||
# else
|
||||
struct ifaddrs * ret;
|
||||
int s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
if (getifaddrs(&ret) == 0) {
|
||||
while (ret != 0) {
|
||||
if (ret->ifa_addr->sa_family != AF_INET) {
|
||||
ret = ret->ifa_next;
|
||||
continue;
|
||||
}
|
||||
ci.name = PIString(ret->ifa_name);
|
||||
ci.address = getSockAddr(ret->ifa_addr);
|
||||
ci.netmask = getSockAddr(ret->ifa_netmask);
|
||||
ci.mac.clear();
|
||||
# ifdef QNX
|
||||
int fd = ::open((PIString("/dev/io-net/") + ci.name).data(), O_RDONLY);
|
||||
if (fd != 0) {
|
||||
nic_config_t nic;
|
||||
devctl(fd, DCMD_IO_NET_GET_CONFIG, &nic, sizeof(nic), 0);
|
||||
::close(fd);
|
||||
ci.mac = macFromBytes(PIByteArray(nic.permanent_address, 6));
|
||||
}
|
||||
# else
|
||||
# ifdef MAC_OS
|
||||
PIString req = PIString(PIInit::instance()->ifconfigPath) + " " + ci.name + " | grep ether";
|
||||
FILE * fp = popen(req.data(), "r");
|
||||
if (fp != 0) {
|
||||
char in[256];
|
||||
if (fgets(in, 256, fp) != 0) {
|
||||
req = PIString(in).trim();
|
||||
ci.mac = req.cutLeft(req.find(" ") + 1).trim().toUpperCase();
|
||||
}
|
||||
pclose(fp);
|
||||
}
|
||||
# else
|
||||
if (s != -1) {
|
||||
struct ifreq ir;
|
||||
strcpy(ir.ifr_name, ret->ifa_name);
|
||||
if (ioctl(s, SIOCGIFHWADDR, &ir) == 0)
|
||||
ci.mac = macFromBytes(PIByteArray(ir.ifr_hwaddr.sa_data, 6));
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
ci.flags = 0;
|
||||
if (ret->ifa_flags & IFF_UP) ci.flags |= PIEthernet::ifActive;
|
||||
if (ret->ifa_flags & IFF_RUNNING) ci.flags |= PIEthernet::ifRunning;
|
||||
if (ret->ifa_flags & IFF_BROADCAST) ci.flags |= PIEthernet::ifBroadcast;
|
||||
if (ret->ifa_flags & IFF_MULTICAST) ci.flags |= PIEthernet::ifMulticast;
|
||||
if (ret->ifa_flags & IFF_LOOPBACK) ci.flags |= PIEthernet::ifLoopback;
|
||||
if (ret->ifa_flags & IFF_POINTOPOINT) ci.flags |= PIEthernet::ifPTP;
|
||||
ci.broadcast.clear();
|
||||
ci.ptp.clear();
|
||||
if (ci.flags[PIEthernet::ifBroadcast])
|
||||
ci.broadcast = getSockAddr(ret->ifa_broadaddr);
|
||||
if (ci.flags[PIEthernet::ifPTP])
|
||||
ci.ptp = getSockAddr(ret->ifa_dstaddr);
|
||||
ci.index = if_nametoindex(ret->ifa_name);
|
||||
il << ci;
|
||||
ret = ret->ifa_next;
|
||||
}
|
||||
freeifaddrs(ret);
|
||||
} else
|
||||
piCout << "[PIEthernet] Can`t get interfaces:" << errorString();
|
||||
if (s != -1) ::close(s);
|
||||
# endif
|
||||
#endif
|
||||
return il;
|
||||
}
|
||||
|
||||
|
||||
PIString PIEthernet::interfaceAddress(const PIString & interface_) {
|
||||
#ifdef WINDOWS
|
||||
piCout << "[PIEthernet] Not implemented on Windows, use \"PIEthernet::allAddresses\" or \"PIEthernet::interfaces\" instead";
|
||||
return PIString();
|
||||
#else
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strcpy(ifr.ifr_name, interface_.data());
|
||||
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
ioctl(s, SIOCGIFADDR, &ifr);
|
||||
::close(s);
|
||||
struct sockaddr_in * sa = (struct sockaddr_in * )&ifr.ifr_addr;
|
||||
return PIString(inet_ntoa(sa->sin_addr));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
PIStringList PIEthernet::allAddresses() {
|
||||
/*#ifdef WINDOWS
|
||||
PIStringList al;
|
||||
PIString ca;
|
||||
PIP_ADAPTER_INFO pAdapterInfo, pAdapter = 0;
|
||||
int ret = 0;
|
||||
ulong ulOutBufLen = sizeof(IP_ADAPTER_INFO);
|
||||
pAdapterInfo = (IP_ADAPTER_INFO * ) HeapAlloc(GetProcessHeap(), 0, (sizeof (IP_ADAPTER_INFO)));
|
||||
if (pAdapterInfo == 0) {
|
||||
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo";
|
||||
return PIStringList();
|
||||
}
|
||||
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
|
||||
HeapFree(GetProcessHeap(), 0, (pAdapterInfo));
|
||||
pAdapterInfo = (IP_ADAPTER_INFO *) HeapAlloc(GetProcessHeap(), 0, (ulOutBufLen));
|
||||
if (pAdapterInfo == 0) {
|
||||
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo";
|
||||
return PIStringList();
|
||||
}
|
||||
}
|
||||
if ((ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
|
||||
pAdapter = pAdapterInfo;
|
||||
while (pAdapter) {
|
||||
ca = PIString(pAdapter->IpAddressList.IpAddress.String);
|
||||
if (ca != "0.0.0.0") al << ca;
|
||||
pAdapter = pAdapter->Next;
|
||||
}
|
||||
} else
|
||||
piCout << "[PIEthernet] GetAdaptersInfo failed with error: " << ret;
|
||||
if (pAdapterInfo)
|
||||
HeapFree(GetProcessHeap(), 0, (pAdapterInfo));
|
||||
return al;
|
||||
#else*/
|
||||
PIEthernet::InterfaceList il = interfaces();
|
||||
PIStringList al;
|
||||
piForeachC (PIEthernet::Interface & i, il)
|
||||
al << i.address;
|
||||
return al.removeStrings("0.0.0.0");
|
||||
//#endif
|
||||
}
|
||||
364
piethernet.h
364
piethernet.h
@@ -1,364 +0,0 @@
|
||||
/*! \file piethernet.h
|
||||
* \brief Ethernet device
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Ethernet, UDP/TCP Broadcast/Multicast
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIETHERNET_H
|
||||
#define PIETHERNET_H
|
||||
|
||||
#include "pitimer.h"
|
||||
#include "piiodevice.h"
|
||||
#include "piprocess.h"
|
||||
|
||||
class PIP_EXPORT PIEthernet: public PIIODevice
|
||||
{
|
||||
PIIODEVICE(PIEthernet)
|
||||
friend class PIPeer;
|
||||
public:
|
||||
|
||||
//! Contructs UDP %PIEthernet with empty read address
|
||||
PIEthernet();
|
||||
|
||||
//! \brief Type of %PIEthernet
|
||||
enum PIP_EXPORT Type {
|
||||
UDP /** UDP - User Datagram Protocol */ ,
|
||||
TCP_Client /** TCP client - allow connection to TCP server */ ,
|
||||
TCP_Server /** TCP server - receive connections from TCP clients */ ,
|
||||
TCP_SingleTCP
|
||||
};
|
||||
|
||||
//! \brief Parameters of %PIEthernet
|
||||
enum PIP_EXPORT Parameters {
|
||||
ReuseAddress /** Rebind address if there is already binded */ = 0x1,
|
||||
Broadcast /** Broadcast send */ = 0x2
|
||||
};
|
||||
|
||||
//! Contructs %PIEthernet with type "type", read address "ip_port" and parameters "params"
|
||||
PIEthernet(Type type, const PIString & ip_port = PIString(), const PIFlags<Parameters> params = 0);
|
||||
|
||||
virtual ~PIEthernet();
|
||||
|
||||
|
||||
//! Set read address
|
||||
void setReadAddress(const PIString & ip, int port) {setPath(ip + ":" + PIString::fromNumber(port));}
|
||||
|
||||
//! Set read address in format "i.i.i.i:p"
|
||||
void setReadAddress(const PIString & ip_port) {setPath(ip_port);}
|
||||
|
||||
//! Set read IP
|
||||
void setReadIP(const PIString & ip) {parseAddress(path(), &ip_, &port_); setPath(ip + ":" + PIString::fromNumber(port_));}
|
||||
|
||||
//! Set read port
|
||||
void setReadPort(int port) {parseAddress(path(), &ip_, &port_); setPath(ip_ + ":" + PIString::fromNumber(port));}
|
||||
|
||||
|
||||
//! Set send address
|
||||
void setSendAddress(const PIString & ip, int port) {ip_s = ip; port_s = port;}
|
||||
|
||||
//! Set send address in format "i.i.i.i:p"
|
||||
void setSendAddress(const PIString & ip_port) {parseAddress(ip_port, &ip_s, &port_s);}
|
||||
|
||||
//! Set send IP
|
||||
void setSendIP(const PIString & ip) {ip_s = ip;}
|
||||
|
||||
//! Set send port
|
||||
void setSendPort(int port) {port_s = port;}
|
||||
|
||||
|
||||
//! Returns read address in format "i.i.i.i:p"
|
||||
PIString readAddress() const {return path();}
|
||||
|
||||
//! Returns read IP
|
||||
PIString readIP() const {parseAddress(path(), &ip_, &port_); return ip_;}
|
||||
|
||||
//! Returns read port
|
||||
int readPort() const {parseAddress(path(), &ip_, &port_); return port_;}
|
||||
|
||||
|
||||
//! Returns send address in format "i.i.i.i:p"
|
||||
PIString sendAddress() const {return ip_s + ":" + PIString::fromNumber(port_s);}
|
||||
|
||||
//! Returns send IP
|
||||
PIString sendIP() const {return ip_s;}
|
||||
|
||||
//! Returns send port
|
||||
int sendPort() const {return port_s;}
|
||||
|
||||
|
||||
//! Set parameters to "parameters_". You should to reopen %PIEthernet to apply them
|
||||
void setParameters(PIFlags<PIEthernet::Parameters> parameters_) {setProperty("parameters", (int)parameters_);}
|
||||
|
||||
//! Set parameter "parameter" to state "on". You should to reopen %PIEthernet to apply this
|
||||
void setParameter(PIEthernet::Parameters parameter, bool on = true);
|
||||
|
||||
//! Returns if parameter "parameter" is set
|
||||
bool isParameterSet(PIEthernet::Parameters parameter) const {return ((PIFlags<PIEthernet::Parameters>)(property("parameters").toInt()))[parameter];}
|
||||
|
||||
//! Returns parameters
|
||||
PIFlags<PIEthernet::Parameters> parameters() const {return (PIFlags<PIEthernet::Parameters>)(property("parameters").toInt());}
|
||||
|
||||
//PIByteArray macAddress() {if (!init_) init(); struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); memcpy(ifr.ifr_name, "eth0", 5); ioctl(sock, SIOCSIFHWADDR, &ifr); return PIByteArray(&ifr.ifr_hwaddr.sa_data, 6);}
|
||||
|
||||
//! Returns %PIEthernet type
|
||||
Type type() const {return (Type)(property("type").toInt());}
|
||||
|
||||
|
||||
//! Join to multicast group with address "group". Use only for UDP
|
||||
bool joinMulticastGroup(const PIString & group);
|
||||
|
||||
//! Leave multicast group with address "group". Use only for UDP
|
||||
bool leaveMulticastGroup(const PIString & group);
|
||||
|
||||
//! Returns joined multicast groups. Use only for UDP
|
||||
const PIStringList & multicastGroups() const {return mcast_groups;}
|
||||
|
||||
|
||||
//! Connect to TCP server with address \a readAddress(). Use only for TCP_Client
|
||||
bool connect();
|
||||
|
||||
//! Connect to TCP server with address "ip":"port". Use only for TCP_Client
|
||||
bool connect(const PIString & ip, int port) {setPath(ip + ":" + PIString::fromNumber(port)); return connect();}
|
||||
|
||||
//! Connect to TCP server with address "ip_port". Use only for TCP_Client
|
||||
bool connect(const PIString & ip_port) {setPath(ip_port); return connect();}
|
||||
|
||||
//! Returns if %PIEthernet connected to TCP server. Use only for TCP_Client
|
||||
bool isConnected() const {return connected_;}
|
||||
|
||||
|
||||
//! Start listen for incoming TCP connections on address \a readAddress(). Use only for TCP_Server
|
||||
bool listen(bool threaded = false);
|
||||
|
||||
//! Start listen for incoming TCP connections on address "ip":"port". Use only for TCP_Server
|
||||
bool listen(const PIString & ip, int port, bool threaded = false) {setReadAddress(ip, port); return listen(threaded);}
|
||||
|
||||
//! Start listen for incoming TCP connections on address "ip_port". Use only for TCP_Server
|
||||
bool listen(const PIString & ip_port, bool threaded = false) {setReadAddress(ip_port); return listen(threaded);}
|
||||
|
||||
PIEthernet * client(int index) {return clients_[index];}
|
||||
int clientsCount() const {return clients_.size_s();}
|
||||
PIVector<PIEthernet * > clients() const {return clients_;}
|
||||
|
||||
|
||||
//! Send data "data" with size "size" to address "ip":"port"
|
||||
bool send(const PIString & ip, int port, const void * data, int size, bool threaded = false) {ip_s = ip; port_s = port; if (threaded) {writeThreaded(data, size); return true;} return send(data, size);}
|
||||
|
||||
//! Send data "data" with size "size" to address "ip_port"
|
||||
bool send(const PIString & ip_port, const void * data, int size, bool threaded = false) {parseAddress(ip_port, &ip_s, &port_s); if (threaded) {writeThreaded(data, size); return true;} return send(data, size);}
|
||||
|
||||
//! Send data "data" with size "size" to address \a sendAddress() for UDP or \a readAddress() for TCP_Client
|
||||
bool send(const void * data, int size, bool threaded = false) {if (threaded) {writeThreaded(data, size); return true;} return (write(data, size) == size);}
|
||||
|
||||
//! Send data "data" to address \a sendAddress() for UDP or \a readAddress() for TCP_Client
|
||||
bool send(const PIByteArray & data, bool threaded = false) {if (threaded) {writeThreaded(data); return true;} return (write(data) == data.size_s());}
|
||||
|
||||
|
||||
//! Wait for some data and read it to "read_to"
|
||||
int read(void * read_to, int max_size);
|
||||
|
||||
//! Send data "read_to" with size "max_size" to address \a sendAddress() for UDP or \a readAddress() for TCP_Client
|
||||
int write(const void * data, int max_size);
|
||||
|
||||
//! Send data "data" to address \a sendAddress() for UDP or \a readAddress() for TCP_Client
|
||||
int write(const PIByteArray & data) {return write(data.data(), data.size_s());}
|
||||
|
||||
PIString constructFullPath() const;
|
||||
|
||||
EVENT1(newConnection, PIEthernet * , client)
|
||||
EVENT0(connected)
|
||||
EVENT1(disconnected, bool, withError)
|
||||
|
||||
|
||||
//! Flags of network interface
|
||||
enum PIP_EXPORT InterfaceFlag {
|
||||
ifActive /** Is active */ = 0x1,
|
||||
ifRunning /** Is running */ = 0x2,
|
||||
ifBroadcast /** Support broadcast */ = 0x4,
|
||||
ifMulticast /** Support multicast */ = 0x8,
|
||||
ifLoopback /** Is loopback */ = 0x10,
|
||||
ifPTP /** Is point-to-point */ = 0x20
|
||||
};
|
||||
|
||||
//! %PIFlags of network interface flags
|
||||
typedef PIFlags<InterfaceFlag> InterfaceFlags;
|
||||
|
||||
|
||||
//! Network interface descriptor
|
||||
struct PIP_EXPORT Interface {
|
||||
|
||||
//! System index
|
||||
int index;
|
||||
|
||||
//! System name
|
||||
PIString name;
|
||||
|
||||
//! MAC address in format "hh:hh:hh:hh:hh:hh" or empty if there is no MAC address
|
||||
PIString mac;
|
||||
|
||||
//! IP address in format "i.i.i.i" or empty if there is no IP address
|
||||
PIString address;
|
||||
|
||||
//! Netmask of IP address in format "i.i.i.i" or empty if there is no netmask
|
||||
PIString netmask;
|
||||
|
||||
//! Broadcast address in format "i.i.i.i" or empty if there is no broadcast address
|
||||
PIString broadcast;
|
||||
|
||||
//! Point-to-point address or empty if there is no point-to-point address
|
||||
PIString ptp;
|
||||
|
||||
//! Flags of interface
|
||||
InterfaceFlags flags;
|
||||
|
||||
//! Returns if interface is active
|
||||
bool isActive() const {return flags[PIEthernet::ifActive];}
|
||||
|
||||
//! Returns if interface is running
|
||||
bool isRunning() const {return flags[PIEthernet::ifRunning];}
|
||||
|
||||
//! Returns if interface support broadcast
|
||||
bool isBroadcast() const {return flags[PIEthernet::ifBroadcast];}
|
||||
|
||||
//! Returns if interface support multicast
|
||||
bool isMulticast() const {return flags[PIEthernet::ifMulticast];}
|
||||
|
||||
//! Returns if interface is loopback
|
||||
bool isLoopback() const {return flags[PIEthernet::ifLoopback];}
|
||||
|
||||
//! Returns if interface is point-to-point
|
||||
bool isPTP() const {return flags[PIEthernet::ifPTP];}
|
||||
};
|
||||
|
||||
|
||||
//! Array of \a Interface with some features
|
||||
class PIP_EXPORT InterfaceList: public PIVector<PIEthernet::Interface> {
|
||||
public:
|
||||
InterfaceList(): PIVector<PIEthernet::Interface>() {}
|
||||
|
||||
//! Get interface with system index "index" or 0 if there is no one
|
||||
const Interface * getByIndex(int index) const {for (int i = 0; i < size_s(); ++i) if ((*this)[i].index == index) return &((*this)[i]); return 0;}
|
||||
|
||||
//! Get interface with system name "name" or 0 if there is no one
|
||||
const Interface * getByName(const PIString & name) const {for (int i = 0; i < size_s(); ++i) if ((*this)[i].name == name) return &((*this)[i]); return 0;}
|
||||
|
||||
//! Get interface with IP address "address" or 0 if there is no one
|
||||
const Interface * getByAddress(const PIString & address) const {for (int i = 0; i < size_s(); ++i) if ((*this)[i].address == address) return &((*this)[i]); return 0;}
|
||||
|
||||
//! Get loopback interface or 0 if there is no one
|
||||
const Interface * getLoopback() const {for (int i = 0; i < size_s(); ++i) if ((*this)[i].isLoopback()) return &((*this)[i]); return 0;}
|
||||
};
|
||||
|
||||
|
||||
//! Returns all system network interfaces
|
||||
static InterfaceList interfaces();
|
||||
|
||||
static PIString interfaceAddress(const PIString & interface_);
|
||||
|
||||
//! Returns all system network IP addresses
|
||||
static PIStringList allAddresses();
|
||||
|
||||
static void parseAddress(const PIString & ipp, PIString * ip, int * port);
|
||||
static PIString macFromBytes(const PIByteArray & mac) {PIString r; for (int i = 0; i < mac.size_s(); ++i) {r += PIString::fromNumber(mac[i], 16).expandLeftTo(2, '0'); if (i < mac.size_s() - 1) r += ":";} return r;}
|
||||
static PIByteArray macToBytes(const PIString & mac) {PIByteArray r; PIStringList sl = mac.split(":"); piForeachC (PIString & i, sl) r << uchar(i.toInt(16)); return r;}
|
||||
static PIString applyMask(const PIString & ip, const PIString & mask) {struct in_addr ia; ia.s_addr = inet_addr(ip.data()) & inet_addr(mask.data()); return PIString(inet_ntoa(ia));}
|
||||
static PIString getBroadcast(const PIString & ip, const PIString & mask) {struct in_addr ia; ia.s_addr = inet_addr(ip.data()) | ~inet_addr(mask.data()); return PIString(inet_ntoa(ia));}
|
||||
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void newConnection(PIEthernet * client)
|
||||
//! \brief Raise on new TCP connection received
|
||||
|
||||
//! \fn void connected()
|
||||
//! \brief Raise if succesfull TCP connection
|
||||
|
||||
//! \fn void disconnected(bool withError)
|
||||
//! \brief Raise if TCP connection was closed
|
||||
|
||||
//! \}
|
||||
//! \ioparams
|
||||
//! \{
|
||||
#ifdef DOXYGEN
|
||||
//! \brief read ip, default ""
|
||||
string ip;
|
||||
|
||||
//! \brief read port, default 0
|
||||
int port;
|
||||
|
||||
//! \brief Broadcast parameter, default false
|
||||
bool broadcast;
|
||||
|
||||
//! \brief ReuseAddress parameter, default false
|
||||
bool reuseAddress;
|
||||
#endif
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
PIEthernet(int sock, PIString ip_port);
|
||||
|
||||
PIString fullPathPrefix() const {return "eth";}
|
||||
void configureFromFullPath(const PIString & full_path);
|
||||
bool configureDevice(const void * e_main, const void * e_parent = 0);
|
||||
|
||||
//! Executes when any read function was successful. Default implementation does nothing
|
||||
virtual void received(const void * data, int size) {;}
|
||||
|
||||
bool init();
|
||||
bool openDevice();
|
||||
bool closeDevice();
|
||||
void closeSocket(int & sd);
|
||||
#ifndef WINDOWS
|
||||
static PIString getSockAddr(sockaddr * s) {return s == 0 ? PIString() : PIString(inet_ntoa(((sockaddr_in*)s)->sin_addr));}
|
||||
#endif
|
||||
|
||||
|
||||
int sock, sock_s, wrote;
|
||||
mutable int port_, port_s, port_c;
|
||||
bool connected_, connecting_, listen_threaded, server_bounded;
|
||||
sockaddr_in addr_, saddr_;
|
||||
mutable PIString ip_, ip_s, ip_c;
|
||||
PIThread server_thread_;
|
||||
PIVector<PIEthernet * > clients_;
|
||||
PIQueue<PIString> mcast_queue;
|
||||
PIStringList mcast_groups;
|
||||
#ifdef WINDOWS
|
||||
PIMap<PIString, SOCKET> leafs;
|
||||
#endif
|
||||
|
||||
private:
|
||||
static void server_func(void * eth);
|
||||
void setType(Type t, bool reopen = true) {setProperty("type", (int)t); if (reopen && isOpened()) {closeDevice(); init(); openDevice();}}
|
||||
|
||||
static std::string ethErrorString() {
|
||||
#ifdef WINDOWS
|
||||
char * msg;
|
||||
int err = WSAGetLastError();
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&msg, 0, NULL);
|
||||
return "code " + itos(err) + " - " + string(msg);
|
||||
#else
|
||||
return errorString();
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline bool operator <(const PIEthernet::Interface & v0, const PIEthernet::Interface & v1) {return (v0.name < v1.name);}
|
||||
|
||||
#endif // PIETHERNET_H
|
||||
1252
pievaluator.cpp
1252
pievaluator.cpp
@@ -1,1252 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Evaluator designed for stream computing
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pievaluator.h"
|
||||
|
||||
|
||||
/*! \class PIEvaluator
|
||||
* \brief This class provide mathematical evaluations of custom expression
|
||||
*
|
||||
* \section PIEvaluator_sec0 Synopsis
|
||||
* %PIEvaluator developed for stream evaluations of once set expression.
|
||||
* It`s create internal list of instructions on function \a check() and
|
||||
* executes very fast on function \a evaluate(). Once given expression
|
||||
* can be evaluated any times with different variable values. Evaluator
|
||||
* supports many common mathematic functions described below. Also it`s
|
||||
* automatic puts unnecessarily signs and bracets. Processed expression
|
||||
* can be obtains with function \a expression(). If there is an error
|
||||
* in expression you can get it with function \a error(). Last evaluated
|
||||
* result you can get with function \a lastResult().
|
||||
* \section PIEvaluator_sec1 Using
|
||||
* First you should set your variables with function \a setVariable().
|
||||
* Next give your expression with function \a check() and check for error
|
||||
* with functions \a isCorrect() and \a error(). If expression is correct
|
||||
* you can get processed expression with function \a expression() and
|
||||
* evaluate it with function \a evaluate(). You can change variable values
|
||||
* without rechecking expression.
|
||||
*
|
||||
* \section PIEvaluator_sec2 Functions
|
||||
* %PIEvaluator supports arithmetical operations with complex numbers, this
|
||||
* is their list in priority order:
|
||||
* * ^ (power)
|
||||
* * * (multiply)
|
||||
* * / (divide)
|
||||
* * % (residue)
|
||||
* * + (add)
|
||||
* * - (subtract)
|
||||
*
|
||||
* In addition there are compare and logical operations:
|
||||
* * == (equal)
|
||||
* * != (not equal)
|
||||
* * > (greater)
|
||||
* * < (smaller)
|
||||
* * >= (greater or equal)
|
||||
* * <= (smaller or equal)
|
||||
* * && (and)
|
||||
* * || (or)
|
||||
*
|
||||
* Compare and logical functions works with real operators part and returns 0 or 1.
|
||||
*
|
||||
* Mathematical functions:
|
||||
* * sin(x) - sine
|
||||
* * cos(x) - cosine
|
||||
* * tg(x) - tangent
|
||||
* * ctg(x) - cotangent
|
||||
* * arcsin(x) - arcsine
|
||||
* * arccos(x) - arccosine
|
||||
* * arctg(x) -arccotangent
|
||||
* * arcctg(x) - arctangent
|
||||
* * sh(x) - hyperbolical sine
|
||||
* * ch(x) - hyperbolical cosine
|
||||
* * th(x) - hyperbolical tangent
|
||||
* * cth(x) - hyperbolical cotangent
|
||||
* * sqr(x) - square
|
||||
* * sqrt(x) - square root
|
||||
* * abs(x) - absolute value
|
||||
* * sign(x) - sign of real part (-1 or 1)
|
||||
* * exp(x) - exponent
|
||||
* * pow(x, p) - x in power p
|
||||
* * ln(x) - natural logarithm
|
||||
* * lg(x) - decimal logarithm
|
||||
* * log(x, b) - logarithm of x with base b
|
||||
* * im(x) - imaginary part of complex number
|
||||
* * re(x) - real part of complex number
|
||||
* * arg(x) - argument of complex number
|
||||
* * len(x) - length of complex number
|
||||
* * conj(x) - length of complex number
|
||||
* * rad(x) - convert degrees to radians
|
||||
* * deg(x) - convert radians to degrees
|
||||
* * j0(x) - Bessel function first kind order 0
|
||||
* * j1(x) - Bessel function first kind order 1
|
||||
* * jn(x, n) - Bessel function first kind order n
|
||||
* * y0(x) - Bessel function second kind order 0
|
||||
* * y1(x) - Bessel function second kind order 1
|
||||
* * yn(x, n) - Bessel function second kind order n
|
||||
* * random(s, f) - regular random number in range [s, f]
|
||||
* * min(x0, x1, ...) - minimum of x0, x1, ...
|
||||
* * max(x0, x1, ...) - maximum of x0, x1, ...
|
||||
* * clamp(x, a, b) - trim x on range [a, b]
|
||||
* * step(x, s) - 0 if x < s, else 1
|
||||
* * mix(x, a, b) - interpolate between a and b linear for x (a * (1 - x) + b * x)
|
||||
*
|
||||
* There are some built-in constans:
|
||||
* * i (imaginary 1)
|
||||
* * e
|
||||
* * pi
|
||||
*
|
||||
* All trigonometric functions takes angle in radians.
|
||||
*
|
||||
* \section PIEvaluator_sec3 Example
|
||||
* \snippet pievaluator.cpp main
|
||||
*/
|
||||
|
||||
|
||||
PIEvaluatorContent::PIEvaluatorContent() {
|
||||
addFunction("arcsin", 1);
|
||||
addFunction("arccos", 1);
|
||||
addFunction("arctg", 1);
|
||||
addFunction("arcctg", 1);
|
||||
addFunction("random", 2);
|
||||
addFunction("sin", 1);
|
||||
addFunction("cos", 1);
|
||||
addFunction("ctg", 1);
|
||||
addFunction("tg", 1);
|
||||
addFunction("exp", 1);
|
||||
addFunction("cth", 1);
|
||||
addFunction("sh", 1);
|
||||
addFunction("ch", 1);
|
||||
addFunction("th", 1);
|
||||
addFunction("sqrt", 1);
|
||||
addFunction("sqr", 1);
|
||||
addFunction("pow", 2);
|
||||
addFunction("abs", 1);
|
||||
addFunction("ln", 1);
|
||||
addFunction("lg", 1);
|
||||
addFunction("log", 2);
|
||||
addFunction("im", 1);
|
||||
addFunction("re", 1);
|
||||
addFunction("arg", 1);
|
||||
addFunction("len", 1);
|
||||
addFunction("conj", 1);
|
||||
addFunction("sign", 1);
|
||||
addFunction("rad", 1);
|
||||
addFunction("deg", 1);
|
||||
addFunction("j0", 1);
|
||||
addFunction("j1", 1);
|
||||
addFunction("jn", 2);
|
||||
addFunction("y0", 1);
|
||||
addFunction("y1", 1);
|
||||
addFunction("yn", 2);
|
||||
addFunction("min", -2); // (x0,x1,...)
|
||||
addFunction("max", -2); // (x0,x1,...)
|
||||
addFunction("clamp", 3); // (x,a,b) = x < a ? a : (x > b ? b : x)
|
||||
addFunction("step", 2); // (x,s) = x >= s ? 1. : 0. (1 if 'x' >= 's', else 0)
|
||||
addFunction("mix", 3); // (x,a,b) = a*(1.-x) + b*x (interpolate between 'a' and 'b' linear for 'x')
|
||||
addFunction("defined", 1);
|
||||
clearCustomVariables();
|
||||
//addVariable("n", 0.);
|
||||
//addVariable("x1", 123);
|
||||
}
|
||||
|
||||
|
||||
bool PIEvaluatorContent::setVariableValue(int index, complexd new_value) {
|
||||
if (index < 0 || index >= variables.size_s()) return false;
|
||||
variables[index].value = new_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIEvaluatorContent::setVariableName(int index, const PIString & new_name) {
|
||||
if (index < 0 || index >= variables.size_s()) return false;
|
||||
variables[index].name = new_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluatorContent::clearCustomVariables() {
|
||||
variables.clear();
|
||||
addVariable("i", complexd_i);
|
||||
addVariable("pi", atan(1.) * 4.);
|
||||
addVariable("e", exp(1.));
|
||||
cv_count = variables.size();
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluatorContent::sortVariables() {
|
||||
PIEvaluatorTypes::Variable tv;
|
||||
for (uint i = 0; i < variables.size(); i++) {
|
||||
for (uint j = variables.size() - 1; j > i; j--) {
|
||||
if (variables[j].name.length() <= variables[i].name.length()) continue;
|
||||
piSwap<PIEvaluatorTypes::Variable>(variables[i], variables[j]);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* qDebug() << "---";
|
||||
* for (int i = 0; i < variables.size(); i++) {
|
||||
* qDebug() << variables[i].name;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
PIEvaluatorTypes::BaseFunctions PIEvaluatorContent::getBaseFunction(const PIString & name) {
|
||||
if (name == "sin") return PIEvaluatorTypes::bfSin;
|
||||
if (name == "cos") return PIEvaluatorTypes::bfCos;
|
||||
if (name == "tg") return PIEvaluatorTypes::bfTg;
|
||||
if (name == "ctg") return PIEvaluatorTypes::bfCtg;
|
||||
if (name == "arcsin") return PIEvaluatorTypes::bfArcsin;
|
||||
if (name == "arccos") return PIEvaluatorTypes::bfArccos;
|
||||
if (name == "arctg") return PIEvaluatorTypes::bfArctg;
|
||||
if (name == "arcctg") return PIEvaluatorTypes::bfArcctg;
|
||||
if (name == "exp") return PIEvaluatorTypes::bfExp;
|
||||
if (name == "random") return PIEvaluatorTypes::bfRandom;
|
||||
if (name == "sh") return PIEvaluatorTypes::bfSh;
|
||||
if (name == "ch") return PIEvaluatorTypes::bfCh;
|
||||
if (name == "th") return PIEvaluatorTypes::bfTh;
|
||||
if (name == "cth") return PIEvaluatorTypes::bfCth;
|
||||
if (name == "sqrt") return PIEvaluatorTypes::bfSqrt;
|
||||
if (name == "sqr") return PIEvaluatorTypes::bfSqr;
|
||||
if (name == "pow") return PIEvaluatorTypes::bfPow;
|
||||
if (name == "abs") return PIEvaluatorTypes::bfAbs;
|
||||
if (name == "ln") return PIEvaluatorTypes::bfLn;
|
||||
if (name == "lg") return PIEvaluatorTypes::bfLg;
|
||||
if (name == "log") return PIEvaluatorTypes::bfLog;
|
||||
if (name == "im") return PIEvaluatorTypes::bfIm;
|
||||
if (name == "re") return PIEvaluatorTypes::bfRe;
|
||||
if (name == "arg") return PIEvaluatorTypes::bfArg;
|
||||
if (name == "len") return PIEvaluatorTypes::bfLen;
|
||||
if (name == "conj") return PIEvaluatorTypes::bfConj;
|
||||
if (name == "sign") return PIEvaluatorTypes::bfSign;
|
||||
if (name == "rad") return PIEvaluatorTypes::bfRad;
|
||||
if (name == "deg") return PIEvaluatorTypes::bfDeg;
|
||||
if (name == "j0") return PIEvaluatorTypes::bfJ0;
|
||||
if (name == "j1") return PIEvaluatorTypes::bfJ1;
|
||||
if (name == "jn") return PIEvaluatorTypes::bfJN;
|
||||
if (name == "y0") return PIEvaluatorTypes::bfY0;
|
||||
if (name == "y1") return PIEvaluatorTypes::bfY1;
|
||||
if (name == "yn") return PIEvaluatorTypes::bfYN;
|
||||
if (name == "min") return PIEvaluatorTypes::bfMin;
|
||||
if (name == "max") return PIEvaluatorTypes::bfMax;
|
||||
if (name == "clamp") return PIEvaluatorTypes::bfClamp;
|
||||
if (name == "step") return PIEvaluatorTypes::bfStep;
|
||||
if (name == "mix") return PIEvaluatorTypes::bfMix;
|
||||
if (name == "defined") return PIEvaluatorTypes::bfDefined;
|
||||
return PIEvaluatorTypes::bfUnknown;
|
||||
}
|
||||
|
||||
const PIString & PIEvaluator::prepare(const PIString & string) {
|
||||
currentString = string.trimmed();
|
||||
if (currentString.isEmpty()) currentString = "0";
|
||||
replaceOperators();
|
||||
removeSpaces();
|
||||
checkBrackets();
|
||||
while (fillElements()) checkBrackets();
|
||||
while (setSignes()) fillElements();
|
||||
removeJunk();
|
||||
findUnknownVariables();
|
||||
return currentString;
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::removeSpaces() {
|
||||
PIString tmps = currentString;
|
||||
for (int i = 0; i < tmps.length(); i++) {
|
||||
if (tmps[i] == ' ' || tmps[i] == '\t') {
|
||||
tmps.remove(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
currentString = tmps;
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::removeJunk() {
|
||||
PIChar cc;
|
||||
bool junk = true;
|
||||
int bcnt;
|
||||
while (junk) {
|
||||
if (currentString.left(1) != "(" || currentString.right(1) != ")") return;
|
||||
bcnt = 1;
|
||||
junk = false;
|
||||
for (int i = 1; i < currentString.length(); i++) {
|
||||
cc = currentString[i];
|
||||
if (cc == '(') bcnt++;
|
||||
if (cc == ')') bcnt--;
|
||||
if (bcnt == 0) {
|
||||
if (i == currentString.length() - 1) {
|
||||
currentString = currentString.mid(1, currentString.length() - 2);
|
||||
elements.pop_front();
|
||||
elements.pop_back();
|
||||
junk = true;
|
||||
break;
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::replaceOperators() {
|
||||
currentString.replaceAll("==", "=");
|
||||
currentString.replaceAll("!=", ":");
|
||||
currentString.replaceAll(">=", "}");
|
||||
currentString.replaceAll("<=", "{");
|
||||
currentString.replaceAll("&&", "&");
|
||||
currentString.replaceAll("||", "|");
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::makeOutput(PIString & string) {
|
||||
string.replaceAll(":", "≠");
|
||||
string.replaceAll("}", "≥");
|
||||
string.replaceAll("{", "≤");
|
||||
string.replaceAll("&", "⋀");
|
||||
string.replaceAll("|", "⋁");
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::findUnknownVariables() {
|
||||
PIString cvar;
|
||||
unknownVars.clear();
|
||||
for (int i = 0; i < currentString.length(); i++) {
|
||||
if (elements[i].var_num == -666) cvar += currentString[i];
|
||||
else {
|
||||
if (cvar.length() == 0) continue;
|
||||
unknownVars << cvar;
|
||||
cvar = "";
|
||||
}
|
||||
}
|
||||
if (cvar.length() > 0) unknownVars << cvar;
|
||||
unknownVars.removeDuplicates();
|
||||
}
|
||||
|
||||
|
||||
bool PIEvaluator::isSign(const PIChar & ch) {
|
||||
return ch == '+' || ch == '-' ||
|
||||
ch == '*' || ch == '/' ||
|
||||
ch == '%' || ch == '^' ||
|
||||
ch == '=' || ch == ':' ||
|
||||
ch == '>' || ch == '<' ||
|
||||
ch == '}' || ch == '{' ||
|
||||
ch == '&' || ch == '|';
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::checkBrackets() {
|
||||
PIString tmps = currentString;
|
||||
PIChar fc, sc;
|
||||
int bcnt = 0, bpos = 0, inserted = 0;
|
||||
currentString = tmps;
|
||||
for (int i = 0; i < tmps.length(); i++) {
|
||||
if (tmps[i] == '(') {
|
||||
if (bcnt == 0) bpos = i;
|
||||
bcnt++;
|
||||
}
|
||||
if (tmps[i] == ')') {
|
||||
if (bcnt == 0) {
|
||||
currentString.insert(bpos + inserted, "(");
|
||||
inserted++;
|
||||
} else bcnt--;
|
||||
}
|
||||
}
|
||||
if (bcnt > 0) currentString += PIString(bcnt, ')');
|
||||
tmps = currentString;
|
||||
for (int i = 0; i < tmps.length() - 1; i++) {
|
||||
fc = tmps[i].toLower();
|
||||
sc = tmps[i + 1].toLower();
|
||||
if ((fc == ')' && sc == '(') ||
|
||||
(fc == ')' && sc >= '0' && sc <= '9') ||
|
||||
(fc == ')' && sc >= 'a' && sc <= 'z') ) tmps.insert(++i, '*');
|
||||
}
|
||||
currentString = tmps;
|
||||
}
|
||||
|
||||
|
||||
bool PIEvaluator::fillElements() {
|
||||
int fstart, flen, cnum = 0, cpart = 0, cfunc;
|
||||
PIChar cc, nc, pc, fc = '!';
|
||||
bool numFound = false;
|
||||
PIString curfind, tmps = currentString;
|
||||
elements.resize(tmps.length());
|
||||
for (uint i = 0; i < elements.size(); i++) {
|
||||
elements[i].type = PIEvaluatorTypes::etVariable;
|
||||
elements[i].var_num = -666;
|
||||
}
|
||||
currentVariables.clear();
|
||||
//qDebug().nospace() << "search for functions ...";
|
||||
for (int i = 0; i < content.functionsCount(); i++) {
|
||||
curfind = content.function(i).identifier;
|
||||
cfunc = i; //(int)content.function(i).type;
|
||||
flen = curfind.length();
|
||||
fstart = 0;
|
||||
while (fstart >= 0) {
|
||||
fstart = tmps.find(curfind, fstart);
|
||||
if (fstart < 0) break;
|
||||
if (tmps[fstart + flen] != '(') {
|
||||
currentString.insert(fstart + flen, "(");
|
||||
return true;
|
||||
}
|
||||
for (int j = fstart; j < fstart + flen; j++) {
|
||||
elements[j].set(PIEvaluatorTypes::etFunction, cnum, cfunc);
|
||||
tmps.replace(j, 1, fc);
|
||||
}
|
||||
cnum++;
|
||||
}
|
||||
}
|
||||
cnum = 0;
|
||||
//qDebug().nospace() << "search for variables ...";
|
||||
for (int i = 0; i < content.variablesCount(); i++) {
|
||||
curfind = content.variable(i).name;
|
||||
flen = curfind.length();
|
||||
fstart = 0;
|
||||
while (fstart >= 0) {
|
||||
fstart = tmps.find(curfind, fstart);
|
||||
if (fstart < 0) break;
|
||||
for (int j = fstart; j < fstart + flen; j++) {
|
||||
elements[j].set(PIEvaluatorTypes::etVariable, cnum, i);
|
||||
tmps.replace(j, 1, fc);
|
||||
}
|
||||
cnum++;
|
||||
}
|
||||
}
|
||||
curfind = "";
|
||||
cnum = 1;
|
||||
//qDebug().nospace() << "search for numbers ...";
|
||||
for (int i = 0; i < tmps.length(); i++) {
|
||||
cc = tmps[i];
|
||||
/*if (cc == " " || cc == "(" || cc == ")") {
|
||||
curfind = "";
|
||||
cpart = 0;
|
||||
numFound = false;
|
||||
continue;
|
||||
}*/
|
||||
switch (cpart) {
|
||||
case 0:
|
||||
if ((cc >= '0' && cc <= '9')) {// || cc == '-' || cc == '+') {
|
||||
curfind += cc;
|
||||
cpart = 1;
|
||||
continue;
|
||||
}
|
||||
if (cc == '.') {
|
||||
curfind += cc;
|
||||
cpart = 2;
|
||||
continue;
|
||||
}
|
||||
if (cc == 'E') {
|
||||
curfind += cc;
|
||||
cpart = 3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (cc >= '0' && cc <= '9') {
|
||||
curfind += cc;
|
||||
continue;
|
||||
}
|
||||
if (cc == '.') {
|
||||
curfind += cc;
|
||||
cpart = 2;
|
||||
continue;
|
||||
}
|
||||
if (cc == 'E') {
|
||||
curfind += cc;
|
||||
cpart = 3;
|
||||
continue;
|
||||
}
|
||||
numFound = true;
|
||||
break;
|
||||
case 2:
|
||||
if (cc >= '0' && cc <= '9') {
|
||||
curfind += cc;
|
||||
continue;
|
||||
}
|
||||
if (cc == 'E') {
|
||||
curfind += cc;
|
||||
cpart = 3;
|
||||
continue;
|
||||
}
|
||||
numFound = true;
|
||||
break;
|
||||
case 3:
|
||||
if ((cc >= '0' && cc <= '9') || cc == '-' || cc == '+') {
|
||||
curfind += cc;
|
||||
cpart = 4;
|
||||
continue;
|
||||
}
|
||||
numFound = true;
|
||||
break;
|
||||
case 4:
|
||||
if (cc >= '0' && cc <= '9') {
|
||||
curfind += cc;
|
||||
continue;
|
||||
}
|
||||
numFound = true;
|
||||
break;
|
||||
}
|
||||
if (numFound) {
|
||||
//qDebug().nospace() << "add " << cnum << ": " << curfind << " = " << curfind.toDouble();
|
||||
currentVariables.push_back(PIEvaluatorTypes::Variable("tmp" + PIString::fromNumber(cnum), curfind.toDouble()));
|
||||
for (int j = i - curfind.length(); j < i; j++) {
|
||||
elements[j].set(PIEvaluatorTypes::etNumber, cnum, -cnum);
|
||||
tmps.replace(j, 1, fc);
|
||||
}
|
||||
curfind = "";
|
||||
cnum++;
|
||||
cpart = 0;
|
||||
numFound = false;
|
||||
}
|
||||
}
|
||||
if (cpart > 0) {
|
||||
//qDebug().nospace() << "add " << cnum << ": " << curfind << " = " << curfind.toDouble();
|
||||
currentVariables.push_back(PIEvaluatorTypes::Variable("tmp" + PIString::fromNumber(cnum), curfind.toDouble()));
|
||||
for (int j = tmps.length() - curfind.length(); j < tmps.length(); j++) {
|
||||
elements[j].set(PIEvaluatorTypes::etNumber, cnum, -cnum);
|
||||
tmps.replace(j, 1, fc);
|
||||
}
|
||||
}
|
||||
cc = nc = fc;
|
||||
//qDebug().nospace() << "search for signes ...";
|
||||
for (int i = 0; i < tmps.length(); i++) {
|
||||
cc = tmps[i];
|
||||
if (i > 0) pc = tmps[i - 1];
|
||||
else pc = fc;
|
||||
if (i < tmps.length() - 1) nc = tmps[i + 1];
|
||||
else nc = fc;
|
||||
if (cc == '(' || cc == ')' || cc == ',') {
|
||||
elements[i].set(PIEvaluatorTypes::etOperator, -1);
|
||||
continue;
|
||||
}
|
||||
if (cc == '-' || cc == '+') {
|
||||
elements[i].set(PIEvaluatorTypes::etOperator, -1);
|
||||
if (i < tmps.length() - 1) if (elements[i + 1].type == PIEvaluatorTypes::etVariable ||
|
||||
elements[i + 1].type == PIEvaluatorTypes::etFunction) continue;
|
||||
if ((pc == '(' || isSign(pc) || i == 0) && i < tmps.length() - 1) {
|
||||
if (elements[i + 1].type != PIEvaluatorTypes::etOperator) {
|
||||
cnum = elements[i + 1].num;
|
||||
elements[i].set(PIEvaluatorTypes::etNumber, cnum);
|
||||
tmps.replace(i, 1, fc);
|
||||
///cout << "found sign " << cc << " :" << cnum - 1 << endl;
|
||||
if (cc == '-' && currentVariables.size_s() >= cnum)
|
||||
currentVariables[cnum - 1].value = -currentVariables[cnum - 1].value;
|
||||
//i++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isSign(cc)) {
|
||||
elements[i].set(PIEvaluatorTypes::etOperator, -1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/*
|
||||
qDebug().nospace() << tmps;
|
||||
cout << " ";
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
switch (elements[i].type) {
|
||||
case etFunction: cout << "f"; break;
|
||||
case etNumber: cout << "n"; break;
|
||||
case etOperator: cout << "o"; break;
|
||||
case etVariable: cout << "v"; break;
|
||||
}
|
||||
}
|
||||
cout << endl;
|
||||
*/
|
||||
return false;
|
||||
//for (int i = 0; i < currentVariables.size(); i++) qDebug() << "var " << i << ": " << currentVariables[i].value.real();
|
||||
}
|
||||
|
||||
|
||||
bool PIEvaluator::setSignes() {
|
||||
int inserted = 0, ni, pi = 0, needInsert = 0;
|
||||
PIChar fc, sc, pc;
|
||||
PIString tmps = currentString;
|
||||
for (int i = 0; i < tmps.length() - 1; i++) {
|
||||
needInsert = 0;
|
||||
ni = i + 1;
|
||||
if (i > 0) pi = i - 1;
|
||||
fc = tmps[i].toLower();
|
||||
sc = tmps[ni].toLower();
|
||||
pc = tmps[pi].toLower();
|
||||
//if (elements[i].type == etOperator || elements[ni].type == etVariable) continue;
|
||||
if (fc == ',' || sc == ',') continue;
|
||||
if (elements[i].type == PIEvaluatorTypes::etOperator && elements[ni].type == PIEvaluatorTypes::etOperator) continue;
|
||||
if (fc == ')' && (elements[ni].type == PIEvaluatorTypes::etNumber || elements[ni].type == PIEvaluatorTypes::etVariable || elements[ni].type == PIEvaluatorTypes::etFunction)) needInsert = 1;
|
||||
if (sc == '(' && (elements[i].type == PIEvaluatorTypes::etNumber || elements[i].type == PIEvaluatorTypes::etVariable)) needInsert = 1;
|
||||
if (elements[i].type == PIEvaluatorTypes::etNumber && elements[ni].type == PIEvaluatorTypes::etNumber && elements[i].num != elements[ni].num) needInsert = 1;
|
||||
if (elements[i].type == PIEvaluatorTypes::etVariable && elements[ni].type == PIEvaluatorTypes::etVariable && elements[i].num != elements[ni].num) needInsert = 1;
|
||||
if ((elements[i].type == PIEvaluatorTypes::etNumber && elements[ni].type == PIEvaluatorTypes::etVariable) || (elements[i].type == PIEvaluatorTypes::etVariable && elements[ni].type == PIEvaluatorTypes::etNumber)) needInsert = 1;
|
||||
if ((elements[i].type == PIEvaluatorTypes::etNumber || elements[i].type == PIEvaluatorTypes::etVariable) && elements[ni].type == PIEvaluatorTypes::etFunction) needInsert = 1;
|
||||
if (elements[i].type == PIEvaluatorTypes::etFunction && elements[ni].type == PIEvaluatorTypes::etFunction && elements[i].num != elements[ni].num) needInsert = 2;
|
||||
if (elements[i].type == PIEvaluatorTypes::etFunction && elements[ni].type != PIEvaluatorTypes::etFunction && sc != '(') needInsert = 2;
|
||||
if (elements[pi].type == PIEvaluatorTypes::etOperator && (elements[ni].type == PIEvaluatorTypes::etFunction || elements[ni].type == PIEvaluatorTypes::etVariable) && fc == '-') needInsert = 3;
|
||||
switch (needInsert) {
|
||||
case 1:
|
||||
currentString.insert(ni + inserted, "*");
|
||||
elements.insert(ni + inserted, PIEvaluatorTypes::Element(PIEvaluatorTypes::etOperator, -1));
|
||||
//inserted++;
|
||||
//i++;
|
||||
return true;
|
||||
/*case 2:
|
||||
currentString.insert(ni + inserted, ")");
|
||||
currentString.insert(ni + inserted, "(");
|
||||
elements.insert(ni + inserted, Element(etOperator, -1));
|
||||
elements.insert(ni + inserted, Element(etOperator, -1));
|
||||
inserted++;
|
||||
i++;
|
||||
return true;*/
|
||||
case 3:
|
||||
currentString.insert(ni + inserted, "1*");
|
||||
elements.insert(ni + inserted, PIEvaluatorTypes::Element(PIEvaluatorTypes::etOperator, -1));
|
||||
//inserted;
|
||||
//i++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/*if (elements[tmps.length() - 1].type == etFunction) {
|
||||
currentString.insert(tmps.length() + inserted, ")");
|
||||
currentString.insert(tmps.length() + inserted, "(");
|
||||
elements.insert(tmps.length() + inserted, Element(etOperator, -1));
|
||||
elements.insert(tmps.length() + inserted, Element(etOperator, -1));
|
||||
return true;
|
||||
}*/
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::convert() {
|
||||
int j;
|
||||
PIEvaluatorTypes::Element ce, pe;
|
||||
for (int i = 0; i < currentString.length(); i++) {
|
||||
pe = elements[i];
|
||||
if (pe.type != PIEvaluatorTypes::etFunction) continue;
|
||||
j = i + 1;
|
||||
while (j < currentString.length()) {
|
||||
ce = elements[j];
|
||||
if (ce != pe) break;
|
||||
j++;
|
||||
}
|
||||
currentString.replace(i, j - i, " ");
|
||||
for (int k = i + 1; k < j; k++) elements.remove(i);
|
||||
//i++;
|
||||
}
|
||||
for (int i = 0; i < currentString.length(); i++) {
|
||||
pe = elements[i];
|
||||
if (pe.type != PIEvaluatorTypes::etNumber) continue;
|
||||
j = i + 1;
|
||||
while (j < currentString.length()) {
|
||||
ce = elements[j];
|
||||
if (ce != pe) break;
|
||||
j++;
|
||||
}
|
||||
currentString.replace(i, j - i, " ");
|
||||
for (int k = i + 1; k < j; k++) elements.remove(i);
|
||||
//i++;
|
||||
}
|
||||
for (int i = 0; i < currentString.length(); i++) {
|
||||
pe = elements[i];
|
||||
if (pe.type != PIEvaluatorTypes::etVariable) continue;
|
||||
j = i + 1;
|
||||
while (j < currentString.length()) {
|
||||
ce = elements[j];
|
||||
if (ce != pe) break;
|
||||
j++;
|
||||
}
|
||||
currentString.replace(i, j - i, " ");
|
||||
for (int k = i + 1; k < j; k++) elements.remove(i);
|
||||
//i++;
|
||||
}
|
||||
/*qDebug().nospace() << currentString;
|
||||
cout << " ";
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
switch (elements[i].type) {
|
||||
case etFunction: cout << "f"; break;
|
||||
case etNumber: cout << "n"; break;
|
||||
case etOperator: cout << "o"; break;
|
||||
case etVariable: cout << "v"; break;
|
||||
}
|
||||
}
|
||||
cout << endl;*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
const PIString & PIEvaluator::preprocess(const PIString & string) {
|
||||
static PIString ret;
|
||||
int lind;
|
||||
ret = prepare(string);
|
||||
convert();
|
||||
instructions.clear();
|
||||
//qDebug() << preproc->currentString;
|
||||
variables = currentVariables;
|
||||
lind = parse(currentString);
|
||||
if (instructions.size() == 0) {
|
||||
variables.push_back(PIEvaluatorTypes::Variable());
|
||||
instructions.push_back(PIEvaluatorTypes::Instruction(PIEvaluatorTypes::oNone, PIVector<int>(1, lind), -variables.size_s()));
|
||||
}
|
||||
kvars = &(content.variables);
|
||||
/*
|
||||
cout << endl << "variables:" << endl;
|
||||
for (int i = 0; i < variables.size(); i++)
|
||||
cout << i << " value = " << variables[i].value << endl;
|
||||
|
||||
cout << endl << "instructions:" << endl;
|
||||
for (int i = 0; i < instructions.size(); i++) {
|
||||
cout << i << endl;
|
||||
cout << " operation " << instructions[i].operation << endl;
|
||||
cout << " operators: ";
|
||||
for (int j = 0; j < instructions[i].operators.size(); j++)
|
||||
cout << instructions[i].operators[j] << "; ";
|
||||
cout << endl << " function " << instructions[i].function << endl;
|
||||
cout << " out " << instructions[i].out << endl;
|
||||
}
|
||||
*/
|
||||
makeOutput(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIEvaluatorTypes::Operation PIEvaluator::operationInOrder(const int & index) {
|
||||
switch (index) {
|
||||
case 0: return PIEvaluatorTypes::oPower;
|
||||
case 1: return PIEvaluatorTypes::oMultiply;
|
||||
case 2: return PIEvaluatorTypes::oDivide;
|
||||
case 3: return PIEvaluatorTypes::oResidue;
|
||||
case 4: return PIEvaluatorTypes::oAdd;
|
||||
case 5: return PIEvaluatorTypes::oSubtract;
|
||||
case 6: return PIEvaluatorTypes::oEqual;
|
||||
case 7: return PIEvaluatorTypes::oNotEqual;
|
||||
case 8: return PIEvaluatorTypes::oGreaterEqual;
|
||||
case 9: return PIEvaluatorTypes::oSmallerEqual;
|
||||
case 10: return PIEvaluatorTypes::oGreater;
|
||||
case 11: return PIEvaluatorTypes::oSmaller;
|
||||
case 12: return PIEvaluatorTypes::oAnd;
|
||||
case 13: return PIEvaluatorTypes::oOr;
|
||||
default: return PIEvaluatorTypes::oNone;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int PIEvaluator::parse(const PIString & string, int offset) {
|
||||
int slen = string.length(), /*facnt,*/ farg, bcnt, k;
|
||||
PIChar cc;
|
||||
PIEvaluatorTypes::Element ce;
|
||||
PIEvaluatorTypes::Function cfunc;
|
||||
PIEvaluatorTypes::Operation coper;
|
||||
PIString sbrackets, carg;
|
||||
PIVector<int> args, atmp;
|
||||
PIVector<PIEvaluatorTypes::Operation> opers;
|
||||
|
||||
///qDebug() << "to parse :" + string;
|
||||
///cout << " "; for (int i = 0; i < slen; i++) cout << preproc->elements[i + offset].type; cout << endl;
|
||||
|
||||
for (int i = 0; i < slen; i++) {
|
||||
ce = elements[i + offset];
|
||||
cc = string[i];
|
||||
switch (ce.type) {
|
||||
case PIEvaluatorTypes::etNumber:
|
||||
args.push_back(ce.var_num);
|
||||
continue;
|
||||
case PIEvaluatorTypes::etVariable:
|
||||
args.push_back(ce.var_num);
|
||||
continue;
|
||||
case PIEvaluatorTypes::etFunction:
|
||||
i++;
|
||||
cfunc = content.function(ce.var_num);
|
||||
//facnt = cfunc.arguments;
|
||||
atmp.clear();
|
||||
bcnt = farg = 1;
|
||||
///qDebug() << "function: " + cfunc.identifier;
|
||||
//for (int k = 0; k < facnt; k++) {
|
||||
bcnt = 1;
|
||||
carg = "";
|
||||
k = i + 1;
|
||||
//if (string.size_s() <= k || k < 0) return -666;
|
||||
while (bcnt > 0) {
|
||||
//if (k < facnt - 1) fcomma = string.indexOf(',', j);
|
||||
cc = string[k];
|
||||
switch (cc.toAscii()) {
|
||||
case '(': bcnt++; break;
|
||||
case ')':
|
||||
bcnt--;
|
||||
if (bcnt == 0) {
|
||||
///qDebug() << "arument: " << carg;
|
||||
atmp.push_back(parse(carg, k + offset - carg.length()));
|
||||
k++;
|
||||
carg = "";
|
||||
if (atmp.size_s() > 0) if (atmp.back() < 0 && farg > 0) farg = atmp.back();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
if (bcnt == 1) {
|
||||
///qDebug() << "arument: " << carg;
|
||||
atmp.push_back(parse(carg, k + offset - carg.length()));
|
||||
k++;
|
||||
carg = "";
|
||||
if (atmp.size_s() > 0) if (atmp.back() < 0 && farg > 0) farg = atmp.back();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
carg += cc;
|
||||
k++;
|
||||
}
|
||||
i = k - 1;
|
||||
if (farg > 0) {
|
||||
variables.push_back(PIEvaluatorTypes::Variable());
|
||||
farg = -variables.size_s();
|
||||
}
|
||||
instructions.push_back(PIEvaluatorTypes::Instruction(PIEvaluatorTypes::oFunction, atmp, farg, ce.var_num));
|
||||
args.push_back(farg);
|
||||
//for (int i = 0; i < args.size_s(); i++) cout << preproc->currentVariables[-args[i]].value << endl;
|
||||
//i = j + 1;
|
||||
continue;
|
||||
case PIEvaluatorTypes::etOperator:
|
||||
//qDebug() << "operator: " << cc;
|
||||
if (cc == '(') {
|
||||
sbrackets = inBrackets(string.right(slen - i));
|
||||
args.push_back(parse(sbrackets, i + offset + 1));
|
||||
i += sbrackets.length() + 1;
|
||||
continue;
|
||||
}
|
||||
if (cc == '+') {opers.push_back(PIEvaluatorTypes::oAdd); continue;}
|
||||
if (cc == '-') {opers.push_back(PIEvaluatorTypes::oSubtract); continue;}
|
||||
if (cc == '*') {opers.push_back(PIEvaluatorTypes::oMultiply); continue;}
|
||||
if (cc == '/') {opers.push_back(PIEvaluatorTypes::oDivide); continue;}
|
||||
if (cc == '%') {opers.push_back(PIEvaluatorTypes::oResidue); continue;}
|
||||
if (cc == '^') {opers.push_back(PIEvaluatorTypes::oPower); continue;}
|
||||
if (cc == '=') {opers.push_back(PIEvaluatorTypes::oEqual); continue;}
|
||||
if (cc == ':') {opers.push_back(PIEvaluatorTypes::oNotEqual); continue;}
|
||||
if (cc == '}') {opers.push_back(PIEvaluatorTypes::oGreaterEqual); continue;}
|
||||
if (cc == '{') {opers.push_back(PIEvaluatorTypes::oSmallerEqual); continue;}
|
||||
if (cc == '>') {opers.push_back(PIEvaluatorTypes::oGreater); continue;}
|
||||
if (cc == '<') {opers.push_back(PIEvaluatorTypes::oSmaller); continue;}
|
||||
if (cc == '&') {opers.push_back(PIEvaluatorTypes::oAnd); continue;}
|
||||
if (cc == '|') {opers.push_back(PIEvaluatorTypes::oOr); continue;}
|
||||
}
|
||||
}
|
||||
/*
|
||||
cout << "stack: " << endl << "args: ";
|
||||
for (int i = 0; i < args.size_s(); i++) cout << args[i] << ", ";
|
||||
cout << endl << "opers: ";
|
||||
for (int i = 0; i < opers.size_s(); i++) cout << opers[i] << ", ";
|
||||
*/
|
||||
if (opers.size_s() == 0) {
|
||||
if (args.size_s() > 0) return args.back();
|
||||
else return -666;
|
||||
}
|
||||
for (int i = 0; i < PIEvaluatorTypes::operationCount; i++) {
|
||||
coper = operationInOrder(i);
|
||||
for (int j = 0; j < opers.size_s(); j++) {
|
||||
if (coper == PIEvaluatorTypes::oDivide || coper == PIEvaluatorTypes::oMultiply) {
|
||||
if (opers[j] != PIEvaluatorTypes::oDivide && opers[j] != PIEvaluatorTypes::oMultiply) continue;
|
||||
} else {
|
||||
if (opers[j] != coper) continue;
|
||||
}
|
||||
atmp.clear();
|
||||
if (j < args.size_s() && j >= 0) atmp.push_back(args[j]);
|
||||
else atmp.push_back(-666);
|
||||
if (j + 1 < args.size_s() && j >= -1) atmp.push_back(args[j + 1]);
|
||||
else atmp.push_back(-666);
|
||||
farg = 1;
|
||||
if (atmp[0] < 0) farg = atmp[0];
|
||||
else {
|
||||
if (atmp[1] < 0) farg = atmp[1];
|
||||
else {
|
||||
variables.push_back(PIEvaluatorTypes::Variable());
|
||||
farg = -variables.size_s();
|
||||
}
|
||||
}
|
||||
instructions.push_back(PIEvaluatorTypes::Instruction(opers[j], atmp, farg));
|
||||
if (j >= 0 && j < args.size_s()) {
|
||||
args.remove(j);
|
||||
if (j < args.size_s()) args[j] = farg;
|
||||
}
|
||||
opers.remove(j);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
return instructions.back().out;
|
||||
///cout << endl;
|
||||
}
|
||||
|
||||
|
||||
bool PIEvaluator::check() {
|
||||
PIEvaluatorTypes::Instruction ci;
|
||||
bool error;
|
||||
if (unknownVars.size_s() > 0) {
|
||||
lastError = "Unknown variables: \"" + unknownVars.join("\", \"") + "\"";
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < instructions.size_s(); i++) {
|
||||
error = false;
|
||||
ci = instructions[i];
|
||||
PIEvaluatorTypes::Function cf;
|
||||
int fac, gac;
|
||||
switch (ci.operation) {
|
||||
case PIEvaluatorTypes::oNone: break;
|
||||
case PIEvaluatorTypes::oFunction:
|
||||
cf = content.function(ci.function);
|
||||
fac = cf.arguments;
|
||||
gac = ci.operators.size_s();
|
||||
for (int j = 0; j < ci.operators.size_s(); j++) {
|
||||
if (ci.operators[j] == -666) { //(ci.operators[j] < -variables.size_s() || ci.operators[j] >= kvars->size()) {
|
||||
error = true;
|
||||
gac--;
|
||||
}
|
||||
}
|
||||
if (fac > 0) {
|
||||
if (gac != fac) {
|
||||
lastError = "Invalid arguments count for function \"" + cf.identifier +
|
||||
"\", expected " + PIString::fromNumber(fac) + " but " +
|
||||
PIString::fromNumber(gac) + " given";
|
||||
return false;
|
||||
}
|
||||
if (error) {
|
||||
lastError = "Invalid at least one of function \"" + cf.identifier + "\" argument";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (fac < 0) {
|
||||
if (gac < -fac) {
|
||||
lastError = "Invalid arguments count for function \"" + cf.identifier +
|
||||
"\", expected at least " + PIString::fromNumber(-fac) + " but " +
|
||||
PIString::fromNumber(gac) + " given";
|
||||
return false;
|
||||
}
|
||||
if (error) {
|
||||
lastError = "Invalid at least one of function \"" + cf.identifier + "\" argument";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (ci.operators[0] == -666 || ci.operators[1] == -666) error = true;
|
||||
if (ci.operators.size_s() != 2 || error) {
|
||||
lastError = "Invalid arguments count for operation \" " + operationChar(ci.operation) + " \"";
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ci.out < -variables.size_s()) {
|
||||
lastError = "Invalid variable index \"" + PIString::fromNumber(ci.out) + "\"";
|
||||
return false;
|
||||
}
|
||||
for (int j = 0; j < ci.operators.size_s(); j++) {
|
||||
if (ci.operators[j] < -variables.size_s() || ci.operators[j] >= kvars->size_s()) {
|
||||
lastError = "Invalid variable index \"" + PIString::fromNumber(ci.operators[j]) + "\"";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PIString PIEvaluator::inBrackets(const PIString & string) {
|
||||
int slen = string.length(), bcnt = 0;
|
||||
PIChar cc;
|
||||
for (int i = 0; i < slen; i++) {
|
||||
cc = string[i];
|
||||
if (cc == '(') bcnt++;
|
||||
if (cc == ')') {
|
||||
bcnt--;
|
||||
if (bcnt == 0) return string.mid(1, i - 1);
|
||||
}
|
||||
}
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
PIString PIEvaluator::operationChar(const PIEvaluatorTypes::Operation & operation) {
|
||||
switch (operation) {
|
||||
case PIEvaluatorTypes::oAdd: return "+";
|
||||
case PIEvaluatorTypes::oSubtract: return "-";
|
||||
case PIEvaluatorTypes::oMultiply: return "*";
|
||||
case PIEvaluatorTypes::oDivide: return "/";
|
||||
case PIEvaluatorTypes::oPower: return "^";
|
||||
case PIEvaluatorTypes::oResidue: return "%";
|
||||
case PIEvaluatorTypes::oEqual: return "=";
|
||||
case PIEvaluatorTypes::oNotEqual: return ("≠");
|
||||
case PIEvaluatorTypes::oGreaterEqual: return ("≥");
|
||||
case PIEvaluatorTypes::oSmallerEqual: return ("≤");
|
||||
case PIEvaluatorTypes::oGreater: return ">";
|
||||
case PIEvaluatorTypes::oSmaller: return "<";
|
||||
case PIEvaluatorTypes::oAnd: return ("⋀");
|
||||
case PIEvaluatorTypes::oOr: return ("⋁");
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline complexd PIEvaluator::residue(const complexd & f, const complexd & s) {
|
||||
complexd ret;
|
||||
if (s.real() != 0.) ret = complexd(f.real() - ((int)(f.real() / s.real())) * s.real(), 0.);
|
||||
if (s.imag() != 0.) ret = complexd(ret.real(), f.imag() - ((int)(f.imag() / s.imag())) * s.imag());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
inline void PIEvaluator::execFunction(const PIEvaluatorTypes::Instruction & ci) {
|
||||
PIEvaluatorTypes::Function cfunc = content.function(ci.function);
|
||||
int oi = -ci.out - 1;
|
||||
complexd tmp, stmp, ttmp;
|
||||
//qDebug() << "function " << (int)cfunc.type;
|
||||
switch (cfunc.type) {
|
||||
case PIEvaluatorTypes::bfSin:
|
||||
tmpvars[oi].value = sin(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfCos:
|
||||
tmpvars[oi].value = cos(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfTg:
|
||||
tmpvars[oi].value = tan(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfCtg:
|
||||
tmp = tan(value(ci.operators[0]));
|
||||
if (tmp == complexd_0) tmpvars[oi].value = 0.;
|
||||
else tmpvars[oi].value = complexd_1 / tmp;
|
||||
break;
|
||||
case PIEvaluatorTypes::bfArcsin:
|
||||
tmpvars[oi].value = asinc(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfArccos:
|
||||
tmpvars[oi].value = acosc(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfArctg:
|
||||
tmpvars[oi].value = atanc(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfArcctg:
|
||||
tmp = atanc(value(ci.operators[0]));
|
||||
if (tmp == complexd_0) tmpvars[oi].value = 0.;
|
||||
else tmpvars[oi].value = complexd_1 / tmp;
|
||||
break;
|
||||
case PIEvaluatorTypes::bfSh:
|
||||
tmpvars[oi].value = sinh(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfCh:
|
||||
tmpvars[oi].value = cosh(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfTh:
|
||||
tmpvars[oi].value = tanh(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfCth:
|
||||
tmp = tanh(value(ci.operators[0]));
|
||||
if (tmp == complexd_0) tmpvars[oi].value = 0.;
|
||||
else tmpvars[oi].value = complexd_1 / tmp;
|
||||
break;
|
||||
case PIEvaluatorTypes::bfAbs:
|
||||
tmpvars[oi].value = abs(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfSqrt:
|
||||
tmpvars[oi].value = sqrt(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfSqr:
|
||||
tmpvars[oi].value = value(ci.operators[0]) * value(ci.operators[0]);
|
||||
break;
|
||||
case PIEvaluatorTypes::bfExp:
|
||||
tmpvars[oi].value = exp(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfPow:
|
||||
tmpvars[oi].value = pow(value(ci.operators[0]), value(ci.operators[1]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfLn:
|
||||
tmpvars[oi].value = log(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfLg:
|
||||
tmpvars[oi].value = log10(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfLog:
|
||||
tmp = log(value(ci.operators[1]));
|
||||
if (tmp == complexd_0) tmpvars[oi].value = 0.;
|
||||
else tmpvars[oi].value = log(value(ci.operators[0])) / tmp;
|
||||
break;
|
||||
case PIEvaluatorTypes::bfRe:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real();
|
||||
break;
|
||||
case PIEvaluatorTypes::bfIm:
|
||||
tmpvars[oi].value = value(ci.operators[0]).imag();
|
||||
break;
|
||||
case PIEvaluatorTypes::bfArg:
|
||||
tmpvars[oi].value = arg(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfLen:
|
||||
tmpvars[oi].value = abs(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfConj:
|
||||
tmpvars[oi].value = conj(value(ci.operators[0]));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfSign:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() >= 0. ? complexd_1 : -complexd_1;
|
||||
break;
|
||||
case PIEvaluatorTypes::bfRad:
|
||||
tmpvars[oi].value = value(ci.operators[0]) * complexd(deg2rad, 0.);
|
||||
break;
|
||||
case PIEvaluatorTypes::bfDeg:
|
||||
tmpvars[oi].value = value(ci.operators[0]) * complexd(rad2deg, 0.);
|
||||
break;
|
||||
case PIEvaluatorTypes::bfJ0:
|
||||
tmpvars[oi].value = piJ0(value(ci.operators[0]).real());
|
||||
break;
|
||||
case PIEvaluatorTypes::bfJ1:
|
||||
tmpvars[oi].value = piJ1(value(ci.operators[0]).real());
|
||||
break;
|
||||
case PIEvaluatorTypes::bfJN:
|
||||
tmpvars[oi].value = piJn(piRoundd(value(ci.operators[1]).real()), value(ci.operators[0]).real());
|
||||
break;
|
||||
case PIEvaluatorTypes::bfY0:
|
||||
tmpvars[oi].value = piY0(value(ci.operators[0]).real());
|
||||
break;
|
||||
case PIEvaluatorTypes::bfY1:
|
||||
tmpvars[oi].value = piY1(value(ci.operators[0]).real());
|
||||
break;
|
||||
case PIEvaluatorTypes::bfYN:
|
||||
tmpvars[oi].value = piYn(piRoundd(value(ci.operators[1]).real()), value(ci.operators[0]).real());
|
||||
break;
|
||||
case PIEvaluatorTypes::bfMin:
|
||||
tmp = value(ci.operators[0]);
|
||||
for (int i = 1; i < ci.operators.size_s(); ++i) {
|
||||
stmp = value(ci.operators[i]);
|
||||
tmp = complexd(piMind(tmp.real(), stmp.real()), piMind(tmp.imag(), stmp.imag()));
|
||||
}
|
||||
tmpvars[oi].value = tmp;
|
||||
break;
|
||||
case PIEvaluatorTypes::bfMax:
|
||||
tmp = value(ci.operators[0]);
|
||||
for (int i = 1; i < ci.operators.size_s(); ++i) {
|
||||
stmp = value(ci.operators[i]);
|
||||
tmp = complexd(piMaxd(tmp.real(), stmp.real()), piMaxd(tmp.imag(), stmp.imag()));
|
||||
}
|
||||
tmpvars[oi].value = tmp;
|
||||
break;
|
||||
case PIEvaluatorTypes::bfClamp:
|
||||
tmp = value(ci.operators[0]);
|
||||
stmp = value(ci.operators[1]);
|
||||
ttmp = value(ci.operators[2]);
|
||||
tmpvars[oi].value = complexd(piClampd(tmp.real(), stmp.real(), ttmp.real()), piClampd(tmp.imag(), stmp.imag(), ttmp.imag()));
|
||||
break;
|
||||
case PIEvaluatorTypes::bfStep:
|
||||
tmpvars[oi].value = complexd(value(ci.operators[0]).real() >= value(ci.operators[1]).real() ? complexld_1 : complexld_0);
|
||||
break;
|
||||
case PIEvaluatorTypes::bfMix:
|
||||
tmp = value(ci.operators[0]);
|
||||
stmp = value(ci.operators[1]);
|
||||
ttmp = value(ci.operators[2]);
|
||||
tmpvars[oi].value = stmp.real() * (1. - tmp.real()) + ttmp.real() * tmp.real();
|
||||
break;
|
||||
case PIEvaluatorTypes::bfDefined:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() > 0. ? complexd_1 : complexd_0;
|
||||
break;
|
||||
case PIEvaluatorTypes::bfRandom:
|
||||
tmp = static_cast<ldouble>(rand()) / RAND_MAX;
|
||||
stmp = value(ci.operators[1]) - value(ci.operators[0]);
|
||||
tmpvars[oi].value = value(ci.operators[0]) + tmp * stmp;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool PIEvaluator::execInstructions() {
|
||||
PIEvaluatorTypes::Instruction ci;
|
||||
int oi;
|
||||
complexd tmp;
|
||||
tmpvars = variables;
|
||||
//cout << "var count " << tmpvars.size_s() << endl;
|
||||
for (int i = 0; i < instructions.size_s(); i++) {
|
||||
ci = instructions[i];
|
||||
oi = -ci.out - 1;
|
||||
//cout << value(ci.operators[0]) << operationChar(ci.operation) << value(ci.operators[1]) << ", " << oi << endl;
|
||||
switch (ci.operation) {
|
||||
case PIEvaluatorTypes::oAdd:
|
||||
tmpvars[oi].value = value(ci.operators[0]) + value(ci.operators[1]);
|
||||
break;
|
||||
case PIEvaluatorTypes::oSubtract:
|
||||
tmpvars[oi].value = value(ci.operators[0]) - value(ci.operators[1]);
|
||||
break;
|
||||
case PIEvaluatorTypes::oMultiply:
|
||||
tmpvars[oi].value = value(ci.operators[0]) * value(ci.operators[1]);
|
||||
break;
|
||||
case PIEvaluatorTypes::oDivide:
|
||||
tmp = value(ci.operators[1]);
|
||||
if (tmp == complexd(0., 0.)) tmpvars[oi].value = 0.;
|
||||
else tmpvars[oi].value = value(ci.operators[0]) / tmp;
|
||||
break;
|
||||
case PIEvaluatorTypes::oResidue:
|
||||
tmpvars[oi].value = residue(value(ci.operators[0]), value(ci.operators[1]));
|
||||
break;
|
||||
case PIEvaluatorTypes::oPower:
|
||||
tmpvars[oi].value = pow(value(ci.operators[0]), value(ci.operators[1]));
|
||||
break;
|
||||
case PIEvaluatorTypes::oEqual:
|
||||
tmpvars[oi].value = value(ci.operators[0]) == value(ci.operators[1]);
|
||||
break;
|
||||
case PIEvaluatorTypes::oNotEqual:
|
||||
tmpvars[oi].value = value(ci.operators[0]) != value(ci.operators[1]);
|
||||
break;
|
||||
case PIEvaluatorTypes::oGreaterEqual:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() >= value(ci.operators[1]).real();
|
||||
break;
|
||||
case PIEvaluatorTypes::oSmallerEqual:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() <= value(ci.operators[1]).real();
|
||||
break;
|
||||
case PIEvaluatorTypes::oGreater:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() > value(ci.operators[1]).real();
|
||||
break;
|
||||
case PIEvaluatorTypes::oSmaller:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() < value(ci.operators[1]).real();
|
||||
break;
|
||||
case PIEvaluatorTypes::oAnd:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() > 0. && value(ci.operators[1]).real() > 0.;
|
||||
break;
|
||||
case PIEvaluatorTypes::oOr:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() > 0. || value(ci.operators[1]).real() > 0.;
|
||||
break;
|
||||
case PIEvaluatorTypes::oFunction:
|
||||
execFunction(ci);
|
||||
break;
|
||||
case PIEvaluatorTypes::oNone:
|
||||
tmpvars[oi].value = value(ci.operators[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!instructions.isEmpty())
|
||||
out = value(instructions.back().out);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIEvaluator::check(const PIString & string) {
|
||||
currentString = preprocess(string);
|
||||
correct = check();
|
||||
if (!correct) {
|
||||
instructions.clear();
|
||||
return false;
|
||||
}
|
||||
lastError = "Correct";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
complexd PIEvaluator::evaluate() {
|
||||
if (!execInstructions()) out = 0.;
|
||||
if (fabs(out.real()) < 1E-300) out = complexd(0., out.imag());
|
||||
if (fabs(out.imag()) < 1E-300) out = complexd(out.real(), 0.);
|
||||
return out;
|
||||
}
|
||||
227
pievaluator.h
227
pievaluator.h
@@ -1,227 +0,0 @@
|
||||
/*! \file pievaluator.h
|
||||
* \brief Mathematic expressions calculator
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Evaluator designed for stream computing
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIEVALUATOR_H
|
||||
#define PIEVALUATOR_H
|
||||
|
||||
#include "pistring.h"
|
||||
#include "pimath.h"
|
||||
|
||||
typedef complexd (*FuncFunc)(void * , int, complexd * );
|
||||
|
||||
namespace PIEvaluatorTypes {
|
||||
static const int operationCount = 14;
|
||||
|
||||
enum eType {etNumber, etOperator, etVariable, etFunction};
|
||||
enum Operation {oNone, oAdd, oSubtract, oMultiply, oDivide, oResidue, oPower,
|
||||
oEqual, oNotEqual, oGreater, oSmaller, oGreaterEqual, oSmallerEqual,
|
||||
oAnd, oOr, oFunction
|
||||
};
|
||||
enum BaseFunctions {bfUnknown, bfSin, bfCos, bfTg, bfCtg,
|
||||
bfArcsin, bfArccos, bfArctg, bfArcctg,
|
||||
bfExp, bfRandom, bfSh, bfCh, bfTh, bfCth,
|
||||
bfSqrt, bfSqr, bfPow, bfAbs,
|
||||
bfLn, bfLg, bfLog, bfSign,
|
||||
bfIm, bfRe, bfArg, bfLen, bfConj,
|
||||
bfRad, bfDeg, bfJ0, bfJ1, bfJN,
|
||||
bfY0, bfY1, bfYN, bfMin, bfMax,
|
||||
bfClamp, bfStep, bfMix, bfDefined,
|
||||
bfCustom = 0xFFFF
|
||||
};
|
||||
|
||||
struct Instruction {
|
||||
Instruction() {;}
|
||||
Instruction(Operation oper, PIVector<int> opers, int out_ind, int func = -1) {
|
||||
operation = oper; operators = opers; out = out_ind; function = func;}
|
||||
Operation operation;
|
||||
PIVector<int> operators;
|
||||
int out;
|
||||
int function;
|
||||
};
|
||||
struct Element {
|
||||
Element() {;}
|
||||
Element(eType new_type, int new_num, int new_var_num = -1) {set(new_type, new_num, new_var_num);}
|
||||
void set(eType new_type, int new_num, int new_var_num = -1) {type = new_type; num = new_num; var_num = new_var_num;}
|
||||
eType type;
|
||||
int num;
|
||||
int var_num;
|
||||
};
|
||||
struct Function {
|
||||
Function() {arguments = 0; type = bfUnknown; handler = 0;}
|
||||
Function(const PIString & name, int args, BaseFunctions ftype) {identifier = name; arguments = args; type = ftype; handler = 0;}
|
||||
Function(const PIString & name, int args, FuncFunc h) {identifier = name; arguments = args; type = bfCustom; handler = h;}
|
||||
PIString identifier;
|
||||
BaseFunctions type;
|
||||
FuncFunc handler;
|
||||
int arguments;
|
||||
};
|
||||
struct Variable {
|
||||
Variable() {value = 0.;}
|
||||
Variable(const PIString & var_name, complexd val) {name = var_name; value = val;}
|
||||
PIString name;
|
||||
complexd value;
|
||||
};
|
||||
};
|
||||
/*
|
||||
≠ :
|
||||
≥ }
|
||||
≤ {
|
||||
⋀ &
|
||||
⋁ |
|
||||
*/
|
||||
|
||||
class PIP_EXPORT PIEvaluatorContent
|
||||
{
|
||||
friend class PIEvaluator;
|
||||
public:
|
||||
PIEvaluatorContent();
|
||||
~PIEvaluatorContent() {;}
|
||||
|
||||
void addFunction(const PIString & name, int args = 1) {functions.push_back(PIEvaluatorTypes::Function(name, args, getBaseFunction(name)));}
|
||||
void addVariable(const PIString & name, const complexd & val = 0.) {variables.push_back(PIEvaluatorTypes::Variable(name, val)); sortVariables();}
|
||||
void addCustomFunction(const PIString & name, int args_count, FuncFunc func) {functions << PIEvaluatorTypes::Function(name, args_count, func);}
|
||||
int functionsCount() const {return functions.size();}
|
||||
int variablesCount() const {return variables.size();}
|
||||
int customVariablesCount() const {return variables.size() - cv_count;}
|
||||
int findFunction(const PIString & name) const {for (uint i = 0; i < functions.size(); i++) if (functions[i].identifier == name) return i; return -1;}
|
||||
int findVariable(const PIString & var_name) const {for (uint i = 0; i < variables.size(); i++) if (variables[i].name == var_name) return i; return -1;}
|
||||
PIEvaluatorTypes::Function function(int index) {if (index < 0 || index >= functions.size_s()) return PIEvaluatorTypes::Function(); return functions[index];}
|
||||
PIEvaluatorTypes::Variable variable(int index) {if (index < 0 || index >= variables.size_s()) return PIEvaluatorTypes::Variable(); return variables[index];}
|
||||
PIEvaluatorTypes::Function function(const PIString & name) {return function(findFunction(name));}
|
||||
PIEvaluatorTypes::Variable variable(const PIString & name) {return variable(findVariable(name));}
|
||||
PIEvaluatorTypes::Variable customVariable(int index) {if (index < cv_count || index >= variables.size_s() + cv_count) return PIEvaluatorTypes::Variable(); return variables[index + cv_count];}
|
||||
bool setVariableValue(int index, complexd new_value);
|
||||
bool setVariableName(int index, const PIString & new_name);
|
||||
bool setVariableValue(const PIString & var_name, const complexd & new_value) {return setVariableValue(findVariable(var_name), new_value);}
|
||||
bool setVariableName(const PIString & var_name, const PIString & new_name) {return setVariableName(findVariable(var_name), new_name);}
|
||||
void removeVariable(int index) {variables.remove(index);}
|
||||
void removeVariable(const PIString & var_name) {removeVariable(findVariable(var_name));}
|
||||
void clearCustomVariables();
|
||||
void sortVariables();
|
||||
PIEvaluatorTypes::BaseFunctions getBaseFunction(const PIString & name);
|
||||
|
||||
private:
|
||||
PIVector<PIEvaluatorTypes::Function> functions;
|
||||
PIVector<PIEvaluatorTypes::Variable> variables;
|
||||
int cv_count;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class PIP_EXPORT PIEvaluator
|
||||
{
|
||||
public:
|
||||
|
||||
//! Constructs an empty evaluator
|
||||
PIEvaluator() {correct = false; data_ = 0;}
|
||||
|
||||
~PIEvaluator() {;}
|
||||
|
||||
|
||||
//! Returns custom data
|
||||
void * data() {return data_;}
|
||||
|
||||
//! Set custom data to "_data"
|
||||
void setData(void * _data) {data_ = _data;}
|
||||
|
||||
|
||||
//! Check mathematical expression and parse it to list of instructions
|
||||
bool check(const PIString & string);
|
||||
|
||||
//! Returns true if expression was checked succesfully
|
||||
bool isCorrect() const {return correct;}
|
||||
|
||||
//! Set variable value with name "name" to value "value". Add variable if it doesn`t exists
|
||||
int setVariable(const PIString & name, complexd value = 0.) {if (content.findVariable(name) < 0) content.addVariable(name, value); else content.setVariableValue(name, value); return content.findVariable(name);}
|
||||
|
||||
//! Set variable value with index "index" to value "value". Don`t add variable if it doesn`t exists
|
||||
void setVariable(int index, complexd value = 0.) {if (index >= 0 && index < content.variablesCount()) content.setVariableValue(index, value);}
|
||||
|
||||
void setCustomVariableValue(int index, complexd value = 0.) {content.variables[index + content.cv_count].value = value;}
|
||||
/*
|
||||
//! Add function "name" with arguments count "args_count" and handler "func". Three arguments will be passed to handler: \a data(), "args_count" and array of input values.
|
||||
void addFunction(const PIString & name, int args_count, FuncFunc func) {content.addCustomFunction(name, args_count, func);}
|
||||
*/
|
||||
//! Evaluate last successfully checked with function \a check() expression and returns result
|
||||
complexd evaluate();
|
||||
|
||||
//! Remove variable with name "name"
|
||||
void removeVariable(const PIString & name) {content.removeVariable(name);}
|
||||
|
||||
//! Remove all manually added variables
|
||||
void clearCustomVariables() {content.clearCustomVariables();}
|
||||
|
||||
//! Returns index of variable with name "name"
|
||||
int variableIndex(const PIString & name) const {return content.findVariable(name);}
|
||||
|
||||
//! Returns all unknown variables founded in last expression passed to \a check() function
|
||||
const PIStringList & unknownVariables() const {return unknownVars;}
|
||||
|
||||
//! Returns processed last expression passed to \a check() function
|
||||
const PIString & expression() const {return currentString;}
|
||||
|
||||
//! Returns last error description occured in \a check() function
|
||||
const PIString & error() const {return lastError;}
|
||||
|
||||
//! Returns last result of \a evaluate()
|
||||
const complexd & lastResult() const {return out;}
|
||||
|
||||
PIEvaluatorContent content;
|
||||
|
||||
private:
|
||||
const PIString & prepare(const PIString & string);
|
||||
const PIString & preprocess(const PIString & string);
|
||||
int parse(const PIString & string, int offset = 0);
|
||||
void convert();
|
||||
void checkBrackets();
|
||||
void removeSpaces();
|
||||
void findUnknownVariables();
|
||||
void removeJunk();
|
||||
void replaceOperators();
|
||||
void makeOutput(PIString & string);
|
||||
bool fillElements();
|
||||
bool setSignes();
|
||||
bool isSign(const PIChar & ch);
|
||||
PIString inverse(const PIString & string) {int len = string.length(); PIString s; for (int i = 0; i < len; i++) s += string[len - i - 1]; return s;}
|
||||
bool check();
|
||||
bool execInstructions();
|
||||
PIString inBrackets(const PIString & string);
|
||||
PIString operationChar(const PIEvaluatorTypes::Operation & operation);
|
||||
PIEvaluatorTypes::Operation operationInOrder(const int & index);
|
||||
complexd value(const int & index) {if (index < 0) return tmpvars[-index - 1].value; else return kvars->at(index).value;}
|
||||
inline complexd residue(const complexd & f, const complexd & s);
|
||||
inline void execFunction(const PIEvaluatorTypes::Instruction & ci);
|
||||
|
||||
PIVector<PIEvaluatorTypes::Element> elements;
|
||||
PIVector<PIEvaluatorTypes::Variable> currentVariables, variables, tmpvars, * kvars;
|
||||
PIVector<PIEvaluatorTypes::Instruction> instructions;
|
||||
PIStringList unknownVars;
|
||||
PIString currentString, lastError;
|
||||
complexd out;
|
||||
bool correct;
|
||||
void * data_;
|
||||
};
|
||||
|
||||
inline bool operator ==(PIEvaluatorTypes::Element e1, PIEvaluatorTypes::Element e2) {return (e1.type == e2.type && e1.num == e2.num);}
|
||||
inline bool operator !=(PIEvaluatorTypes::Element e1, PIEvaluatorTypes::Element e2) {return (e1.type != e2.type || e1.num != e2.num);}
|
||||
|
||||
#endif // PIEVALUATOR_H
|
||||
158
pifile.cpp
158
pifile.cpp
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
File
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pifile.h"
|
||||
|
||||
|
||||
/*! \class PIFile
|
||||
* \brief Local file
|
||||
*
|
||||
* \section PIFile_sec0 Synopsis
|
||||
* This class provide access to local file. You can manipulate
|
||||
* binary content or use this class as text stream. To binary
|
||||
* access there are function \a read(), \a write(), and many
|
||||
* \a writeBinary() functions. For write variables to file in
|
||||
* their text representation threr are many "<<" operators.
|
||||
*
|
||||
* \section PIFile_sec1 Position
|
||||
* Each opened file has a read/write position - logical position
|
||||
* in the file content you read from or you write to. You can
|
||||
* find out current position with function \a pos(). Function
|
||||
* \a seek(llong position) move position to position "position",
|
||||
* \a seekToBegin() move position to the begin of file,
|
||||
* \a seekToEnd() move position to the end of file.
|
||||
*
|
||||
*/
|
||||
|
||||
REGISTER_DEVICE(PIFile);
|
||||
|
||||
|
||||
bool PIFile::openDevice() {
|
||||
close();
|
||||
if (path().isEmpty()) return false;
|
||||
//piCout << "fopen " << path_.data() << ": " << strType(mode_).data() << fd;
|
||||
fd = fopen(path().data(), strType(mode_).data());
|
||||
opened_ = (fd != 0);
|
||||
#ifndef WINDOWS
|
||||
if (opened_) fcntl(fileno(fd), F_SETFL, O_NONBLOCK);
|
||||
#endif
|
||||
seekToBegin();
|
||||
//piCout << "open file" << fd << opened_;
|
||||
return opened_;
|
||||
}
|
||||
|
||||
|
||||
bool PIFile::closeDevice() {
|
||||
//piCout << "close file" << fd << opened_;
|
||||
if (!opened_ || fd == 0) return true;
|
||||
bool cs = (fclose(fd) == 0);
|
||||
if (cs) fd = 0;
|
||||
//piCout << "closed file" << fd << opened_;
|
||||
return cs;
|
||||
}
|
||||
|
||||
|
||||
PIString PIFile::readLine() {
|
||||
PIString str;
|
||||
if (!opened_) return str;
|
||||
int cc, cp = 0;
|
||||
while (!isEnd() && cp < 4095) {
|
||||
cc = fgetc(fd);
|
||||
if (char(cc) == '\n' || cc == EOF) break;
|
||||
str.push_back(char(cc));
|
||||
}
|
||||
//cout << "readline: " << str << endl;
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
llong PIFile::readAll(void * data) {
|
||||
llong cp = pos(), s = size(), i = -1;
|
||||
seekToBegin();
|
||||
if (s < 0) {
|
||||
while (!isEnd())
|
||||
read(&(((char*)data)[++i]), 1);
|
||||
} else
|
||||
read((char * )data, s);
|
||||
seek(cp);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIFile::readAll(bool forceRead) {
|
||||
PIByteArray a;
|
||||
llong cp = pos();
|
||||
if (forceRead) {
|
||||
seekToBegin();
|
||||
while (!isEnd())
|
||||
a.push_back(readChar());
|
||||
seek(cp);
|
||||
return a;
|
||||
}
|
||||
llong s = size();
|
||||
if (s < 0) return a;
|
||||
a.resize(s);
|
||||
s = readAll(a.data());
|
||||
seek(cp);
|
||||
if (s >= 0) a.resize(s);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
llong PIFile::size() {
|
||||
if (!opened_) return -1;
|
||||
llong s, cp = pos();
|
||||
seekToEnd();
|
||||
s = pos();
|
||||
seek(cp);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
void PIFile::resize(llong new_size, uchar fill_) {
|
||||
llong ds = new_size - size();
|
||||
if (ds == 0) return;
|
||||
if (ds > 0) {
|
||||
uchar * buff = new uchar[ds];
|
||||
memset(buff, fill_, ds);
|
||||
write(buff, ds);
|
||||
delete[] buff;
|
||||
return;
|
||||
}
|
||||
piCoutObj << "Downsize is not support yet :-(";
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool PIFile::isExists(const PIString & path) {
|
||||
FILE * f = fopen(PIString(path).data(), "r");
|
||||
bool ok = (f != 0);
|
||||
if (ok) fclose(f);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
PIString PIFile::constructFullPath() const {
|
||||
return fullPathPrefix() + "://" + path();
|
||||
}
|
||||
|
||||
|
||||
void PIFile::configureFromFullPath(const PIString & full_path) {
|
||||
setPath(full_path);
|
||||
}
|
||||
240
pifile.h
240
pifile.h
@@ -1,240 +0,0 @@
|
||||
/*! \file pifile.h
|
||||
* \brief Local file
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
File
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIFILE_H
|
||||
#define PIFILE_H
|
||||
|
||||
#include "piiodevice.h"
|
||||
#include <cstdio>
|
||||
|
||||
class PIP_EXPORT PIFile: public PIIODevice
|
||||
{
|
||||
PIIODEVICE(PIFile)
|
||||
public:
|
||||
|
||||
//! Constructs a file with path "path" nad open mode "type"
|
||||
PIFile(const PIString & path = PIString(), DeviceMode mode = ReadWrite): PIIODevice(path, mode) {setPrecision(5); if (!path.isEmpty()) openDevice();}
|
||||
|
||||
~PIFile() {close();}
|
||||
|
||||
//PIFile & operator =(const PIFile & f) {path_ = f.path_; type_ = f.type_; return *this;}
|
||||
|
||||
|
||||
//! Immediate write all buffered data to disk
|
||||
void flush() {if (opened_) fflush(fd);}
|
||||
|
||||
//! Move read/write position to "position"
|
||||
void seek(llong position) {if (!opened_) return; fseek(fd, position, SEEK_SET); clearerr(fd);}
|
||||
|
||||
//! Move read/write position to the begin of the file
|
||||
void seekToBegin() {if (!opened_) return; fseek(fd, 0, SEEK_SET); clearerr(fd);}
|
||||
|
||||
//! Move read/write position to the end of the file
|
||||
void seekToEnd() {if (!opened_) return; fseek(fd, 0, SEEK_END); clearerr(fd);}
|
||||
|
||||
//! Move read/write position to text line number "line"
|
||||
void seekToLine(llong line) {if (!opened_) return; seekToBegin(); piForTimes (line) readLine(); clearerr(fd);} // line 0 - begin of file
|
||||
//void fill(char c) {stream.fill(c);}
|
||||
|
||||
//! Read one char and return it
|
||||
char readChar() {return (char)fgetc(fd);}
|
||||
|
||||
//! Read one text line and return it
|
||||
PIString readLine();
|
||||
|
||||
//! Read all file content to "data" and return readed bytes count. Position leaved unchanged
|
||||
llong readAll(void * data);
|
||||
|
||||
//! Read all file content to byte array and return it. Position leaved unchanged
|
||||
PIByteArray readAll(bool forceRead = false);
|
||||
|
||||
|
||||
//! Set file path to "path" and reopen file if need
|
||||
void setPath(const PIString & path) {PIIODevice::setPath(path); if (opened_) openDevice();}
|
||||
|
||||
//! Returns file size
|
||||
llong size();
|
||||
|
||||
//! Returns read/write position
|
||||
llong pos() {if (!opened_) return -1; return ftell(fd);}
|
||||
|
||||
//! Returns if position is at the end of file
|
||||
bool isEnd() {if (!opened_) return true; return (feof(fd) || ferror(fd));}
|
||||
|
||||
//! Returns if file is empty
|
||||
bool isEmpty() {return (size() <= 0);}
|
||||
|
||||
|
||||
//! Returns float numbers write precision
|
||||
int precision() const {return prec_;}
|
||||
|
||||
//! Set float numbers write precision to "prec_" digits
|
||||
void setPrecision(int prec) {prec_ = prec; if (prec_ >= 0) prec_str = "." + itos(prec_); else prec_str = "";}
|
||||
|
||||
|
||||
//! Read from file to "read_to" no more than "max_size" and return readed bytes count
|
||||
int read(void * read_to, int max_size) {if (!canRead() || fd == 0) return -1; return fread(read_to, 1, max_size, fd);}
|
||||
|
||||
//! Write to file "data" with size "max_size" and return written bytes count
|
||||
int write(const void * data, int max_size) {if (!canWrite() || fd == 0) return -1; return fwrite(data, 1, max_size, fd);}
|
||||
|
||||
PIFile & writeToBinLog(ushort id, const void * data, int size) {if (!isWriteable() || fd == 0) return *this; writeBinary(id).writeBinary((ushort)size); write(data, size); flush(); return *this;}
|
||||
|
||||
|
||||
//! Write to file binary content of "v"
|
||||
PIFile & writeBinary(const char v) {write(&v, sizeof(v)); return *this;}
|
||||
//! Write to file binary content of "v"
|
||||
PIFile & writeBinary(const short v) {write(&v, sizeof(v)); return *this;}
|
||||
//! Write to file binary content of "v"
|
||||
PIFile & writeBinary(const int v) {write(&v, sizeof(v)); return *this;}
|
||||
//! Write to file binary content of "v"
|
||||
PIFile & writeBinary(const long v) {write(&v, sizeof(v)); return *this;}
|
||||
//! Write to file binary content of "v"
|
||||
PIFile & writeBinary(const llong v) {write(&v, sizeof(v)); return *this;}
|
||||
//! Write to file binary content of "v"
|
||||
PIFile & writeBinary(const uchar v) {write(&v, sizeof(v)); return *this;}
|
||||
//! Write to file binary content of "v"
|
||||
PIFile & writeBinary(const ushort v) {write(&v, sizeof(v)); return *this;}
|
||||
//! Write to file binary content of "v"
|
||||
PIFile & writeBinary(const uint v) {write(&v, sizeof(v)); return *this;}
|
||||
//! Write to file binary content of "v"
|
||||
PIFile & writeBinary(const ulong v) {write(&v, sizeof(v)); return *this;}
|
||||
//! Write to file binary content of "v"
|
||||
PIFile & writeBinary(const ullong v) {write(&v, sizeof(v)); return *this;}
|
||||
//! Write to file binary content of "v"
|
||||
PIFile & writeBinary(const float v) {write(&v, sizeof(v)); return *this;}
|
||||
//! Write to file binary content of "v"
|
||||
PIFile & writeBinary(const double v) {write(&v, sizeof(v)); return *this;}
|
||||
|
||||
PIFile & operator =(const PIFile & f) {PIIODevice::setPath(f.path()); mode_ = f.mode_; return *this;}
|
||||
|
||||
//! Write to file text representation of "v"
|
||||
PIFile & operator <<(const char v) {if (canWrite() && fd != 0) write(&v, 1); return *this;}
|
||||
//PIFile & operator <<(const string & v) {write(v.c_str(), v.size()); return *this;}
|
||||
//! Write to file string "v"
|
||||
PIFile & operator <<(const PIString & v) {if (canWrite() && fd != 0) write(v.data(), v.lengthAscii()); return *this;}
|
||||
//! Write to file text representation of "v"
|
||||
PIFile & operator <<(const PIByteArray & v) {if (canWrite() && fd != 0) write(v.data(), v.size()); return *this;}
|
||||
//! Write to file text representation of "v"
|
||||
PIFile & operator <<(short v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%hd", v); return *this;}
|
||||
//! Write to file text representation of "v"
|
||||
PIFile & operator <<(int v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%d", v); return *this;}
|
||||
//! Write to file text representation of "v"
|
||||
PIFile & operator <<(long v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%ld", v); return *this;}
|
||||
//! Write to file text representation of "v"
|
||||
PIFile & operator <<(llong v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%lld", v); return *this;}
|
||||
//! Write to file text representation of "v"
|
||||
PIFile & operator <<(uchar v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%u", int(v)); return *this;}
|
||||
//! Write to file text representation of "v"
|
||||
PIFile & operator <<(ushort v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%hu", v); return *this;}
|
||||
//! Write to file text representation of "v"
|
||||
PIFile & operator <<(uint v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%u", v); return *this;}
|
||||
//! Write to file text representation of "v"
|
||||
PIFile & operator <<(ulong v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%lu", v); return *this;}
|
||||
//! Write to file text representation of "v"
|
||||
PIFile & operator <<(ullong v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%llu", v); return *this;}
|
||||
//! Write to file text representation of "v" with precision \a precision()
|
||||
PIFile & operator <<(float v) {if (canWrite() && fd != 0) ret = fprintf(fd, ("%" + prec_str + "f").c_str(), v); return *this;}
|
||||
//! Write to file text representation of "v" with precision \a precision()
|
||||
PIFile & operator <<(double v) {if (canWrite() && fd != 0) ret = fprintf(fd, ("%" + prec_str + "lf").c_str(), v); return *this;}
|
||||
|
||||
|
||||
//! Read from file text representation of "v"
|
||||
PIFile & operator >>(char & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%hhn", &v); return *this;}
|
||||
//! Read from file text representation of "v"
|
||||
PIFile & operator >>(short & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%hn", &v); return *this;}
|
||||
//! Read from file text representation of "v"
|
||||
PIFile & operator >>(int & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%n", &v); return *this;}
|
||||
//! Read from file text representation of "v"
|
||||
PIFile & operator >>(long & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%ln", &v); return *this;}
|
||||
//! Read from file text representation of "v"
|
||||
PIFile & operator >>(llong & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%lln", &v); return *this;}
|
||||
//! Read from file text representation of "v"
|
||||
PIFile & operator >>(uchar & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%hhn", &v); return *this;}
|
||||
//! Read from file text representation of "v"
|
||||
PIFile & operator >>(ushort & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%hn", &v); return *this;}
|
||||
//! Read from file text representation of "v"
|
||||
PIFile & operator >>(uint & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%n", &v); return *this;}
|
||||
//! Read from file text representation of "v"
|
||||
PIFile & operator >>(ulong & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%ln", &v); return *this;}
|
||||
//! Read from file text representation of "v"
|
||||
PIFile & operator >>(ullong & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%lln", &v); return *this;}
|
||||
//! Read from file text representation of "v"
|
||||
PIFile & operator >>(float & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%f", &v); return *this;}
|
||||
//! Read from file text representation of "v"
|
||||
PIFile & operator >>(double & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%lf", &v); return *this;}
|
||||
|
||||
PIString constructFullPath() const;
|
||||
|
||||
EVENT_HANDLER(void, clear) {close(); fd = fopen(path().data(), "w"); if (fd != 0) fclose(fd); fd = 0; opened_ = false; open();}
|
||||
EVENT_HANDLER0(void, remove) {close(); std::remove(path().data());}
|
||||
EVENT_HANDLER1(void, resize, llong, new_size) {resize(new_size, 0);}
|
||||
EVENT_HANDLER2(void, resize, llong, new_size, uchar, fill);
|
||||
|
||||
|
||||
//! Returns not opened temporary file with open mode "mode"
|
||||
static PIFile openTemporary(PIIODevice::DeviceMode mode = PIIODevice::ReadWrite) {return PIFile(PIString(tmpnam(0)), mode);}
|
||||
|
||||
//! Returns if file with path "path" does exists
|
||||
static bool isExists(const PIString & path);
|
||||
|
||||
//! Remove file with path "path" and returns if remove was successful
|
||||
static bool remove(const PIString & path) {return std::remove(path.data()) == 0;}
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void clear()
|
||||
//! \brief Raise on new TCP connection received
|
||||
|
||||
//! \fn void resize(llong new_size)
|
||||
//! \brief Resize file to "new_size" with "fill" filling
|
||||
|
||||
//! \fn void resize(llong new_size, uchar fill)
|
||||
//! \brief Resize file to "new_size" with "fill" filling
|
||||
|
||||
//! \fn void remove()
|
||||
//! \brief Remove file
|
||||
|
||||
//! \}
|
||||
//! \ioparams
|
||||
//! \{
|
||||
#ifdef DOXYGEN
|
||||
#endif
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
PIString fullPathPrefix() const {return "file";}
|
||||
void configureFromFullPath(const PIString & full_path);
|
||||
bool openDevice();
|
||||
bool closeDevice();
|
||||
|
||||
private:
|
||||
PIString strType(const PIIODevice::DeviceMode type) {switch (type) {case PIIODevice::ReadOnly: return "rb"; case WriteOnly: return "ab"; case ReadWrite: return "a+b";} return "rb";}
|
||||
|
||||
FILE * fd;
|
||||
int ret, prec_;
|
||||
string prec_str;
|
||||
|
||||
};
|
||||
|
||||
#endif // PIFILE_H
|
||||
137
pigeometry.h
137
pigeometry.h
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Geometry
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIGEOMETRY_H
|
||||
#define PIGEOMETRY_H
|
||||
|
||||
#include "pimath.h"
|
||||
|
||||
template<typename Type>
|
||||
class PIP_EXPORT PIPoint {
|
||||
public:
|
||||
Type x;
|
||||
Type y;
|
||||
|
||||
PIPoint() {x = y = 0;};
|
||||
PIPoint(Type x_, Type y_) {set(x_, y_);}
|
||||
|
||||
PIPoint<Type> & set(Type x_, Type y_) {x = x_; y = y_; return *this;}
|
||||
PIPoint<Type> & move(Type x_, Type y_) {x += x_; y += y_; return *this;}
|
||||
PIPoint<Type> & move(const PIPoint<Type> & p) {x += p.x; y += p.y; return *this;}
|
||||
double angleRad() const {return atan2(y, x);}
|
||||
int angleDeg() const {return round(atan2(y, x) * 180. / M_PI);}
|
||||
PIPoint<Type> toPolar(bool isDeg = false) const {return PIPoint<Type>(sqrt(x*x + y*y), isDeg ? angleDeg() : angleRad());}
|
||||
static PIPoint<Type> fromPolar(const PIPoint<Type> & p) {return PIPoint<Type>(p.y * cos(p.x), p.y * sin(p.x));}
|
||||
|
||||
PIPoint<Type> operator +(const PIPoint<Type> & p) {return PIPoint<Type>(x + p.x, y + p.y);}
|
||||
PIPoint<Type> operator +(const Type & p) {return PIPoint<Type>(x + p, y + p);}
|
||||
PIPoint<Type> operator -(const PIPoint<Type> & p) {return PIPoint<Type>(x - p.x, y - p.y);}
|
||||
PIPoint<Type> operator -(const Type & p) {return PIPoint<Type>(x - p, y - p);}
|
||||
PIPoint<Type> operator -() {return PIPoint<Type>(-x, -y);}
|
||||
PIPoint<Type> operator *(const Type & d) {return PIPoint<Type>(x * d, y * d);}
|
||||
PIPoint<Type> operator /(const Type & d) {return PIPoint<Type>(x / d, y / d);}
|
||||
bool operator ==(const PIPoint<Type> & p) const {return (x == p.x && y == p.y);}
|
||||
bool operator !=(const PIPoint<Type> & p) const {return (x != p.x || y != p.y);}
|
||||
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
std::ostream & operator <<(std::ostream & s, const PIPoint<Type> & v) {s << '{' << v.x << ", " << v.y << '}'; return s;}
|
||||
|
||||
template<typename Type>
|
||||
class PIP_EXPORT PIRect {
|
||||
public:
|
||||
Type x0;
|
||||
Type y0;
|
||||
Type x1;
|
||||
Type y1;
|
||||
|
||||
PIRect() {x0 = y0 = x1 = y1 = 0;};
|
||||
PIRect(Type x, Type y, Type w, Type h) {set(x, y, w, h);}
|
||||
PIRect(const PIPoint<Type> & tl, const PIPoint<Type> & br) {set(tl.x, tl.y, br.x, br.y);}
|
||||
PIRect(const PIPoint<Type> & p0, const PIPoint<Type> & p1, const PIPoint<Type> & p2) {set(piMin<Type>(p0.x, p1.x, p2.x), piMin<Type>(p0.y, p1.y, p2.y),
|
||||
piMax<Type>(p0.x, p1.x, p2.x), piMax<Type>(p0.y, p1.y, p2.y));}
|
||||
|
||||
PIRect<Type> & set(Type x, Type y, Type w, Type h) {x0 = x; y0 = y; x1 = x + w; y1 = y + h; return *this;}
|
||||
bool pointIn(Type x, Type y) const {return (x <= x1 && x >= x0 && y <= y1 && y >= y0);}
|
||||
bool pointIn(const PIPoint<Type> & p) const {return pointIn(p.x, p.y);}
|
||||
bool isEmpty() const {return (x1 - x0 == 0 && y1 - y0 == 0);}
|
||||
PIRect<Type> & translate(Type x, Type y) {x0 += x; x1 += x; y0 += y; y1 += y; return *this;}
|
||||
PIRect<Type> & translate(const PIPoint<Type> & p) {x0 += p.x; x1 += p.x; y0 += p.y; y1 += p.y; return *this;}
|
||||
PIRect<Type> translated(Type x, Type y) {PIRect<Type> r(*this); r.translate(x, y); return r;}
|
||||
PIRect<Type> translated(const PIPoint<Type> & p) {PIRect<Type> r(*this); r.translate(p); return r;}
|
||||
PIRect<Type> & scale(Type x, Type y) {setWidth(width() * x); setHeight(height() * y); return *this;}
|
||||
PIRect<Type> & scale(const PIPoint<Type> & p) {setWidth(width() * p.x); setHeight(height() * p.y); return *this;}
|
||||
PIRect<Type> scaled(Type x, Type y) {PIRect<Type> r(*this); r.scale(x, y); return r;}
|
||||
PIRect<Type> scaled(const PIPoint<Type> & p) {PIRect<Type> r(*this); r.scale(p); return r;}
|
||||
PIRect<Type> & normalize() {if (x0 > x1) piSwap<Type>(x0, x1); if (y0 > y1) piSwap<Type>(y0, y1); return *this;}
|
||||
PIRect<Type> normalized() {PIRect<Type> r(*this); r.normalize(); return r;}
|
||||
PIRect<Type> & unite(const PIRect<Type> & r) {x0 = piMin<Type>(x0, r.x0); y0 = piMin<Type>(y0, r.y0); x1 = piMax<Type>(x1, r.x1); y1 = piMax<Type>(y1, r.y1); return *this;}
|
||||
PIRect<Type> united(const PIRect<Type> & rect) {PIRect<Type> r(*this); r.unite(rect); return r;}
|
||||
PIRect<Type> & intersect(const PIRect<Type> & r) {x0 = piMax<Type>(x0, r.x0); y0 = piMax<Type>(y0, r.y0); x1 = piMin<Type>(x1, r.x1); y1 = piMin<Type>(y1, r.y1); if (x0 > x1 || y0 > y1) x0 = x1 = y0 = y1 = Type(0); return *this;}
|
||||
PIRect<Type> intersected(const PIRect<Type> & rect) {PIRect<Type> r(*this); r.intersect(rect); return r;}
|
||||
Type top() const {return y0;}
|
||||
Type left() const {return x0;}
|
||||
Type right() const {return x1;}
|
||||
Type bottom() const {return y1;}
|
||||
Type width() const {return x1 - x0;}
|
||||
Type height() const {return y1 - y0;}
|
||||
PIPoint<Type> topLeft() {return PIPoint<Type>(x0, y0);}
|
||||
PIPoint<Type> topRigth() {return PIPoint<Type>(x1, y0);}
|
||||
PIPoint<Type> bottomLeft() {return PIPoint<Type>(x0, y1);}
|
||||
PIPoint<Type> bottomRight() {return PIPoint<Type>(x1, y1);}
|
||||
void setTop(Type v) {y0 = v;}
|
||||
void setLeft(Type v) {x0 = v;}
|
||||
void setRigth(Type v) {x1 = v;}
|
||||
void setBottom(Type v) {y1 = v;}
|
||||
void setWidth(Type v) {x1 = x0 + v;}
|
||||
void setHeight(Type v) {y1 = y0 + v;}
|
||||
|
||||
PIRect<Type> operator -() {return PIRect<Type>(-x0, -y0, -width(), -height());}
|
||||
void operator +=(Type x) {translate(x, x);}
|
||||
void operator +=(const PIPoint<Type> & p) {translate(p);}
|
||||
void operator -=(Type x) {translate(-x, -x);}
|
||||
void operator -=(const PIPoint<Type> & p) {translate(-p);}
|
||||
void operator *=(Type p) {x0 *= p; x1 *= p; y0 *= p; y1 *= p;}
|
||||
void operator /=(Type p) {x0 /= p; x1 /= p; y0 /= p; y1 /= p;}
|
||||
void operator |=(const PIRect<Type> & r) {unite(r);}
|
||||
void operator &=(const PIRect<Type> & r) {intersect(r);}
|
||||
PIRect<Type> operator +(const PIPoint<Type> & p) {return PIRect<Type>(*this).translated(p);}
|
||||
PIRect<Type> operator -(const PIPoint<Type> & p) {return PIRect<Type>(*this).translated(-p);}
|
||||
PIRect<Type> operator |(const PIRect<Type> & r) {return PIRect<Type>(*this).united(r);}
|
||||
PIRect<Type> operator &(const PIRect<Type> & r) {return PIRect<Type>(*this).intersected(r);}
|
||||
bool operator ==(const PIRect<Type> & r) const {return (x0 == r.x0 && y0 == r.y0 && x1 == r.x1 && y1 == r.y10);}
|
||||
bool operator !=(const PIRect<Type> & r) const {return (x0 != r.x0 || y0 != r.y0 || x1 != r.x1 || y1 != r.y10);}
|
||||
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
std::ostream & operator <<(std::ostream & s, const PIRect<Type> & v) {s << '{' << v.x0 << ", " << v.y0 << "; " << v.x1 - v.x0 << ", " << v.y1 - v.y0 << '}'; return s;}
|
||||
|
||||
typedef PIPoint<int> PIPointi;
|
||||
typedef PIPoint<uint> PIPointu;
|
||||
typedef PIPoint<float> PIPointf;
|
||||
typedef PIPoint<double> PIPointd;
|
||||
|
||||
typedef PIRect<int> PIRecti;
|
||||
typedef PIRect<uint> PIRectu;
|
||||
typedef PIRect<float> PIRectf;
|
||||
typedef PIRect<double> PIRectd;
|
||||
|
||||
#endif // PIGEOMETRY_H
|
||||
592
piincludes.cpp
592
piincludes.cpp
@@ -1,592 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Global includes
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piincludes.h"
|
||||
#include "piconsole.h"
|
||||
|
||||
bool isPIInit = false;
|
||||
bool piDebug = true;
|
||||
string ifconfigPath;
|
||||
|
||||
PIInit piInit;
|
||||
lconv * currentLocale =
|
||||
#ifdef ANDROID
|
||||
0;
|
||||
#else
|
||||
std::localeconv();
|
||||
#endif
|
||||
#ifdef HAS_LOCALE
|
||||
static locale_t currentLocale_t = 0;
|
||||
#endif
|
||||
|
||||
#ifdef MAC_OS
|
||||
clock_serv_t __pi_mac_clock;
|
||||
#endif
|
||||
|
||||
PIMutex __PICout_mutex__;
|
||||
PIString __PICout_string__;
|
||||
|
||||
|
||||
#ifdef WINDOWS
|
||||
FILETIME __pi_ftjan1970;
|
||||
long long __pi_perf_freq = -1;
|
||||
PINtSetTimerResolution setTimerResolutionAddr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
PIInit::PIInit() {
|
||||
if (isPIInit) return;
|
||||
isPIInit = true;
|
||||
#ifndef WINDOWS
|
||||
sigset_t ss;
|
||||
sigemptyset(&ss);
|
||||
sigaddset(&ss, SIGALRM);
|
||||
sigprocmask(SIG_BLOCK, &ss, 0);
|
||||
pthread_sigmask(SIG_BLOCK, &ss, 0);
|
||||
ifconfigPath = "/bin/ifconfig";
|
||||
if (!fileExists(ifconfigPath)) {
|
||||
ifconfigPath = "/sbin/ifconfig";
|
||||
if (!fileExists(ifconfigPath)) {
|
||||
ifconfigPath = "/usr/bin/ifconfig";
|
||||
if (!fileExists(ifconfigPath)) {
|
||||
ifconfigPath = "/usr/sbin/ifconfig";
|
||||
if (!fileExists(ifconfigPath)) {
|
||||
ifconfigPath = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
// WinSock inint
|
||||
WSADATA wsaData;
|
||||
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
|
||||
// Timers init
|
||||
SYSTEMTIME jan1970 = {1970, 1, 4, 1, 0, 14, 15, 0};
|
||||
SystemTimeToFileTime(&jan1970, &__pi_ftjan1970);
|
||||
LARGE_INTEGER pf;
|
||||
pf.QuadPart = -1;
|
||||
if (QueryPerformanceFrequency(&pf) != 0) __pi_perf_freq = pf.QuadPart;
|
||||
if (__pi_perf_freq == 0) __pi_perf_freq = -1;
|
||||
|
||||
// Sleep precision init
|
||||
ntlib = LoadLibrary("ntdll.dll");
|
||||
if (ntlib) setTimerResolutionAddr = (PINtSetTimerResolution)GetProcAddress(ntlib, "NtSetTimerResolution");
|
||||
/*if (setTimerResolution) setTimerResolutionAddr(1, TRUE, &prev_res);*/
|
||||
#endif
|
||||
//piDebug = true;
|
||||
#ifdef HAS_LOCALE
|
||||
//cout << "has locale" << endl;
|
||||
if (currentLocale_t != 0) {
|
||||
freelocale(currentLocale_t);
|
||||
currentLocale_t = 0;
|
||||
}
|
||||
currentLocale_t = newlocale(LC_ALL, setlocale(LC_ALL, ""), 0);
|
||||
#else
|
||||
setlocale(LC_ALL, "");
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
#endif
|
||||
#ifdef MAC_OS
|
||||
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &__pi_mac_clock);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PIInit::~PIInit() {
|
||||
#ifdef WINDOWS
|
||||
WSACleanup();
|
||||
//if (setTimerResolution) setTimerResolutionAddr(prev_res, TRUE, &prev_res);
|
||||
if (ntlib) FreeLibrary(ntlib);
|
||||
#endif
|
||||
#ifdef MAC_OS
|
||||
mach_port_deallocate(mach_task_self(), __pi_mac_clock);
|
||||
#endif
|
||||
//if (currentLocale_t != 0) freelocale(currentLocale_t);
|
||||
}
|
||||
|
||||
|
||||
#ifdef WINDOWS
|
||||
void * PICout::hOut = 0;
|
||||
WORD PICout::dattr = 0;
|
||||
DWORD PICout::smode = 0;
|
||||
#endif
|
||||
|
||||
|
||||
bool PICout::buffer_ = false;
|
||||
|
||||
|
||||
PICout::PICout(PIFlags<PICoutControl> controls): fo_(true), cc_(false), fc_(false), cnb_(10), co_(controls) {
|
||||
#ifdef WINDOWS
|
||||
if (hOut == 0) {
|
||||
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
GetConsoleScreenBufferInfo(hOut, &sbi);
|
||||
dattr = sbi.wAttributes;
|
||||
}
|
||||
attr_ = dattr;
|
||||
#endif
|
||||
__PICout_mutex__.lock();
|
||||
}
|
||||
|
||||
|
||||
PICout::~PICout() {
|
||||
if (fc_) applyFormat(PICoutManipulators::Default);
|
||||
if (cc_) return;
|
||||
newLine();
|
||||
__PICout_mutex__.unlock();
|
||||
}
|
||||
|
||||
|
||||
PICout PICout::operator <<(const PICoutAction v) {
|
||||
#ifdef WINDOWS
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
COORD coord;
|
||||
CONSOLE_CURSOR_INFO curinfo;
|
||||
#endif
|
||||
switch (v) {
|
||||
case PICoutManipulators::Flush:
|
||||
if (!PICout::buffer_)
|
||||
std::cout << std::flush;
|
||||
break;
|
||||
case PICoutManipulators::Backspace:
|
||||
if (!PICout::buffer_) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleScreenBufferInfo(hOut, &sbi);
|
||||
coord = sbi.dwCursorPosition;
|
||||
coord.X = piMax<int>(0, int(coord.X) - 1);
|
||||
SetConsoleCursorPosition(hOut, coord);
|
||||
printf(" ");
|
||||
SetConsoleCursorPosition(hOut, coord);
|
||||
#else
|
||||
printf("\e[1D \e[1D");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::ShowCursor:
|
||||
if (!PICout::buffer_) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleCursorInfo(hOut, &curinfo);
|
||||
curinfo.bVisible = true;
|
||||
SetConsoleCursorInfo(hOut, &curinfo);
|
||||
#else
|
||||
printf("\e[?25h");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::HideCursor:
|
||||
if (!PICout::buffer_) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleCursorInfo(hOut, &curinfo);
|
||||
curinfo.bVisible = false;
|
||||
SetConsoleCursorInfo(hOut, &curinfo);
|
||||
#else
|
||||
printf("\e[?25l");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::ClearScreen:
|
||||
if (!PICout::buffer_) {
|
||||
#ifdef WINDOWS
|
||||
/// TODO !!!
|
||||
/*GetConsoleCursorInfo(hOut, &curinfo);
|
||||
curinfo.bVisible = false;
|
||||
SetConsoleCursorInfo(hOut, &curinfo);
|
||||
|
||||
SetConsoleCursorPosition(hOut, ulcoord);
|
||||
FillConsoleOutputAttribute(hOut, dattr, width * (height + 1), ulcoord, &written);
|
||||
FillConsoleOutputCharacter(hOut, ' ', width * (height + 1), ulcoord, &written);*/
|
||||
#else
|
||||
printf("\e[H\e[J");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::SaveContol: saveControl(); break;
|
||||
case PICoutManipulators::RestoreControl: restoreControl(); break;
|
||||
default: break;
|
||||
};
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
#define PICOUTTOTARGET(v) {if (PICout::buffer_) __PICout_string__ << (v); else std::cout << (v);}
|
||||
#define PINUMERICCOUT if (cnb_ == 10) PICOUTTOTARGET(v) else PICOUTTOTARGET(PIString::fromNumber(v, cnb_))
|
||||
|
||||
|
||||
PICout PICout::operator <<(const char * v) {space(); quote(); PICOUTTOTARGET(v) quote(); return *this;}
|
||||
|
||||
PICout PICout::operator <<(const string & v) {space(); quote(); PICOUTTOTARGET(v) quote(); return *this;}
|
||||
|
||||
PICout PICout::operator <<(const bool v) {space(); if (v) PICOUTTOTARGET("true") else PICOUTTOTARGET("false") return *this;}
|
||||
|
||||
PICout PICout::operator <<(const char v) {space(); PICOUTTOTARGET(v) return *this;}
|
||||
|
||||
PICout PICout::operator <<(const uchar v) {space(); if (cnb_ == 10) PICOUTTOTARGET(ushort(v)) else PICOUTTOTARGET(PIString::fromNumber(v, cnb_)) return *this;}
|
||||
|
||||
PICout PICout::operator <<(const short int v) {space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const ushort v) {space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const int v) {space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const uint v) {space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const long v) {space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const ulong v) {space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const llong v) {space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const ullong v) {space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const float v) {space(); PICOUTTOTARGET(v) return *this;}
|
||||
|
||||
PICout PICout::operator <<(const double v) {space(); PICOUTTOTARGET(v) return *this;}
|
||||
|
||||
PICout PICout::operator <<(const void * v) {space(); PICOUTTOTARGET("0x") PICOUTTOTARGET(PIString::fromNumber(ullong(v), 16)) return *this;}
|
||||
|
||||
PICout PICout::operator <<(const PIObject * v) {
|
||||
space();
|
||||
if (v == 0) PICOUTTOTARGET("PIObject*(0x0)")
|
||||
else {
|
||||
PICOUTTOTARGET(v->className())
|
||||
PICOUTTOTARGET("*(0x")
|
||||
PICOUTTOTARGET(PIString::fromNumber(ullong(v), 16))
|
||||
PICOUTTOTARGET(", \"")
|
||||
PICOUTTOTARGET(v->name())
|
||||
PICOUTTOTARGET("\")")
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
PICout PICout::operator <<(const PICoutSpecialChar v) {
|
||||
switch (v) {
|
||||
case Null:
|
||||
if (PICout::buffer_) __PICout_string__ << PIChar(0);
|
||||
else std::cout << char(0);
|
||||
break;
|
||||
case NewLine:
|
||||
if (PICout::buffer_) __PICout_string__ << "\n";
|
||||
else std::cout << '\n';
|
||||
fo_ = true;
|
||||
break;
|
||||
case Tab:
|
||||
if (PICout::buffer_) __PICout_string__ << "\t";
|
||||
else std::cout << '\t';
|
||||
break;
|
||||
case Esc:
|
||||
#ifdef CC_VC
|
||||
if (PICout::buffer_) __PICout_string__ << PIChar(27);
|
||||
else std::cout << char(27);
|
||||
#else
|
||||
if (PICout::buffer_) __PICout_string__ << "\e";
|
||||
else std::cout << '\e';
|
||||
#endif
|
||||
break;
|
||||
case Quote:
|
||||
if (PICout::buffer_) __PICout_string__ << "\"";
|
||||
else std::cout << '"';
|
||||
break;
|
||||
};
|
||||
return *this;
|
||||
}
|
||||
|
||||
#undef PICOUTTOTARGET
|
||||
#undef PINUMERICCOUT
|
||||
|
||||
PICout & PICout::space() {
|
||||
if (!fo_ && co_[AddSpaces]) {
|
||||
if (PICout::buffer_) __PICout_string__ << " ";
|
||||
else std::cout << ' ';
|
||||
}
|
||||
fo_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PICout & PICout::quote() {
|
||||
if (co_[AddQuotes]) {
|
||||
if (PICout::buffer_) __PICout_string__ << "\"";
|
||||
else std::cout << '"';
|
||||
}
|
||||
fo_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PICout & PICout::newLine() {
|
||||
if (co_[AddNewLine]) {
|
||||
if (PICout::buffer_) __PICout_string__ << "\n";
|
||||
else std::cout << std::endl;
|
||||
}
|
||||
fo_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void PICout::applyFormat(PICoutFormat f) {
|
||||
if (PICout::buffer_) return;
|
||||
fc_ = true;
|
||||
#ifdef WINDOWS
|
||||
static int mask_fore = ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
static int mask_back = ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
|
||||
switch (f) {
|
||||
case Bin: 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_ = dattr; break;
|
||||
default: break;
|
||||
}
|
||||
SetConsoleTextAttribute(hOut, attr_);
|
||||
#else
|
||||
switch (f) {
|
||||
case Bin: case Oct: case Dec: case Hex: break;
|
||||
case PICoutManipulators::Bold: printf("\e[1m"); break;
|
||||
case PICoutManipulators::Faint: printf("\e[2m"); break;
|
||||
case PICoutManipulators::Italic: printf("\e[3m"); break;
|
||||
case PICoutManipulators::Underline: printf("\e[4m"); break;
|
||||
case PICoutManipulators::Blink: printf("\e[5m"); break;
|
||||
case PICoutManipulators::Black: printf("\e[30m"); break;
|
||||
case PICoutManipulators::Red: printf("\e[31m"); break;
|
||||
case PICoutManipulators::Green: printf("\e[32m"); break;
|
||||
case PICoutManipulators::Blue: printf("\e[34m"); break;
|
||||
case PICoutManipulators::Yellow: printf("\e[33m"); break;
|
||||
case PICoutManipulators::Magenta: printf("\e[35m"); break;
|
||||
case PICoutManipulators::Cyan: printf("\e[36m"); break;
|
||||
case PICoutManipulators::White: printf("\e[37m"); break;
|
||||
case PICoutManipulators::BackBlack: printf("\e[40m"); break;
|
||||
case PICoutManipulators::BackRed: printf("\e[41m"); break;
|
||||
case PICoutManipulators::BackGreen: printf("\e[42m"); break;
|
||||
case PICoutManipulators::BackBlue: printf("\e[44m"); break;
|
||||
case PICoutManipulators::BackYellow: printf("\e[43m"); break;
|
||||
case PICoutManipulators::BackMagenta: printf("\e[45m"); break;
|
||||
case PICoutManipulators::BackCyan: printf("\e[46m"); break;
|
||||
case PICoutManipulators::BackWhite: printf("\e[47m"); break;
|
||||
case PICoutManipulators::Default: printf("\e[0m"); break;
|
||||
default: break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PICout::setBufferActive(bool on, bool clear) {
|
||||
PIMutexLocker ml(__PICout_mutex__);
|
||||
bool ret = PICout::buffer_;
|
||||
if (clear) __PICout_string__.clear();
|
||||
PICout::buffer_ = on;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PICout::isBufferActive() {
|
||||
return PICout::buffer_;
|
||||
}
|
||||
|
||||
|
||||
PIString PICout::buffer(bool clear) {
|
||||
PIMutexLocker ml(__PICout_mutex__);
|
||||
PIString ret = __PICout_string__;
|
||||
if (clear) __PICout_string__.clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PICout::clearBuffer() {
|
||||
PIMutexLocker ml(__PICout_mutex__);
|
||||
__PICout_string__.clear();
|
||||
}
|
||||
|
||||
|
||||
/*! \class PICout
|
||||
* \brief Class for formatted output similar std::cout
|
||||
*
|
||||
* \section PICout_sec0 Synopsis
|
||||
* This class provide many stream operators for output with some features.
|
||||
* Output to PICout is thread-sequential, i.e. doesn`t mixed from parallel
|
||||
* threads.
|
||||
*
|
||||
* \section PICout_sec1 Features
|
||||
* - insertion spaces between entries
|
||||
* - insertion new line at the end of output
|
||||
* - strings are quoted
|
||||
* - custom output operator can be easily written
|
||||
*
|
||||
* \section PICout_ex0 Usage
|
||||
* \snippet picout.cpp 0
|
||||
*
|
||||
* \section PICout_ex1 Writing your own output operator
|
||||
* \snippet picout.cpp own
|
||||
*/
|
||||
|
||||
|
||||
/*! \mainpage What is PIP
|
||||
* PIP - Platform-Independent Primitives - is crossplatform library for C++ developers.
|
||||
* It is wrap around STL and pure C++. This library can help developers write non-GUI
|
||||
* projects much more quickly, efficiently and customizable than on pure C++.
|
||||
* Library contains many classes, some of them are pure abstract, some classes
|
||||
* can be used as they are, some classes should be inherited to new classes.
|
||||
* PIP provide classes:
|
||||
* * direct output to console (\a PICout)
|
||||
* * containers (\a PIVector, \a PIList, \a PIMap, \a PIStack)
|
||||
* * byte array (\a PIByteArray)
|
||||
* * string (\a PIString, \a PIStringList)
|
||||
* * base object (events and handlers) (\a PIObject)
|
||||
* * thread (\a PIThread)
|
||||
* * timer (\a PITimer)
|
||||
* * console (information output) (\a PIConsole)
|
||||
* * stand-alone
|
||||
* * server
|
||||
* * client
|
||||
* * i/o devices
|
||||
* * base class (\a PIIODevice)
|
||||
* * file (\a PIFile)
|
||||
* * serial port (\a PISerial)
|
||||
* * ethernet (\a PIEthernet)
|
||||
* * USB (\a PIUSB)
|
||||
* * packets extractor (\a PIPacketExtractor)
|
||||
* * binary log (\a PIBinaryLog)
|
||||
* * connection quality diagnotic (\a PIDiagnostics)
|
||||
* * command-line arguments parser (\a PICLI)
|
||||
* * math evaluator (\a PIEvaluator)
|
||||
* * peering net node (\a PIPeer)
|
||||
* * process (\a PIProcess)
|
||||
* * state machine (\a PIStateMachine)
|
||||
* \n \n Basic using of PIP described at page \ref using_basic */
|
||||
|
||||
|
||||
/*! \page using_basic Getting started
|
||||
* Many novice programmers are solved many common task with system integrity: output to console,
|
||||
* keyboard buttons press detecting, working with serial ports, ethernet or files, and many other.
|
||||
* These tasks can solve this library, and code, based only on PIP will be compile and work
|
||||
* similar on many systems: Windows, any Linux, Red Hat, FreeBSD, MacOS X and QNX.
|
||||
* Typical application on PIP looks like this: \n
|
||||
\code{.cpp}
|
||||
#include <pip.h>
|
||||
|
||||
|
||||
// declare key press handler
|
||||
void key_event(char key, void * );
|
||||
|
||||
|
||||
PIConsole console(false, key_event); // don`t start now, key handler is "key_event"
|
||||
|
||||
|
||||
// some vars
|
||||
int i = 2, j = 3;
|
||||
|
||||
|
||||
// implicit key press handler
|
||||
void key_event(char key, void * ) {
|
||||
switch (key) {
|
||||
case '-':
|
||||
i--;
|
||||
break;
|
||||
case '+':
|
||||
i++;
|
||||
break;
|
||||
case '(':
|
||||
j--;
|
||||
break;
|
||||
case ')':
|
||||
j++;
|
||||
break;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
class MainClass: public PITimer {
|
||||
PIOBJECT(MainClass)
|
||||
public:
|
||||
MainClass() {}
|
||||
protected:
|
||||
void tick(void * data, int delimiter) {
|
||||
piCout << "timer tick";
|
||||
// timer tick
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
MainClass main_class;
|
||||
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
// enabling auto-detection of exit button press, by default 'Q' (shift+q)
|
||||
console.enableExitCapture();
|
||||
|
||||
// if we want to parse command-line arguments
|
||||
PICLI cli(argc, argv);
|
||||
cli.addArgument("console"); // "-c" or "--console"
|
||||
cli.addArgument("debug"); // "-d" or "--debug"
|
||||
|
||||
// enabling or disabling global debug flag
|
||||
piDebug = cli.hasArgument("debug");
|
||||
|
||||
// configure console
|
||||
console.addTab("first tab", '1');
|
||||
console.addString("PIP console", 1, PIConsole::Bold);
|
||||
console.addVariable("int var (i)", &i, 1);
|
||||
console.addVariable("int green var (j)", &j, 1, PIConsole::Green);
|
||||
console.addString("'-' - i--", 2);
|
||||
console.addString("'+' - i++", 2);
|
||||
console.addString("'(' - j--", 2);
|
||||
console.addString("')' - j++", 2);
|
||||
console.addTab("second tab", '2');
|
||||
console.addString("col 1", 1);
|
||||
console.addString("col 2", 2);
|
||||
console.addString("col 3", 3);
|
||||
console.setTab("first tab");
|
||||
|
||||
// start output to console if "console" argument exists
|
||||
if (cli.hasArgument("console"))
|
||||
console.start();
|
||||
|
||||
// start main class, e.g. 40 Hz
|
||||
main_class.start(25.);
|
||||
|
||||
// wait for 'Q' press, independently if console is started or not
|
||||
console.waitForFinish();
|
||||
|
||||
return 0;
|
||||
};
|
||||
\endcode
|
||||
* This code demonstrates simple interactive configurable program, which can be started with console
|
||||
* display or not, and with debug or not. \b MainClass is central class that also can be inherited from
|
||||
* \a PIThread and reimplement \a run() function.
|
||||
* \n Many PIP classes has events and event handlers, which can be connected one to another.
|
||||
* Details you can see at \a PIObject reference page (\ref PIObject_sec0).
|
||||
* \n To configure your program from file use \a PIConfig.
|
||||
* \n If you want more information see \ref using_advanced */
|
||||
|
||||
|
||||
/*! \page using_advanced Advanced using
|
||||
* Sorry, creativity crisis xD
|
||||
*/
|
||||
978
piincludes.h
978
piincludes.h
@@ -1,978 +0,0 @@
|
||||
/*! \file piincludes.h
|
||||
* \brief Global includes of PIP
|
||||
*
|
||||
* This file include all needed system headers, STL
|
||||
* and declare many useful macros and functions
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Global includes
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIINCLUDES_H
|
||||
#define PIINCLUDES_H
|
||||
|
||||
//! Version of PIP in hex - 0x##(Major)##(Minor)##(Revision)
|
||||
#define PIP_VERSION 0x000400
|
||||
|
||||
//! Major value of PIP version
|
||||
#define PIP_VERSION_MAJOR (PIP_VERSION & 0xFF0000) >> 16
|
||||
|
||||
//! Minor value of PIP version
|
||||
#define PIP_VERSION_MINOR (PIP_VERSION & 0xFF00) >> 8
|
||||
|
||||
//! Revision value of PIP version
|
||||
#define PIP_VERSION_REVISION PIP_VERSION & 0xFF
|
||||
|
||||
//! Suffix of PIP version
|
||||
#define PIP_VERSION_SUFFIX "_r5"
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
//! Macro is defined when compile-time debug is enabled
|
||||
# define PIP_DEBUG
|
||||
|
||||
//! Macro is defined when host is any Windows
|
||||
# define WINDOWS
|
||||
|
||||
//! Macro is defined when host is QNX
|
||||
# define QNX
|
||||
|
||||
//! Macro is defined when host is FreeBSD
|
||||
# define FREE_BSD
|
||||
|
||||
//! Macro is defined when host is Mac OS
|
||||
# define MAC_OS
|
||||
|
||||
//! Macro is defined when host is Android
|
||||
# define ANDROID
|
||||
|
||||
//! Macro is defined when host is any Linux
|
||||
# define LINUX
|
||||
|
||||
//! Macro is defined when compiler is GCC or MinGW
|
||||
# define CC_GCC
|
||||
|
||||
//! Macro is defined when PIP is decided that host is support language
|
||||
# define HAS_LOCALE
|
||||
|
||||
//! Macro is defined when compiler is Visual Studio
|
||||
# define CC_VC
|
||||
|
||||
//! Macro is defined when compiler is unknown
|
||||
# define CC_OTHER
|
||||
|
||||
//! Macro is defined when PIP use "rt" library for timers implementation
|
||||
# define PIP_TIMER_RT
|
||||
|
||||
//! Define this macro to use STL implementation of containers, else PIP implementation will be used
|
||||
# define PIP_CONTAINERS_STL
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
|
||||
# define WINDOWS
|
||||
# define ARCH_BITS_32
|
||||
#endif
|
||||
#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
|
||||
# define WINDOWS
|
||||
# define ARCH_BITS_64
|
||||
#endif
|
||||
#if defined(__QNX__) || defined(__QNXNTO__)
|
||||
# define QNX
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
# define FREE_BSD
|
||||
#endif
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
# define MAC_OS
|
||||
#endif
|
||||
#if defined(__ANDROID__) || defined(_ANDROID_) || defined(ANDROID)
|
||||
# ifndef ANDROID
|
||||
# define ANDROID
|
||||
# endif
|
||||
#endif
|
||||
#ifndef WINDOWS
|
||||
# ifndef QNX
|
||||
# ifndef FREE_BSD
|
||||
# ifndef MAC_OS
|
||||
# ifndef ANDROID
|
||||
# define LINUX
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef WINDOWS
|
||||
# if defined(__LP64__) || defined(_LP64_) || defined(LP64)
|
||||
# define ARCH_BITS_64
|
||||
# else
|
||||
# define ARCH_BITS_32
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define CC_GCC
|
||||
# define CC_GCC_VERSION ((__GNUC__ << 8) | __GNUC_MINOR__)
|
||||
# if CC_GCC_VERSION > 0x025F // > 2.95
|
||||
# ifdef LINUX
|
||||
# define HAS_LOCALE
|
||||
# endif
|
||||
# pragma GCC diagnostic ignored "-Wformat"
|
||||
# pragma GCC diagnostic ignored "-Wformat-extra-args"
|
||||
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
# endif
|
||||
# ifdef ANDROID
|
||||
# pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
# pragma GCC diagnostic ignored "-Wextra"
|
||||
# pragma GCC diagnostic ignored "-Wliteral-suffix"
|
||||
# endif
|
||||
# define DEPRECATED __attribute__((deprecated))
|
||||
#elif defined(_MSC_VER)
|
||||
# define CC_VC
|
||||
# pragma warning(disable: 4018)
|
||||
# pragma warning(disable: 4061)
|
||||
# pragma warning(disable: 4100)
|
||||
# pragma warning(disable: 4239)
|
||||
# pragma warning(disable: 4242)
|
||||
# pragma warning(disable: 4244)
|
||||
# pragma warning(disable: 4251)
|
||||
# pragma warning(disable: 4365)
|
||||
# pragma warning(disable: 4512)
|
||||
# pragma warning(disable: 4668)
|
||||
# pragma warning(disable: 4710)
|
||||
# pragma warning(disable: 4800)
|
||||
# pragma warning(disable: 4820)
|
||||
# pragma warning(disable: 4986)
|
||||
# pragma warning(disable: 4996)
|
||||
# define DEPRECATED
|
||||
# ifdef ARCH_BITS_32
|
||||
typedef long ssize_t;
|
||||
# else
|
||||
typedef long long ssize_t;
|
||||
# endif
|
||||
#else
|
||||
# define CC_OTHER
|
||||
# define DEPRECATED
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS
|
||||
# ifdef CC_GCC
|
||||
# define typeof __typeof
|
||||
# endif
|
||||
#else
|
||||
# define typeof __typeof__
|
||||
#endif
|
||||
|
||||
#include "pip_export.h"
|
||||
#if defined(DOXYGEN) || defined(CC_GCC) || defined(PICODE)
|
||||
# undef PIP_EXPORT
|
||||
# define PIP_EXPORT
|
||||
#endif
|
||||
#include <iostream>
|
||||
#ifdef CC_GCC
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#ifndef QNX
|
||||
# include <cstdio>
|
||||
# include <cstdlib>
|
||||
# include <clocale>
|
||||
#else
|
||||
# include <stdio.h>
|
||||
# include <locale.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <cctype>
|
||||
#include <ctime>
|
||||
#include <csignal>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
//#include <signal.h>
|
||||
#include <typeinfo>
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <deque>
|
||||
#include <stack>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#ifdef WINDOWS
|
||||
# include <conio.h>
|
||||
# include <io.h>
|
||||
# include <winsock2.h>
|
||||
# ifdef CC_VC
|
||||
# define SHUT_RDWR 2
|
||||
# pragma comment(lib, "Ws2_32.lib")
|
||||
# pragma comment(lib, "Iphlpapi.lib")
|
||||
# else
|
||||
# define SHUT_RDWR SD_BOTH
|
||||
# endif
|
||||
# include <windows.h>
|
||||
# include <wincon.h>
|
||||
# include <iphlpapi.h>
|
||||
typedef int socklen_t;
|
||||
typedef void(*PINtSetTimerResolution)(ULONG, BOOLEAN, PULONG);
|
||||
extern FILETIME __pi_ftjan1970;
|
||||
extern long long __pi_perf_freq;
|
||||
extern PINtSetTimerResolution setTimerResolutionAddr;
|
||||
inline long long __PIQueryPerformanceCounter() {LARGE_INTEGER li; QueryPerformanceCounter(&li); return li.QuadPart;}
|
||||
inline void __PISetTimerResolution() {if (setTimerResolutionAddr == NULL) return; ULONG ret; setTimerResolutionAddr(1, TRUE, &ret);}
|
||||
#else
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <sys/socket.h>
|
||||
# include <fcntl.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <net/if.h>
|
||||
# include <pthread.h>
|
||||
# ifndef ANDROID
|
||||
# include <ifaddrs.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef ANDROID
|
||||
//# include "ifaddrs_3rd.h"
|
||||
# define tcdrain(fd) ioctl(fd, TCSBRK, 1)
|
||||
inline int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;}
|
||||
inline int mbtowc(wchar_t * w, const char * c, size_t) {*w = ((wchar_t * )&c)[0]; return 1;}
|
||||
#endif
|
||||
#ifdef MAC_OS
|
||||
# include <mach/mach_traps.h>
|
||||
# include <mach/mach.h>
|
||||
# include <mach/clock.h>
|
||||
# include <crt_externs.h>
|
||||
# define environ (*_NSGetEnviron())
|
||||
typedef long time_t;
|
||||
extern clock_serv_t __pi_mac_clock;
|
||||
#endif
|
||||
#ifdef LINUX
|
||||
# define environ __environ
|
||||
#endif
|
||||
#if !defined(WINDOWS) && !defined(MAC_OS)
|
||||
# define PIP_TIMER_RT
|
||||
#endif
|
||||
#ifdef FREE_BSD
|
||||
extern char ** environ;
|
||||
#endif
|
||||
#if defined(DOXYGEN) || defined(PICODE)
|
||||
# undef PIP_EXPORT
|
||||
# define PIP_EXPORT
|
||||
# undef DEPRECATED
|
||||
# define DEPRECATED
|
||||
#endif
|
||||
|
||||
#include "pimonitor.h"
|
||||
|
||||
extern PIMonitor piMonitor;
|
||||
|
||||
//! Macro used for infinite loop
|
||||
#define FOREVER for (;;)
|
||||
|
||||
//! Macro used for infinite wait
|
||||
#define FOREVER_WAIT FOREVER msleep(1);
|
||||
|
||||
//! Macro used for infinite wait
|
||||
#define WAIT_FOREVER FOREVER msleep(1);
|
||||
|
||||
typedef long long llong;
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned short int ushort;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned long long ullong;
|
||||
typedef long double ldouble;
|
||||
|
||||
using std::cout;
|
||||
using std::cin;
|
||||
using std::endl;
|
||||
using std::flush;
|
||||
using std::vector;
|
||||
using std::list;
|
||||
using std::queue;
|
||||
using std::deque;
|
||||
using std::stack;
|
||||
using std::set;
|
||||
using std::map;
|
||||
using std::multimap;
|
||||
using std::string;
|
||||
#ifndef QNX
|
||||
using std::wstring;
|
||||
#else
|
||||
typedef std::basic_string<wchar_t> wstring;
|
||||
#endif
|
||||
|
||||
/*! \brief Templated function for swap two values
|
||||
* \details Example:\n \snippet piincludes.cpp swap */
|
||||
template<typename T> inline void piSwap(T & f, T & s) {T t = f; f = s; s = t;}
|
||||
|
||||
/*! \brief Templated function for swap two values without "="
|
||||
* \details Example:\n \snippet piincludes.cpp swapBinary */
|
||||
template<typename T> inline void piSwapBinary(T & f, T & s) {
|
||||
static size_t j = (sizeof(T) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(T);
|
||||
size_t i = 0;
|
||||
for (i = 0; i < j; ++i) {
|
||||
((size_t*)(&f))[i] ^= ((size_t*)(&s))[i];
|
||||
((size_t*)(&s))[i] ^= ((size_t*)(&f))[i];
|
||||
((size_t*)(&f))[i] ^= ((size_t*)(&s))[i];
|
||||
}
|
||||
for (i = bs; i < bf; ++i) {
|
||||
((uchar*)(&f))[i] ^= ((uchar*)(&s))[i];
|
||||
((uchar*)(&s))[i] ^= ((uchar*)(&f))[i];
|
||||
((uchar*)(&f))[i] ^= ((uchar*)(&s))[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Templated function return round of float falue
|
||||
* \details Round is the nearest integer value \n
|
||||
* There are some macros:
|
||||
* - \c piRoundf for "float"
|
||||
* - \c piRoundd for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp round */
|
||||
template<typename T> inline int piRound(const T & v) {return int(v >= T(0.) ? v + T(0.5) : v - T(0.5));}
|
||||
|
||||
/*! \brief Templated function return floor of float falue
|
||||
* \details Floor is the largest integer that is not greater than value \n
|
||||
* There are some macros:
|
||||
* - \c piFloorf for "float"
|
||||
* - \c piFloord for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp floor */
|
||||
template<typename T> inline int piFloor(const T & v) {return v < T(0) ? int(v) - 1 : int(v);}
|
||||
|
||||
/*! \brief Templated function return ceil of float falue
|
||||
* \details Ceil is the smallest integer that is not less than value \n
|
||||
* There are some macros:
|
||||
* - \c piCeilf for "float"
|
||||
* - \c piCeild for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp ceil */
|
||||
template<typename T> inline int piCeil(const T & v) {return v < T(0) ? int(v) : int(v) + 1;}
|
||||
|
||||
/*! \brief Templated function return absolute of numeric falue
|
||||
* \details Absolute is the positive or equal 0 value \n
|
||||
* There are some macros:
|
||||
* - \c piAbss for "short"
|
||||
* - \c piAbsi for "int"
|
||||
* - \c piAbsl for "long"
|
||||
* - \c piAbsll for "llong"
|
||||
* - \c piAbsf for "float"
|
||||
* - \c piAbsd for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp abs */
|
||||
template<typename T> inline T piAbs(const T & v) {return (v >= T(0) ? v : -v);}
|
||||
|
||||
/*! \brief Templated function return minimum of two values
|
||||
* \details There are some macros:
|
||||
* - \c piMins for "short"
|
||||
* - \c piMini for "int"
|
||||
* - \c piMinl for "long"
|
||||
* - \c piMinll for "llong"
|
||||
* - \c piMinf for "float"
|
||||
* - \c piMind for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp min2 */
|
||||
template<typename T> inline T piMin(const T & f, const T & s) {return ((f > s) ? s : f);}
|
||||
|
||||
/*! \brief Templated function return minimum of tree values
|
||||
* \details There are some macros:
|
||||
* - \c piMins for "short"
|
||||
* - \c piMini for "int"
|
||||
* - \c piMinl for "long"
|
||||
* - \c piMinll for "llong"
|
||||
* - \c piMinf for "float"
|
||||
* - \c piMind for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp min3 */
|
||||
template<typename T> inline T piMin(const T & f, const T & s, const T & t) {return ((f < s && f < t) ? f : ((s < t) ? s : t));}
|
||||
|
||||
/*! \brief Templated function return maximum of two values
|
||||
* \details There are some macros:
|
||||
* - \c piMaxs for "short"
|
||||
* - \c piMaxi for "int"
|
||||
* - \c piMaxl for "long"
|
||||
* - \c piMaxll for "llong"
|
||||
* - \c piMaxf for "float"
|
||||
* - \c piMaxd for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp max2 */
|
||||
template<typename T> inline T piMax(const T & f, const T & s) {return ((f < s) ? s : f);}
|
||||
|
||||
/*! \brief Templated function return maximum of tree values
|
||||
* \details There are some macros:
|
||||
* - \c piMaxs for "short"
|
||||
* - \c piMaxi for "int"
|
||||
* - \c piMaxl for "long"
|
||||
* - \c piMaxll for "llong"
|
||||
* - \c piMaxf for "float"
|
||||
* - \c piMaxd for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp max3 */
|
||||
template<typename T> inline T piMax(const T & f, const T & s, const T & t) {return ((f > s && f > t) ? f : ((s > t) ? s : t));}
|
||||
|
||||
/*! \brief Templated function return clamped value
|
||||
* \details Clamped is the not greater than "max" and not lesser than "min" value \n
|
||||
* There are some macros:
|
||||
* - \c piClamps for "short"
|
||||
* - \c piClampi for "int"
|
||||
* - \c piClampl for "long"
|
||||
* - \c piClampll for "llong"
|
||||
* - \c piClampf for "float"
|
||||
* - \c piClampd for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp clamp */
|
||||
template<typename T> inline T piClamp(const T & v, const T & min, const T & max) {return (v > max ? max : (v < min ? min : v));}
|
||||
|
||||
/// Function inverse byte order in memory block
|
||||
inline void piLetobe(void * data, int size) {
|
||||
for (int i = 0; i < size / 2; i++)
|
||||
piSwap<uchar>(((uchar*)data)[size - i - 1], ((uchar*)data)[i]);
|
||||
}
|
||||
|
||||
/// \brief Templated function that inverse byte order of value "v"
|
||||
template<typename T> inline void piLetobe(T * v) {piLetobe(v, sizeof(T));}
|
||||
|
||||
/*! \brief Templated function that returns "v" with inversed byte order
|
||||
* \details This function used to convert values between little and big endian \n
|
||||
* There are some macros:
|
||||
* - \c piLetobes for "ushort"
|
||||
* - \c piLetobei for "uint"
|
||||
* - \c piLetobel for "ulong"
|
||||
* - \c piLetobell for "ullong"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp letobe */
|
||||
template<typename T> inline T piLetobe(const T & v) {T tv(v); piLetobe(&tv, sizeof(T)); return tv;}
|
||||
|
||||
// specialization
|
||||
template<> inline ushort piLetobe(const ushort & v) {return (v << 8) | (v >> 8);}
|
||||
template<> inline uint piLetobe(const uint & v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
|
||||
|
||||
DEPRECATED inline ushort letobe_s(const ushort & v) {return (v << 8) | (v >> 8);}
|
||||
DEPRECATED inline uint letobe_i(const uint & v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
/// \deprecated \brief Use \a piLetobe() instead of this function
|
||||
ushort letobe_s(ushort v) {return (v << 8) | (v >> 8);}
|
||||
|
||||
/// \deprecated \brief Use \a piLetobe() instead of this function
|
||||
uint letobe_i(uint v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
|
||||
|
||||
#endif
|
||||
|
||||
#define piRoundf piRound<float>
|
||||
#define piRoundd piRound<double>
|
||||
#define piFloorf piFloor<float>
|
||||
#define piFloord piFloor<double>
|
||||
#define piCeilf piCeil<float>
|
||||
#define piCeild piCeil<double>
|
||||
#define piAbss piAbs<short>
|
||||
#define piAbsi piAbs<int>
|
||||
#define piAbsl piAbs<long>
|
||||
#define piAbsll piAbs<llong>
|
||||
#define piAbsf piAbs<float>
|
||||
#define piAbsd piAbs<double>
|
||||
#define piMins piMin<short>
|
||||
#define piMini piMin<int>
|
||||
#define piMinl piMin<long>
|
||||
#define piMinll piMin<llong>
|
||||
#define piMinf piMin<float>
|
||||
#define piMind piMin<double>
|
||||
#define piMaxs piMax<short>
|
||||
#define piMaxi piMax<int>
|
||||
#define piMaxl piMax<long>
|
||||
#define piMaxll piMax<llong>
|
||||
#define piMaxf piMax<float>
|
||||
#define piMaxd piMax<double>
|
||||
#define piClamps piClamp<short>
|
||||
#define piClampi piClamp<int>
|
||||
#define piClampl piClamp<long>
|
||||
#define piClampll piClamp<llong>
|
||||
#define piClampf piClamp<float>
|
||||
#define piClampd piClamp<double>
|
||||
#define piLetobes piLetobe<ushort>
|
||||
#define piLetobei piLetobe<uint>
|
||||
#define piLetobel piLetobe<ulong>
|
||||
#define piLetobell piLetobe<ullong>
|
||||
|
||||
extern bool isPIInit;
|
||||
|
||||
//! global variable enabling output to piCout
|
||||
extern PIP_EXPORT bool piDebug;
|
||||
|
||||
extern string ifconfigPath;
|
||||
|
||||
class PIInit {
|
||||
public:
|
||||
PIInit();
|
||||
~PIInit();
|
||||
private:
|
||||
bool fileExists(const string & p) {FILE * f = fopen(p.c_str(), "r"); if (f == 0) return false; fclose(f); return true;}
|
||||
#ifdef WINDOWS
|
||||
HMODULE ntlib;
|
||||
ULONG prev_res;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern PIInit piInit;
|
||||
extern lconv * currentLocale;
|
||||
|
||||
#ifdef WINDOWS
|
||||
inline int random() {return rand();}
|
||||
# ifdef CC_VC
|
||||
inline double round(const double & v) {return floor(v + 0.5);}
|
||||
# endif
|
||||
#endif
|
||||
inline bool atob(const string & str) {return str == "1" ? true : false;}
|
||||
inline string btos(const bool num) {return num ? "0" : "1";}
|
||||
inline string itos(const int num) {
|
||||
char ch[256];
|
||||
#ifndef CC_VC
|
||||
sprintf(ch, "%d", num);
|
||||
#else
|
||||
sprintf_s(ch, 256, "%d", num);
|
||||
#endif
|
||||
return string(ch);}
|
||||
inline string ltos(const long num) {
|
||||
char ch[256];
|
||||
#ifndef CC_VC
|
||||
sprintf(ch, "%ld", num);
|
||||
#else
|
||||
sprintf_s(ch, 256, "%ld", num);
|
||||
#endif
|
||||
return string(ch);}
|
||||
inline string uitos(const uint num) {
|
||||
char ch[256];
|
||||
#ifndef CC_VC
|
||||
sprintf(ch, "%u", num);
|
||||
#else
|
||||
sprintf_s(ch, 256, "%u", num);
|
||||
#endif
|
||||
return string(ch);}
|
||||
inline string ultos(const ulong num) {
|
||||
char ch[256];
|
||||
#ifndef CC_VC
|
||||
sprintf(ch, "%lu", num);
|
||||
#else
|
||||
sprintf_s(ch, 256, "%lu", num);
|
||||
#endif
|
||||
return string(ch);}
|
||||
inline string ftos(const float num) {
|
||||
char ch[256];
|
||||
#ifndef CC_VC
|
||||
sprintf(ch, "%g", num);
|
||||
#else
|
||||
sprintf_s(ch, 256, "%g", num);
|
||||
#endif
|
||||
return string(ch);}
|
||||
inline string dtos(const double num) {
|
||||
char ch[256];
|
||||
#ifndef CC_VC
|
||||
sprintf(ch, "%g", num);
|
||||
#else
|
||||
sprintf_s(ch, 256, "%g", num);
|
||||
#endif
|
||||
return string(ch);}
|
||||
|
||||
/*! \fn errorString()
|
||||
* \brief Return readable error description in format "code <number> - <description>" */
|
||||
#ifdef WINDOWS
|
||||
inline void errorClear() {SetLastError(0);}
|
||||
inline string errorString() {
|
||||
char * msg;
|
||||
int err = GetLastError();
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&msg, 0, NULL);
|
||||
return "code " + itos(err) + " - " + string(msg);
|
||||
}
|
||||
#else
|
||||
inline void errorClear() {errno = 0;}
|
||||
inline string errorString() {int e = errno; return "code " + itos(e) + " - " + string(strerror(e));}
|
||||
#endif
|
||||
|
||||
/// Return readable version of PIP
|
||||
inline string PIPVersion() {return itos(PIP_VERSION_MAJOR) + "." + itos(PIP_VERSION_MINOR) + "." + itos(PIP_VERSION_REVISION) + PIP_VERSION_SUFFIX;}
|
||||
|
||||
/*! \brief This class used as container for bit flags
|
||||
* \details PIFlags is wrapper around \c "int". There are many
|
||||
* bit-wise operators, native conversion to int and function
|
||||
* to test flag. \n Example:
|
||||
* \snippet piincludes.cpp flags
|
||||
*/
|
||||
template<typename Enum>
|
||||
class PIP_EXPORT PIFlags {
|
||||
public:
|
||||
//! Constructor with flags = 0
|
||||
PIFlags(): flags(0) {;}
|
||||
//! Constructor with flags = Enum "e"
|
||||
PIFlags(Enum e): flags(e) {;}
|
||||
//! Constructor with flags = PIFlags "f"
|
||||
PIFlags(const PIFlags & f): flags(f.flags) {;}
|
||||
//! Constructor with flags = int "i"
|
||||
PIFlags(const int i): flags(i) {;}
|
||||
//! Set flags "f" to value "on"
|
||||
PIFlags & setFlag(const PIFlags & f, bool on = true) {if (on) flags |= f.flags; else flags &= ~f.flags; return *this;}
|
||||
//! Set flag "e" to value "on"
|
||||
PIFlags & setFlag(const Enum & e, bool on = true) {if (on) flags |= e; else flags &= ~e; return *this;}
|
||||
//! Set flag "i" to value "on"
|
||||
PIFlags & setFlag(const int & i, bool on = true) {if (on) flags |= i; else flags &= ~i; return *this;}
|
||||
//! copy operator
|
||||
void operator =(const PIFlags & f) {flags = f.flags;}
|
||||
//! copy operator
|
||||
void operator =(const Enum & e) {flags = e;}
|
||||
//! copy operator
|
||||
void operator =(const int & i) {flags = i;}
|
||||
//! compare operator
|
||||
void operator ==(const PIFlags & f) {flags == f.flags;}
|
||||
//! compare operator
|
||||
void operator ==(const Enum & e) {flags == e;}
|
||||
//! compare operator
|
||||
void operator ==(const int i) {flags == i;}
|
||||
//! compare operator
|
||||
void operator !=(const PIFlags & f) {flags != f.flags;}
|
||||
//! compare operator
|
||||
void operator !=(const Enum & e) {flags != e;}
|
||||
//! compare operator
|
||||
void operator !=(const int i) {flags != i;}
|
||||
//! compare operator
|
||||
void operator >(const PIFlags & f) {flags > f.flags;}
|
||||
//! compare operator
|
||||
void operator >(const Enum & e) {flags > e;}
|
||||
//! compare operator
|
||||
void operator >(const int i) {flags > i;}
|
||||
//! compare operator
|
||||
void operator <(const PIFlags & f) {flags < f.flags;}
|
||||
//! compare operator
|
||||
void operator <(const Enum & e) {flags < e;}
|
||||
//! compare operator
|
||||
void operator <(const int i) {flags < i;}
|
||||
//! compare operator
|
||||
void operator >=(const PIFlags & f) {flags >= f.flags;}
|
||||
//! compare operator
|
||||
void operator >=(const Enum & e) {flags >= e;}
|
||||
//! compare operator
|
||||
void operator >=(const int i) {flags >= i;}
|
||||
//! compare operator
|
||||
void operator <=(const PIFlags & f) {flags <= f.flags;}
|
||||
//! compare operator
|
||||
void operator <=(const Enum & e) {flags <= e;}
|
||||
//! compare operator
|
||||
void operator <=(const int i) {flags <= i;}
|
||||
//! Bit-wise AND operator
|
||||
void operator &=(const PIFlags & f) {flags &= f.flags;}
|
||||
//! Bit-wise AND operator
|
||||
void operator &=(const Enum & e) {flags &= e;}
|
||||
//! Bit-wise AND operator
|
||||
void operator &=(const int i) {flags &= i;}
|
||||
//! Bit-wise OR operator
|
||||
void operator |=(const PIFlags & f) {flags |= f.flags;}
|
||||
//! Bit-wise OR operator
|
||||
void operator |=(const Enum & e) {flags |= e;}
|
||||
//! Bit-wise OR operator
|
||||
void operator |=(const int i) {flags |= i;}
|
||||
//! Bit-wise XOR operator
|
||||
void operator ^=(const PIFlags & f) {flags ^= f.flags;}
|
||||
//! Bit-wise XOR operator
|
||||
void operator ^=(const Enum & e) {flags ^= e;}
|
||||
//! Bit-wise XOR operator
|
||||
void operator ^=(const int i) {flags ^= i;}
|
||||
//! Bit-wise AND operator
|
||||
PIFlags operator &(PIFlags f) const {PIFlags tf(flags & f.flags); return tf;}
|
||||
//! Bit-wise AND operator
|
||||
PIFlags operator &(Enum e) const {PIFlags tf(flags & e); return tf;}
|
||||
//! Bit-wise AND operator
|
||||
PIFlags operator &(int i) const {PIFlags tf(flags & i); return tf;}
|
||||
//! Bit-wise OR operator
|
||||
PIFlags operator |(PIFlags f) const {PIFlags tf(flags | f.flags); return tf;}
|
||||
//! Bit-wise OR operator
|
||||
PIFlags operator |(Enum e) const {PIFlags tf(flags | e); return tf;}
|
||||
//! Bit-wise OR operator
|
||||
PIFlags operator |(int i) const {PIFlags tf(flags | i); return tf;}
|
||||
//! Bit-wise XOR operator
|
||||
PIFlags operator ^(PIFlags f) const {PIFlags tf(flags ^ f.flags); return tf;}
|
||||
//! Bit-wise XOR operator
|
||||
PIFlags operator ^(Enum e) const {PIFlags tf(flags ^ e); return tf;}
|
||||
//! Bit-wise XOR operator
|
||||
PIFlags operator ^(int i) const {PIFlags tf(flags ^ i); return tf;}
|
||||
//! Test flag operator
|
||||
bool operator [](Enum e) const {return (flags & e) == e;}
|
||||
//! Implicity conversion to \c int
|
||||
operator int() const {return flags;}
|
||||
private:
|
||||
int flags;
|
||||
};
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
//! \brief Macro used for conditional (piDebug) output to PICout
|
||||
# define piCout
|
||||
|
||||
//! \relatesalso PIObject \brief Macro used for conditional (piDebug and PIObject::debug()) output to PICout for subclasses of PIObject
|
||||
# define piCoutObj
|
||||
|
||||
#else
|
||||
# define piCout if (piDebug) PICout()
|
||||
# define piCoutObj if (piDebug && debug()) PICout() << "" << (PIString("[") + className() + " \"" + name() + "\"]")
|
||||
#endif
|
||||
|
||||
class PIObject;
|
||||
class PIMutex;
|
||||
class PIString;
|
||||
|
||||
extern PIMutex __PICout_mutex__;
|
||||
extern PIString __PICout_string__;
|
||||
|
||||
//! \brief Namespace contains enums controlled PICout
|
||||
namespace PICoutManipulators {
|
||||
|
||||
//! \brief Enum contains special characters
|
||||
enum PIP_EXPORT PICoutSpecialChar {
|
||||
Null /*! Null-character, '\\0' */,
|
||||
NewLine /*! New line character, '\\n' */,
|
||||
Tab /*! Tab character, '\\t' */,
|
||||
Esc /*! Escape character, '\\e' */,
|
||||
Quote /*! Quote character, '"' */
|
||||
};
|
||||
|
||||
//! \brief Enum contains immediate action
|
||||
enum PIP_EXPORT PICoutAction {
|
||||
Flush /*! Flush the output */,
|
||||
Backspace /*! Remove last symbol */,
|
||||
ShowCursor /*! Show cursor */,
|
||||
HideCursor /*! Hide cursor */,
|
||||
ClearScreen /*! Clear the screen */,
|
||||
SaveContol /*! Save control flags, equivalent to \a saveControl() */,
|
||||
RestoreControl /*! Restore control flags, equivalent to \a restoreControl() */
|
||||
};
|
||||
|
||||
//! \brief Enum contains control of PICout
|
||||
enum PIP_EXPORT PICoutControl {
|
||||
AddNone /*! No controls */ = 0x0,
|
||||
AddSpaces /*! Spaces will be appear after each output */ = 0x1,
|
||||
AddNewLine /*! New line will be appear after all output */ = 0x2,
|
||||
AddQuotes /*! Each string will be quoted */ = 0x4,
|
||||
AddAll /*! All controls */ = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
//! \brief Enum contains output format
|
||||
enum PIP_EXPORT PICoutFormat {
|
||||
Bin /*! Binary representation of integers */ = 0x01,
|
||||
Oct /*! Octal representation of integers */ = 0x02,
|
||||
Dec /*! Decimal representation of integers */ = 0x04,
|
||||
Hex /*! Hexadecimal representation of integers */ = 0x08,
|
||||
Bold /*! Bold */ = 0x10,
|
||||
Faint /*! */ = 0x20,
|
||||
Italic /*! */ = 0x40,
|
||||
Underline /*! Underline */ = 0x80,
|
||||
Blink /*! Blink */ = 0x100,
|
||||
Black /*! Black font */ = 0x400,
|
||||
Red /*! Red font */ = 0x800,
|
||||
Green /*! Green font */ = 0x1000,
|
||||
Blue /*! Blue font */ = 0x2000,
|
||||
Yellow /*! Yellow font */ = 0x4000,
|
||||
Magenta /*! Magenta font */ = 0x8000,
|
||||
Cyan /*! Cyan font */ = 0x10000,
|
||||
White /*! White font */ = 0x20000,
|
||||
BackBlack /*! Black background */ = 0x40000,
|
||||
BackRed /*! Red background */ = 0x80000,
|
||||
BackGreen /*! Green background */ = 0x100000,
|
||||
BackBlue /*! Blue background */ = 0x200000,
|
||||
BackYellow /*! Yellow background */ = 0x400000,
|
||||
BackMagenta /*! Magenta background */ = 0x800000,
|
||||
BackCyan /*! Cyan background */ = 0x1000000,
|
||||
BackWhite /*! White background */ = 0x2000000,
|
||||
Default /*! Default format */ = 0x4000000
|
||||
};
|
||||
};
|
||||
|
||||
using namespace PICoutManipulators;
|
||||
|
||||
typedef PIFlags<PICoutControl> PICoutControls;
|
||||
|
||||
class PIP_EXPORT PICout {
|
||||
public:
|
||||
//! Default constructor with default features (AddSpaces and AddNewLine)
|
||||
PICout(PIFlags<PICoutControl> controls = AddSpaces | AddNewLine);
|
||||
|
||||
PICout(const PICout & other): fo_(other.fo_), cc_(true), fc_(false), cnb_(other.cnb_), attr_(other.attr_), co_(other.co_) {;}
|
||||
~PICout();
|
||||
|
||||
//! Output operator for strings with <tt>"const char * "</tt> type
|
||||
PICout operator <<(const char * v);
|
||||
|
||||
//! Output operator for strings with <tt>"std::string"</tt> type
|
||||
PICout operator <<(const string & v);
|
||||
|
||||
//! Output operator for boolean values
|
||||
PICout operator <<(const bool v);
|
||||
|
||||
//! Output operator for <tt>"char"</tt> values
|
||||
PICout operator <<(const char v);
|
||||
|
||||
//! Output operator for <tt>"unsigned char"</tt> values
|
||||
PICout operator <<(const uchar v);
|
||||
|
||||
//! Output operator for <tt>"short"</tt> values
|
||||
PICout operator <<(const short v);
|
||||
|
||||
//! Output operator for <tt>"unsigned short"</tt> values
|
||||
PICout operator <<(const ushort v);
|
||||
|
||||
//! Output operator for <tt>"int"</tt> values
|
||||
PICout operator <<(const int v);
|
||||
|
||||
//! Output operator for <tt>"unsigned int"</tt> values
|
||||
PICout operator <<(const uint v);
|
||||
|
||||
//! Output operator for <tt>"long"</tt> values
|
||||
PICout operator <<(const long v);
|
||||
|
||||
//! Output operator for <tt>"unsigned long"</tt> values
|
||||
PICout operator <<(const ulong v);
|
||||
|
||||
//! Output operator for <tt>"long long"</tt> values
|
||||
PICout operator <<(const llong v);
|
||||
|
||||
//! Output operator for <tt>"unsigned long long"</tt> values
|
||||
PICout operator <<(const ullong v);
|
||||
|
||||
//! Output operator for <tt>"float"</tt> values
|
||||
PICout operator <<(const float v);
|
||||
|
||||
//! Output operator for <tt>"double"</tt> values
|
||||
PICout operator <<(const double v);
|
||||
|
||||
//! Output operator for pointers
|
||||
PICout operator <<(const void * v);
|
||||
|
||||
//! Output operator for PIObject and ancestors
|
||||
PICout operator <<(const PIObject * v);
|
||||
|
||||
//! Output operator for \a PICoutSpecialChar values
|
||||
PICout operator <<(const PICoutSpecialChar v);
|
||||
|
||||
//! Output operator for \a PIFlags<PICoutFormat> values
|
||||
PICout operator <<(const PIFlags<PICoutFormat> v) {
|
||||
if (v[Bin]) cnb_ = 2;
|
||||
if (v[Oct]) cnb_ = 8;
|
||||
if (v[Dec]) cnb_ = 10;
|
||||
if (v[Hex]) cnb_ = 16;
|
||||
if (v[Bold]) applyFormat(Bold);
|
||||
if (v[Faint]) applyFormat(Faint);
|
||||
if (v[Italic]) applyFormat(Italic);
|
||||
if (v[Underline]) applyFormat(Underline);
|
||||
if (v[Blink]) applyFormat(Blink);
|
||||
if (v[Black]) applyFormat(Black);
|
||||
if (v[Red]) applyFormat(Red);
|
||||
if (v[Green]) applyFormat(Green);
|
||||
if (v[Blue]) applyFormat(Blue);
|
||||
if (v[Yellow]) applyFormat(Yellow);
|
||||
if (v[Magenta]) applyFormat(Magenta);
|
||||
if (v[Cyan]) applyFormat(Cyan);
|
||||
if (v[White]) applyFormat(White);
|
||||
if (v[BackBlack]) applyFormat(BackBlack);
|
||||
if (v[BackRed]) applyFormat(BackRed);
|
||||
if (v[BackGreen]) applyFormat(BackGreen);
|
||||
if (v[BackBlue]) applyFormat(BackBlue);
|
||||
if (v[BackYellow]) applyFormat(BackYellow);
|
||||
if (v[BackMagenta]) applyFormat(BackMagenta);
|
||||
if (v[BackCyan]) applyFormat(BackCyan);
|
||||
if (v[BackWhite]) applyFormat(BackWhite);
|
||||
if (v[Default]) applyFormat(Default);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Output operator for \a PICoutFormat values
|
||||
PICout operator <<(const PICoutFormat v) {
|
||||
switch (v) {
|
||||
case Bin: cnb_ = 2; break;
|
||||
case Oct: cnb_ = 8; break;
|
||||
case Dec: cnb_ = 10; break;
|
||||
case Hex: cnb_ = 16; break;
|
||||
default: applyFormat(v);
|
||||
};
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Do some action
|
||||
PICout operator <<(const PICoutAction v);
|
||||
|
||||
//! Set control flag "c" is "on" state
|
||||
PICout & setControl(PICoutControl c, bool on = true) {co_.setFlag(c, on); return *this;}
|
||||
|
||||
//! Set control flags "c" and if "save" exec \a saveControl()
|
||||
PICout & setControl(PICoutControls c, bool save = false) {if (save) saveControl(); co_ = c; return *this;}
|
||||
|
||||
//! Save control flags to internal stack \sa \a restoreControl()
|
||||
PICout & saveControl() {cos_.push(co_); return *this;}
|
||||
|
||||
//! Restore control flags from internal stack \sa \a saveControl()
|
||||
PICout & restoreControl() {if (!cos_.empty()) {co_ = cos_.top(); cos_.pop();} return *this;}
|
||||
|
||||
/*! \brief Conditional put space character to output
|
||||
* \details If it is not a first output and control \a AddSpaces is set
|
||||
* space character is put \sa \a quote(), \a newLine() */
|
||||
PICout & space();
|
||||
|
||||
/*! \brief Conditional put quote character to output
|
||||
* \details If control \a AddQuotes is set
|
||||
* quote character is put \sa \a space(), \a newLine() */
|
||||
PICout & quote();
|
||||
|
||||
/*! \brief Conditional put new line character to output
|
||||
* \details If control \a AddNewLine is set
|
||||
* new line character is put \sa \a space(), \a quote() */
|
||||
PICout & newLine();
|
||||
|
||||
static bool setBufferActive(bool on, bool clear = false);
|
||||
static bool isBufferActive();
|
||||
static PIString buffer(bool clear = false);
|
||||
static void clearBuffer();
|
||||
|
||||
private:
|
||||
void applyFormat(PICoutFormat f);
|
||||
|
||||
static bool buffer_;
|
||||
bool fo_, cc_, fc_;
|
||||
int cnb_, attr_;
|
||||
PICoutControls co_;
|
||||
std::stack<PICoutControls> cos_;
|
||||
#ifdef WINDOWS
|
||||
static void * hOut;
|
||||
static WORD dattr;
|
||||
static DWORD smode;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // PIINCLUDES_H
|
||||
292
piiodevice.cpp
292
piiodevice.cpp
@@ -1,292 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Abstract input/output device
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piiodevice.h"
|
||||
#include "piconfig.h"
|
||||
|
||||
|
||||
/*! \class PIIODevice
|
||||
* \brief Base class for input/output classes
|
||||
*
|
||||
* \section PIIODevice_sec0 Synopsis
|
||||
* This class provide open/close logic, threaded read/write and virtual input/output
|
||||
* functions \a read() and \a write(). You should implement pure virtual
|
||||
* function \a openDevice() in your subclass.
|
||||
*
|
||||
* \section PIIODevice_sec1 Open and close
|
||||
* PIIODevice have boolean variable indicated open status. Returns of functions
|
||||
* \a openDevice() and \a closeDevice() change this variable.
|
||||
*
|
||||
* \section PIIODevice_sec2 Threaded read
|
||||
* PIIODevice based on PIThread, so it`s overload \a run() to exec \a read()
|
||||
* in background thread. If read is successful virtual function \a threadedRead()
|
||||
* is executed. Default implementation of this function execute external static
|
||||
* function set by \a setThreadedReadSlot() with data set by \a setThreadedReadData().
|
||||
* Extrenal static function should have format \n
|
||||
* bool func_name(void * Threaded_read_data, uchar * readed_data, int readed_size)\n
|
||||
* Threaded read starts with function \a startThreadedRead().
|
||||
*
|
||||
* \section PIIODevice_sec3 Threaded write
|
||||
* PIIODevice aggregate another PIThread to perform a threaded write by function
|
||||
* \a writeThreaded(). This function add task to internal queue and return
|
||||
* queue entry ID. You should start write thread by function \a startThreadedWrite.
|
||||
* On successful write event \a threadedWriteEvent is raised with two arguments -
|
||||
* task ID and written bytes count.
|
||||
*
|
||||
* \section PIIODevice_sec4 Internal buffer
|
||||
* PIIODevice have internal buffer for threaded read, and \a threadedRead() function
|
||||
* receive pointer to this buffer in first argument. You can adjust size of this buffer
|
||||
* by function \a setThreadedReadBufferSize() \n
|
||||
* Default size of this buffer is 4096 bytes.
|
||||
*
|
||||
* \section PIIODevice_sec5 Reopen
|
||||
* When threaded read is begin its call \a open() if device is closed. While threaded
|
||||
* read running PIIODevice check if device opened every read and if not call \a open()
|
||||
* every reopen timeout if reopen enabled. Reopen timeout is set by \a setReopenTimeout(),
|
||||
* reopen enable is set by \a setReopenEnabled().
|
||||
*
|
||||
* \section PIIODevice_sec6 Configuration
|
||||
* This is virtual function \a configureDevice() which executes when \a configure()
|
||||
* executes. This function takes two arguments: "e_main" and "e_parent" as void*. There
|
||||
* are pointers to PIConfig::Entry entries of section "section" and their parent. If
|
||||
* there is no parent "e_parent" = 0. Function \a configure() set three parameters of
|
||||
* device: "reopenEnabled", "reopenTimeout" and "threadedReadBufferSize", then execute
|
||||
* function \a configureDevice().
|
||||
* \n Each ancestor of %PIIODevice reimlements \a configureDevice() function to be able
|
||||
* to be confured from configuration file. This parameters described at section
|
||||
* "Configurable parameters" in the class reference. \n Usage example:
|
||||
* \snippet piiodevice.cpp configure
|
||||
* Implementation example:
|
||||
* \snippet piiodevice.cpp configureDevice
|
||||
*
|
||||
* \section PIIODevice_sec7 Creating devices by unambiguous string
|
||||
* There are some virtual functions to describe child class without its declaration.
|
||||
* \n \a fullPathPrefix() should returns unique prefix of device
|
||||
* \n \a constructFullPath() should returns full unambiguous string, contains prefix and all device parameters
|
||||
* \n \a configureFromFullPath() provide configuring device from full unambiguous string without prefix and "://"
|
||||
* \n Macro PIIODEVICE should be used instead of PIOBJECT
|
||||
* \n Macro REGISTER_DEVICE should be used after definition of class, i.e. at the last line of *.cpp file
|
||||
* \n \n If custom I/O device corresponds there rules, it can be returned by function \a createFromFullPath().
|
||||
* \n Each PIP I/O device has custom unambiguous string description:
|
||||
* * PIFile: "file://<path>"
|
||||
* * PIBinaryLog: "binlog://<logDir>[:<filePrefix>][:<defaultID>]"
|
||||
* * PISerial: "ser://<device>:<speed(50|...|115200)>[:<dataBitsCount(6|7|8)>][:<parity(N|E|O)>][:<stopBits(1|2)>]"
|
||||
* * PIEthernet: "eth://<type(UDP|TCP)>:<readIP>:<readPort>[:<multicast(mcast:<ip>)>]"
|
||||
* * PIUSB: "usb://<vid>:<pid>[:<deviceNumber>][:<readEndpointNumber>][:<writeEndpointNumber>]"
|
||||
* \n \n Examples:
|
||||
* * PIFile: "file://../text.txt"
|
||||
* * PIBinaryLog: "binlog://../logs/:mylog_:1"
|
||||
* * PISerial: "ser:///dev/ttyUSB0:9600:8:N:1", equivalent "ser:///dev/ttyUSB0:9600"
|
||||
* * PIEthernet: "eth://TCP:127.0.0.1:16666", "eth://UDP:192.168.0.5:16666:mcast:234.0.2.1:mcast:234.0.2.2"
|
||||
* * PIUSB: "usb://0bb4:0c86:1:1:2"
|
||||
* \n \n
|
||||
* So, custom I/O device can be created with next call:
|
||||
* \code{cpp}
|
||||
* // creatring devices
|
||||
* PISerial * ser = (PISerial * )PIIODevice::createFromFullPath("ser://COM1:115200");
|
||||
* PIEthernet * eth = (PIEthernet * )PIIODevice::createFromFullPath("eth://UDP:127.0.0.1:4001");
|
||||
* // examine devices
|
||||
* piCout << ser << ser->properties();
|
||||
* piCout << eth << eth->properties();
|
||||
* \endcode
|
||||
*
|
||||
* \section PIIODevice_ex0 Example
|
||||
* \snippet piiodevice.cpp 0
|
||||
*/
|
||||
|
||||
|
||||
PIIODevice::PIIODevice(): PIThread() {
|
||||
mode_ = ReadOnly;
|
||||
_init();
|
||||
setPath(PIString());
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Constructs a PIIODevice with path and mode
|
||||
* \param path path to device
|
||||
* \param type mode for open */
|
||||
PIIODevice::PIIODevice(const PIString & path, PIIODevice::DeviceMode mode): PIThread() {
|
||||
mode_ = mode;
|
||||
_init();
|
||||
setPath(path);
|
||||
}
|
||||
|
||||
|
||||
PIIODevice::~PIIODevice() {
|
||||
stop();
|
||||
if (opened_) {
|
||||
closeDevice();
|
||||
if (!opened_)
|
||||
closed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIIODevice::_init() {
|
||||
opened_ = init_ = thread_started_ = false;
|
||||
raise_threaded_read_ = true;
|
||||
ret_func_ = 0;
|
||||
ret_data_ = 0;
|
||||
tri = 0;
|
||||
setReopenEnabled(true);
|
||||
setReopenTimeout(1000);
|
||||
setThreadedReadBufferSize(4096);
|
||||
CONNECT2(void, void * , int, &timer, timeout, this, check_start);
|
||||
CONNECT(void, &write_thread, started, this, write_func);
|
||||
}
|
||||
|
||||
|
||||
void PIIODevice::check_start(void * data, int delim) {
|
||||
//cout << "check " << tread_started_ << endl;
|
||||
if (open()) {
|
||||
thread_started_ = true;
|
||||
timer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIIODevice::write_func() {
|
||||
while (!write_thread.isStopping()) {
|
||||
while (!write_queue.isEmpty()) {
|
||||
if (write_thread.isStopping()) return;
|
||||
write_thread.lock();
|
||||
PIPair<PIByteArray, ullong> item(write_queue.dequeue());
|
||||
write_thread.unlock();
|
||||
int ret = write(item.first);
|
||||
threadedWriteEvent(item.second, ret);
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIIODevice::terminate() {
|
||||
thread_started_ = false;
|
||||
if (!isInitialized()) return;
|
||||
if (isRunning()) {
|
||||
stop();
|
||||
PIThread::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIIODevice::begin() {
|
||||
//cout << " begin\n";
|
||||
thread_started_ = false;
|
||||
if (!opened_) {
|
||||
if (open()) {
|
||||
thread_started_ = true;
|
||||
//cout << " open && ok\n";
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
thread_started_ = true;
|
||||
//cout << " ok\n";
|
||||
return;
|
||||
}
|
||||
//init();
|
||||
if (!timer.isRunning() && isReopenEnabled()) timer.start(reopenTimeout());
|
||||
}
|
||||
|
||||
|
||||
void PIIODevice::run() {
|
||||
if (!isReadable()) {
|
||||
//cout << "not readable\n";
|
||||
PIThread::stop();
|
||||
return;
|
||||
}
|
||||
if (!thread_started_) {
|
||||
msleep(1);
|
||||
//cout << "not started\n";
|
||||
return;
|
||||
}
|
||||
readed_ = read(buffer_tr.data(), buffer_tr.size_s());
|
||||
if (readed_ <= 0) {
|
||||
msleep(10);
|
||||
//cout << readed_ << ", " << errno << ", " << errorString() << endl;
|
||||
return;
|
||||
}
|
||||
threadedRead(buffer_tr.data(), readed_);
|
||||
if (raise_threaded_read_) threadedReadEvent(buffer_tr.data(), readed_);
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIIODevice::readForTime(double timeout_ms) {
|
||||
PIByteArray str;
|
||||
if (timeout_ms <= 0.) return str;
|
||||
int ret;
|
||||
uchar * td = new uchar[threadedReadBufferSize()];
|
||||
timer.reset();
|
||||
while (timer.elapsed_m() < timeout_ms) {
|
||||
ret = read(td, threadedReadBufferSize());
|
||||
if (ret <= 0) msleep(1);
|
||||
else str.append(td, ret);
|
||||
}
|
||||
delete td;
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
ullong PIIODevice::writeThreaded(const PIByteArray & data) {
|
||||
write_thread.lock();
|
||||
write_queue.enqueue(PIPair<PIByteArray, ullong>(data, tri));
|
||||
++tri;
|
||||
write_thread.unlock();
|
||||
return tri - 1;
|
||||
}
|
||||
|
||||
|
||||
bool PIIODevice::configure(const PIString & config_file, const PIString & section, bool parent_section) {
|
||||
PIConfig conf(config_file, PIIODevice::ReadOnly);
|
||||
if (!conf.isOpened()) return false;
|
||||
bool ex = true;
|
||||
PIConfig::Entry em;
|
||||
if (section.isEmpty()) em = conf.rootEntry();
|
||||
else em = conf.getValue(section, PIString(), &ex);
|
||||
if (!ex) return false;
|
||||
PIConfig::Entry * ep = 0;
|
||||
if (parent_section) ep = em.parent();
|
||||
if (ep != 0) {
|
||||
setReopenEnabled(ep->getValue("reopenEnabled", isReopenEnabled(), &ex));
|
||||
if (!ex) setReopenEnabled(em.getValue("reopenEnabled", isReopenEnabled()));
|
||||
setReopenTimeout(ep->getValue("reopenTimeout", reopenTimeout(), &ex));
|
||||
if (!ex) setReopenTimeout(em.getValue("reopenTimeout", reopenTimeout()));
|
||||
setThreadedReadBufferSize(ep->getValue("threadedReadBufferSize", buffer_tr.size_s(), &ex));
|
||||
if (!ex) setThreadedReadBufferSize(em.getValue("threadedReadBufferSize", buffer_tr.size_s()));
|
||||
} else {
|
||||
setReopenEnabled(em.getValue("reopenEnabled", isReopenEnabled()));
|
||||
setReopenTimeout(em.getValue("reopenTimeout", reopenTimeout()));
|
||||
setThreadedReadBufferSize(em.getValue("threadedReadBufferSize", buffer_tr.size_s()));
|
||||
}
|
||||
return configureDevice(&em, ep);
|
||||
}
|
||||
|
||||
|
||||
PIIODevice * PIIODevice::createFromFullPath(const PIString & full_path) {
|
||||
PIString prefix = full_path.left(full_path.find(":"));
|
||||
if (prefix.isEmpty()) return 0;
|
||||
PIVector<const PIObject * > rd(PICollection::groupElements("__PIIODevices__"));
|
||||
piForeachC (PIObject * d, rd)
|
||||
if (prefix == ((const PIIODevice * )d)->fullPathPrefix()) {
|
||||
PIIODevice * nd = ((const PIIODevice * )d)->copy();
|
||||
if (nd) nd->configureFromFullPath(full_path.mid(prefix.length() + 3));
|
||||
return nd;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
329
piiodevice.h
329
piiodevice.h
@@ -1,329 +0,0 @@
|
||||
/*! \file piiodevice.h
|
||||
* \brief Abstract input/output device
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Abstract input/output device
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIIODEVICE_H
|
||||
#define PIIODEVICE_H
|
||||
|
||||
#include "picollection.h"
|
||||
#include "pivariant.h"
|
||||
#include "pitimer.h"
|
||||
|
||||
// function executed from threaded read, pass ThreadedReadData, readedData, sizeOfData
|
||||
typedef bool (*ReadRetFunc)(void * , uchar * , int );
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
//! \relatesalso PIIODevice \brief Use this macro to enable automatic creation instances of your class with \a createFromFullPath() function
|
||||
# define REGISTER_DEVICE(class)
|
||||
|
||||
//! \relatesalso PIIODevice \brief Use this macro instead of PIOBJECT when describe your own PIIODevice
|
||||
# define PIIODEVICE(class)
|
||||
|
||||
#else
|
||||
|
||||
# define REGISTER_DEVICE(class) ADD_NEW_TO_COLLECTION(__PIIODevices__, class)
|
||||
# define PIIODEVICE(class) PIOBJECT(class) PIIODevice * copy() const {return new class();}
|
||||
|
||||
#endif
|
||||
|
||||
class PIP_EXPORT PIIODevice: public PIThread
|
||||
{
|
||||
PIOBJECT(PIIODevice)
|
||||
public:
|
||||
|
||||
//! Constructs a empty PIIODevice
|
||||
PIIODevice();
|
||||
|
||||
//! \brief Open modes for PIIODevice
|
||||
enum DeviceMode {
|
||||
ReadOnly /*! Device can only read */ = 0x01,
|
||||
WriteOnly /*! Device can only write */ = 0x02,
|
||||
ReadWrite /*! Device can both read and write */ = 0x03
|
||||
};
|
||||
|
||||
PIIODevice(const PIString & path, DeviceMode mode = ReadWrite);
|
||||
virtual ~PIIODevice();
|
||||
|
||||
//! Current open mode of device
|
||||
DeviceMode mode() const {return mode_;}
|
||||
|
||||
//! Current path of device
|
||||
PIString path() const {return property("path").toString();}
|
||||
|
||||
//! Set path of device
|
||||
void setPath(const PIString & path) {setProperty("path", path);}
|
||||
|
||||
//! Return \b true if mode is ReadOnly or ReadWrite
|
||||
bool isReadable() const {return (mode_ & ReadOnly);}
|
||||
|
||||
//! Return \b true if mode is WriteOnly or ReadWrite
|
||||
bool isWriteable() const {return (mode_ & WriteOnly);}
|
||||
|
||||
bool isInitialized() const {return init_;}
|
||||
|
||||
//! Return \b true if device is successfully opened
|
||||
bool isOpened() const {return opened_;}
|
||||
|
||||
//! Return \b true if device is closed
|
||||
bool isClosed() const {return !opened_;}
|
||||
|
||||
//! Return \b true if device can read \b now
|
||||
bool canRead() const {return opened_ && (mode_ & ReadOnly);}
|
||||
|
||||
//! Return \b true if device can write \b now
|
||||
bool canWrite() const {return opened_ && (mode_ & WriteOnly);}
|
||||
|
||||
|
||||
//! Set execution of \a open enabled while threaded read on closed device
|
||||
void setReopenEnabled(bool yes = true) {setProperty("reopenEnabled", yes);}
|
||||
|
||||
//! Set timeout in milliseconds between \a open tryings if reopen is enabled
|
||||
void setReopenTimeout(int msecs) {setProperty("reopenTimeout", msecs);}
|
||||
|
||||
|
||||
//! Return reopen enable
|
||||
bool isReopenEnabled() const {return property("reopenEnabled").toBool();}
|
||||
|
||||
//! Return reopen timeout
|
||||
int reopenTimeout() {return property("reopenTimeout").toInt();}
|
||||
|
||||
|
||||
/** \brief Set "threaded read slot"
|
||||
* \details Set external static function of threaded read that will be executed
|
||||
* at every successful threaded read. Function should have format
|
||||
* "bool func(void * data, uchar * readed, int size)" */
|
||||
void setThreadedReadSlot(ReadRetFunc func) {ret_func_ = func;}
|
||||
|
||||
//! Set custom data that will be passed to "threaded read slot"
|
||||
void setThreadedReadData(void * d) {ret_data_ = d;}
|
||||
|
||||
/** \brief Set size of threaded read buffer
|
||||
* \details Default size is 4096 bytes. If your device can read at single read
|
||||
* more than 4096 bytes you should use this function to adjust buffer size */
|
||||
void setThreadedReadBufferSize(int new_size) {buffer_tr.resize(new_size);}
|
||||
|
||||
//! Return size of threaded read buffer
|
||||
int threadedReadBufferSize() const {return buffer_tr.size_s();}
|
||||
|
||||
//! Return content of threaded read buffer
|
||||
const uchar * threadedReadBuffer() const {return buffer_tr.data();}
|
||||
|
||||
//! Return custom data that will be passed to "threaded read slot"
|
||||
void * threadedReadData() const {return ret_data_;}
|
||||
|
||||
|
||||
//! Return \b true if threaded read is started
|
||||
bool isThreadedRead() const {return isRunning();}
|
||||
|
||||
//! Start threaded read
|
||||
void startThreadedRead() {if (!isRunning()) PIThread::start();}
|
||||
|
||||
//! Start threaded read and assign "threaded read slot" to "func"
|
||||
void startThreadedRead(ReadRetFunc func) {ret_func_ = func; if (!isRunning()) PIThread::start();}
|
||||
|
||||
//! Stop threaded read
|
||||
void stopThreadedRead() {PIThread::terminate();}
|
||||
|
||||
|
||||
//! Return \b true if threaded write is started
|
||||
bool isThreadedWrite() const {return write_thread.isRunning();}
|
||||
|
||||
//! Start threaded write
|
||||
void startThreadedWrite() {if (!write_thread.isRunning()) write_thread.startOnce();}
|
||||
|
||||
//! Stop threaded write
|
||||
void stopThreadedWrite() {write_thread.terminate();}
|
||||
|
||||
//! Clear threaded write task queue
|
||||
void clearThreadedWriteQueue() {write_thread.lock(); write_queue.clear(); write_thread.unlock();}
|
||||
|
||||
|
||||
//! Start both threaded read and threaded write
|
||||
void start() {startThreadedRead(); startThreadedWrite();}
|
||||
|
||||
//! Stop both threaded read and threaded write and if "wait" block until both threads are stop
|
||||
void stop(bool wait = false) {stopThreadedRead(); stopThreadedWrite(); if (wait) while (write_thread.isRunning() || isRunning()) msleep(1);}
|
||||
|
||||
|
||||
//! Reimplement this function to read from your device
|
||||
virtual int read(void * read_to, int max_size) {piCoutObj << "\"read\" is not implemented!"; return -2;}
|
||||
|
||||
//! Reimplement this function to write to your device
|
||||
virtual int write(const void * data, int max_size) {piCoutObj << "\"write\" is not implemented!"; return -2;}
|
||||
|
||||
|
||||
//! Read from device maximum "max_size" bytes and return them as PIByteArray
|
||||
PIByteArray read(int max_size) {buffer_in.resize(max_size); int ret = read(buffer_in.data(), max_size); if (ret < 0) return PIByteArray(); return buffer_in.resized(ret);}
|
||||
|
||||
//! Read from device for "timeout_ms" milliseconds and return readed data as PIByteArray. Timeout should to be greater than 0
|
||||
PIByteArray readForTime(double timeout_ms);
|
||||
|
||||
//! Write "data" to device
|
||||
int write(const PIByteArray & data) {return write(data.data(), data.size_s());}
|
||||
|
||||
|
||||
//! Add task to threaded write queue and return task ID
|
||||
ullong writeThreaded(const void * data, int max_size) {return writeThreaded(PIByteArray(data, uint(max_size)));}
|
||||
|
||||
//! Add task to threaded write queue and return task ID
|
||||
ullong writeThreaded(const PIByteArray & data);
|
||||
|
||||
|
||||
//! Configure device from section "section" of file "config_file", if "parent_section" parent section also will be read
|
||||
bool configure(const PIString & config_file, const PIString & section, bool parent_section = false);
|
||||
|
||||
|
||||
//! Reimplement to construct full unambiguous string, describes this device, default returns \a path()
|
||||
virtual PIString constructFullPath() const {return path();}
|
||||
|
||||
//! \brief Try to determine suitable device, create new one, configure it with \a configureFromFullPath() and returns it.
|
||||
//! \details To function \a configureFromFullPath() "full_path" passed without \a fullPathPrefix() + "://".
|
||||
//! See \ref PIIODevice_sec7
|
||||
static PIIODevice * createFromFullPath(const PIString & full_path);
|
||||
|
||||
|
||||
EVENT_HANDLER(bool, open) {if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;}
|
||||
EVENT_HANDLER1(bool, open, const PIString &, _path) {setPath(_path); if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;}
|
||||
EVENT_HANDLER1(bool, open, const DeviceMode &, _mode) {mode_ = _mode; if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;}
|
||||
EVENT_HANDLER2(bool, open, const PIString &, _path, const DeviceMode &, _mode) {setPath(_path); mode_ = _mode; if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;}
|
||||
EVENT_HANDLER(bool, close) {opened_ = !closeDevice(); if (!opened_) closed(); return !opened_;}
|
||||
EVENT_HANDLER(bool, initialize) {init_ = init(); return init_;}
|
||||
|
||||
EVENT_VHANDLER(void, flush) {;}
|
||||
|
||||
EVENT(opened)
|
||||
EVENT(closed)
|
||||
EVENT2(threadedReadEvent, uchar * , readed, int, size)
|
||||
EVENT2(threadedWriteEvent, ullong, id, int, written_size)
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn bool open()
|
||||
//! \brief Open device
|
||||
|
||||
//! \fn bool open(const PIString & path)
|
||||
//! \brief Open device with path "path"
|
||||
|
||||
//! \fn bool open(const DeviceMode & mode)
|
||||
//! \brief Open device with mode "mode"
|
||||
|
||||
//! \fn bool open(const PIString & path, const DeviceMode & mode)
|
||||
//! \brief Open device with path "path" and mode "mode"
|
||||
|
||||
//! \fn bool close()
|
||||
//! \brief Close device
|
||||
|
||||
//! \fn bool initialize()
|
||||
//! \brief Initialize device
|
||||
|
||||
//! \}
|
||||
//! \vhandlers
|
||||
//! \{
|
||||
|
||||
//! \fn void flush()
|
||||
//! \brief Immediate write all buffers
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void opened()
|
||||
//! \brief Raise if succesfull open
|
||||
|
||||
//! \fn void closed()
|
||||
//! \brief Raise if succesfull close
|
||||
|
||||
//! \fn void threadedReadEvent(uchar * readed, int size)
|
||||
//! \brief Raise if read thread succesfull read some data
|
||||
|
||||
//! \fn void threadedWriteEvent(ullong id, int written_size)
|
||||
//! \brief Raise if write thread succesfull write some data of task with ID "id"
|
||||
|
||||
//! \}
|
||||
//! \ioparams
|
||||
//! \{
|
||||
#ifdef DOXYGEN
|
||||
//! \brief setReopenEnabled, default "true"
|
||||
bool reopenEnabled;
|
||||
|
||||
//! \brief setReopenTimeout in ms, default 1000
|
||||
int reopenTimeout;
|
||||
|
||||
//! \brief setThreadedReadBufferSize in bytes, default 4096
|
||||
int threadedReadBufferSize;
|
||||
#endif
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
|
||||
//! Function executed before first \a openDevice() or from constructor
|
||||
virtual bool init() {return true;}
|
||||
|
||||
//! Reimplement to configure device from entries "e_main" and "e_parent", cast arguments to \a PIConfig::Entry*
|
||||
virtual bool configureDevice(const void * e_main, const void * e_parent = 0) {return true;}
|
||||
|
||||
//! Reimplement to open device, return value will be set to "opened_" variable
|
||||
virtual bool openDevice() = 0; // use path_, type_, opened_, init_ variables
|
||||
|
||||
//! Reimplement to close device, inverse return value will be set to "opened_" variable
|
||||
virtual bool closeDevice() {return true;} // use path_, type_, opened_, init_ variables
|
||||
|
||||
//! Function executed when thread read some data, default implementation execute external slot "ret_func_"
|
||||
virtual bool threadedRead(uchar * readed, int size) {if (ret_func_ != 0) return ret_func_(ret_data_, readed, size); return true;}
|
||||
|
||||
|
||||
//! Reimplement to construct full unambiguous string prefix. \ref PIIODevice_sec7
|
||||
virtual PIString fullPathPrefix() const {return PIString();}
|
||||
|
||||
//! Reimplement to configure your device with parameters of full unambiguous string. Default implementation does nothing
|
||||
virtual void configureFromFullPath(const PIString & full_path) {;}
|
||||
|
||||
|
||||
void terminate();
|
||||
|
||||
|
||||
DeviceMode mode_;
|
||||
ReadRetFunc ret_func_;
|
||||
bool init_, opened_, thread_started_, raise_threaded_read_;
|
||||
void * ret_data_;
|
||||
|
||||
private:
|
||||
EVENT_HANDLER2(void, check_start, void * , data, int, delim);
|
||||
EVENT_HANDLER(void, write_func);
|
||||
|
||||
virtual PIIODevice * copy() const {return 0;}
|
||||
void _init();
|
||||
void begin();
|
||||
void run();
|
||||
void end() {terminate();}
|
||||
|
||||
PITimer timer;
|
||||
PIThread write_thread;
|
||||
PIByteArray buffer_in, buffer_tr;
|
||||
PIQueue<PIPair<PIByteArray, ullong> > write_queue;
|
||||
ullong tri;
|
||||
int readed_;
|
||||
|
||||
};
|
||||
|
||||
#endif // PIIODEVICE_H
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Keyboard grabber for console
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pikbdlistener.h"
|
||||
|
||||
|
||||
/** \class PIKbdListener
|
||||
* \brief Keyboard console input listener
|
||||
* \details This class provide listening of console keyboard input.
|
||||
* There is two ways to receive pressed key:
|
||||
* * external static functionwith format "void func(char key, void * data_)"
|
||||
* * event \a keyPressed()
|
||||
*
|
||||
* Also there is static variable \a exiting which by default is set to
|
||||
* \b false. If \a enableExitCapture() was called and listener was started
|
||||
* with function \a start(), this variable will be set to \b true if exit
|
||||
* key will be pressed. By default exit key is 'Q' = shift + 'q'.
|
||||
* To wait for this variable changes to \b true there is WAIT_FOR_EXIT macro
|
||||
* \snippet pikbdlistener.cpp main
|
||||
* */
|
||||
|
||||
|
||||
bool PIKbdListener::exiting;
|
||||
|
||||
PIKbdListener::PIKbdListener(KBFunc slot, void * _data): PIThread() {
|
||||
#ifdef WINDOWS
|
||||
hIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
GetConsoleMode(hIn, &smode);
|
||||
#else
|
||||
struct termios term;
|
||||
tcgetattr(0, &term);
|
||||
sterm = term;
|
||||
#endif
|
||||
is_active = true;
|
||||
ret_func = slot;
|
||||
data_ = _data;
|
||||
PIKbdListener::exiting = exit_enabled = false;
|
||||
start();
|
||||
}
|
||||
|
||||
|
||||
void PIKbdListener::begin() {
|
||||
//cout << "list begin" << endl;
|
||||
#ifdef WINDOWS
|
||||
GetConsoleMode(hIn, &tmode);
|
||||
SetConsoleMode(hIn, ENABLE_PROCESSED_INPUT);
|
||||
#else
|
||||
struct termios term;
|
||||
tcgetattr(0, &term);
|
||||
term.c_lflag &= ~(ECHO | ICANON) | NOFLSH;
|
||||
tterm = term;
|
||||
tcsetattr(0, TCSAFLUSH, &term);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIKbdListener::run() {
|
||||
rc = 0;
|
||||
char lc = 0;
|
||||
#ifdef WINDOWS
|
||||
INPUT_RECORD ir;
|
||||
ReadConsoleInput(hIn, &ir, 1, &ret);
|
||||
if (ir.EventType == KEY_EVENT) {
|
||||
KEY_EVENT_RECORD ker = ir.Event.KeyEvent;
|
||||
if (ker.bKeyDown) {
|
||||
bool ctrl = ((ker.dwControlKeyState & LEFT_CTRL_PRESSED) || (ker.dwControlKeyState & RIGHT_CTRL_PRESSED));
|
||||
bool shift = (ker.dwControlKeyState & SHIFT_PRESSED);
|
||||
if (ker.dwControlKeyState & CAPSLOCK_ON) shift = !shift;
|
||||
//cout << "key " << int(ker.wVirtualKeyCode) << endl;
|
||||
switch (ker.wVirtualKeyCode) {
|
||||
case 37: ret = 1; lc = (ctrl ? CtrlLeftArrow : LeftArrow); break;
|
||||
case 38: ret = 1; lc = (ctrl ? CtrlUpArrow : UpArrow); break;
|
||||
case 39: ret = 1; lc = (ctrl ? CtrlRightArrow : RightArrow); break;
|
||||
case 40: ret = 1; lc = (ctrl ? CtrlDownArrow : DownArrow); break;
|
||||
default: ret = 1; lc = (shift ? char(toupper(ker.uChar.AsciiChar)) : ker.uChar.AsciiChar); break;
|
||||
}
|
||||
if (lc == 0) {piMSleep(10); return;}
|
||||
} else {piMSleep(10); return;}
|
||||
} else {piMSleep(10); return;}
|
||||
/*if (lc == 0) {
|
||||
ReadConsole(hIn, &rc, 1, &ret, 0);
|
||||
//cout << "read console" << endl;
|
||||
lc = char(rc);
|
||||
}*/
|
||||
/*if (ret < 0 || ret > 3) return;
|
||||
lc = char(((uchar * )&rc)[ret - 1]);
|
||||
for (int i = 0; i < ret; ++i)
|
||||
cout << std::hex << int(((uchar * )&rc)[i]) << ' ';
|
||||
cout << endl << std::hex << rc << endl;*/
|
||||
#else
|
||||
ret = read(0, &rc, 4);
|
||||
if (ret < 0 || ret > 3) {piMSleep(10); return;}
|
||||
lc = char(((uchar * )&rc)[ret - 1]);
|
||||
//for (int i = 0; i < ret; ++i)
|
||||
// cout << std::hex << int(((uchar * )&rc)[i]) << ' ';
|
||||
//cout << endl << std::hex << rc << endl;
|
||||
if (((char * )&rc)[0] == '\e' && ret == 3) {
|
||||
if (((char * )&rc)[1] == '[') {
|
||||
switch (((char * )&rc)[2]) {
|
||||
case 'A': lc = UpArrow; break; // up
|
||||
case 'B': lc = DownArrow; break; // down
|
||||
case 'C': lc = RightArrow; break; // right
|
||||
case 'D': lc = LeftArrow; break; // left
|
||||
}
|
||||
}
|
||||
}
|
||||
if (((char * )&rc)[0] == '5' && ret == 2) {
|
||||
switch (((char * )&rc)[1]) {
|
||||
case 'A': lc = CtrlUpArrow; break; // up
|
||||
case 'B': lc = CtrlDownArrow; break; // down
|
||||
case 'C': lc = CtrlRightArrow; break; // right
|
||||
case 'D': lc = CtrlLeftArrow; break; // left
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (exit_enabled && ret == 1 && lc == exit_key) {
|
||||
PIKbdListener::exiting = true;
|
||||
return;
|
||||
}
|
||||
if (ret > 0) {
|
||||
keyPressed(lc, data_);
|
||||
if (ret_func != 0) ret_func(lc, data_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIKbdListener::end() {
|
||||
//cout << "list end" << endl;
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(hIn, smode);
|
||||
#else
|
||||
tcsetattr(0, TCSANOW, &sterm);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIKbdListener::setActive(bool yes) {
|
||||
is_active = yes;
|
||||
if (is_active) {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(hIn, tmode);
|
||||
#else
|
||||
tcsetattr(0, TCSANOW, &tterm);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(hIn, smode);
|
||||
#else
|
||||
tcsetattr(0, TCSANOW, &sterm);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
130
pikbdlistener.h
130
pikbdlistener.h
@@ -1,130 +0,0 @@
|
||||
/*! \file pikbdlistener.h
|
||||
* \brief Keyboard console input listener
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Keyboard grabber for console
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIKBDLISTENER_H
|
||||
#define PIKBDLISTENER_H
|
||||
|
||||
#include "pithread.h"
|
||||
#ifndef WINDOWS
|
||||
# include <termios.h>
|
||||
#endif
|
||||
|
||||
#define WAIT_FOR_EXIT while (!PIKbdListener::exiting) msleep(1);
|
||||
|
||||
typedef void (*KBFunc)(char, void * );
|
||||
|
||||
class PIP_EXPORT PIKbdListener: public PIThread
|
||||
{
|
||||
PIOBJECT(PIKbdListener)
|
||||
friend class PIConsole;
|
||||
public:
|
||||
|
||||
//! Special keyboard keys
|
||||
enum SpecialSymbol {
|
||||
UpArrow /** Up arrow key */ = -1,
|
||||
DownArrow /** Down arrow key */ = -2,
|
||||
RightArrow /** Right arrow key */ = -3,
|
||||
LeftArrow /** Left arrow key */ = -4,
|
||||
CtrlUpArrow /** Ctrl + Up arrow key */ = -5,
|
||||
CtrlDownArrow /** Ctrl + Down arrow key */ = -6,
|
||||
CtrlRightArrow /** Ctrl + Right arrow key */ = -7,
|
||||
CtrlLeftArrow /** Ctrl + Left arrow key */ = -8
|
||||
};
|
||||
|
||||
//! Constructs keyboard listener with external function "slot" and custom data "data"
|
||||
PIKbdListener(KBFunc slot = 0, void * data = 0);
|
||||
|
||||
~PIKbdListener() {terminate(); end();}
|
||||
|
||||
|
||||
//! Returns custom data
|
||||
void * data() {return data_;}
|
||||
|
||||
//! Set custom data to "_data"
|
||||
void setData(void * _data) {data_ = _data;}
|
||||
|
||||
//! Set external function to "slot"
|
||||
void setSlot(KBFunc slot) {ret_func = slot;}
|
||||
|
||||
//! Returns if exit key if awaiting
|
||||
bool exitCaptured() const {return exit_enabled;}
|
||||
|
||||
//! Returns exit key, default 'Q'
|
||||
char exitKey() const {return exit_key;}
|
||||
|
||||
|
||||
//! Returns if keyboard listening is active (not running!)
|
||||
bool isActive() {return is_active;}
|
||||
|
||||
EVENT_HANDLER( void, enableExitCapture) {enableExitCapture('Q');}
|
||||
EVENT_HANDLER1(void, enableExitCapture, char, key) {exit_enabled = true; exit_key = key;}
|
||||
EVENT_HANDLER(void, disableExitCapture) {exit_enabled = false;}
|
||||
EVENT_HANDLER(void, setActive) {setActive(true);}
|
||||
EVENT_HANDLER1(void, setActive, bool, yes);
|
||||
|
||||
EVENT2(keyPressed, char, key, void * , data)
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void enableExitCapture(char key = 'Q')
|
||||
//! \brief Enable exit key "key" awaiting
|
||||
|
||||
//! \fn void disableExitCapture()
|
||||
//! \brief Disable exit key awaiting
|
||||
|
||||
//! \fn void setActive(bool yes = true)
|
||||
//! \brief Set keyboard listening is active or not
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void keyPressed(char key, void * data)
|
||||
//! \brief Raise on key "key" pressed, "data" is custom data
|
||||
|
||||
//! \}
|
||||
|
||||
static bool exiting;
|
||||
|
||||
private:
|
||||
void begin();
|
||||
void run();
|
||||
void end();
|
||||
|
||||
KBFunc ret_func;
|
||||
char exit_key;
|
||||
bool exit_enabled, is_active;
|
||||
void * data_;
|
||||
#ifdef WINDOWS
|
||||
DWORD ret, rc;
|
||||
void * hIn;
|
||||
DWORD smode, tmode;
|
||||
#else
|
||||
int rc;
|
||||
int ret;
|
||||
struct termios sterm, tterm;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // PIKBDLISTENER_H
|
||||
452
pimap.h
452
pimap.h
@@ -1,452 +0,0 @@
|
||||
/*! \file pimap.h
|
||||
* \brief Associative array with custom types of key and value
|
||||
*
|
||||
* This file declares PIMap
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Dynamic array of any type
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIMAP_H
|
||||
#define PIMAP_H
|
||||
|
||||
#include "pivector.h"
|
||||
#include "pideque.h"
|
||||
|
||||
|
||||
#if !defined(PIP_CONTAINERS_STL) || defined(DOXYGEN)
|
||||
|
||||
template<class T>
|
||||
void piQuickSort(T * a, ssize_t N) {
|
||||
if (N < 1) return;
|
||||
ssize_t i = 0, j = N;
|
||||
T & p(a[N >> 1]);
|
||||
do {
|
||||
while (a[i] < p) i++;
|
||||
while (a[j] > p) j--;
|
||||
if (i <= j) {
|
||||
if (i != j) {
|
||||
//piCout << "swap" << i << j << a[i] << a[j];
|
||||
piSwapBinary<T>(a[i], a[j]);
|
||||
}
|
||||
i++; j--;
|
||||
}
|
||||
} while (i <= j);
|
||||
if (j > 0) piQuickSort(a, j);
|
||||
if (N > i) piQuickSort(a + i, N - i);
|
||||
}
|
||||
|
||||
template <typename Key, typename T>
|
||||
class PIMap {
|
||||
public:
|
||||
PIMap() {;}
|
||||
PIMap(const PIMap<Key, T> & other) {*this = other;}
|
||||
~PIMap() {;}
|
||||
|
||||
PIMap<Key, T> & operator =(const PIMap<Key, T> & other) {
|
||||
if (this == &other) return *this;
|
||||
clear();
|
||||
pim_content = other.pim_content;
|
||||
pim_index = other.pim_index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef T mapped_type;
|
||||
typedef Key key_type;
|
||||
typedef PIPair<Key, T> value_type;
|
||||
|
||||
class iterator {
|
||||
friend class PIMap<Key, T>;
|
||||
private:
|
||||
iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
|
||||
const PIMap<Key, T> * parent;
|
||||
ssize_t pos;
|
||||
public:
|
||||
iterator(): parent(0) {}
|
||||
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
|
||||
T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
|
||||
void operator ++() {++pos;}
|
||||
void operator ++(int) {++pos;}
|
||||
void operator --() {--pos;}
|
||||
void operator --(int) {--pos;}
|
||||
bool operator ==(const iterator & it) const {return (pos == it.pos);}
|
||||
bool operator !=(const iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
class reverse_iterator {
|
||||
friend class PIMap<Key, T>;
|
||||
private:
|
||||
reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
|
||||
const PIMap<Key, T> * parent;
|
||||
ssize_t pos;
|
||||
public:
|
||||
reverse_iterator(): parent(0) {}
|
||||
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
|
||||
T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
|
||||
void operator ++() {--pos;}
|
||||
void operator ++(int) {--pos;}
|
||||
void operator --() {++pos;}
|
||||
void operator --(int) {++pos;}
|
||||
bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);}
|
||||
bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
class const_iterator {
|
||||
friend class PIMap<Key, T>;
|
||||
private:
|
||||
const_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
|
||||
const PIMap<Key, T> * parent;
|
||||
ssize_t pos;
|
||||
public:
|
||||
const_iterator(): parent(0) {}
|
||||
const PIMap<Key, T>::value_type operator *() const {return parent->_pair(pos);}
|
||||
const PIMap<Key, T>::value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
|
||||
void operator ++() {++pos;}
|
||||
void operator ++(int) {++pos;}
|
||||
void operator --() {--pos;}
|
||||
void operator --(int) {--pos;}
|
||||
bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
|
||||
bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
|
||||
mutable value_type cval;
|
||||
};
|
||||
|
||||
class const_reverse_iterator {
|
||||
friend class PIMap<Key, T>;
|
||||
private:
|
||||
const_reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
|
||||
const PIMap<Key, T> * parent;
|
||||
ssize_t pos;
|
||||
public:
|
||||
const_reverse_iterator(): parent(0) {}
|
||||
const PIMap<Key, T>::value_type operator *() const {return parent->_pair(pos);}
|
||||
const PIMap<Key, T>::value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
|
||||
void operator ++() {--pos;}
|
||||
void operator ++(int) {--pos;}
|
||||
void operator --() {++pos;}
|
||||
void operator --(int) {++pos;}
|
||||
bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
|
||||
bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
|
||||
mutable value_type cval;
|
||||
};
|
||||
|
||||
iterator begin() {return iterator(this, 0);}
|
||||
iterator end() {return iterator(this, size());}
|
||||
const_iterator begin() const {return const_iterator(this, 0);}
|
||||
const_iterator end() const {return const_iterator(this, size());}
|
||||
reverse_iterator rbegin() {return reverse_iterator(this, size() - 1);}
|
||||
reverse_iterator rend() {return reverse_iterator(this, -1);}
|
||||
const_reverse_iterator rbegin() const {return const_reverse_iterator(this, size() - 1);}
|
||||
const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
|
||||
|
||||
size_t size() const {return pim_content.size();}
|
||||
int size_s() const {return pim_content.size_s();}
|
||||
size_t length() const {return pim_content.size();}
|
||||
bool isEmpty() const {return (pim_content.size() == 0);}
|
||||
|
||||
T & operator [](const Key & key) {
|
||||
bool f(false);
|
||||
ssize_t i = _find(key, f);
|
||||
if (f) return pim_content[pim_index[i].index];
|
||||
pim_content.push_back(T());
|
||||
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
|
||||
return pim_content.back();
|
||||
}
|
||||
const T operator [](const Key & key) const {bool f(false); ssize_t i = _find(key, f); if (f) return pim_content[pim_index[i].index]; return T();}
|
||||
T & at(const Key & key) {return (*this)[key];}
|
||||
const T at(const Key & key) const {return (*this)[key];}
|
||||
|
||||
PIMap<Key, T> & operator <<(const PIMap<Key, T> & other) {
|
||||
if (other.isEmpty()) return *this;
|
||||
if (other.size() == 1) {insert(other.pim_index[0].key, other.pim_content[0]); return *this;}
|
||||
if (other.size() == 2) {insert(other.pim_index[0].key, other.pim_content[0]); insert(other.pim_index[1].key, other.pim_content[1]); return *this;}
|
||||
pim_content << other.pim_content;
|
||||
size_t si = pim_index.size();
|
||||
for (int i = 0; i < other.pim_content.size_s(); ++i)
|
||||
pim_index << MapIndex(other.pim_index[i].key, other.pim_index[i].index + si);
|
||||
_sort();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator ==(const PIMap<Key, T> & t) const {return (pim_content == t.pim_content && pim_index == t.pim_index);}
|
||||
bool operator !=(const PIMap<Key, T> & t) const {return (pim_content != t.pim_content || pim_index != t.pim_index);}
|
||||
bool contains(const Key & key) const {bool f(false); _find(key, f); return f;}
|
||||
//int etries(const T & v) const {int ec = 0; for (size_t i = 0; i < pim_size; ++i) if (v == pim_data[i]) ++ec; return ec;}
|
||||
|
||||
PIMap<Key, T> & reserve(size_t new_size) {pim_content.reserve(new_size); pim_index.reserve(new_size); return *this;}
|
||||
|
||||
//PIMap<Key, T> & removeAll(const T & v) {for (llong i = 0; i < pim_size; ++i) if (pim_data[i] == v) {remove(i); --i;} return *this;}
|
||||
PIMap<Key, T> & removeOne(const Key & key) {bool f(false); ssize_t i = _find(key, f); if (f) _remove(i); return *this;}
|
||||
PIMap<Key, T> & remove(const Key & key) {return removeOne(key);}
|
||||
PIMap<Key, T> & erase(const Key & key) {return removeOne(key);}
|
||||
PIMap<Key, T> & clear() {pim_content.clear(); pim_index.clear(); return *this;}
|
||||
|
||||
void swap(PIMap<Key, T> & other) {
|
||||
piSwapBinary<PIVector<T> >(pim_content, other.pim_content);
|
||||
piSwapBinary<PIVector<MapIndex> >(pim_index, other.pim_index);
|
||||
}
|
||||
|
||||
PIMap<Key, T> & insert(const Key & key, const T & value) {
|
||||
//MapIndex * i = _find(key);
|
||||
bool f(false);
|
||||
ssize_t i = _find(key, f);
|
||||
//piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value;
|
||||
if (f) {
|
||||
pim_content[pim_index[i].index] = value;
|
||||
} else {
|
||||
pim_content.push_back(value);
|
||||
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
|
||||
//_sort();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
//const T value(const Key & key, const T & default_ = T()) const {MapIndex * i = _find(key); if (i == 0) return default_; return pim_content[i->index];}
|
||||
const T value(const Key & key, const T & default_ = T()) const {bool f(false); ssize_t i = _find(key, f); if (!f) return default_; return pim_content[pim_index[i].index];}
|
||||
Key key(const T & value_, const Key & default_ = Key()) const {for (int i = 0; i < pim_index.size_s(); ++i) if (pim_content[pim_index[i].index] == value_) return pim_index[i].key; return default_;}
|
||||
PIVector<Key> keys() const {
|
||||
PIVector<Key> ret;
|
||||
for (int i = 0; i < pim_index.size_s(); ++i)
|
||||
ret << pim_index[i].key;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dump() {
|
||||
piCout << "PIMap" << size() << "entries" << NewLine << "content:";
|
||||
for (size_t i = 0; i < pim_content.size(); ++i)
|
||||
piCout << Tab << i << ":" << pim_content[i];
|
||||
piCout << "index:";
|
||||
for (size_t i = 0; i < pim_index.size(); ++i)
|
||||
piCout << Tab << i << ":" << pim_index[i].key << "->" << pim_index[i].index;
|
||||
}
|
||||
|
||||
private:
|
||||
struct MapIndex {
|
||||
MapIndex(Key k = Key(), size_t i = 0): key(k), index(i) {;}
|
||||
Key key;
|
||||
size_t index;
|
||||
bool operator ==(const MapIndex & s) const {return key == s.key;}
|
||||
bool operator !=(const MapIndex & s) const {return key != s.key;}
|
||||
bool operator <(const MapIndex & s) const {return key < s.key;}
|
||||
bool operator >(const MapIndex & s) const {return key > s.key;}
|
||||
};
|
||||
|
||||
ssize_t binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const {
|
||||
ssize_t mid;
|
||||
while (first <= last) {
|
||||
mid = (first + last) / 2;
|
||||
if (key > pim_index[mid].key) first = mid + 1;
|
||||
else if (key < pim_index[mid].key) last = mid - 1;
|
||||
else {found = true; return mid;}
|
||||
}
|
||||
found = false;
|
||||
return first;
|
||||
}
|
||||
void _sort() {piQuickSort<MapIndex>(pim_index.data(), pim_index.size_s() - 1);}
|
||||
ssize_t _find(const Key & k, bool & found) const {
|
||||
/*for (size_t i = 0; i < pim_index.size(); ++i)
|
||||
if (pim_index[i].key == k) {
|
||||
return (MapIndex * )&(pim_index[i]);
|
||||
}
|
||||
return 0;*/
|
||||
//piCout << "find for" << k << pim_index.size_s();
|
||||
if (pim_index.isEmpty()) {
|
||||
found = false;
|
||||
return 0;
|
||||
}
|
||||
//piCout << k << ret << found;
|
||||
return binarySearch(0, pim_index.size_s() - 1, k, found);
|
||||
}
|
||||
void _remove(ssize_t i) {
|
||||
//if (i >= pim_index.size()) return;
|
||||
size_t ci = pim_index[i].index, bi = pim_index.size() - 1;
|
||||
pim_index.remove(i);
|
||||
for (size_t i = 0; i < pim_index.size(); ++i)
|
||||
if (pim_index[i].index == bi) {
|
||||
pim_index[i].index = ci;
|
||||
break;
|
||||
}
|
||||
piSwapBinary<T>(pim_content[ci], pim_content.back());
|
||||
pim_content.resize(pim_index.size());
|
||||
}
|
||||
const value_type _pair(ssize_t index) const {
|
||||
if (index < 0 || index >= pim_index.size_s())
|
||||
return value_type();
|
||||
//piCout << "_pair" << index << pim_index[index].index;
|
||||
return value_type(pim_index[index].key, pim_content[pim_index[index].index]);
|
||||
}
|
||||
Key & _key(ssize_t index) {return pim_index[index].key;}
|
||||
T & _value(ssize_t index) {return pim_content[pim_index[index].index];}
|
||||
|
||||
PIVector<T> pim_content;
|
||||
PIDeque<MapIndex> pim_index;
|
||||
};
|
||||
//template <typename Key, typename T> bool operator <(const typename PIMap<Key, T>::MapIndex & f, const typename PIMap<Key, T>::MapIndex & s) {return f.key < s.key;}
|
||||
//template <typename Key, typename T> bool operator >(const typename PIMap<Key, T>::MapIndex & f, const typename PIMap<Key, T>::MapIndex & s) {return f.key > s.key;}
|
||||
|
||||
|
||||
/*#define __PIMAP_SIMPLE_FUNCTIONS__(T)
|
||||
template<> inline PIMap<Key, T>::~PIMap() {dealloc(); _reset();} \
|
||||
template<> inline PIMap<Key, T> & PIMap<Key, T>::push_back(const T & v) {alloc(pim_size + 1); pim_data[pim_size - 1] = v; return *this;} \
|
||||
template<> inline PIMap<Key, T> & PIMap<Key, T>::fill(const T & f) { \
|
||||
for (size_t i = 0; i < pim_size; ++i) \
|
||||
pim_data[i] = f; \
|
||||
return *this; \
|
||||
} \
|
||||
template<> inline PIMap<Key, T> & PIMap<Key, T>::resize(size_t new_size, const T & f) { \
|
||||
if (new_size < pim_size) \
|
||||
pim_size = new_size; \
|
||||
if (new_size > pim_size) { \
|
||||
size_t os = pim_size; \
|
||||
alloc(new_size); \
|
||||
for (size_t i = os; i < new_size; ++i) pim_data[i] = f; \
|
||||
} \
|
||||
return *this; \
|
||||
} \
|
||||
template<> inline PIMap<Key, T> & PIMap<Key, T>::insert(size_t index, const T & v) { \
|
||||
alloc(pim_size + 1); \
|
||||
if (index < pim_size - 1) { \
|
||||
size_t os = pim_size - index - 1; \
|
||||
memmove(&(pim_data[index + 1]), &(pim_data[index]), os * sizeof(T)); \
|
||||
} \
|
||||
pim_data[index] = v; \
|
||||
return *this; \
|
||||
} \
|
||||
template<> inline PIMap<Key, T> & PIMap<Key, T>::remove(size_t index, size_t count) { \
|
||||
if (index + count >= pim_size) { \
|
||||
resize(index); \
|
||||
return *this; \
|
||||
} \
|
||||
size_t os = pim_size - index - count; \
|
||||
memmove(&(pim_data[index]), &(pim_data[index + count]), os * sizeof(T)); \
|
||||
pim_size -= count; \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
__PIMAP_SIMPLE_FUNCTIONS__(char)
|
||||
__PIMAP_SIMPLE_FUNCTIONS__(uchar)
|
||||
__PIMAP_SIMPLE_FUNCTIONS__(short)
|
||||
__PIMAP_SIMPLE_FUNCTIONS__(ushort)
|
||||
__PIMAP_SIMPLE_FUNCTIONS__(int)
|
||||
__PIMAP_SIMPLE_FUNCTIONS__(uint)
|
||||
__PIMAP_SIMPLE_FUNCTIONS__(long)
|
||||
__PIMAP_SIMPLE_FUNCTIONS__(ulong)
|
||||
__PIMAP_SIMPLE_FUNCTIONS__(llong)
|
||||
__PIMAP_SIMPLE_FUNCTIONS__(ullong)
|
||||
__PIMAP_SIMPLE_FUNCTIONS__(float)
|
||||
__PIMAP_SIMPLE_FUNCTIONS__(double)
|
||||
__PIMAP_SIMPLE_FUNCTIONS__(ldouble)*/
|
||||
|
||||
#else
|
||||
|
||||
|
||||
template<typename Key, typename Type>
|
||||
class PIP_EXPORT PIMap: public map<Key, Type> {
|
||||
typedef PIMap<Key, Type> _CMap;
|
||||
typedef map<Key, Type> _stlc;
|
||||
typedef std::pair<Key, Type> _stlpair;
|
||||
public:
|
||||
PIMap() {;}
|
||||
PIMap(const Key & key_, const Type & value_) {insert(key_, value_);}
|
||||
bool isEmpty() const {return _stlc::empty();}
|
||||
bool contains(const Key & key_) const {return _stlc::count(key_) > 0;}
|
||||
int size_s() const {return static_cast<int>(_stlc::size());}
|
||||
_CMap & insert(const Key & key_, const Type & value_) {_stlc::insert(_stlpair(key_, value_)); return *this;}
|
||||
_CMap & insert(PIPair<Key, Type> entry_) {_stlc::insert(_stlpair(entry_.first, entry_.second)); return *this;}
|
||||
Key key(Type value_, const Key & default_ = Key()) const {for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); i++) if (i->second == value_) return i->first; return default_;}
|
||||
PIVector<Key> keys() const {
|
||||
PIVector<Key> ret;
|
||||
for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); i++)
|
||||
ret << i->first;
|
||||
return ret;
|
||||
}
|
||||
Type & at(const Key & key_) {return _stlc::find(key_)->second;}
|
||||
Type value(const Key & key_) const {typename _stlc::const_iterator it = _stlc::find(key_); if (it != _stlc::end()) return it->second; return Type();}
|
||||
};
|
||||
|
||||
|
||||
template<typename Key, typename Type>
|
||||
class PIP_EXPORT PIMultiMap: public multimap<Key, Type> {
|
||||
typedef PIMultiMap<Key, Type> _CMultiMap;
|
||||
typedef multimap<Key, Type> _stlc;
|
||||
typedef std::pair<Key, Type> _stlpair;
|
||||
public:
|
||||
PIMultiMap() {;}
|
||||
PIMultiMap(const Key & key_, const Type & value_) {insert(key_, value_);}
|
||||
_CMultiMap & insert(const Key & key_, const Type & value_) {_stlc::insert(_stlpair(key_, value_)); return *this;}
|
||||
_CMultiMap & insert(PIPair<Key, Type> entry_) {_stlc::insert(_stlpair(entry_.first, entry_.second)); return *this;}
|
||||
bool isEmpty() const {return _stlc::empty();}
|
||||
bool contains(const Key & key_) const {return _stlc::count(key_) > 0;}
|
||||
Key key(Type value_, const Key & default_ = Key()) const {for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); i++) if (i->second == value_) return i->first; return default_;}
|
||||
PIVector<Key> keys(Type value_) const {
|
||||
PIVector<Key> ret;
|
||||
for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); i++)
|
||||
if (i->second == value_)
|
||||
ret << i->first;
|
||||
return ret;
|
||||
}
|
||||
Type & value(const Key & key_) {typename _stlc::iterator i = _stlc::find(key_); if (i == _stlc::end()) return Type(); return i->second;}
|
||||
Type value(const Key & key_) const {typename _stlc::const_iterator i = _stlc::find(key_); if (i == _stlc::end()) return Type(); return i->second;}
|
||||
PIVector<Type> values(const Key & key_) const {
|
||||
std::pair<typename _stlc::const_iterator, typename _stlc::const_iterator> range = _stlc::equal_range(key_);
|
||||
PIVector<Type> ret;
|
||||
for (typename _stlc::const_iterator i = range.first; i != range.second; ++i)
|
||||
ret << i->second;
|
||||
return ret;
|
||||
}
|
||||
Type & operator [](const Key & key_) {if (!contains(key_)) return _stlc::insert(_stlpair(key_, Type()))->second; return _stlc::find(key_)->second;}
|
||||
Type operator [](const Key & key_) const {return _stlc::find(key_)->second;}
|
||||
};
|
||||
|
||||
#define __PIMAP_SIMPLE_FUNCTIONS__(T)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
template<typename Key, typename Type>
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIMap<Key, Type> & v) {
|
||||
s << "{";
|
||||
bool first = true;
|
||||
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); i++) {
|
||||
if (!first)
|
||||
s << ", ";
|
||||
first = false;
|
||||
s << i->first << ": " << i->second;
|
||||
}
|
||||
s << "}";
|
||||
return s;
|
||||
}
|
||||
|
||||
template<typename Key, typename Type>
|
||||
inline PICout operator <<(PICout s, const PIMap<Key, Type> & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s << "{";
|
||||
bool first = true;
|
||||
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); i++) {
|
||||
if (!first)
|
||||
s << ", ";
|
||||
first = false;
|
||||
s << i->first << ": " << i->second;
|
||||
}
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
#endif // PIMAP_H
|
||||
1627
pimath.cpp
1627
pimath.cpp
@@ -1,1627 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Math
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pimath.h"
|
||||
|
||||
|
||||
double piJ0(const double & v) {
|
||||
#ifndef PIP_MATH_J0
|
||||
double x = v;
|
||||
double xsq;
|
||||
double nn;
|
||||
double pzero;
|
||||
double qzero;
|
||||
double p1;
|
||||
double q1;
|
||||
double result;
|
||||
if (x < 0) x = -x;
|
||||
if (x > 8.) {
|
||||
double xsq_;
|
||||
double p2;
|
||||
double q2;
|
||||
double p3;
|
||||
double q3;
|
||||
xsq_ = 64. / (x * x);
|
||||
p2 = 0.0;
|
||||
p2 = 2485.271928957404011288128951 + xsq_ * p2;
|
||||
p2 = 153982.6532623911470917825993 + xsq_ * p2;
|
||||
p2 = 2016135.283049983642487182349 + xsq_ * p2;
|
||||
p2 = 8413041.456550439208464315611 + xsq_ * p2;
|
||||
p2 = 12332384.76817638145232406055 + xsq_ * p2;
|
||||
p2 = 5393485.083869438325262122897 + xsq_ * p2;
|
||||
q2 = 1.0;
|
||||
q2 = 2615.700736920839685159081813 + xsq_ * q2;
|
||||
q2 = 156001.7276940030940592769933 + xsq_ * q2;
|
||||
q2 = 2025066.801570134013891035236 + xsq_ * q2;
|
||||
q2 = 8426449.050629797331554404810 + xsq_ * q2;
|
||||
q2 = 12338310.22786324960844856182 + xsq_ * q2;
|
||||
q2 = 5393485.083869438325560444960 + xsq_ * q2;
|
||||
p3 = -0.0;
|
||||
p3 = -4.887199395841261531199129300 +xsq_ * p3;
|
||||
p3 = -226.2630641933704113967255053 +xsq_ * p3;
|
||||
p3 = -2365.956170779108192723612816 +xsq_ * p3;
|
||||
p3 = -8239.066313485606568803548860 +xsq_ * p3;
|
||||
p3 = -10381.41698748464093880530341 +xsq_ * p3;
|
||||
p3 = -3984.617357595222463506790588 +xsq_ * p3;
|
||||
q3 = 1.0;
|
||||
q3 = 408.7714673983499223402830260 + xsq_ * q3;
|
||||
q3 = 15704.89191515395519392882766 + xsq_ * q3;
|
||||
q3 = 156021.3206679291652539287109 + xsq_ * q3;
|
||||
q3 = 533291.3634216897168722255057 + xsq_ * q3;
|
||||
q3 = 666745.4239319826986004038103 + xsq_ * q3;
|
||||
q3 = 255015.5108860942382983170882 + xsq_ * q3;
|
||||
pzero = p2 / q2;
|
||||
qzero = 8. * p3 / q3 / x;
|
||||
nn = x- M_PI / 4.;
|
||||
result = sqrt(2. / M_PI / x) * (pzero * cos(nn) - qzero * sin(nn));
|
||||
return result;
|
||||
}
|
||||
xsq = x * x;
|
||||
p1 = 26857.86856980014981415848441;
|
||||
p1 = -40504123.71833132706360663322 + xsq * p1;
|
||||
p1 = 25071582855.36881945555156435 + xsq * p1;
|
||||
p1 = -8085222034853.793871199468171 + xsq * p1;
|
||||
p1 = 1434354939140344.111664316553 + xsq * p1;
|
||||
p1 = -136762035308817138.6865416609 + xsq * p1;
|
||||
p1 = 6382059341072356562.289432465 + xsq * p1;
|
||||
p1 = -117915762910761053603.8440800 + xsq * p1;
|
||||
p1 = 493378725179413356181.6813446 + xsq * p1;
|
||||
q1 = 1.;
|
||||
q1 = 1363.063652328970604442810507 + xsq * q1;
|
||||
q1 = 1114636.098462985378182402543 + xsq * q1;
|
||||
q1 = 669998767.2982239671814028660 + xsq * q1;
|
||||
q1 = 312304311494.1213172572469442 + xsq * q1;
|
||||
q1 = 112775673967979.8507056031594 + xsq * q1;
|
||||
q1 = 30246356167094626.98627330784 + xsq * q1;
|
||||
q1 = 5428918384092285160.200195092 + xsq * q1;
|
||||
q1 = 493378725179413356211.3278438 + xsq * q1;
|
||||
return p1 / q1;
|
||||
#else
|
||||
return j0(v);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
double piJ1(const double & v) {
|
||||
#ifndef PIP_MATH_J1
|
||||
double x = v;
|
||||
double s;
|
||||
double xsq;
|
||||
double nn;
|
||||
double pzero;
|
||||
double qzero;
|
||||
double p1;
|
||||
double q1;
|
||||
double result;
|
||||
s = sign(x);
|
||||
if (x < 0)
|
||||
x = -x;
|
||||
if (x > 8.) {
|
||||
double xsq_;
|
||||
double p2;
|
||||
double q2;
|
||||
double p3;
|
||||
double q3;
|
||||
xsq_ = 64.0 / (x * x);
|
||||
p2 = -1611.616644324610116477412898;
|
||||
p2 = -109824.0554345934672737413139 + xsq_ * p2;
|
||||
p2 = -1523529.351181137383255105722 + xsq_ * p2;
|
||||
p2 = -6603373.248364939109255245434 + xsq_ * p2;
|
||||
p2 = -9942246.505077641195658377899 + xsq_ * p2;
|
||||
p2 = -4435757.816794127857114720794 + xsq_ * p2;
|
||||
q2 = 1.0;
|
||||
q2 = -1455.009440190496182453565068 + xsq_ * q2;
|
||||
q2 = -107263.8599110382011903063867 + xsq_ * q2;
|
||||
q2 = -1511809.506634160881644546358 + xsq_ * q2;
|
||||
q2 = -6585339.479723087072826915069 + xsq_ * q2;
|
||||
q2 = -9934124.389934585658967556309 + xsq_ * q2;
|
||||
q2 = -4435757.816794127856828016962 + xsq_ * q2;
|
||||
p3 = 35.26513384663603218592175580;
|
||||
p3 = 1706.375429020768002061283546 + xsq_ * p3;
|
||||
p3 = 18494.26287322386679652009819 + xsq_ * p3;
|
||||
p3 = 66178.83658127083517939992166 + xsq_ * p3;
|
||||
p3 = 85145.16067533570196555001171 + xsq_ * p3;
|
||||
p3 = 33220.91340985722351859704442 + xsq_ * p3;
|
||||
q3 = 1.0;
|
||||
q3 = 863.8367769604990967475517183 + xsq_ * q3;
|
||||
q3 = 37890.22974577220264142952256 + xsq_ * q3;
|
||||
q3 = 400294.4358226697511708610813 + xsq_ * q3;
|
||||
q3 = 1419460.669603720892855755253 + xsq_ * q3;
|
||||
q3 = 1819458.042243997298924553839 + xsq_ * q3;
|
||||
q3 = 708712.8194102874357377502472 + xsq_ * q3;
|
||||
pzero = p2 / q2;
|
||||
qzero = 8 * p3 / q3 / x;
|
||||
nn = x - 3 * M_PI / 4;
|
||||
result = sqrt(2 / M_PI / x) * (pzero * cos(nn) - qzero * sin(nn));
|
||||
if (s < 0)
|
||||
result = -result;
|
||||
return result;
|
||||
}
|
||||
xsq = sqr(x);
|
||||
p1 = 2701.122710892323414856790990;
|
||||
p1 = -4695753.530642995859767162166 + xsq * p1;
|
||||
p1 = 3413234182.301700539091292655 + xsq * p1;
|
||||
p1 = -1322983480332.126453125473247 + xsq * p1;
|
||||
p1 = 290879526383477.5409737601689 + xsq * p1;
|
||||
p1 = -35888175699101060.50743641413 + xsq * p1;
|
||||
p1 = 2316433580634002297.931815435 + xsq * p1;
|
||||
p1 = -66721065689249162980.20941484 + xsq * p1;
|
||||
p1 = 581199354001606143928.050809 + xsq * p1;
|
||||
q1 = 1.0;
|
||||
q1 = 1606.931573481487801970916749 + xsq * q1;
|
||||
q1 = 1501793.594998585505921097578 + xsq * q1;
|
||||
q1 = 1013863514.358673989967045588 + xsq * q1;
|
||||
q1 = 524371026216.7649715406728642 + xsq * q1;
|
||||
q1 = 208166122130760.7351240184229 + xsq * q1;
|
||||
q1 = 60920613989175217.46105196863 + xsq * q1;
|
||||
q1 = 11857707121903209998.37113348 + xsq * q1;
|
||||
q1 = 1162398708003212287858.529400 + xsq * q1;
|
||||
result = s * x * p1 / q1;
|
||||
return result;
|
||||
#else
|
||||
return j1(v);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
double piJn(int n, const double & v) {
|
||||
#ifndef PIP_MATH_JN
|
||||
double x = v;
|
||||
double pkm2;
|
||||
double pkm1;
|
||||
double pk;
|
||||
double xk;
|
||||
double r;
|
||||
double ans;
|
||||
int k;
|
||||
int sg;
|
||||
double result;
|
||||
if (n < 0) {
|
||||
n = -n;
|
||||
if (n % 2 == 0)
|
||||
sg = 1;
|
||||
else
|
||||
sg = -1;
|
||||
} else
|
||||
sg = 1;
|
||||
if (x < 0) {
|
||||
if (n % 2 != 0)
|
||||
sg = -sg;
|
||||
x = -x;
|
||||
}
|
||||
if (n == 0) {
|
||||
result = sg * piJ0(x);
|
||||
return result;
|
||||
}
|
||||
if (n == 1) {
|
||||
result = sg * piJ1(x);
|
||||
return result;
|
||||
}
|
||||
if (n == 2) {
|
||||
if (x == 0)
|
||||
result = 0;
|
||||
else
|
||||
result = sg * (2.0 * piJ1(x) / x - piJ0(x));
|
||||
return result;
|
||||
}
|
||||
if (x < 1E-16) {
|
||||
result = 0;
|
||||
return result;
|
||||
}
|
||||
k = 53;
|
||||
pk = 2 * (n + k);
|
||||
ans = pk;
|
||||
xk = x * x;
|
||||
do {
|
||||
pk = pk - 2.0;
|
||||
ans = pk - xk / ans;
|
||||
k = k - 1;
|
||||
} while (k != 0);
|
||||
ans = x / ans;
|
||||
pk = 1.0;
|
||||
pkm1 = 1.0 / ans;
|
||||
k = n - 1;
|
||||
r = 2 * k;
|
||||
do {
|
||||
pkm2 = (pkm1 * r - pk * x) / x;
|
||||
pk = pkm1;
|
||||
pkm1 = pkm2;
|
||||
r = r - 2.0;
|
||||
k = k - 1;
|
||||
} while (k != 0);
|
||||
if (fabs(pk) > fabs(pkm1))
|
||||
ans = piJ1(x) / pk;
|
||||
else
|
||||
ans = piJ0(x) / pkm1;
|
||||
result = sg * ans;
|
||||
return result;
|
||||
#else
|
||||
return jn(n, v);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
double piY0(const double & v) {
|
||||
#ifndef PIP_MATH_Y0
|
||||
double x = v;
|
||||
double nn;
|
||||
double xsq;
|
||||
double pzero;
|
||||
double qzero;
|
||||
double p4;
|
||||
double q4;
|
||||
double result;
|
||||
if (x > 8.) {
|
||||
double xsq_;
|
||||
double p2;
|
||||
double q2;
|
||||
double p3;
|
||||
double q3;
|
||||
xsq_ = 64.0 / (x * x);
|
||||
p2 = 0.0;
|
||||
p2 = 2485.271928957404011288128951 + xsq_ * p2;
|
||||
p2 = 153982.6532623911470917825993 + xsq_ * p2;
|
||||
p2 = 2016135.283049983642487182349 + xsq_ * p2;
|
||||
p2 = 8413041.456550439208464315611 + xsq_ * p2;
|
||||
p2 = 12332384.76817638145232406055 + xsq_ * p2;
|
||||
p2 = 5393485.083869438325262122897 + xsq_ * p2;
|
||||
q2 = 1.0;
|
||||
q2 = 2615.700736920839685159081813 + xsq_ * q2;
|
||||
q2 = 156001.7276940030940592769933 + xsq_ * q2;
|
||||
q2 = 2025066.801570134013891035236 + xsq_ * q2;
|
||||
q2 = 8426449.050629797331554404810 + xsq_ * q2;
|
||||
q2 = 12338310.22786324960844856182 + xsq_ * q2;
|
||||
q2 = 5393485.083869438325560444960 + xsq_ * q2;
|
||||
p3 = -0.0;
|
||||
p3 = -4.887199395841261531199129300 + xsq_ * p3;
|
||||
p3 = -226.2630641933704113967255053 + xsq_ * p3;
|
||||
p3 = -2365.956170779108192723612816 + xsq_ * p3;
|
||||
p3 = -8239.066313485606568803548860 + xsq_ * p3;
|
||||
p3 = -10381.41698748464093880530341 + xsq_ * p3;
|
||||
p3 = -3984.617357595222463506790588 + xsq_ * p3;
|
||||
q3 = 1.0;
|
||||
q3 = 408.7714673983499223402830260 + xsq_ * q3;
|
||||
q3 = 15704.89191515395519392882766 + xsq_ * q3;
|
||||
q3 = 156021.3206679291652539287109 + xsq_ * q3;
|
||||
q3 = 533291.3634216897168722255057 + xsq_ * q3;
|
||||
q3 = 666745.4239319826986004038103 + xsq_ * q3;
|
||||
q3 = 255015.5108860942382983170882 + xsq_ * q3;
|
||||
pzero = p2 / q2;
|
||||
qzero = 8 * p3 / q3 / x;
|
||||
nn = x - M_PI / 4;
|
||||
result = sqrt(2 / M_PI / x) * (pzero * sin(nn) + qzero * cos(nn));
|
||||
return result;
|
||||
}
|
||||
xsq = sqr(x);
|
||||
p4 = -41370.35497933148554125235152;
|
||||
p4 = 59152134.65686889654273830069 + xsq * p4;
|
||||
p4 = -34363712229.79040378171030138 + xsq * p4;
|
||||
p4 = 10255208596863.94284509167421 + xsq * p4;
|
||||
p4 = -1648605817185729.473122082537 + xsq * p4;
|
||||
p4 = 137562431639934407.8571335453 + xsq * p4;
|
||||
p4 = -5247065581112764941.297350814 + xsq * p4;
|
||||
p4 = 65874732757195549259.99402049 + xsq * p4;
|
||||
p4 = -27502866786291095837.01933175 + xsq * p4;
|
||||
q4 = 1.0;
|
||||
q4 = 1282.452772478993804176329391 + xsq * q4;
|
||||
q4 = 1001702.641288906265666651753 + xsq * q4;
|
||||
q4 = 579512264.0700729537480087915 + xsq * q4;
|
||||
q4 = 261306575504.1081249568482092 + xsq * q4;
|
||||
q4 = 91620380340751.85262489147968 + xsq * q4;
|
||||
q4 = 23928830434997818.57439356652 + xsq * q4;
|
||||
q4 = 4192417043410839973.904769661 + xsq * q4;
|
||||
q4 = 372645883898616588198.9980 + xsq * q4;
|
||||
result = p4 / q4 + 2 / M_PI * piJ0(x) * log(x);
|
||||
return result;
|
||||
#else
|
||||
return y0(v);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
double piY1(const double & v) {
|
||||
#ifndef PIP_MATH_Y1
|
||||
double x = v;
|
||||
double nn;
|
||||
double xsq;
|
||||
double pzero;
|
||||
double qzero;
|
||||
double p4;
|
||||
double q4;
|
||||
double result;
|
||||
if (x > 8.) {
|
||||
double xsq_;
|
||||
double p2;
|
||||
double q2;
|
||||
double p3;
|
||||
double q3;
|
||||
xsq_ = 64.0 / (x * x);
|
||||
p2 = -1611.616644324610116477412898;
|
||||
p2 = -109824.0554345934672737413139 + xsq_ * p2;
|
||||
p2 = -1523529.351181137383255105722 + xsq_ * p2;
|
||||
p2 = -6603373.248364939109255245434 + xsq_ * p2;
|
||||
p2 = -9942246.505077641195658377899 + xsq_ * p2;
|
||||
p2 = -4435757.816794127857114720794 + xsq_ * p2;
|
||||
q2 = 1.0;
|
||||
q2 = -1455.009440190496182453565068 + xsq_ * q2;
|
||||
q2 = -107263.8599110382011903063867 + xsq_ * q2;
|
||||
q2 = -1511809.506634160881644546358 + xsq_ * q2;
|
||||
q2 = -6585339.479723087072826915069 + xsq_ * q2;
|
||||
q2 = -9934124.389934585658967556309 + xsq_ * q2;
|
||||
q2 = -4435757.816794127856828016962 + xsq_ * q2;
|
||||
p3 = 35.26513384663603218592175580;
|
||||
p3 = 1706.375429020768002061283546 + xsq_ * p3;
|
||||
p3 = 18494.26287322386679652009819 + xsq_ * p3;
|
||||
p3 = 66178.83658127083517939992166 + xsq_ * p3;
|
||||
p3 = 85145.16067533570196555001171 + xsq_ * p3;
|
||||
p3 = 33220.91340985722351859704442 + xsq_ * p3;
|
||||
q3 = 1.0;
|
||||
q3 = 863.8367769604990967475517183 + xsq_ * q3;
|
||||
q3 = 37890.22974577220264142952256 + xsq_ * q3;
|
||||
q3 = 400294.4358226697511708610813 + xsq_ * q3;
|
||||
q3 = 1419460.669603720892855755253 + xsq_ * q3;
|
||||
q3 = 1819458.042243997298924553839 + xsq_ * q3;
|
||||
q3 = 708712.8194102874357377502472 + xsq_ * q3;
|
||||
pzero = p2 / q2;
|
||||
qzero = 8 * p3 / q3 / x;
|
||||
nn = x - 3 * M_PI / 4;
|
||||
result = sqrt(2 / M_PI / x) * (pzero * sin(nn) + qzero * cos(nn));
|
||||
return result;
|
||||
}
|
||||
xsq = sqr(x);
|
||||
p4 = -2108847.540133123652824139923;
|
||||
p4 = 3639488548.124002058278999428 + xsq * p4;
|
||||
p4 = -2580681702194.450950541426399 + xsq * p4;
|
||||
p4 = 956993023992168.3481121552788 + xsq * p4;
|
||||
p4 = -196588746272214065.8820322248 + xsq * p4;
|
||||
p4 = 21931073399177975921.11427556 + xsq * p4;
|
||||
p4 = -1212297555414509577913.561535 + xsq * p4;
|
||||
p4 = 26554738314348543268942.48968 + xsq * p4;
|
||||
p4 = -99637534243069222259967.44354 + xsq * p4;
|
||||
q4 = 1.0;
|
||||
q4 = 1612.361029677000859332072312 + xsq * q4;
|
||||
q4 = 1563282.754899580604737366452 + xsq * q4;
|
||||
q4 = 1128686837.169442121732366891 + xsq * q4;
|
||||
q4 = 646534088126.5275571961681500 + xsq * q4;
|
||||
q4 = 297663212564727.6729292742282 + xsq * q4;
|
||||
q4 = 108225825940881955.2553850180 + xsq * q4;
|
||||
q4 = 29549879358971486742.90758119 + xsq * q4;
|
||||
q4 = 5435310377188854170800.653097 + xsq * q4;
|
||||
q4 = 508206736694124324531442.4152 + xsq * q4;
|
||||
result = x * p4 / q4 + 2 / M_PI * (piJ1(x) * log(x) - 1 / x);
|
||||
return result;
|
||||
#else
|
||||
return y1(v);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
double piYn(int n, const double & v) {
|
||||
#ifndef PIP_MATH_YN
|
||||
int i;
|
||||
double x = v;
|
||||
double a;
|
||||
double b;
|
||||
double tmp;
|
||||
double s;
|
||||
double result;
|
||||
s = 1;
|
||||
if (n < 0) {
|
||||
n = -n;
|
||||
if (n % 2 != 0)
|
||||
s = -1;
|
||||
}
|
||||
if (n == 0) {
|
||||
result = piY0(x);
|
||||
return result;
|
||||
}
|
||||
if (n == 1) {
|
||||
result = s * piY1(x);
|
||||
return result;
|
||||
}
|
||||
a = piY0(x);
|
||||
b = piY1(x);
|
||||
for (i = 1; i <= n - 1; i++) {
|
||||
tmp = b;
|
||||
b = 2 * i / x * b - a;
|
||||
a = tmp;
|
||||
}
|
||||
result = s * b;
|
||||
return result;
|
||||
#else
|
||||
return yn(n, v);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
double randomn(double dv, double sv) {
|
||||
static bool agen = false;
|
||||
double s = 2., v0 = 0., v1 = 0.;
|
||||
if (agen) {
|
||||
agen = false;
|
||||
v1 = v1 * sqrt(-2 * log(s) / s);
|
||||
return v1 * sv + dv;
|
||||
}
|
||||
while (s > 1. || s == 0.) {
|
||||
v0 = randomd();
|
||||
v1 = randomd();
|
||||
s = v0*v0 + v1*v1;
|
||||
}
|
||||
v0 = v0 * sqrt(-2 * log(s) / s);
|
||||
return v0 * sv + dv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char Solver::methods_desc[] = "b{Methods:}\
|
||||
\n -1 - Global settings\
|
||||
\n 01 - Eyler 1\
|
||||
\n 02 - Eyler 2\
|
||||
\n 14 - Runge-Kutta 4\
|
||||
\n 23 - Adams-Bashfort-Moulton 3\
|
||||
\n 24 - Adams-Bashfort-Moulton 4\
|
||||
\n 32 - Polynomial Approximation 2\
|
||||
\n 33 - Polynomial Approximation 3\
|
||||
\n 34 - Polynomial Approximation 4\
|
||||
\n 35 - Polynomial Approximation 5";
|
||||
|
||||
Solver::Method Solver::method_global = Solver::Eyler_2;
|
||||
|
||||
|
||||
void Solver::solve(double u, double h) {
|
||||
switch (method) {
|
||||
case Global:
|
||||
switch (method_global) {
|
||||
case Eyler_1: solveEyler1(u, h); break;
|
||||
case Eyler_2: solveEyler2(u, h); break;
|
||||
case RungeKutta_4: solveRK4(u, h); break;
|
||||
case AdamsBashfortMoulton_2: solveABM2(u, h); break;
|
||||
case AdamsBashfortMoulton_3: solveABM3(u, h); break;
|
||||
case AdamsBashfortMoulton_4: default: solveABM4(u, h); break;
|
||||
case PolynomialApproximation_2: solvePA2(u, h); break;
|
||||
case PolynomialApproximation_3: solvePA3(u, h); break;
|
||||
case PolynomialApproximation_4: solvePA4(u, h); break;
|
||||
case PolynomialApproximation_5: solvePA5(u, h); break;
|
||||
}
|
||||
break;
|
||||
case Eyler_1: solveEyler1(u, h); break;
|
||||
case Eyler_2: solveEyler2(u, h); break;
|
||||
case RungeKutta_4: solveRK4(u, h); break;
|
||||
case AdamsBashfortMoulton_2: solveABM2(u, h); break;
|
||||
case AdamsBashfortMoulton_3: solveABM3(u, h); break;
|
||||
case AdamsBashfortMoulton_4: default: solveABM4(u, h); break;
|
||||
case PolynomialApproximation_2: solvePA2(u, h); break;
|
||||
case PolynomialApproximation_3: solvePA3(u, h); break;
|
||||
case PolynomialApproximation_4: solvePA4(u, h); break;
|
||||
case PolynomialApproximation_5: solvePA5(u, h); break;
|
||||
}
|
||||
step++;
|
||||
}
|
||||
|
||||
|
||||
void Solver::fromTF(const TransferFunction & TF) {
|
||||
if (TF.vector_An.size() >= TF.vector_Bm.size())
|
||||
size = TF.vector_An.size()-1;
|
||||
else {
|
||||
piCout << "Solver error: {A} should be greater than {B}";
|
||||
return;
|
||||
}
|
||||
if (size == 0) return;
|
||||
|
||||
step = 0;
|
||||
times.fill(0.);
|
||||
A.resize(size, size);
|
||||
d.resize(size + 1); d.fill(0.);
|
||||
a1.resize(size + 1); a1.fill(0.);
|
||||
b1.resize(size + 1); b1.fill(0.);
|
||||
X.resize(size); X.fill(0.);
|
||||
F.resize(5);
|
||||
for (uint i = 0; i < 5; ++i)
|
||||
F[i].resize(size), F[i].fill(0.);
|
||||
k1.resize(size); k1.fill(0.);
|
||||
k2.resize(size); k2.fill(0.);
|
||||
k3.resize(size); k3.fill(0.);
|
||||
k4.resize(size); k4.fill(0.);
|
||||
xx.resize(size); xx.fill(0.);
|
||||
XX.resize(size); XX.fill(0.);
|
||||
for (uint i = 0; i < size + 1; ++i)
|
||||
a1[size - i] = TF.vector_An[i];
|
||||
for (uint i = 0; i < TF.vector_Bm.size(); ++i)
|
||||
b1[size - i] = TF.vector_Bm[i];
|
||||
double a0 = a1[0];
|
||||
a1 /= a0;
|
||||
b1 /= a0;
|
||||
|
||||
d[0] = b1[0]; // Рассчитываем вектор d
|
||||
for (uint i = 1; i < size + 1; ++i) {
|
||||
sum = 0.;
|
||||
for (uint m = 0; m < i; ++m)
|
||||
sum += a1[i - m] * d[m];
|
||||
d[i] = b1[i] - sum;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < size - 1; ++i) // Заполняем матрицу А
|
||||
for (uint j = 0; j < size; ++j)
|
||||
A[j][i] = (j == i + 1);
|
||||
for (uint i = 0; i < size; ++i)
|
||||
A[i][size - 1] = -a1[size - i];
|
||||
for (uint i = 0; i < size; ++i)
|
||||
d[i] = d[i + 1];
|
||||
}
|
||||
|
||||
|
||||
void Solver::solveEyler1(double u, double h) {
|
||||
/*for (uint i = 0; i < size; ++i) {
|
||||
* sum = 0.;
|
||||
* for (uint j = 0; j < size; ++j)
|
||||
* sum += A[j][i] * X[j];
|
||||
* xx[i] = sum + d[i] * u;
|
||||
}*/
|
||||
F[0] = A * X + d * u;
|
||||
X += F[0] * h;
|
||||
moveF();
|
||||
}
|
||||
|
||||
|
||||
void Solver::solveEyler2(double u, double h) {
|
||||
F[0] = A * X + d * u;
|
||||
X += (F[0] + F[1]) * h / 2.;
|
||||
moveF();
|
||||
}
|
||||
|
||||
|
||||
void Solver::solveRK4(double u, double h) {
|
||||
td = X[0] - F[0][0];
|
||||
k1 = A * X + d * u; xx = k1 * h / 2.; XX = X + xx;
|
||||
k2 = A * (XX + k1 * h / 2.) + d * (u + td/3.); xx = k2 * h / 2.; XX += xx;
|
||||
k3 = A * (XX + k2 * h / 2.) + d * (u + td*2./3.); xx = k3 * h; XX += xx;
|
||||
k4 = A * (XX + k3 * h) + d * (u + td);
|
||||
//cout << k1 << k2 << k3 << k4 << endl;
|
||||
X += (k1 + k2 * 2. + k3 * 2. + k4) * h / 6.;
|
||||
F[0] = X;
|
||||
}
|
||||
|
||||
|
||||
void Solver::solveABM2(double u, double h) {
|
||||
F[0] = A * X + d * u;
|
||||
XX = X + (F[0] * 3. - F[1]) * (h / 2.);
|
||||
F[1] = A * XX + d * u;
|
||||
X += (F[1] + F[0]) * (h / 2.);
|
||||
moveF();
|
||||
}
|
||||
|
||||
|
||||
void Solver::solveABM3(double u, double h) {
|
||||
F[0] = A * X + d * u;
|
||||
XX = X + (F[0] * 23. - F[1] * 16. + F[2] * 5.) * (h / 12.);
|
||||
F[2] = A * XX + d * u;
|
||||
X += (F[2] * 5. + F[0] * 8. - F[1]) * (h / 12.);
|
||||
moveF();
|
||||
}
|
||||
|
||||
|
||||
void Solver::solveABM4(double u, double h) {
|
||||
F[0] = A * X + d * u;
|
||||
XX = X + (F[0] * 55. - F[1] * 59. + F[2] * 37. - F[3] * 9.) * (h / 24.);
|
||||
F[3] = A * XX + d * u;
|
||||
X += (F[3] * 9. + F[0] * 19. - F[1] * 5. + F[2]) * (h / 24.);
|
||||
moveF();
|
||||
}
|
||||
|
||||
|
||||
void Solver::solvePA(double u, double h, uint deg) {
|
||||
F[0] = A * X + d * u;
|
||||
M.resize(deg, deg);
|
||||
Y.resize(deg);
|
||||
pY.resize(deg);
|
||||
|
||||
for (uint k = 0; k < size; ++k) {
|
||||
for (uint i = 0; i < deg; ++i) {
|
||||
td = 1.;
|
||||
ct = times[i];
|
||||
for (uint j = 0; j < deg; ++j) {
|
||||
M[j][i] = td;
|
||||
td *= ct;
|
||||
}
|
||||
}
|
||||
for (uint i = 0; i < deg; ++i)
|
||||
Y[i] = F[i][k];
|
||||
/// find polynom
|
||||
//if (step == 1) cout << M << endl << Y << endl;
|
||||
M.invert(&ok, &Y);
|
||||
//if (step == 1) cout << Y << endl;
|
||||
if (!ok) {
|
||||
solveEyler2(u, h);
|
||||
break;
|
||||
}
|
||||
/// calc last piece
|
||||
x0 = 0.;
|
||||
td = 1.;
|
||||
t = times[0];
|
||||
for (uint i = 0; i < deg; ++i) {
|
||||
x0 += Y[i] * td / (i + 1.);
|
||||
td *= t;
|
||||
}
|
||||
x0 *= t;
|
||||
|
||||
x1 = 0.;
|
||||
td = 1.;
|
||||
t = times[1];
|
||||
for (uint i = 0; i < deg; ++i) {
|
||||
x1 += Y[i] * td / (i + 1.);
|
||||
td *= t;
|
||||
}
|
||||
x1 *= t;
|
||||
lp = x0 - x1;
|
||||
|
||||
if (deg > 2) {
|
||||
/// calc prev piece
|
||||
x0 = 0.;
|
||||
td = 1.;
|
||||
dh = times[1] - times[2];
|
||||
if (dh != 0. && step > 1) {
|
||||
t = times[2];
|
||||
for (uint i = 0; i < deg; ++i) {
|
||||
x0 += Y[i] * td / (i + 1.);
|
||||
td *= t;
|
||||
}
|
||||
x0 *= t;
|
||||
ct = x1 - x0;
|
||||
/// calc correction
|
||||
ct -= pY[k];
|
||||
}
|
||||
/// calc final
|
||||
X[k] += lp - ct;
|
||||
pY[k] = lp;
|
||||
} else {
|
||||
X[k] += lp;
|
||||
pY[k] = lp;
|
||||
}
|
||||
}
|
||||
moveF();
|
||||
}
|
||||
|
||||
|
||||
|
||||
PIFFT::PIFFT() {
|
||||
prepared = false;
|
||||
}
|
||||
|
||||
|
||||
PIVector<complexd> * PIFFT::calcFFT(const PIVector<complexd> & val) {
|
||||
// for (uint i=0; i<result.size(); i+=2)
|
||||
// {
|
||||
// result[i] = val.at(indexes[i]) + val.at(indexes[i+1]);
|
||||
// result[i+1] = val.at(indexes[i]) - val.at(indexes[i+1]);
|
||||
// }
|
||||
// return &result;
|
||||
result.clear();
|
||||
if (val.size_s() < 4) return &result;
|
||||
fftc1d(val, val.size());
|
||||
return &result;
|
||||
}
|
||||
|
||||
|
||||
PIVector<complexd> *PIFFT::calcFFTinverse(const PIVector<complexd> &val)
|
||||
{
|
||||
result.clear();
|
||||
if (val.size_s() < 4) return &result;
|
||||
fftc1dinv(val, val.size());
|
||||
return &result;
|
||||
}
|
||||
|
||||
|
||||
PIVector<complexd> *PIFFT::calcHilbert(const PIVector<double> &val)
|
||||
{
|
||||
result.clear();
|
||||
if (val.size_s() < 4) return &result;
|
||||
fftc1r(val, val.size());
|
||||
for (uint i=0; i<result.size()/2; i++) result[i] = result[i]*2.;
|
||||
for (uint i=result.size()/2; i<result.size(); i++) result[i] = 0;
|
||||
fftc1dinv(result, result.size());
|
||||
return &result;
|
||||
}
|
||||
|
||||
|
||||
PIVector< complexd >* PIFFT::calcFFT(const PIVector<double> & val) {
|
||||
result.clear();
|
||||
if (val.size_s() < 4) return &result;
|
||||
fftc1r(val, val.size());
|
||||
return &result;
|
||||
}
|
||||
|
||||
|
||||
PIVector<double> PIFFT::getAmplitude() {
|
||||
PIVector<double> a;
|
||||
double tmp;
|
||||
for (uint i=0; i<result.size(); i++) {
|
||||
tmp = sqrt(result.at(i).real()*result.at(i).real()+result.at(i).imag()*result.at(i).imag());
|
||||
a.push_back(tmp);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
void PIFFT::fftc1d(const PIVector<complexd> &a, uint n) {
|
||||
createPlan(n);
|
||||
uint i;
|
||||
PIVector<double> buf;
|
||||
buf.resize(2*n);
|
||||
for(i=0; i<n; i++) {
|
||||
buf[2*i+0] = a.at(i).real();// a->ptr.p_complex[i].x;
|
||||
buf[2*i+1] = a.at(i).imag();//a->ptr.p_complex[i].y;
|
||||
}
|
||||
ftbaseexecuteplan(&buf, 0, n, &curplan);
|
||||
result.resize(n);
|
||||
for(i=0; i<n; i++)
|
||||
result[i]=complexd(buf[2*i+0],buf[2*i+1]);
|
||||
}
|
||||
|
||||
|
||||
void PIFFT::fftc1r(const PIVector<double> & a, uint n) {
|
||||
uint i;
|
||||
if( n%2==0) {
|
||||
PIVector<double> buf;
|
||||
uint n2 = n/2;
|
||||
//buf.resize(n);
|
||||
buf = a;
|
||||
createPlan(n2);
|
||||
//cout << "fftr " << n2 << endl;
|
||||
ftbaseexecuteplan(&buf, 0, n2, &curplan);
|
||||
result.resize(n);
|
||||
uint idx;
|
||||
complexd hn, hmnc, v;
|
||||
for(i=0; i<=n2; i++) {
|
||||
idx = 2*(i%n2);
|
||||
hn = complexd(buf[idx+0], buf[idx+1]);
|
||||
idx = 2*((n2-i)%n2);
|
||||
hmnc = complexd(buf[idx+0], -buf[idx+1]);
|
||||
v = complexd(sin(M_PI*i/n2), cos(M_PI*i/n2));
|
||||
result[i] = ((hn + hmnc) - (v * (hn - hmnc)));
|
||||
result[i] *= 0.5;
|
||||
}
|
||||
for(i=n2+1; i<n; i++)
|
||||
result[i] = conj(result[n-i]);
|
||||
} else {
|
||||
PIVector<complexd> cbuf;
|
||||
cbuf.resize(n);
|
||||
for(i=0; i<n; i++)
|
||||
cbuf[i] = complexd(a[i], 0.);
|
||||
fftc1d(cbuf, n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIFFT::fftc1dinv(const PIVector<complexd> &a, uint n)
|
||||
{
|
||||
PIVector<complexd> cbuf;
|
||||
cbuf.resize(n);
|
||||
uint i;
|
||||
for(i=0; i<n; i++)
|
||||
{
|
||||
cbuf[i] = conj(a[i]);
|
||||
}
|
||||
fftc1d(cbuf, n);
|
||||
// result.resize(n);
|
||||
for(i=0; i<n; i++)
|
||||
{
|
||||
result[i] = conj(result[i] / (double)n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIFFT::createPlan(uint n) {
|
||||
curplan.plan.clear();
|
||||
curplan.precomputed.clear();
|
||||
curplan.stackbuf.clear();
|
||||
curplan.tmpbuf.clear();
|
||||
if (n<2) return;
|
||||
ftbasegeneratecomplexfftplan(n, &curplan);
|
||||
prepared = true;
|
||||
}
|
||||
|
||||
|
||||
void PIFFT::ftbasegeneratecomplexfftplan(uint n, ftplan* plan) {
|
||||
int planarraysize;
|
||||
int plansize;
|
||||
int precomputedsize;
|
||||
int tmpmemsize;
|
||||
int stackmemsize;
|
||||
ae_int_t stackptr;
|
||||
planarraysize = 1;
|
||||
plansize = 0;
|
||||
precomputedsize = 0;
|
||||
stackmemsize = 0;
|
||||
stackptr = 0;
|
||||
tmpmemsize = 2*n;
|
||||
curplan.plan.resize(planarraysize);
|
||||
int ftbase_ftbasecffttask = 0;
|
||||
ftbase_ftbasegenerateplanrec(n, ftbase_ftbasecffttask, plan, &plansize, &precomputedsize, &planarraysize, &tmpmemsize, &stackmemsize, stackptr);
|
||||
if (stackptr!=0) { return;}//ae_assert(stackptr==0, "Internal error in FTBaseGenerateComplexFFTPlan: stack ptr!");
|
||||
curplan.stackbuf.resize(piMax<int>(stackmemsize,1));//ae_vector_set_length(&curplan.stackbuf, ae_maxint(stackmemsize, 1));
|
||||
curplan.tmpbuf.resize(piMax<int>(tmpmemsize,1));//ae_vector_set_length(&(curplan.tmpbuf), ae_maxint(tmpmemsize, 1));
|
||||
curplan.precomputed.resize(piMax<int>(precomputedsize,1));//ae_vector_set_length(&curplan.precomputed, ae_maxint(precomputedsize, 1));
|
||||
stackptr = 0;
|
||||
ftbase_ftbaseprecomputeplanrec(plan, 0, stackptr);
|
||||
if (stackptr!=0) { return;}//ae_assert(stackptr==0, "Internal error in FTBaseGenerateComplexFFTPlan: stack ptr!");
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Recurrent subroutine for the FFTGeneratePlan:
|
||||
|
||||
PARAMETERS:
|
||||
N plan size
|
||||
IsReal whether input is real or not.
|
||||
subroutine MUST NOT ignore this flag because real
|
||||
inputs comes with non-initialized imaginary parts,
|
||||
so ignoring this flag will result in corrupted output
|
||||
HalfOut whether full output or only half of it from 0 to
|
||||
floor(N/2) is needed. This flag may be ignored if
|
||||
doing so will simplify calculations
|
||||
Plan plan array
|
||||
PlanSize size of used part (in integers)
|
||||
PrecomputedSize size of precomputed array allocated yet
|
||||
PlanArraySize plan array size (actual)
|
||||
TmpMemSize temporary memory required size
|
||||
BluesteinMemSize temporary memory required size
|
||||
|
||||
-- ALGLIB --
|
||||
Copyright 01.05.2009 by Bochkanov Sergey
|
||||
*************************************************************************/
|
||||
void PIFFT::ftbase_ftbasegenerateplanrec(
|
||||
int n,
|
||||
int tasktype,
|
||||
ftplan* plan,
|
||||
int* plansize,
|
||||
int* precomputedsize,
|
||||
int* planarraysize,
|
||||
int* tmpmemsize,
|
||||
int* stackmemsize,
|
||||
ae_int_t stackptr, int debugi)
|
||||
{
|
||||
int k, m, n1, n2, esize, entryoffset;
|
||||
int ftbase_ftbaseplanentrysize = 8;
|
||||
int ftbase_ftbasecffttask = 0;
|
||||
int ftbase_fftcooleytukeyplan = 0;
|
||||
int ftbase_fftbluesteinplan = 1;
|
||||
int ftbase_fftcodeletplan = 2;
|
||||
int ftbase_fftrealcooleytukeyplan = 5;
|
||||
int ftbase_fftemptyplan = 6;
|
||||
if( *plansize+ftbase_ftbaseplanentrysize>(*planarraysize)) {
|
||||
curplan.plan.resize(8*(*planarraysize));
|
||||
*planarraysize = 8*(*planarraysize);
|
||||
}
|
||||
entryoffset = *plansize;
|
||||
esize = ftbase_ftbaseplanentrysize;
|
||||
*plansize = *plansize+esize;
|
||||
if( n==1) {
|
||||
curplan.plan[entryoffset+0] = esize;
|
||||
curplan.plan[entryoffset+1] = -1;
|
||||
curplan.plan[entryoffset+2] = -1;
|
||||
curplan.plan[entryoffset+3] = ftbase_fftemptyplan;
|
||||
curplan.plan[entryoffset+4] = -1;
|
||||
curplan.plan[entryoffset+5] = -1;
|
||||
curplan.plan[entryoffset+6] = -1;
|
||||
curplan.plan[entryoffset+7] = -1;
|
||||
return;
|
||||
}
|
||||
ftbasefactorize(n, &n1, &n2);
|
||||
if( n1!=1) {
|
||||
*tmpmemsize = piMax<int>(*tmpmemsize, 2*n1*n2);
|
||||
curplan.plan[entryoffset+0] = esize;
|
||||
curplan.plan[entryoffset+1] = n1;
|
||||
curplan.plan[entryoffset+2] = n2;
|
||||
if( tasktype==ftbase_ftbasecffttask)
|
||||
curplan.plan[entryoffset+3] = ftbase_fftcooleytukeyplan;
|
||||
else
|
||||
curplan.plan[entryoffset+3] = ftbase_fftrealcooleytukeyplan;
|
||||
curplan.plan[entryoffset+4] = 0;
|
||||
curplan.plan[entryoffset+5] = *plansize;
|
||||
debugi++;
|
||||
ftbase_ftbasegenerateplanrec(n1, ftbase_ftbasecffttask, plan, plansize, precomputedsize, planarraysize, tmpmemsize, stackmemsize, stackptr,debugi);
|
||||
curplan.plan[entryoffset+6] = *plansize;
|
||||
ftbase_ftbasegenerateplanrec(n2, ftbase_ftbasecffttask, plan, plansize, precomputedsize, planarraysize, tmpmemsize, stackmemsize, stackptr,debugi);
|
||||
curplan.plan[entryoffset+7] = -1;
|
||||
return;
|
||||
} else {
|
||||
if (n>=2 && n<=5) {
|
||||
curplan.plan[entryoffset+0] = esize;
|
||||
curplan.plan[entryoffset+1] = n1;
|
||||
curplan.plan[entryoffset+2] = n2;
|
||||
curplan.plan[entryoffset+3] = ftbase_fftcodeletplan;
|
||||
curplan.plan[entryoffset+4] = 0;
|
||||
curplan.plan[entryoffset+5] = -1;
|
||||
curplan.plan[entryoffset+6] = -1;
|
||||
curplan.plan[entryoffset+7] = *precomputedsize;
|
||||
if( n==3)
|
||||
*precomputedsize = *precomputedsize+2;
|
||||
if( n==5)
|
||||
*precomputedsize = *precomputedsize+5;
|
||||
return;
|
||||
} else {
|
||||
k = 2*n2-1;
|
||||
m = ftbasefindsmooth(k);
|
||||
*tmpmemsize = piMax<int>(*tmpmemsize, 2*m);
|
||||
curplan.plan[entryoffset+0] = esize;
|
||||
curplan.plan[entryoffset+1] = n2;
|
||||
curplan.plan[entryoffset+2] = -1;
|
||||
curplan.plan[entryoffset+3] = ftbase_fftbluesteinplan;
|
||||
curplan.plan[entryoffset+4] = m;
|
||||
curplan.plan[entryoffset+5] = *plansize;
|
||||
stackptr = stackptr+2*2*m;
|
||||
*stackmemsize = piMax<int>(*stackmemsize, stackptr);
|
||||
ftbase_ftbasegenerateplanrec(m, ftbase_ftbasecffttask, plan, plansize, precomputedsize, planarraysize, tmpmemsize, stackmemsize, stackptr);
|
||||
stackptr = stackptr-2*2*m;
|
||||
curplan.plan[entryoffset+6] = -1;
|
||||
curplan.plan[entryoffset+7] = *precomputedsize;
|
||||
*precomputedsize = *precomputedsize+2*m+2*n;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Recurrent subroutine for precomputing FFT plans
|
||||
|
||||
-- ALGLIB --
|
||||
Copyright 01.05.2009 by Bochkanov Sergey
|
||||
*************************************************************************/
|
||||
void PIFFT::ftbase_ftbaseprecomputeplanrec(ftplan* plan,
|
||||
int entryoffset,
|
||||
ae_int_t stackptr)
|
||||
{
|
||||
int n1, n2, n, m, offs;
|
||||
double v, bx, by;
|
||||
int ftbase_fftcooleytukeyplan = 0;
|
||||
int ftbase_fftbluesteinplan = 1;
|
||||
int ftbase_fftcodeletplan = 2;
|
||||
int ftbase_fhtcooleytukeyplan = 3;
|
||||
int ftbase_fhtcodeletplan = 4;
|
||||
int ftbase_fftrealcooleytukeyplan = 5;
|
||||
if( (curplan.plan[entryoffset+3]==ftbase_fftcooleytukeyplan||curplan.plan[entryoffset+3]==ftbase_fftrealcooleytukeyplan)||curplan.plan[entryoffset+3]==ftbase_fhtcooleytukeyplan) {
|
||||
ftbase_ftbaseprecomputeplanrec(plan, curplan.plan[entryoffset+5], stackptr);
|
||||
ftbase_ftbaseprecomputeplanrec(plan, curplan.plan[entryoffset+6], stackptr);
|
||||
return;
|
||||
}
|
||||
if( curplan.plan[entryoffset+3]==ftbase_fftcodeletplan||curplan.plan[entryoffset+3]==ftbase_fhtcodeletplan) {
|
||||
n1 = curplan.plan[entryoffset+1];
|
||||
n2 = curplan.plan[entryoffset+2];
|
||||
n = n1*n2;
|
||||
if( n==3) {
|
||||
offs = curplan.plan[entryoffset+7];
|
||||
curplan.precomputed[offs+0] = cos(2*M_PI/3)-1;
|
||||
curplan.precomputed[offs+1] = sin(2*M_PI/3);
|
||||
return;
|
||||
}
|
||||
if( n==5) {
|
||||
offs = curplan.plan[entryoffset+7];
|
||||
v = 2*M_PI/5;
|
||||
curplan.precomputed[offs+0] = (cos(v)+cos(2*v))/2-1;
|
||||
curplan.precomputed[offs+1] = (cos(v)-cos(2*v))/2;
|
||||
curplan.precomputed[offs+2] = -sin(v);
|
||||
curplan.precomputed[offs+3] = -(sin(v)+sin(2*v));
|
||||
curplan.precomputed[offs+4] = sin(v)-sin(2*v);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( curplan.plan[entryoffset+3]==ftbase_fftbluesteinplan) {
|
||||
ftbase_ftbaseprecomputeplanrec(plan, curplan.plan[entryoffset+5], stackptr);
|
||||
n = curplan.plan[entryoffset+1];
|
||||
m = curplan.plan[entryoffset+4];
|
||||
offs = curplan.plan[entryoffset+7];
|
||||
for(int i=0; i<=2*m-1; i++)
|
||||
curplan.precomputed[offs+i] = 0;
|
||||
for(int i=0; i<n; i++) {
|
||||
bx = cos(M_PI*sqr(i)/n);
|
||||
by = sin(M_PI*sqr(i)/n);
|
||||
curplan.precomputed[offs+2*i+0] = bx;
|
||||
curplan.precomputed[offs+2*i+1] = by;
|
||||
curplan.precomputed[offs+2*m+2*i+0] = bx;
|
||||
curplan.precomputed[offs+2*m+2*i+1] = by;
|
||||
if( i>0) {
|
||||
curplan.precomputed[offs+2*(m-i)+0] = bx;
|
||||
curplan.precomputed[offs+2*(m-i)+1] = by;
|
||||
}
|
||||
}
|
||||
ftbaseexecuteplanrec(&curplan.precomputed, offs, plan, curplan.plan[entryoffset+5], stackptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIFFT::ftbasefactorize(int n, int* n1, int* n2) {
|
||||
*n1 = *n2 = 0;
|
||||
int ftbase_ftbasecodeletrecommended = 5;
|
||||
if( (*n1)*(*n2)!=n) {
|
||||
for(int j=ftbase_ftbasecodeletrecommended; j>=2; j--) {
|
||||
if( n%j==0) {
|
||||
*n1 = j;
|
||||
*n2 = n/j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( (*n1)*(*n2)!=n) {
|
||||
for(int j=ftbase_ftbasecodeletrecommended+1; j<=n-1; j++) {
|
||||
if( n%j==0) {
|
||||
*n1 = j;
|
||||
*n2 = n/j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( (*n1)*(*n2)!=n) {
|
||||
*n1 = 1;
|
||||
*n2 = n;
|
||||
}
|
||||
if( (*n2)==1 && (*n1)!=1) {
|
||||
*n2 = *n1;
|
||||
*n1 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Is number smooth?
|
||||
|
||||
-- ALGLIB --
|
||||
Copyright 01.05.2009 by Bochkanov Sergey
|
||||
*************************************************************************/
|
||||
void PIFFT::ftbase_ftbasefindsmoothrec(int n, int seed, int leastfactor, int* best) {
|
||||
if( seed>=n) {
|
||||
*best = piMin<int>(*best, seed);
|
||||
return;
|
||||
}
|
||||
if( leastfactor<=2)
|
||||
ftbase_ftbasefindsmoothrec(n, seed*2, 2, best);
|
||||
if( leastfactor<=3)
|
||||
ftbase_ftbasefindsmoothrec(n, seed*3, 3, best);
|
||||
if( leastfactor<=5)
|
||||
ftbase_ftbasefindsmoothrec(n, seed*5, 5, best);
|
||||
}
|
||||
|
||||
|
||||
int PIFFT::ftbasefindsmooth(int n) {
|
||||
int best, result;
|
||||
best = 2;
|
||||
while(best<n)
|
||||
best = 2*best;
|
||||
ftbase_ftbasefindsmoothrec(n, 1, 2, &best);
|
||||
result = best;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void PIFFT::ftbase_internalreallintranspose(PIVector<double>* a, int m, int n, int astart, PIVector<double>* buf) {
|
||||
ftbase_fftirltrec(a, astart, n, buf, 0, m, m, n);
|
||||
for (int i=0; i<2*m*n; i++) (*a)[astart+i] = (*buf)[i];
|
||||
}
|
||||
|
||||
|
||||
void PIFFT::ftbase_fftirltrec(PIVector<double>* a, int astart, int astride, PIVector<double>* b, int bstart, int bstride, int m, int n) {
|
||||
int idx1, idx2;
|
||||
int m1, n1;
|
||||
if( m==0||n==0)
|
||||
return;
|
||||
if( piMax<int>(m, n)<=8) {
|
||||
for(int i=0; i<=m-1; i++) {
|
||||
idx1 = bstart+i;
|
||||
idx2 = astart+i*astride;
|
||||
for(int j=0; j<=n-1; j++) {
|
||||
(*b)[idx1] = a->at(idx2);
|
||||
idx1 = idx1+bstride;
|
||||
idx2 = idx2+1;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if( n>m) {
|
||||
n1 = n/2;
|
||||
if( n-n1>=8&&n1%8!=0)
|
||||
n1 = n1+(8-n1%8);
|
||||
ftbase_fftirltrec(a, astart, astride, b, bstart, bstride, m, n1);
|
||||
ftbase_fftirltrec(a, astart+n1, astride, b, bstart+n1*bstride, bstride, m, n-n1);
|
||||
} else {
|
||||
m1 = m/2;
|
||||
if( m-m1>=8&&m1%8!=0)
|
||||
m1 = m1+(8-m1%8);
|
||||
ftbase_fftirltrec(a, astart, astride, b, bstart, bstride, m1, n);
|
||||
ftbase_fftirltrec(a, astart+m1*astride, astride, b, bstart+m1, bstride, m-m1, n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIFFT::ftbase_internalcomplexlintranspose(PIVector<double>* a, int m, int n, int astart, PIVector<double>* buf) {
|
||||
ftbase_ffticltrec(a, astart, n, buf, 0, m, m, n);
|
||||
for (int i=0; i<2*m*n; i++)
|
||||
(*a)[astart+i] = (*buf)[i];
|
||||
}
|
||||
|
||||
|
||||
void PIFFT::ftbase_ffticltrec(PIVector<double>* a, int astart, int astride, PIVector<double>* b, int bstart, int bstride, int m, int n) {
|
||||
int idx1, idx2, m2, m1, n1;
|
||||
if( m==0||n==0)
|
||||
return;
|
||||
if( piMax<int>(m, n)<=8) {
|
||||
m2 = 2*bstride;
|
||||
for(int i=0; i<=m-1; i++) {
|
||||
idx1 = bstart+2*i;
|
||||
idx2 = astart+2*i*astride;
|
||||
for(int j=0; j<=n-1; j++) {
|
||||
(*b)[idx1+0] = a->at(idx2+0);
|
||||
(*b)[idx1+1] = a->at(idx2+1);
|
||||
idx1 = idx1+m2;
|
||||
idx2 = idx2+2;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if( n>m) {
|
||||
n1 = n/2;
|
||||
if( n-n1>=8&&n1%8!=0)
|
||||
n1 = n1+(8-n1%8);
|
||||
ftbase_ffticltrec(a, astart, astride, b, bstart, bstride, m, n1);
|
||||
ftbase_ffticltrec(a, astart+2*n1, astride, b, bstart+2*n1*bstride, bstride, m, n-n1);
|
||||
} else {
|
||||
m1 = m/2;
|
||||
if( m-m1>=8&&m1%8!=0)
|
||||
m1 = m1+(8-m1%8);
|
||||
ftbase_ffticltrec(a, astart, astride, b, bstart, bstride, m1, n);
|
||||
ftbase_ffticltrec(a, astart+2*m1*astride, astride, b, bstart+2*m1, bstride, m-m1, n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIFFT::ftbaseexecuteplan(PIVector<double>* a, int aoffset, int n, ftplan* plan) {
|
||||
ae_int_t stackptr;
|
||||
stackptr = 0;
|
||||
ftbaseexecuteplanrec(a, aoffset, plan, 0, stackptr);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Recurrent subroutine for the FTBaseExecutePlan
|
||||
|
||||
Parameters:
|
||||
A FFT'ed array
|
||||
AOffset offset of the FFT'ed part (distance is measured in doubles)
|
||||
|
||||
-- ALGLIB --
|
||||
Copyright 01.05.2009 by Bochkanov Sergey
|
||||
*************************************************************************/
|
||||
void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan, int entryoffset, ae_int_t stackptr) {
|
||||
int n1, n2, n, m, offs, offs1, offs2, offsa, offsb, offsp;
|
||||
double hk, hnk, x, y, bx, by, v0, v1, v2, v3;
|
||||
double a0x, a0y, a1x, a1y, a2x, a2y, a3x, a3y;
|
||||
double t1x, t1y, t2x, t2y, t3x, t3y, t4x, t4y, t5x, t5y;
|
||||
double m1x, m1y, m2x, m2y, m3x, m3y, m4x, m4y, m5x, m5y;
|
||||
double s1x, s1y, s2x, s2y, s3x, s3y, s4x, s4y, s5x, s5y;
|
||||
double c1, c2, c3, c4, c5;
|
||||
int ftbase_fftcooleytukeyplan = 0;
|
||||
int ftbase_fftbluesteinplan = 1;
|
||||
int ftbase_fftcodeletplan = 2;
|
||||
int ftbase_fhtcooleytukeyplan = 3;
|
||||
int ftbase_fhtcodeletplan = 4;
|
||||
int ftbase_fftrealcooleytukeyplan = 5;
|
||||
int ftbase_fftemptyplan = 6;
|
||||
PIVector<double> & tmpb(curplan.tmpbuf);
|
||||
|
||||
if( curplan.plan[entryoffset+3]==ftbase_fftemptyplan)
|
||||
return;
|
||||
if( curplan.plan[entryoffset+3]==ftbase_fftcooleytukeyplan) {
|
||||
n1 = curplan.plan[entryoffset+1];
|
||||
n2 = curplan.plan[entryoffset+2];
|
||||
ftbase_internalcomplexlintranspose(a, n1, n2, aoffset, &(curplan.tmpbuf));
|
||||
for(int i=0; i<=n2-1; i++)
|
||||
ftbaseexecuteplanrec(a, aoffset+i*n1*2, plan, curplan.plan[entryoffset+5], stackptr);
|
||||
ftbase_ffttwcalc(a, aoffset, n1, n2);
|
||||
ftbase_internalcomplexlintranspose(a, n2, n1, aoffset, &(curplan.tmpbuf));
|
||||
for(int i=0; i<=n1-1; i++)
|
||||
ftbaseexecuteplanrec(a, aoffset+i*n2*2, plan, curplan.plan[entryoffset+6], stackptr);
|
||||
ftbase_internalcomplexlintranspose(a, n1, n2, aoffset, &(curplan.tmpbuf));
|
||||
return;
|
||||
}
|
||||
if( curplan.plan[entryoffset+3]==ftbase_fftrealcooleytukeyplan) {
|
||||
n1 = curplan.plan[entryoffset+1];
|
||||
n2 = curplan.plan[entryoffset+2];
|
||||
ftbase_internalcomplexlintranspose(a, n2, n1, aoffset, &(curplan.tmpbuf));
|
||||
for(int i=0; i<=n1/2-1; i++) {
|
||||
offs = aoffset+2*i*n2*2;
|
||||
for(int k=0; k<=n2-1; k++)
|
||||
(*a)[offs+2*k+1] = (*a)[offs+2*n2+2*k+0];
|
||||
ftbaseexecuteplanrec(a, offs, plan, curplan.plan[entryoffset+6], stackptr);
|
||||
tmpb[0] = (*a)[offs+0];
|
||||
tmpb[1] = 0;
|
||||
tmpb[2*n2+0] = (*a)[offs+1];
|
||||
tmpb[2*n2+1] = 0;
|
||||
for(int k=1; k<=n2-1; k++) {
|
||||
offs1 = 2*k;
|
||||
offs2 = 2*n2+2*k;
|
||||
hk = (*a)[offs+2*k+0];
|
||||
hnk = (*a)[offs+2*(n2-k)+0];
|
||||
tmpb[offs1+0] = 0.5*(hk+hnk);
|
||||
tmpb[offs2+1] = -0.5*(hk-hnk);
|
||||
hk = (*a)[offs+2*k+1];
|
||||
hnk = (*a)[offs+2*(n2-k)+1];
|
||||
tmpb[offs2+0] = 0.5*(hk+hnk);
|
||||
tmpb[offs1+1] = 0.5*(hk-hnk);
|
||||
}
|
||||
for (int i=0; i<2*n2*2; i++) (*a)[offs+i] = tmpb[i];
|
||||
}
|
||||
if( n1%2!=0)
|
||||
ftbaseexecuteplanrec(a, aoffset+(n1-1)*n2*2, plan, curplan.plan[entryoffset+6], stackptr);
|
||||
ftbase_ffttwcalc(a, aoffset, n2, n1);
|
||||
ftbase_internalcomplexlintranspose(a, n1, n2, aoffset, &(curplan.tmpbuf));
|
||||
for(int i=0; i<=n2-1; i++)
|
||||
ftbaseexecuteplanrec(a, aoffset+i*n1*2, plan, curplan.plan[entryoffset+5], stackptr);
|
||||
ftbase_internalcomplexlintranspose(a, n2, n1, aoffset, &(curplan.tmpbuf));
|
||||
return;
|
||||
}
|
||||
if( curplan.plan[entryoffset+3]==ftbase_fhtcooleytukeyplan) {
|
||||
n1 = curplan.plan[entryoffset+1];
|
||||
n2 = curplan.plan[entryoffset+2];
|
||||
n = n1*n2;
|
||||
ftbase_internalreallintranspose(a, n1, n2, aoffset, &(curplan.tmpbuf));
|
||||
for(int i=0; i<=n2-1; i++)
|
||||
ftbaseexecuteplanrec(a, aoffset+i*n1, plan, curplan.plan[entryoffset+5], stackptr);
|
||||
for(int i=0; i<=n2-1; i++) {
|
||||
for(int j=0; j<=n1-1; j++) {
|
||||
offsa = aoffset+i*n1;
|
||||
hk = (*a)[offsa+j];
|
||||
hnk = (*a)[offsa+(n1-j)%n1];
|
||||
offs = 2*(i*n1+j);
|
||||
tmpb[offs+0] = -0.5*(hnk-hk);
|
||||
tmpb[offs+1] = 0.5*(hk+hnk);
|
||||
}
|
||||
}
|
||||
ftbase_ffttwcalc(&(curplan.tmpbuf), 0, n1, n2);
|
||||
for(int j=0; j<=n1-1; j++)
|
||||
(*a)[aoffset+j] = tmpb[2*j+0]+tmpb[2*j+1];
|
||||
if( n2%2==0) {
|
||||
offs = 2*(n2/2)*n1;
|
||||
offsa = aoffset+n2/2*n1;
|
||||
for(int j=0; j<=n1-1; j++)
|
||||
(*a)[offsa+j] = tmpb[offs+2*j+0]+tmpb[offs+2*j+1];
|
||||
}
|
||||
for(int i=1; i<=(n2+1)/2-1; i++) {
|
||||
offs = 2*i*n1;
|
||||
offs2 = 2*(n2-i)*n1;
|
||||
offsa = aoffset+i*n1;
|
||||
for(int j=0; j<=n1-1; j++)
|
||||
(*a)[offsa+j] = tmpb[offs+2*j+1]+tmpb[offs2+2*j+0];
|
||||
offsa = aoffset+(n2-i)*n1;
|
||||
for(int j=0; j<=n1-1; j++)
|
||||
(*a)[offsa+j] = tmpb[offs+2*j+0]+tmpb[offs2+2*j+1];
|
||||
}
|
||||
ftbase_internalreallintranspose(a, n2, n1, aoffset, &(curplan.tmpbuf));
|
||||
for(int i=0; i<=n1-1; i++)
|
||||
ftbaseexecuteplanrec(a, aoffset+i*n2, plan, curplan.plan[entryoffset+6], stackptr);
|
||||
ftbase_internalreallintranspose(a, n1, n2, aoffset, &(curplan.tmpbuf));
|
||||
return;
|
||||
}
|
||||
if( curplan.plan[entryoffset+3]==ftbase_fftcodeletplan) {
|
||||
n1 = curplan.plan[entryoffset+1];
|
||||
n2 = curplan.plan[entryoffset+2];
|
||||
n = n1*n2;
|
||||
if( n==2) {
|
||||
a0x = (*a)[aoffset+0];
|
||||
a0y = (*a)[aoffset+1];
|
||||
a1x = (*a)[aoffset+2];
|
||||
a1y = (*a)[aoffset+3];
|
||||
v0 = a0x+a1x;
|
||||
v1 = a0y+a1y;
|
||||
v2 = a0x-a1x;
|
||||
v3 = a0y-a1y;
|
||||
(*a)[aoffset+0] = v0;
|
||||
(*a)[aoffset+1] = v1;
|
||||
(*a)[aoffset+2] = v2;
|
||||
(*a)[aoffset+3] = v3;
|
||||
return;
|
||||
}
|
||||
if( n==3) {
|
||||
offs = curplan.plan[entryoffset+7];
|
||||
c1 = curplan.precomputed[offs+0];
|
||||
c2 = curplan.precomputed[offs+1];
|
||||
a0x = (*a)[aoffset+0];
|
||||
a0y = (*a)[aoffset+1];
|
||||
a1x = (*a)[aoffset+2];
|
||||
a1y = (*a)[aoffset+3];
|
||||
a2x = (*a)[aoffset+4];
|
||||
a2y = (*a)[aoffset+5];
|
||||
t1x = a1x+a2x;
|
||||
t1y = a1y+a2y;
|
||||
a0x = a0x+t1x;
|
||||
a0y = a0y+t1y;
|
||||
m1x = c1*t1x;
|
||||
m1y = c1*t1y;
|
||||
m2x = c2*(a1y-a2y);
|
||||
m2y = c2*(a2x-a1x);
|
||||
s1x = a0x+m1x;
|
||||
s1y = a0y+m1y;
|
||||
a1x = s1x+m2x;
|
||||
a1y = s1y+m2y;
|
||||
a2x = s1x-m2x;
|
||||
a2y = s1y-m2y;
|
||||
(*a)[aoffset+0] = a0x;
|
||||
(*a)[aoffset+1] = a0y;
|
||||
(*a)[aoffset+2] = a1x;
|
||||
(*a)[aoffset+3] = a1y;
|
||||
(*a)[aoffset+4] = a2x;
|
||||
(*a)[aoffset+5] = a2y;
|
||||
return;
|
||||
}
|
||||
if( n==4) {
|
||||
a0x = (*a)[aoffset+0];
|
||||
a0y = (*a)[aoffset+1];
|
||||
a1x = (*a)[aoffset+2];
|
||||
a1y = (*a)[aoffset+3];
|
||||
a2x = (*a)[aoffset+4];
|
||||
a2y = (*a)[aoffset+5];
|
||||
a3x = (*a)[aoffset+6];
|
||||
a3y = (*a)[aoffset+7];
|
||||
t1x = a0x+a2x;
|
||||
t1y = a0y+a2y;
|
||||
t2x = a1x+a3x;
|
||||
t2y = a1y+a3y;
|
||||
m2x = a0x-a2x;
|
||||
m2y = a0y-a2y;
|
||||
m3x = a1y-a3y;
|
||||
m3y = a3x-a1x;
|
||||
(*a)[aoffset+0] = t1x+t2x;
|
||||
(*a)[aoffset+1] = t1y+t2y;
|
||||
(*a)[aoffset+4] = t1x-t2x;
|
||||
(*a)[aoffset+5] = t1y-t2y;
|
||||
(*a)[aoffset+2] = m2x+m3x;
|
||||
(*a)[aoffset+3] = m2y+m3y;
|
||||
(*a)[aoffset+6] = m2x-m3x;
|
||||
(*a)[aoffset+7] = m2y-m3y;
|
||||
return;
|
||||
}
|
||||
if( n==5) {
|
||||
offs = curplan.plan[entryoffset+7];
|
||||
c1 = curplan.precomputed[offs+0];
|
||||
c2 = curplan.precomputed[offs+1];
|
||||
c3 = curplan.precomputed[offs+2];
|
||||
c4 = curplan.precomputed[offs+3];
|
||||
c5 = curplan.precomputed[offs+4];
|
||||
t1x = (*a)[aoffset+2]+(*a)[aoffset+8];
|
||||
t1y = (*a)[aoffset+3]+(*a)[aoffset+9];
|
||||
t2x = (*a)[aoffset+4]+(*a)[aoffset+6];
|
||||
t2y = (*a)[aoffset+5]+(*a)[aoffset+7];
|
||||
t3x = (*a)[aoffset+2]-(*a)[aoffset+8];
|
||||
t3y = (*a)[aoffset+3]-(*a)[aoffset+9];
|
||||
t4x = (*a)[aoffset+6]-(*a)[aoffset+4];
|
||||
t4y = (*a)[aoffset+7]-(*a)[aoffset+5];
|
||||
t5x = t1x+t2x;
|
||||
t5y = t1y+t2y;
|
||||
(*a)[aoffset+0] = (*a)[aoffset+0]+t5x;
|
||||
(*a)[aoffset+1] = (*a)[aoffset+1]+t5y;
|
||||
m1x = c1*t5x;
|
||||
m1y = c1*t5y;
|
||||
m2x = c2*(t1x-t2x);
|
||||
m2y = c2*(t1y-t2y);
|
||||
m3x = -c3*(t3y+t4y);
|
||||
m3y = c3*(t3x+t4x);
|
||||
m4x = -c4*t4y;
|
||||
m4y = c4*t4x;
|
||||
m5x = -c5*t3y;
|
||||
m5y = c5*t3x;
|
||||
s3x = m3x-m4x;
|
||||
s3y = m3y-m4y;
|
||||
s5x = m3x+m5x;
|
||||
s5y = m3y+m5y;
|
||||
s1x = (*a)[aoffset+0]+m1x;
|
||||
s1y = (*a)[aoffset+1]+m1y;
|
||||
s2x = s1x+m2x;
|
||||
s2y = s1y+m2y;
|
||||
s4x = s1x-m2x;
|
||||
s4y = s1y-m2y;
|
||||
(*a)[aoffset+2] = s2x+s3x;
|
||||
(*a)[aoffset+3] = s2y+s3y;
|
||||
(*a)[aoffset+4] = s4x+s5x;
|
||||
(*a)[aoffset+5] = s4y+s5y;
|
||||
(*a)[aoffset+6] = s4x-s5x;
|
||||
(*a)[aoffset+7] = s4y-s5y;
|
||||
(*a)[aoffset+8] = s2x-s3x;
|
||||
(*a)[aoffset+9] = s2y-s3y;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( curplan.plan[entryoffset+3]==ftbase_fhtcodeletplan) {
|
||||
n1 = curplan.plan[entryoffset+1];
|
||||
n2 = curplan.plan[entryoffset+2];
|
||||
n = n1*n2;
|
||||
if( n==2) {
|
||||
a0x = (*a)[aoffset+0];
|
||||
a1x = (*a)[aoffset+1];
|
||||
(*a)[aoffset+0] = a0x+a1x;
|
||||
(*a)[aoffset+1] = a0x-a1x;
|
||||
return;
|
||||
}
|
||||
if( n==3) {
|
||||
offs = curplan.plan[entryoffset+7];
|
||||
c1 = curplan.precomputed[offs+0];
|
||||
c2 = curplan.precomputed[offs+1];
|
||||
a0x = (*a)[aoffset+0];
|
||||
a1x = (*a)[aoffset+1];
|
||||
a2x = (*a)[aoffset+2];
|
||||
t1x = a1x+a2x;
|
||||
a0x = a0x+t1x;
|
||||
m1x = c1*t1x;
|
||||
m2y = c2*(a2x-a1x);
|
||||
s1x = a0x+m1x;
|
||||
(*a)[aoffset+0] = a0x;
|
||||
(*a)[aoffset+1] = s1x-m2y;
|
||||
(*a)[aoffset+2] = s1x+m2y;
|
||||
return;
|
||||
}
|
||||
if( n==4) {
|
||||
a0x = (*a)[aoffset+0];
|
||||
a1x = (*a)[aoffset+1];
|
||||
a2x = (*a)[aoffset+2];
|
||||
a3x = (*a)[aoffset+3];
|
||||
t1x = a0x+a2x;
|
||||
t2x = a1x+a3x;
|
||||
m2x = a0x-a2x;
|
||||
m3y = a3x-a1x;
|
||||
(*a)[aoffset+0] = t1x+t2x;
|
||||
(*a)[aoffset+1] = m2x-m3y;
|
||||
(*a)[aoffset+2] = t1x-t2x;
|
||||
(*a)[aoffset+3] = m2x+m3y;
|
||||
return;
|
||||
}
|
||||
if( n==5) {
|
||||
offs = curplan.plan[entryoffset+7];
|
||||
c1 = curplan.precomputed[offs+0];
|
||||
c2 = curplan.precomputed[offs+1];
|
||||
c3 = curplan.precomputed[offs+2];
|
||||
c4 = curplan.precomputed[offs+3];
|
||||
c5 = curplan.precomputed[offs+4];
|
||||
t1x = (*a)[aoffset+1]+(*a)[aoffset+4];
|
||||
t2x = (*a)[aoffset+2]+(*a)[aoffset+3];
|
||||
t3x = (*a)[aoffset+1]-(*a)[aoffset+4];
|
||||
t4x = (*a)[aoffset+3]-(*a)[aoffset+2];
|
||||
t5x = t1x+t2x;
|
||||
v0 = (*a)[aoffset+0]+t5x;
|
||||
(*a)[aoffset+0] = v0;
|
||||
m2x = c2*(t1x-t2x);
|
||||
m3y = c3*(t3x+t4x);
|
||||
s3y = m3y-c4*t4x;
|
||||
s5y = m3y+c5*t3x;
|
||||
s1x = v0+c1*t5x;
|
||||
s2x = s1x+m2x;
|
||||
s4x = s1x-m2x;
|
||||
(*a)[aoffset+1] = s2x-s3y;
|
||||
(*a)[aoffset+2] = s4x-s5y;
|
||||
(*a)[aoffset+3] = s4x+s5y;
|
||||
(*a)[aoffset+4] = s2x+s3y;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( curplan.plan[entryoffset+3]==ftbase_fftbluesteinplan) {
|
||||
n = curplan.plan[entryoffset+1];
|
||||
m = curplan.plan[entryoffset+4];
|
||||
offs = curplan.plan[entryoffset+7];
|
||||
for(int i=stackptr+2*n; i<=stackptr+2*m-1; i++)
|
||||
curplan.stackbuf[i] = 0;
|
||||
offsp = offs+2*m;
|
||||
offsa = aoffset;
|
||||
offsb = stackptr;
|
||||
for(int i=0; i<n; i++) {
|
||||
bx = curplan.precomputed[offsp+0];
|
||||
by = curplan.precomputed[offsp+1];
|
||||
x = (*a)[offsa+0];
|
||||
y = (*a)[offsa+1];
|
||||
curplan.stackbuf[offsb+0] = x*bx-y*(-by);
|
||||
curplan.stackbuf[offsb+1] = x*(-by)+y*bx;
|
||||
offsp = offsp+2;
|
||||
offsa = offsa+2;
|
||||
offsb = offsb+2;
|
||||
}
|
||||
ftbaseexecuteplanrec(&curplan.stackbuf, stackptr, plan, curplan.plan[entryoffset+5], stackptr+2*2*m);
|
||||
offsb = stackptr;
|
||||
offsp = offs;
|
||||
for(int i=0; i<=m-1; i++) {
|
||||
x = curplan.stackbuf[offsb+0];
|
||||
y = curplan.stackbuf[offsb+1];
|
||||
bx = curplan.precomputed[offsp+0];
|
||||
by = curplan.precomputed[offsp+1];
|
||||
curplan.stackbuf[offsb+0] = x*bx-y*by;
|
||||
curplan.stackbuf[offsb+1] = -(x*by+y*bx);
|
||||
offsb = offsb+2;
|
||||
offsp = offsp+2;
|
||||
}
|
||||
ftbaseexecuteplanrec(&curplan.stackbuf, stackptr, plan, curplan.plan[entryoffset+5], stackptr+2*2*m);
|
||||
offsb = stackptr;
|
||||
offsp = offs+2*m;
|
||||
offsa = aoffset;
|
||||
for(int i=0; i<n; i++) {
|
||||
x = curplan.stackbuf[offsb+0]/m;
|
||||
y = -curplan.stackbuf[offsb+1]/m;
|
||||
bx = curplan.precomputed[offsp+0];
|
||||
by = curplan.precomputed[offsp+1];
|
||||
(*a)[offsa+0] = x*bx-y*(-by);
|
||||
(*a)[offsa+1] = x*(-by)+y*bx;
|
||||
offsp = offsp+2;
|
||||
offsa = offsa+2;
|
||||
offsb = offsb+2;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Twiddle factors calculation
|
||||
|
||||
-- ALGLIB --
|
||||
Copyright 01.05.2009 by Bochkanov Sergey
|
||||
*************************************************************************/
|
||||
void PIFFT::ftbase_ffttwcalc(PIVector<double> * a, int aoffset, int n1, int n2) {
|
||||
int n, idx, offs;
|
||||
double x, y, twxm1, twy, twbasexm1, twbasey, twrowxm1, twrowy, tmpx, tmpy, v;
|
||||
int ftbase_ftbaseupdatetw = 4;
|
||||
n = n1*n2;
|
||||
v = -2*M_PI/n;
|
||||
twbasexm1 = -2*sqr(sin(0.5*v));
|
||||
twbasey = sin(v);
|
||||
twrowxm1 = 0;
|
||||
twrowy = 0;
|
||||
for(int i=0, j = 0; i<=n2-1; i++) {
|
||||
twxm1 = 0;
|
||||
twy = 0;
|
||||
for(j=0; j<=n1-1; j++) {
|
||||
idx = i*n1+j;
|
||||
offs = aoffset+2*idx;
|
||||
x = (*a)[offs+0];
|
||||
y = (*a)[offs+1];
|
||||
tmpx = x*twxm1-y*twy;
|
||||
tmpy = x*twy+y*twxm1;
|
||||
(*a)[offs+0] = x+tmpx;
|
||||
(*a)[offs+1] = y+tmpy;
|
||||
if( j<n1-1) {
|
||||
if( j%ftbase_ftbaseupdatetw==0) {
|
||||
v = -2*M_PI*i*(j+1)/n;
|
||||
twxm1 = -2*sqr(sin(0.5*v));
|
||||
twy = sin(v);
|
||||
} else {
|
||||
tmpx = twrowxm1+twxm1*twrowxm1-twy*twrowy;
|
||||
tmpy = twrowy+twxm1*twrowy+twy*twrowxm1;
|
||||
twxm1 = twxm1+tmpx;
|
||||
twy = twy+tmpy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( i<n2-1) {
|
||||
if( j%ftbase_ftbaseupdatetw==0) {
|
||||
v = -2*M_PI*(i+1)/n;
|
||||
twrowxm1 = -2*sqr(sin(0.5*v));
|
||||
twrowy = sin(v);
|
||||
} else {
|
||||
tmpx = twbasexm1+twrowxm1*twbasexm1-twrowy*twbasey;
|
||||
tmpy = twbasey+twrowxm1*twbasey+twrowy*twbasexm1;
|
||||
twrowxm1 = twrowxm1+tmpx;
|
||||
twrowy = twrowy+tmpy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1025
pimath.h
1025
pimath.h
@@ -1,1025 +0,0 @@
|
||||
/*! \file pimath.h
|
||||
* \brief Many mathematical functions and classes
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Math
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIMATH_H
|
||||
#define PIMATH_H
|
||||
|
||||
#include "pibytearray.h"
|
||||
#ifndef QNX
|
||||
# include <complex>
|
||||
# include <cmath>
|
||||
#else
|
||||
# include <complex.h>
|
||||
# include <math.h>
|
||||
# undef PIP_MATH_J0
|
||||
# undef PIP_MATH_J1
|
||||
# undef PIP_MATH_JN
|
||||
# undef PIP_MATH_Y0
|
||||
# undef PIP_MATH_Y1
|
||||
# undef PIP_MATH_YN
|
||||
#endif
|
||||
|
||||
#ifndef M_LN2
|
||||
# define M_LN2 0.69314718055994530942
|
||||
#endif
|
||||
#ifndef M_LN10
|
||||
# define M_LN10 2.30258509299404568402
|
||||
#endif
|
||||
#ifndef M_SQRT2
|
||||
# define M_SQRT2 1.41421356237309514547
|
||||
#endif
|
||||
#ifndef M_SQRT3
|
||||
# define M_SQRT3 1.73205080756887719318
|
||||
#endif
|
||||
#ifndef M_1_SQRT2
|
||||
# define M_1_SQRT2 0.70710678118654746172
|
||||
#endif
|
||||
#ifndef M_1_SQRT3
|
||||
# define M_1_SQRT3 0.57735026918962584208
|
||||
#endif
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
#ifndef M_2PI
|
||||
# define M_2PI 6.28318530717958647692
|
||||
#endif
|
||||
#ifndef M_PI_3
|
||||
# define M_PI_3 1.04719755119659774615
|
||||
#endif
|
||||
#ifndef M_2PI_3
|
||||
# define M_2PI_3 2.0943951023931954923
|
||||
#endif
|
||||
#ifndef M_180_PI
|
||||
# define M_180_PI 57.2957795130823208768
|
||||
#endif
|
||||
#ifndef M_PI_180
|
||||
# define M_PI_180 1.74532925199432957692e-2
|
||||
#endif
|
||||
#ifndef M_E
|
||||
# define M_E 2.7182818284590452353602874713527
|
||||
#endif
|
||||
#ifndef M_LIGHT_SPEED
|
||||
# define M_LIGHT_SPEED 2.99792458e+8
|
||||
#endif
|
||||
|
||||
using std::complex;
|
||||
|
||||
typedef complex<int> complexi;
|
||||
typedef complex<float> complexf;
|
||||
typedef complex<double> complexd;
|
||||
typedef complex<ldouble> complexld;
|
||||
const complexld complexld_i(0., 1.);
|
||||
const complexld complexld_0(0.);
|
||||
const complexld complexld_1(1.);
|
||||
const complexd complexd_i(0., 1.);
|
||||
const complexd complexd_0(0.);
|
||||
const complexd complexd_1(1.);
|
||||
|
||||
__PICONTAINERS_SIMPLE_TYPE__(complexi)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(complexf)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(complexd)
|
||||
__PICONTAINERS_SIMPLE_TYPE__(complexld)
|
||||
|
||||
const double deg2rad = M_PI_180;
|
||||
const double rad2deg = M_180_PI;
|
||||
|
||||
inline int sign(const float & x) {return (x < 0.) ? -1 : (x > 0. ? 1 : 0);}
|
||||
inline int sign(const double & x) {return (x < 0.) ? -1 : (x > 0. ? 1 : 0);}
|
||||
inline complexd sign(const complexd & x) {return complexd(sign(x.real()), sign(x.imag()));}
|
||||
inline int pow2(const int p) {return 1 << p;}
|
||||
inline double sqr(const int v) {return v * v;}
|
||||
inline double sqr(const float & v) {return v * v;}
|
||||
inline double sqr(const double & v) {return v * v;}
|
||||
inline double sinc(const double & v) {if (v == 0.) return 1.; double t = M_PI * v; return sin(t) / t;}
|
||||
inline complexd round(const complexd & c) {return complexd(piRound<double>(c.real()), piRound<double>(c.imag()));}
|
||||
inline complexd floor(const complexd & c) {return complexd(floor(c.real()), floor(c.imag()));}
|
||||
inline complexd ceil(const complexd & c) {return complexd(ceil(c.real()), ceil(c.imag()));}
|
||||
inline complexd atanc(const complexd & c) {return -complexd(-0.5, 1.) * log((complexd_1 + complexd_i * c) / (complexd_1 - complexd_i * c));}
|
||||
inline complexd asinc(const complexd & c) {return -complexd_i * log(complexd_i * c + sqrt(complexd_1 - c * c));}
|
||||
inline complexd acosc(const complexd & c) {return -complexd_i * log(c + complexd_i * sqrt(complexd_1 - c * c));}
|
||||
#ifdef CC_GCC
|
||||
# if CC_GCC_VERSION <= 0x025F
|
||||
inline complexd tan(const complexd & c) {return sin(c) / cos(c);}
|
||||
inline complexd tanh(const complexd & c) {return sinh(c) / cosh(c);}
|
||||
inline complexd log2(const complexd & c) {return log(c) / M_LN2;}
|
||||
inline complexd log10(const complexd & c) {return log(c) / M_LN10;}
|
||||
# endif
|
||||
#endif
|
||||
double piJ0(const double & v);
|
||||
double piJ1(const double & v);
|
||||
double piJn(int n, const double & v);
|
||||
double piY0(const double & v);
|
||||
double piY1(const double & v);
|
||||
double piYn(int n, const double & v);
|
||||
inline double toDb(double val) {return 10. * log10(val);}
|
||||
inline double fromDb(double val) {return pow(10., val / 10.);}
|
||||
inline double toRad(double deg) {return deg * M_PI_180;}
|
||||
inline double toDeg(double rad) {return rad * M_180_PI;}
|
||||
|
||||
template<typename T>
|
||||
inline PICout operator <<(PICout s, const complex<T> & v) {s.space(); s.setControl(0, true); s << "(" << v.real() << "; " << v.imag() << ")"; s.restoreControl(); return s;}
|
||||
|
||||
// [-1 ; 1]
|
||||
inline double randomd() {return (double)random() / RAND_MAX * 2. - 1.;}
|
||||
// [-1 ; 1] normal
|
||||
double randomn(double dv = 0., double sv = 1.);
|
||||
|
||||
inline PIVector<double> abs(const PIVector<complexd> & v) {
|
||||
PIVector<double> result;
|
||||
result.resize(v.size());
|
||||
for (uint i = 0; i < v.size(); i++)
|
||||
result[i] = abs(v[i]);
|
||||
return result;
|
||||
}
|
||||
inline PIVector<double> abs(const PIVector<double> & v) {
|
||||
PIVector<double> result;
|
||||
result.resize(v.size());
|
||||
for (uint i = 0; i < v.size(); i++)
|
||||
result[i] = abs(v[i]);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<uint Cols, uint Rows, typename Type>
|
||||
class PIMathMatrixT;
|
||||
|
||||
/// Vector templated
|
||||
|
||||
#define PIMV_FOR(v, s) for (uint v = s; v < Size; ++v)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
template<uint Size, typename Type = double>
|
||||
class PIP_EXPORT PIMathVectorT {
|
||||
typedef PIMathVectorT<Size, Type> _CVector;
|
||||
public:
|
||||
PIMathVectorT() {resize(Size);}
|
||||
//PIMathVectorT(Type val) {resize(Size); PIMV_FOR(i, 0) c[i] = val;}
|
||||
PIMathVectorT(Type fval, ...) {resize(Size); c[0] = fval; va_list vl; va_start(vl, fval); PIMV_FOR(i, 1) c[i] = va_arg(vl, Type); va_end(vl);}
|
||||
PIMathVectorT(const PIVector<Type> & val) {resize(Size); PIMV_FOR(i, 0) c[i] = val[i];}
|
||||
PIMathVectorT(const _CVector & st, const _CVector & fn) {resize(Size); set(st, fn);}
|
||||
|
||||
uint size() const {return Size;}
|
||||
_CVector & fill(const Type & v) {PIMV_FOR(i, 0) c[i] = v; return *this;}
|
||||
_CVector & set(Type fval, ...) {c[0] = fval; va_list vl; va_start(vl, fval); PIMV_FOR(i, 1) c[i] = va_arg(vl, Type); va_end(vl); return *this;}
|
||||
_CVector & set(const _CVector & st, const _CVector & fn) {PIMV_FOR(i, 0) c[i] = fn[i] - st[i]; return *this;}
|
||||
_CVector & move(const Type & v) {PIMV_FOR(i, 0) c[i] += v; return *this;}
|
||||
_CVector & move(const _CVector & v) {PIMV_FOR(i, 0) c[i] += v[i]; return *this;}
|
||||
_CVector & move(Type fval, ...) {c[0] += fval; va_list vl; va_start(vl, fval); PIMV_FOR(i, 1) c[i] += va_arg(vl, Type); va_end(vl); return *this;}
|
||||
Type lengthSqr() const {Type tv(0); PIMV_FOR(i, 0) tv += (c[i] * c[i]); return tv;}
|
||||
Type length() const {return sqrt(lengthSqr());}
|
||||
Type manhattanLength() const {Type tv(0); PIMV_FOR(i, 0) tv += fabs(c[i]); return tv;}
|
||||
Type angleCos(const _CVector & v) const {Type tv = v.length() * length(); return (tv == Type(0) ? Type(0) : ((*this) ^ v) / tv);}
|
||||
Type angleSin(const _CVector & v) const {Type tv = angleCos(v); return sqrt(Type(1) - tv * tv);}
|
||||
Type angleRad(const _CVector & v) const {return acos(angleCos(v));}
|
||||
Type angleDeg(const _CVector & v) const {return toDeg(acos(angleCos(v)));}
|
||||
_CVector projection(const _CVector & v) {Type tv = v.length(); return (tv == Type(0) ? _CVector() : v * (((*this) ^ v) / tv));}
|
||||
_CVector & normalize() {Type tv = length(); if (tv == Type(1)) return *this; if (piAbs<Type>(tv) <= Type(1E-100)) {fill(Type(0)); return *this;} PIMV_FOR(i, 0) c[i] /= tv; return *this;}
|
||||
_CVector normalized() {_CVector tv(*this); tv.normalize(); return tv;}
|
||||
bool isNull() const {PIMV_FOR(i, 0) if (c[i] != Type(0)) return false; return true;}
|
||||
bool isOrtho(const _CVector & v) const {return ((*this) ^ v) == Type(0);}
|
||||
|
||||
Type & at(uint index) {return c[index];}
|
||||
Type at(uint index) const {return c[index];}
|
||||
Type & operator [](uint index) {return c[index];}
|
||||
Type operator [](uint index) const {return c[index];}
|
||||
_CVector & operator =(const _CVector & v) {memcpy(c, v.c, sizeof(Type) * Size); return *this;}
|
||||
bool operator ==(const _CVector & v) const {PIMV_FOR(i, 0) if (c[i] != v[i]) return false; return true;}
|
||||
bool operator !=(const _CVector & v) const {return !(*this == c);}
|
||||
void operator +=(const _CVector & v) {PIMV_FOR(i, 0) c[i] += v[i];}
|
||||
void operator -=(const _CVector & v) {PIMV_FOR(i, 0) c[i] -= v[i];}
|
||||
void operator *=(const Type & v) {PIMV_FOR(i, 0) c[i] *= v;}
|
||||
void operator *=(const _CVector & v) {PIMV_FOR(i, 0) c[i] *= v[i];}
|
||||
void operator /=(const Type & v) {PIMV_FOR(i, 0) c[i] /= v;}
|
||||
void operator /=(const _CVector & v) {PIMV_FOR(i, 0) c[i] /= v[i];}
|
||||
_CVector operator -() const {_CVector tv; PIMV_FOR(i, 0) tv[i] = -c[i]; return tv;}
|
||||
_CVector operator +(const _CVector & v) const {_CVector tv = _CVector(*this); PIMV_FOR(i, 0) tv[i] += v[i]; return tv;}
|
||||
_CVector operator -(const _CVector & v) const {_CVector tv = _CVector(*this); PIMV_FOR(i, 0) tv[i] -= v[i]; return tv;}
|
||||
_CVector operator *(const Type & v) const {_CVector tv = _CVector(*this); PIMV_FOR(i, 0) tv[i] *= v; return tv;}
|
||||
_CVector operator /(const Type & v) const {_CVector tv = _CVector(*this); PIMV_FOR(i, 0) tv[i] /= v; return tv;}
|
||||
_CVector operator /(const _CVector & v) const {_CVector tv = _CVector(*this); PIMV_FOR(i, 0) tv[i] /= v[i]; return tv;}
|
||||
_CVector operator *(const _CVector & v) const {if (Size > 3) return _CVector(); _CVector tv; tv.fill(Type(1)); tv[0] = c[1]*v[2] - v[1]*c[2]; tv[1] = v[0]*c[2] - c[0]*v[2]; tv[2] = c[0]*v[1] - v[0]*c[1]; return tv;}
|
||||
Type operator ^(const _CVector & v) const {Type tv(0); PIMV_FOR(i, 0) tv += c[i] * v[i]; return tv;}
|
||||
|
||||
operator PIMathMatrixT<1, Size, Type>() {return PIMathMatrixT<1, Size, Type>(c);}
|
||||
Type distToLine(const _CVector & lp0, const _CVector & lp1) {
|
||||
_CVector a(lp0, lp1), b(lp0, *this), c(lp1, *this);
|
||||
Type f = fabs(a[0]*b[1] - a[1]*b[0]) / a.length();//, s = b.length() + c.length() - a.length();
|
||||
return f;}
|
||||
|
||||
template<uint Size1, typename Type1> /// vector {Size, Type} to vector {Size1, Type1}
|
||||
PIMathVectorT<Size1, Type1> turnTo() const {PIMathVectorT<Size1, Type1> tv; uint sz = piMin<uint>(Size, Size1); for (uint i = 0; i < sz; ++i) tv[i] = c[i]; return tv;}
|
||||
|
||||
private:
|
||||
void resize(uint size, const Type & new_value = Type()) {s = size; for (int i = 0; i < s; ++i) c[i] = new_value;}
|
||||
|
||||
int s;
|
||||
Type c[Size];
|
||||
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
template<uint Size, typename Type>
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIMathVectorT<Size, Type> & v) {s << '{'; PIMV_FOR(i, 0) {s << v[i]; if (i < Size - 1) s << ", ";} s << '}'; return s;}
|
||||
template<uint Size, typename Type>
|
||||
inline PICout operator <<(PICout s, const PIMathVectorT<Size, Type> & v) {s << '{'; PIMV_FOR(i, 0) {s << v[i]; if (i < Size - 1) s << ", ";} s << '}'; return s;}
|
||||
template<uint Size, typename Type>
|
||||
inline bool operator ||(const PIMathVectorT<Size, Type> & f, const PIMathVectorT<Size, Type> & s) {return (f * s).isNull();}
|
||||
template<uint Size, typename Type>
|
||||
inline PIMathVectorT<Size, Type> sqrt(const PIMathVectorT<Size, Type> & v) {PIMathVectorT<Size, Type> ret; PIMV_FOR(i, 0) {ret[i] = sqrt(v[i]);} return ret;}
|
||||
template<uint Size, typename Type>
|
||||
inline PIMathVectorT<Size, Type> sqr(const PIMathVectorT<Size, Type> & v) {PIMathVectorT<Size, Type> ret; PIMV_FOR(i, 0) {ret[i] = sqr(v[i]);} return ret;}
|
||||
|
||||
template<uint Size, typename Type>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIMathVectorT<Size, Type> & v) {for (int i = 0; i < Size; ++i) s << v[i]; return s;}
|
||||
template<uint Size, typename Type>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIMathVectorT<Size, Type> & v) {for (int i = 0; i < Size; ++i) s >> v[i]; return s;}
|
||||
|
||||
//template<uint Size0, typename Type0 = double, uint Size1 = Size0, typename Type1 = Type0> /// vector {Size0, Type0} to vector {Size1, Type1}
|
||||
//inline operator PIMathVectorT<Size1, Type1>(const PIMathVectorT<Size0, Type0> & v) {PIMathVectorT<Size1, Type1> tv; uint sz = piMin<uint>(Size0, Size1); for (uint i = 0; i < sz; ++i) tv[i] = v[i]; return tv;}
|
||||
|
||||
typedef PIMathVectorT<2u, int> PIMathVectorT2i;
|
||||
typedef PIMathVectorT<3u, int> PIMathVectorT3i;
|
||||
typedef PIMathVectorT<4u, int> PIMathVectorT4i;
|
||||
typedef PIMathVectorT<2u, double> PIMathVectorT2d;
|
||||
typedef PIMathVectorT<3u, double> PIMathVectorT3d;
|
||||
typedef PIMathVectorT<4u, double> PIMathVectorT4d;
|
||||
|
||||
/// Matrix templated
|
||||
|
||||
#define PIMM_FOR(c, r) for (uint c = 0; c < Cols; ++c) { for (uint r = 0; r < Rows; ++r) {
|
||||
#define PIMM_FOR_WB(c, r) for (uint c = 0; c < Cols; ++c) for (uint r = 0; r < Rows; ++r) // without brakes
|
||||
#define PIMM_FOR_I(c, r) for (uint r = 0; r < Rows; ++r) { for (uint c = 0; c < Cols; ++c) {
|
||||
#define PIMM_FOR_I_WB(c, r) for (uint r = 0; r < Rows; ++r) for (uint c = 0; c < Cols; ++c) // without brakes
|
||||
#define PIMM_FOR_C(v) for (uint v = 0; v < Cols; ++v)
|
||||
#define PIMM_FOR_R(v) for (uint v = 0; v < Rows; ++v)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
template<uint Cols, uint Rows = Cols, typename Type = double>
|
||||
class PIP_EXPORT PIMathMatrixT {
|
||||
typedef PIMathMatrixT<Cols, Rows, Type> _CMatrix;
|
||||
typedef PIMathMatrixT<Rows, Cols, Type> _CMatrixI;
|
||||
typedef PIMathVectorT<Rows, Type> _CMCol;
|
||||
typedef PIMathVectorT<Cols, Type> _CMRow;
|
||||
public:
|
||||
PIMathMatrixT() {resize(Cols, Rows);}
|
||||
PIMathMatrixT(Type fval, ...) {resize(Cols, Rows); va_list vl; va_start(vl, fval); PIMM_FOR_I_WB(c, r) m[c][r] = (r + c == 0 ? fval : va_arg(vl, Type)); va_end(vl);}
|
||||
PIMathMatrixT(const PIVector<Type> & val) {resize(Cols, Rows); int i = 0; PIMM_FOR_I_WB(c, r) m[c][r] = val[i++];}
|
||||
|
||||
static _CMatrix identity() {_CMatrix tm = _CMatrix(); PIMM_FOR_WB(c, r) tm.m[c][r] = (c == r ? Type(1) : Type(0)); return tm;}
|
||||
static _CMatrix rotation(double angle) {return _CMatrix();}
|
||||
static _CMatrix rotationX(double angle) {return _CMatrix();}
|
||||
static _CMatrix rotationY(double angle) {return _CMatrix();}
|
||||
static _CMatrix rotationZ(double angle) {return _CMatrix();}
|
||||
|
||||
uint cols() const {return Cols;}
|
||||
uint rows() const {return Rows;}
|
||||
_CMCol col(uint index) {_CMCol tv; PIMM_FOR_R(i) tv[i] = m[index][i]; return tv;}
|
||||
_CMRow row(uint index) {_CMRow tv; PIMM_FOR_C(i) tv[i] = m[i][index]; return tv;}
|
||||
_CMatrix & setCol(uint index, const _CMCol & v) {PIMM_FOR_R(i) m[index][i] = v[i]; return *this;}
|
||||
_CMatrix & setRow(uint index, const _CMRow & v) {PIMM_FOR_C(i) m[i][index] = v[i]; return *this;}
|
||||
_CMatrix & swapRows(uint r0, uint r1) {Type t; PIMM_FOR_C(i) {t = m[i][r0]; m[i][r0] = m[i][r1]; m[i][r1] = t;} return *this;}
|
||||
_CMatrix & swapCols(uint c0, uint c1) {Type t; PIMM_FOR_R(i) {t = m[c0][i]; m[c0][i] = m[c1][i]; m[c1][i] = t;} return *this;}
|
||||
_CMatrix & fill(const Type & v) {PIMM_FOR_WB(c, r) m[c][r] = v; return *this;}
|
||||
//inline _CMatrix & set(Type fval, ...) {m[0] = fval; va_list vl; va_start(vl, fval); PIMV_FOR(i, 1) m[i] = va_arg(vl, Type); va_end(vl); return *this;}
|
||||
//inline void normalize() {Type tv = length(); if (tv == Type(1)) return; PIMV_FOR(i, 0) m[i] /= tv;}
|
||||
bool isSquare() const {return cols() == rows();}
|
||||
bool isIdentity() const {PIMM_FOR_WB(c, r) if ((c == r) ? m[c][r] != Type(1) : m[c][r] != Type(0)) return false; return true;}
|
||||
bool isNull() const {PIMM_FOR_WB(c, r) if (m[c][r] != Type(0)) return false; return true;}
|
||||
|
||||
Type & at(uint col, uint row) {return m[col][row];}
|
||||
Type at(uint col, uint row) const {return m[col][row];}
|
||||
Type * operator [](uint col) {return m[col];}
|
||||
const Type * operator [](uint col) const {return m[col];}
|
||||
void operator =(const _CMatrix & sm) {memcpy(m, sm.m, sizeof(Type) * Cols * Rows);}
|
||||
bool operator ==(const _CMatrix & sm) const {PIMM_FOR_WB(c, r) if (m[c][r] != sm.m[c][r]) return false; return true;}
|
||||
bool operator !=(const _CMatrix & sm) const {return !(*this == sm);}
|
||||
void operator +=(const _CMatrix & sm) {PIMM_FOR_WB(c, r) m[c][r] += sm.m[c][r];}
|
||||
void operator -=(const _CMatrix & sm) {PIMM_FOR_WB(c, r) m[c][r] -= sm.m[c][r];}
|
||||
void operator *=(const Type & v) {PIMM_FOR_WB(c, r) m[c][r] *= v;}
|
||||
void operator /=(const Type & v) {PIMM_FOR_WB(c, r) m[c][r] /= v;}
|
||||
_CMatrix operator -() {_CMatrix tm; PIMM_FOR_WB(c, r) tm.m[c][r] = -m[c][r]; return tm;}
|
||||
_CMatrix operator +(const _CMatrix & sm) {_CMatrix tm = _CMatrix(*this); PIMM_FOR_WB(c, r) tm.m[c][r] += sm.m[c][r]; return tm;}
|
||||
_CMatrix operator -(const _CMatrix & sm) {_CMatrix tm = _CMatrix(*this); PIMM_FOR_WB(c, r) tm.m[c][r] -= sm.m[c][r]; return tm;}
|
||||
_CMatrix operator *(const Type & v) {_CMatrix tm = _CMatrix(*this); PIMM_FOR_WB(c, r) tm.m[c][r] *= v; return tm;}
|
||||
_CMatrix operator /(const Type & v) {_CMatrix tm = _CMatrix(*this); PIMM_FOR_WB(c, r) tm.m[c][r] /= v; return tm;}
|
||||
|
||||
_CMatrix & toUpperTriangular(bool * ok = 0) {
|
||||
if (Cols != Rows) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
_CMatrix smat(*this);
|
||||
bool ndet;
|
||||
uint crow;
|
||||
Type mul;
|
||||
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 (ndet) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
for (uint j = 0; j < Cols; ++j) if (smat.m[j][i] != 0) ndet = false;
|
||||
if (ndet) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
for (uint i = 0; i < Cols; ++i) {
|
||||
crow = i;
|
||||
while (smat.m[i][i] == Type(0))
|
||||
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 (fabs(smat.m[i+1][i+1]) < Type(1E-100)) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ok != 0) *ok = true;
|
||||
memcpy(m, smat.m, sizeof(Type) * Cols * Rows);
|
||||
return *this;
|
||||
}
|
||||
|
||||
_CMatrix & invert(bool * ok = 0) {
|
||||
if (Cols != Rows) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
_CMatrix mtmp = _CMatrix::identity(), smat(*this);
|
||||
bool ndet;
|
||||
uint crow;
|
||||
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;
|
||||
if (ndet) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
for (uint j = 0; j < Cols; ++j) if (smat.m[j][i] != 0) ndet = false;
|
||||
if (ndet) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
for (uint i = 0; i < Cols; ++i) {
|
||||
crow = i;
|
||||
while (smat.m[i][i] == Type(0)) {
|
||||
++crow;
|
||||
smat.swapRows(i, crow);
|
||||
mtmp.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];
|
||||
for (uint k = 0; k < Cols; ++k) mtmp.m[k][j] -= mul * mtmp.m[k][i];
|
||||
}
|
||||
//cout << i << endl << smat << endl;
|
||||
if (i < Cols - 1) {
|
||||
if (fabs(smat.m[i+1][i+1]) < Type(1E-100)) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
iddiv = smat.m[i][i];
|
||||
for (uint j = i; j < Cols; ++j) smat.m[j][i] /= iddiv;
|
||||
for (uint j = 0; j < Cols; ++j) mtmp.m[j][i] /= iddiv;
|
||||
}
|
||||
for (uint i = Cols - 1; i > 0; --i) {
|
||||
for (uint j = 0; j < i; ++j) {
|
||||
mul = smat.m[i][j];
|
||||
smat.m[i][j] -= mul;
|
||||
for (uint k = 0; k < Cols; ++k) mtmp.m[k][j] -= mtmp.m[k][i] * mul;
|
||||
}
|
||||
}
|
||||
if (ok != 0) *ok = true;
|
||||
memcpy(m, mtmp.m, sizeof(Type) * Cols * Rows);
|
||||
return *this;
|
||||
}
|
||||
_CMatrix inverted(bool * ok = 0) {_CMatrix tm(*this); tm.invert(ok); return tm;}
|
||||
_CMatrixI transposed() {_CMatrixI tm; PIMM_FOR_WB(c, r) tm[r][c] = m[c][r]; return tm;}
|
||||
|
||||
private:
|
||||
void resize(uint cols_, uint rows_, const Type & new_value = Type()) {c_ = cols_; r_ = rows_; PIMM_FOR_WB(c, r) m[c][r] = new_value;}
|
||||
int c_, r_;
|
||||
Type m[Cols][Rows];
|
||||
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
template<> inline PIMathMatrixT<2u, 2u> PIMathMatrixT<2u, 2u>::rotation(double angle) {double c = cos(angle), s = sin(angle); PIMathMatrixT<2u, 2u> tm; tm[0][0] = tm[1][1] = c; tm[0][1] = -s; tm[1][0] = s; return tm;}
|
||||
template<> inline PIMathMatrixT<3u, 3u> PIMathMatrixT<3u, 3u>::rotationX(double angle) {double c = cos(angle), s = sin(angle); PIMathMatrixT<3u, 3u> tm; tm[0][0] = 1.; tm[1][1] = tm[2][2] = c; tm[2][1] = -s; tm[1][2] = s; return tm;}
|
||||
template<> inline PIMathMatrixT<3u, 3u> PIMathMatrixT<3u, 3u>::rotationY(double angle) {double c = cos(angle), s = sin(angle); PIMathMatrixT<3u, 3u> tm; tm[1][1] = 1.; tm[0][0] = tm[2][2] = c; tm[2][0] = s; tm[0][2] = -s; return tm;}
|
||||
template<> inline PIMathMatrixT<3u, 3u> PIMathMatrixT<3u, 3u>::rotationZ(double angle) {double c = cos(angle), s = sin(angle); PIMathMatrixT<3u, 3u> tm; tm[2][2] = 1.; tm[0][0] = tm[1][1] = c; tm[1][0] = -s; tm[0][1] = s; return tm;}
|
||||
|
||||
template<uint Cols, uint Rows, typename Type>
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIMathMatrixT<Cols, Rows, Type> & m) {s << '{'; PIMM_FOR_I(c, r) s << m[c][r]; if (c < Cols - 1 || r < Rows - 1) s << ", ";} if (r < Rows - 1) s << endl << ' ';} s << '}'; return s;}
|
||||
template<uint Cols, uint Rows, typename Type>
|
||||
inline PICout operator <<(PICout s, const PIMathMatrixT<Cols, Rows, Type> & m) {s << '{'; PIMM_FOR_I(c, r) s << m[c][r]; if (c < Cols - 1 || r < Rows - 1) s << ", ";} if (r < Rows - 1) s << NewLine << ' ';} s << '}'; return s;}
|
||||
|
||||
/// Multiply matrices {CR x Rows0} on {Cols1 x CR}, result is {Cols1 x Rows0}
|
||||
template<uint CR, uint Rows0, uint Cols1, typename Type>
|
||||
inline PIMathMatrixT<Cols1, Rows0, Type> operator *(const PIMathMatrixT<CR, Rows0, Type> & fm,
|
||||
const PIMathMatrixT<Cols1, CR, Type> & sm) {
|
||||
PIMathMatrixT<Cols1, Rows0, Type> tm;
|
||||
Type t;
|
||||
for (uint j = 0; j < Rows0; ++j) {
|
||||
for (uint i = 0; i < Cols1; ++i) {
|
||||
t = Type(0);
|
||||
for (uint k = 0; k < CR; ++k)
|
||||
t += fm[k][j] * sm[i][k];
|
||||
tm[i][j] = t;
|
||||
}
|
||||
}
|
||||
return tm;
|
||||
}
|
||||
|
||||
/// Multiply matrix {Cols x Rows} on vector {Cols}, result is vector {Rows}
|
||||
template<uint Cols, uint Rows, typename Type>
|
||||
inline PIMathVectorT<Rows, Type> operator *(const PIMathMatrixT<Cols, Rows, Type> & fm,
|
||||
const PIMathVectorT<Cols, Type> & sv) {
|
||||
PIMathVectorT<Rows, Type> tv;
|
||||
Type t;
|
||||
for (uint i = 0; i < Rows; ++i) {
|
||||
t = Type(0);
|
||||
for (uint j = 0; j < Cols; ++j)
|
||||
t += fm[j][i] * sv[j];
|
||||
tv[i] = t;
|
||||
}
|
||||
return tv;
|
||||
}
|
||||
|
||||
typedef PIMathMatrixT<2u, 2u, int> PIMathMatrixT22i;
|
||||
typedef PIMathMatrixT<3u, 3u, int> PIMathMatrixT33i;
|
||||
typedef PIMathMatrixT<4u, 4u, int> PIMathMatrixT44i;
|
||||
typedef PIMathMatrixT<2u, 2u, double> PIMathMatrixT22d;
|
||||
typedef PIMathMatrixT<3u, 3u, double> PIMathMatrixT33d;
|
||||
typedef PIMathMatrixT<4u, 4u, double> PIMathMatrixT44d;
|
||||
|
||||
|
||||
template<typename Type>
|
||||
class PIMathMatrix;
|
||||
|
||||
#undef PIMV_FOR
|
||||
#undef PIMM_FOR
|
||||
#undef PIMM_FOR_WB
|
||||
#undef PIMM_FOR_I
|
||||
#undef PIMM_FOR_I_WB
|
||||
#undef PIMM_FOR_C
|
||||
#undef PIMM_FOR_R
|
||||
|
||||
/// Vector
|
||||
|
||||
#define PIMV_FOR(v, s) for (uint v = s; v < size_; ++v)
|
||||
|
||||
template<typename Type>
|
||||
class PIP_EXPORT PIMathVector {
|
||||
typedef PIMathVector<Type> _CVector;
|
||||
public:
|
||||
PIMathVector(const uint size = 3) {resize(size);}
|
||||
PIMathVector(const uint size, Type fval, ...) {resize(size); c[0] = fval; va_list vl; va_start(vl, fval); PIMV_FOR(i, 1) c[i] = va_arg(vl, Type); va_end(vl);}
|
||||
PIMathVector(const PIVector<Type> & val) {resize(val.size); PIMV_FOR(i, 0) c[i] = val[i];}
|
||||
PIMathVector(const _CVector & st, const _CVector & fn) {resize(st.size()); PIMV_FOR(i, 0) c[i] = fn[i] - st[i];}
|
||||
|
||||
uint size() const {return size_;}
|
||||
_CVector & resize(uint size, const Type & new_value = Type()) {size_ = size; c.resize(size, new_value); return *this;}
|
||||
_CVector resized(uint size, const Type & new_value = Type()) {_CVector tv = _CVector(*this); tv.resize(size, new_value); return tv;}
|
||||
_CVector & fill(const Type & v) {PIMV_FOR(i, 0) c[i] = v; return *this;}
|
||||
_CVector & set(Type fval, ...) {c[0] = fval; va_list vl; va_start(vl, fval); PIMV_FOR(i, 1) c[i] = va_arg(vl, Type); va_end(vl); return *this;}
|
||||
_CVector & move(const Type & v) {PIMV_FOR(i, 0) c[i] += v; return *this;}
|
||||
_CVector & move(const _CVector & v) {PIMV_FOR(i, 0) c[i] += v[i]; return *this;}
|
||||
_CVector & move(Type fval, ...) {c[0] += fval; va_list vl; va_start(vl, fval); PIMV_FOR(i, 1) c[i] += va_arg(vl, Type); va_end(vl); return *this;}
|
||||
_CVector & swap(uint fe, uint se) {piSwap<Type>(c[fe], c[se]); return *this;}
|
||||
Type lengthSqr() const {Type tv(0); PIMV_FOR(i, 0) tv += (c[i] * c[i]); return tv;}
|
||||
Type length() const {return sqrt(lengthSqr());}
|
||||
Type manhattanLength() const {Type tv(0); PIMV_FOR(i, 0) tv += fabs(c[i]); return tv;}
|
||||
Type angleCos(const _CVector & v) const {Type tv = v.length() * length(); return (tv == Type(0) ? Type(0) : ((*this) ^ v) / tv);}
|
||||
Type angleSin(const _CVector & v) const {Type tv = angleCos(v); return sqrt(Type(1) - tv * tv);}
|
||||
Type angleRad(const _CVector & v) const {return acos(angleCos(v));}
|
||||
Type angleDeg(const _CVector & v) const {return toDeg(acos(angleCos(v)));}
|
||||
_CVector projection(const _CVector & v) {Type tv = v.length(); return (tv == Type(0) ? _CVector() : v * (((*this) ^ v) / tv));}
|
||||
_CVector & normalize() {Type tv = length(); if (tv == Type(1)) return *this; if (piAbs<Type>(tv) <= Type(1E-100)) {fill(Type(0)); return *this;} PIMV_FOR(i, 0) c[i] /= tv; return *this;}
|
||||
_CVector normalized() {_CVector tv(*this); tv.normalize(); return tv;}
|
||||
bool isNull() const {PIMV_FOR(i, 0) if (c[i] != Type(0)) return false; return true;}
|
||||
bool isOrtho(const _CVector & v) const {return ((*this) ^ v) == Type(0);}
|
||||
|
||||
Type & at(uint index) {return c[index];}
|
||||
Type at(uint index) const {return c[index];}
|
||||
Type & operator [](uint index) {return c[index];}
|
||||
Type operator [](uint index) const {return c[index];}
|
||||
void operator =(const _CVector & v) {c = v.c;}
|
||||
bool operator ==(const _CVector & v) const {PIMV_FOR(i, 0) if (c[i] != v[i]) return false; return true;}
|
||||
bool operator !=(const _CVector & v) const {return !(*this == c);}
|
||||
void operator +=(const _CVector & v) {PIMV_FOR(i, 0) c[i] += v[i];}
|
||||
void operator -=(const _CVector & v) {PIMV_FOR(i, 0) c[i] -= v[i];}
|
||||
void operator *=(const Type & v) {PIMV_FOR(i, 0) c[i] *= v;}
|
||||
void operator *=(const _CVector & v) {PIMV_FOR(i, 0) c[i] *= v[i];}
|
||||
void operator /=(const Type & v) {PIMV_FOR(i, 0) c[i] /= v;}
|
||||
void operator /=(const _CVector & v) {PIMV_FOR(i, 0) c[i] /= v[i];}
|
||||
_CVector operator -() {_CVector tv; PIMV_FOR(i, 0) tv[i] = -c[i]; return tv;}
|
||||
_CVector operator +(const _CVector & v) {_CVector tv = _CVector(*this); PIMV_FOR(i, 0) tv[i] += v[i]; return tv;}
|
||||
_CVector operator -(const _CVector & v) {_CVector tv = _CVector(*this); PIMV_FOR(i, 0) tv[i] -= v[i]; return tv;}
|
||||
_CVector operator *(const Type & v) {_CVector tv = _CVector(*this); PIMV_FOR(i, 0) tv[i] *= v; return tv;}
|
||||
_CVector operator /(const Type & v) {_CVector tv = _CVector(*this); PIMV_FOR(i, 0) tv[i] /= v; return tv;}
|
||||
_CVector operator *(const _CVector & v) {if (size_ < 3) return _CVector(); _CVector tv; tv.fill(Type(1)); tv[0] = c[1]*v[2] - v[1]*c[2]; tv[1] = v[0]*c[2] - c[0]*v[2]; tv[2] = c[0]*v[1] - v[0]*c[1]; return tv;}
|
||||
Type operator ^(const _CVector & v) const {Type tv(0); PIMV_FOR(i, 0) tv += c[i] * v[i]; return tv;}
|
||||
|
||||
//inline operator PIMathMatrix<1, Size, Type>() {return PIMathMatrix<1, Size, Type>(c);}
|
||||
Type distToLine(const _CVector & lp0, const _CVector & lp1) {
|
||||
_CVector a(lp0, lp1), b(lp0, *this), c(lp1, *this);
|
||||
Type f = fabs(a[0]*b[1] - a[1]*b[0]) / a.length();//, s = b.length() + c.length() - a.length();
|
||||
return f;}
|
||||
|
||||
template<typename Type1>
|
||||
PIMathVector turnTo(uint size) {PIMathVector<Type1> tv; uint sz = piMin<uint>(size_, size); for (uint i = 0; i < sz; ++i) tv[i] = c[i]; return tv;}
|
||||
|
||||
private:
|
||||
uint size_;
|
||||
PIVector<Type> c;
|
||||
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIMathVector<Type> & v) {s << '{'; for (uint i = 0; i < v.size(); ++i) {s << v[i]; if (i < v.size() - 1) s << ", ";} s << '}'; return s;}
|
||||
template<typename Type>
|
||||
inline PICout operator <<(PICout s, const PIMathVector<Type> & v) {s << '{'; for (uint i = 0; i < v.size(); ++i) {s << v[i]; if (i < v.size() - 1) s << ", ";} s << '}'; return s;}
|
||||
|
||||
typedef PIMathVector<int> PIMathVectori;
|
||||
typedef PIMathVector<double> PIMathVectord;
|
||||
|
||||
/// Matrix
|
||||
|
||||
#define PIMM_FOR(c, r) for (uint c = 0; c < cols_; ++c) { for (uint r = 0; r < rows_; ++r) {
|
||||
#define PIMM_FOR_WB(c, r) for (uint c = 0; c < cols_; ++c) for (uint r = 0; r < rows_; ++r) // without brakes
|
||||
#define PIMM_FOR_I(c, r) for (uint r = 0; r < rows_; ++r) { for (uint c = 0; c < cols_; ++c) {
|
||||
#define PIMM_FOR_I_WB(c, r) for (uint r = 0; r < rows_; ++r) for (uint c = 0; c < cols_; ++c) // without brakes
|
||||
#define PIMM_FOR_C(v) for (uint v = 0; v < cols_; ++v)
|
||||
#define PIMM_FOR_R(v) for (uint v = 0; v < rows_; ++v)
|
||||
|
||||
template<typename Type>
|
||||
class PIP_EXPORT PIMathMatrix {
|
||||
typedef PIMathMatrix<Type> _CMatrix;
|
||||
typedef PIMathVector<Type> _CMCol;
|
||||
typedef PIMathVector<Type> _CMRow;
|
||||
public:
|
||||
PIMathMatrix(const uint cols = 3, const uint rows = 3) {resize(cols, rows);}
|
||||
PIMathMatrix(const uint cols, const uint rows, Type fval, ...) {resize(cols, rows); va_list vl; va_start(vl, fval); PIMM_FOR_I_WB(c, r) m[c][r] = (r + c == 0 ? fval : va_arg(vl, Type)); va_end(vl);}
|
||||
PIMathMatrix(const uint cols, const uint rows, const PIVector<Type> & val) {resize(cols, rows); int i = 0; PIMM_FOR_I_WB(c, r) m[c][r] = val[i++];}
|
||||
|
||||
static _CMatrix identity(const uint cols_, const uint rows_) {_CMatrix tm(cols_, rows_); PIMM_FOR_WB(c, r) tm.m[c][r] = (c == r ? Type(1) : Type(0)); return tm;}
|
||||
|
||||
uint cols() const {return cols_;}
|
||||
uint rows() const {return rows_;}
|
||||
_CMCol col(uint index) {_CMCol tv; PIMM_FOR_R(i) tv[i] = m[index][i]; return tv;}
|
||||
_CMRow row(uint index) {_CMRow tv; PIMM_FOR_C(i) tv[i] = m[i][index]; return tv;}
|
||||
_CMatrix & resize(const uint cols, const uint rows, const Type & new_value = Type()) {cols_ = cols; rows_ = rows; m.resize(cols); PIMM_FOR_C(i) m[i].resize(rows, new_value); return *this;}
|
||||
_CMatrix & setCol(uint index, const _CMCol & v) {PIMM_FOR_R(i) m[index][i] = v[i]; return *this;}
|
||||
_CMatrix & setRow(uint index, const _CMRow & v) {PIMM_FOR_C(i) m[i][index] = v[i]; return *this;}
|
||||
_CMatrix & swapRows(uint r0, uint r1) {Type t; PIMM_FOR_C(i) {t = m[i][r0]; m[i][r0] = m[i][r1]; m[i][r1] = t;} return *this;}
|
||||
_CMatrix & swapCols(uint c0, uint c1) {Type t; PIMM_FOR_R(i) {t = m[c0][i]; m[c0][i] = m[c1][i]; m[c1][i] = t;} return *this;}
|
||||
_CMatrix & fill(const Type & v) {PIMM_FOR_WB(c, r) m[c][r] = v; return *this;}
|
||||
//inline _CMatrix & set(Type fval, ...) {m[0] = fval; va_list vl; va_start(vl, fval); PIMV_FOR(i, 1) m[i] = va_arg(vl, Type); va_end(vl); return *this;}
|
||||
//inline void normalize() {Type tv = length(); if (tv == Type(1)) return; PIMV_FOR(i, 0) m[i] /= tv;}
|
||||
bool isSquare() const {return cols() == rows();}
|
||||
bool isIdentity() const {PIMM_FOR_WB(c, r) if ((c == r) ? m[c][r] != Type(1) : m[c][r] != Type(0)) return false; return true;}
|
||||
bool isNull() const {PIMM_FOR_WB(c, r) if (m[c][r] != Type(0)) return false; return true;}
|
||||
|
||||
Type & at(uint col, uint row) {return m[col][row];}
|
||||
Type at(uint col, uint row) const {return m[col][row];}
|
||||
PIVector<Type> & operator [](uint col) {return m[col];}
|
||||
PIVector<Type> operator [](uint col) const {return m[col];}
|
||||
void operator =(const _CMatrix & sm) {m = sm.m;}
|
||||
bool operator ==(const _CMatrix & sm) const {PIMM_FOR_WB(c, r) if (m[c][r] != sm.m[c][r]) return false; return true;}
|
||||
bool operator !=(const _CMatrix & sm) const {return !(*this == sm);}
|
||||
void operator +=(const _CMatrix & sm) {PIMM_FOR_WB(c, r) m[c][r] += sm.m[c][r];}
|
||||
void operator -=(const _CMatrix & sm) {PIMM_FOR_WB(c, r) m[c][r] -= sm.m[c][r];}
|
||||
void operator *=(const Type & v) {PIMM_FOR_WB(c, r) m[c][r] *= v;}
|
||||
void operator /=(const Type & v) {PIMM_FOR_WB(c, r) m[c][r] /= v;}
|
||||
_CMatrix operator -() {_CMatrix tm(*this); PIMM_FOR_WB(c, r) tm.m[c][r] = -m[c][r]; return tm;}
|
||||
_CMatrix operator +(const _CMatrix & sm) {_CMatrix tm(*this); PIMM_FOR_WB(c, r) tm.m[c][r] += sm.m[c][r]; return tm;}
|
||||
_CMatrix operator -(const _CMatrix & sm) {_CMatrix tm(*this); PIMM_FOR_WB(c, r) tm.m[c][r] -= sm.m[c][r]; return tm;}
|
||||
_CMatrix operator *(const Type & v) {_CMatrix tm(*this); PIMM_FOR_WB(c, r) tm.m[c][r] *= v; return tm;}
|
||||
_CMatrix operator /(const Type & v) {_CMatrix tm(*this); PIMM_FOR_WB(c, r) tm.m[c][r] /= v; return tm;}
|
||||
|
||||
_CMatrix & toUpperTriangular(bool * ok = 0) {
|
||||
if (cols_ != rows_) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
_CMatrix smat(*this);
|
||||
bool ndet;
|
||||
uint crow;
|
||||
Type mul;
|
||||
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 (ndet) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
for (uint j = 0; j < cols_; ++j) if (smat.m[j][i] != 0) ndet = false;
|
||||
if (ndet) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
for (uint i = 0; i < cols_; ++i) {
|
||||
crow = i;
|
||||
while (smat.m[i][i] == Type(0))
|
||||
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 (fabs(smat.m[i+1][i+1]) < Type(1E-100)) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ok != 0) *ok = true;
|
||||
m = smat.m;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_CMatrix & invert(bool * ok = 0, _CMCol * sv = 0) {
|
||||
if (cols_ != rows_) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
_CMatrix mtmp = _CMatrix::identity(cols_, rows_), smat(*this);
|
||||
bool ndet;
|
||||
uint crow;
|
||||
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;
|
||||
if (ndet) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
for (uint j = 0; j < cols_; ++j) if (smat.m[j][i] != 0) ndet = false;
|
||||
if (ndet) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
for (uint i = 0; i < cols_; ++i) {
|
||||
crow = i;
|
||||
while (smat.m[i][i] == Type(0)) {
|
||||
++crow;
|
||||
smat.swapRows(i, crow);
|
||||
mtmp.swapRows(i, crow);
|
||||
if (sv != 0) sv->swap(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];
|
||||
for (uint k = 0; k < cols_; ++k) mtmp.m[k][j] -= mul * mtmp.m[k][i];
|
||||
if (sv != 0) (*sv)[j] -= mul * (*sv)[i];
|
||||
}
|
||||
//cout << i << endl << smat << endl;
|
||||
if (i < cols_ - 1) {
|
||||
if (fabs(smat.m[i+1][i+1]) < Type(1E-100)) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
iddiv = smat.m[i][i];
|
||||
for (uint j = i; j < cols_; ++j) smat.m[j][i] /= iddiv;
|
||||
for (uint j = 0; j < cols_; ++j) mtmp.m[j][i] /= iddiv;
|
||||
if (sv != 0) (*sv)[i] /= iddiv;
|
||||
}
|
||||
for (uint i = cols_ - 1; i > 0; --i) {
|
||||
for (uint j = 0; j < i; ++j) {
|
||||
mul = smat.m[i][j];
|
||||
smat.m[i][j] -= mul;
|
||||
for (uint k = 0; k < cols_; ++k) mtmp.m[k][j] -= mtmp.m[k][i] * mul;
|
||||
if (sv != 0) (*sv)[j] -= mul * (*sv)[i];
|
||||
}
|
||||
}
|
||||
if (ok != 0) *ok = true;
|
||||
m = mtmp.m;
|
||||
return *this;
|
||||
}
|
||||
_CMatrix inverted(bool * ok = 0) {_CMatrix tm(*this); tm.invert(ok); return tm;}
|
||||
_CMatrix transposed() {_CMatrix tm(rows_, cols_); PIMM_FOR_WB(c, r) tm[r][c] = m[c][r]; return tm;}
|
||||
|
||||
private:
|
||||
uint cols_, rows_;
|
||||
PIVector<PIVector<Type> > m;
|
||||
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIMathMatrix<Type> & m) {s << '{'; for (uint r = 0; r < m.rows(); ++r) { for (uint c = 0; c < m.cols(); ++c) { s << m[c][r]; if (c < m.cols() - 1 || r < m.rows() - 1) s << ", ";} if (r < m.rows() - 1) s << endl << ' ';} s << '}'; return s;}
|
||||
template<typename Type>
|
||||
inline PICout operator <<(PICout s, const PIMathMatrix<Type> & m) {s << '{'; for (uint r = 0; r < m.rows(); ++r) { for (uint c = 0; c < m.cols(); ++c) { s << m[c][r]; if (c < m.cols() - 1 || r < m.rows() - 1) s << ", ";} if (r < m.rows() - 1) s << NewLine << ' ';} s << '}'; return s;}
|
||||
|
||||
/// Multiply matrices {CR x Rows0} on {Cols1 x CR}, result is {Cols1 x Rows0}
|
||||
template<typename Type>
|
||||
inline PIMathMatrix<Type> operator *(const PIMathMatrix<Type> & fm,
|
||||
const PIMathMatrix<Type> & sm) {
|
||||
uint cr = fm.cols(), rows0 = fm.rows(), cols1 = sm.cols();
|
||||
PIMathMatrix<Type> tm(cols1, rows0);
|
||||
if (fm.cols() != sm.rows()) return tm;
|
||||
Type t;
|
||||
for (uint j = 0; j < rows0; ++j) {
|
||||
for (uint i = 0; i < cols1; ++i) {
|
||||
t = Type(0);
|
||||
for (uint k = 0; k < cr; ++k)
|
||||
t += fm[k][j] * sm[i][k];
|
||||
tm[i][j] = t;
|
||||
}
|
||||
}
|
||||
return tm;
|
||||
}
|
||||
|
||||
/// Multiply matrix {Cols x Rows} on vector {Cols}, result is vector {Rows}
|
||||
template<typename Type>
|
||||
inline PIMathVector<Type> operator *(const PIMathMatrix<Type> & fm,
|
||||
const PIMathVector<Type> & sv) {
|
||||
uint c = fm.cols(), r = fm.rows();
|
||||
PIMathVector<Type> tv(r);
|
||||
if (c != sv.size()) return tv;
|
||||
Type t;
|
||||
for (uint i = 0; i < r; ++i) {
|
||||
t = Type(0);
|
||||
for (uint j = 0; j < c; ++j)
|
||||
t += fm[j][i] * sv[j];
|
||||
tv[i] = t;
|
||||
}
|
||||
return tv;
|
||||
}
|
||||
|
||||
typedef PIMathMatrix<int> PIMathMatrixi;
|
||||
typedef PIMathMatrix<double> PIMathMatrixd;
|
||||
|
||||
#undef PIMV_FOR
|
||||
#undef PIMM_FOR
|
||||
#undef PIMM_FOR_WB
|
||||
#undef PIMM_FOR_I
|
||||
#undef PIMM_FOR_I_WB
|
||||
#undef PIMM_FOR_C
|
||||
#undef PIMM_FOR_R
|
||||
|
||||
|
||||
/// Differential evaluations
|
||||
|
||||
struct TransferFunction { // Для задания передаточной функции
|
||||
PIVector<double> vector_Bm, vector_An;
|
||||
};
|
||||
|
||||
// Класс, служащий для перевода передаточной функции в систему ОДУ первого порядка
|
||||
// реализованы след. методы решения дифф. ур-ний:
|
||||
// Эйлера
|
||||
// Рунге-Кутта 4-го порядка
|
||||
// Адамса-Бэшфортса-Моултона 2, 3, 4 порядков
|
||||
class PIP_EXPORT Solver
|
||||
{
|
||||
public:
|
||||
enum Method {Global = -1,
|
||||
Eyler_1 = 01,
|
||||
Eyler_2 = 02,
|
||||
EylerKoshi = 03,
|
||||
RungeKutta_4 = 14,
|
||||
AdamsBashfortMoulton_2 = 22,
|
||||
AdamsBashfortMoulton_3 = 23,
|
||||
AdamsBashfortMoulton_4 = 24,
|
||||
PolynomialApproximation_2 = 32,
|
||||
PolynomialApproximation_3 = 33,
|
||||
PolynomialApproximation_4 = 34,
|
||||
PolynomialApproximation_5 = 35
|
||||
};
|
||||
|
||||
Solver() {times.resize(4); step = 0;}
|
||||
|
||||
void solve(double u, double h);
|
||||
void fromTF(const TransferFunction & TF);
|
||||
void setMethod(Method m) {method = m;}
|
||||
void setTime(double time) {times.pop_back(); times.push_front(time);}
|
||||
|
||||
void solveEyler1(double u, double h);
|
||||
void solveEyler2(double u, double h);
|
||||
void solveRK4(double u, double h);
|
||||
void solveABM2(double u, double h);
|
||||
void solveABM3(double u, double h);
|
||||
void solveABM4(double u, double h);
|
||||
void solvePA(double u, double h, uint deg);
|
||||
void solvePA2(double u, double h) {if (step > 0) solvePA(u, h, 2); else solveEyler1(u, h);}
|
||||
void solvePA3(double u, double h) {if (step > 1) solvePA(u, h, 3); else solvePA2(u, h);}
|
||||
void solvePA4(double u, double h) {if (step > 2) solvePA(u, h, 4); else solvePA3(u, h);}
|
||||
void solvePA5(double u, double h) {if (step > 3) solvePA(u, h, 5); else solvePA4(u, h);}
|
||||
|
||||
PIMathVectord X;
|
||||
static Method method_global;
|
||||
static const char methods_desc[];
|
||||
|
||||
private:
|
||||
void moveF() {for (uint i = F.size() - 1; i > 0; --i) F[i] = F[i - 1];}
|
||||
|
||||
PIMathMatrixd A, M;
|
||||
PIMathVectord d, a1, b1;
|
||||
PIMathVectord k1, k2, k3, k4, xx;
|
||||
PIMathVectord XX, Y, pY;
|
||||
PIVector<PIMathVectord> F;
|
||||
PIVector<double> times;
|
||||
uint size, step;
|
||||
Method method;
|
||||
double sum, td, ct, lp, dh, t, x1, x0;
|
||||
bool ok;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class PIP_EXPORT PIFFT
|
||||
{
|
||||
public:
|
||||
PIFFT();
|
||||
// const PIVector<uint> & getIndexes() {return indexes;}
|
||||
// const PIVector<complexd> & getCoefs() {return coefs;}
|
||||
PIVector<complexd> * calcFFT(const PIVector<complexd> &val);
|
||||
PIVector<complexd> * calcFFT(const PIVector<double> &val);
|
||||
PIVector<complexd> * calcFFTinverse(const PIVector<complexd> &val);
|
||||
PIVector<complexd> * calcHilbert(const PIVector<double> &val);
|
||||
PIVector<double> getAmplitude();
|
||||
private:
|
||||
// PIVector<uint> indexes;
|
||||
// PIVector<complexd> coefs;
|
||||
PIVector<complexd> result;
|
||||
// uint iterations;
|
||||
bool prepared;
|
||||
// uint out_size;
|
||||
typedef ptrdiff_t ae_int_t;
|
||||
void calc_coefs(uint cnt2);
|
||||
void calc_indexes(uint cnt2, uint deep2);
|
||||
complexd coef(uint n, uint k);
|
||||
|
||||
struct ftplan {
|
||||
PIVector<int> plan;
|
||||
PIVector<double> precomputed;
|
||||
PIVector<double> tmpbuf;
|
||||
PIVector<double> stackbuf;
|
||||
};
|
||||
|
||||
ftplan curplan;
|
||||
|
||||
void fftc1d(const PIVector<complexd> &a, uint n);
|
||||
void fftc1r(const PIVector<double> &a, uint n);
|
||||
void fftc1dinv(const PIVector<complexd> &a, uint n);
|
||||
|
||||
void createPlan(uint n);
|
||||
void ftbasegeneratecomplexfftplan(uint n, ftplan *plan);
|
||||
void ftbase_ftbasegenerateplanrec(int n, int tasktype, ftplan *plan, int *plansize, int *precomputedsize, int *planarraysize, int *tmpmemsize, int *stackmemsize, ae_int_t stackptr, int debugi=0);
|
||||
void ftbase_ftbaseprecomputeplanrec(ftplan *plan, int entryoffset, ae_int_t stackptr);
|
||||
void ftbasefactorize(int n, int *n1, int *n2);
|
||||
void ftbase_ftbasefindsmoothrec(int n, int seed, int leastfactor, int *best);
|
||||
int ftbasefindsmooth(int n);
|
||||
void ftbaseexecuteplan(PIVector<double> *a, int aoffset, int n, ftplan *plan);
|
||||
void ftbaseexecuteplanrec(PIVector<double> *a, int aoffset, ftplan *plan, int entryoffset, ae_int_t stackptr);
|
||||
void ftbase_internalcomplexlintranspose(PIVector<double> *a, int m, int n, int astart, PIVector<double> *buf);
|
||||
void ftbase_ffticltrec(PIVector<double> *a, int astart, int astride, PIVector<double> *b, int bstart, int bstride, int m, int n);
|
||||
void ftbase_internalreallintranspose(PIVector<double> *a, int m, int n, int astart, PIVector<double> *buf);
|
||||
void ftbase_fftirltrec(PIVector<double> *a, int astart, int astride, PIVector<double> *b, int bstart, int bstride, int m, int n);
|
||||
void ftbase_ffttwcalc(PIVector<double> *a, int aoffset, int n1, int n2);
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class PIP_EXPORT PIStatistic {
|
||||
public:
|
||||
PIStatistic() {mean = variance = skewness = kurtosis = T();}
|
||||
|
||||
static T calculateMean(const PIVector<T> & val) {
|
||||
T ret = T();
|
||||
int n = val.size();
|
||||
if (n < 1)
|
||||
return ret;
|
||||
for (int i = 0; i < n; i++)
|
||||
ret += val[i];
|
||||
return ret / n;
|
||||
}
|
||||
bool calculate(const PIVector<T> & val, const T & given_mean) {
|
||||
T v = T(), v1 = T(), v2 = T(), stddev = T(), var = T();
|
||||
int i, n = val.size();
|
||||
if (n < 2)
|
||||
return false;
|
||||
mean = given_mean;
|
||||
variance = skewness = kurtosis = T();
|
||||
/*
|
||||
* Variance (using corrected two-pass algorithm)
|
||||
*/
|
||||
for (i = 0; i < n; i++)
|
||||
v1 += sqr(val[i] - mean);
|
||||
for (i = 0; i < n; i++)
|
||||
v2 += val[i] - mean;
|
||||
v2 = sqr(v2) / n;
|
||||
variance = v1 / n;
|
||||
var = (v1 / n - v2) / (n - 1);
|
||||
if (var < T())
|
||||
var = T();
|
||||
stddev = sqrt(var);
|
||||
/*
|
||||
* Skewness and kurtosis
|
||||
*/
|
||||
if (stddev != T()) {
|
||||
for (i = 0; i < n; i++) {
|
||||
v = (val[i] - mean) / stddev;
|
||||
v2 = sqr(v);
|
||||
skewness = skewness + v2 * v;
|
||||
kurtosis = kurtosis + sqr(v2);
|
||||
}
|
||||
skewness /= n;
|
||||
kurtosis = kurtosis / n - 3.;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool calculate(const PIVector<T> & val) {return calculate(val, calculateMean(val));}
|
||||
|
||||
T mean;
|
||||
T variance;
|
||||
T skewness;
|
||||
T kurtosis;
|
||||
};
|
||||
|
||||
typedef PIStatistic<int> PIStatistici;
|
||||
typedef PIStatistic<float> PIStatisticf;
|
||||
typedef PIStatistic<double> PIStatisticd;
|
||||
|
||||
|
||||
template <typename T>
|
||||
bool OLS_Linear(const PIVector<PIPair<T, T> > & input, T * out_a, T * out_b) {
|
||||
if (input.size_s() < 2)
|
||||
return false;
|
||||
int n = input.size_s();
|
||||
T a_t0 = T(), a_t1 = T(), a_t2 = T(), a_t3 = T(), a_t4 = T(), a = T(), b = T();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
const PIPair<T, T> & cv(input[i]);
|
||||
a_t0 += cv.first * cv.second;
|
||||
a_t1 += cv.first;
|
||||
a_t2 += cv.second;
|
||||
a_t3 += cv.first * cv.first;
|
||||
}
|
||||
a_t4 = n * a_t3 - a_t1 * a_t1;
|
||||
if (a_t4 != T())
|
||||
a = (n * a_t0 - a_t1 * a_t2) / a_t4;
|
||||
b = (a_t2 - a * a_t1) / n;
|
||||
if (out_a != 0) *out_a = a;
|
||||
if (out_b != 0) *out_b = b;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
bool WLS_Linear(const PIVector<PIPair<T, T> > & input, const PIVector<T> & weights, T * out_a, T * out_b) {
|
||||
if (input.size_s() < 2)
|
||||
return false;
|
||||
if (input.size_s() != weights.size_s())
|
||||
return false;
|
||||
int n = input.size_s();
|
||||
T a_t0 = T(), a_t1 = T(), a_t2 = T(), a_t3 = T(), a_t4 = T(), a_n = T(), a = T(), b = T();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
T cp = weights[i];
|
||||
const PIPair<T, T> & cv(input[i]);
|
||||
a_t0 += cv.first * cv.second * cp;
|
||||
a_t1 += cv.first * cp;
|
||||
a_t2 += cv.second * cp;
|
||||
a_t3 += cv.first * cv.first * cp;
|
||||
a_n += cp;
|
||||
}
|
||||
a_t4 = a_n * a_t3 - a_t1 * a_t1;
|
||||
if (a_t4 != T())
|
||||
a = (a_n * a_t0 - a_t1 * a_t2) / a_t4;
|
||||
b = (a_t2 - a * a_t1) / a_n;
|
||||
if (out_a != 0) *out_a = a;
|
||||
if (out_b != 0) *out_b = b;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // PIMATH_H
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Counter of some PIP types
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pimonitor.h"
|
||||
|
||||
PIMonitor piMonitor;
|
||||
|
||||
PIMonitor::PIMonitor() {
|
||||
containers = strings = threads = timers = serials = ethernets = files = objects = 0;
|
||||
}
|
||||
39
pimonitor.h
39
pimonitor.h
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Counter of some PIP types
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIMONITOR_H
|
||||
#define PIMONITOR_H
|
||||
|
||||
#include "pip_export.h"
|
||||
|
||||
#if defined(DOXYGEN) || defined(__GNUC__)
|
||||
# undef PIP_EXPORT
|
||||
# define PIP_EXPORT
|
||||
#endif
|
||||
|
||||
class PIP_EXPORT PIMonitor
|
||||
{
|
||||
public:
|
||||
PIMonitor();
|
||||
|
||||
int containers, strings, threads, timers, serials, ethernets, files, objects;
|
||||
|
||||
};
|
||||
|
||||
#endif // PIMONITOR_H
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Multiprotocol
|
||||
Copyright (C) 2012 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pimultiprotocol.h"
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Multiprotocol
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIMULTIPROTOCOL_H
|
||||
#define PIMULTIPROTOCOL_H
|
||||
|
||||
#include "piprotocol.h"
|
||||
|
||||
class PIMultiProtocol: public PIMultiProtocolBase
|
||||
{
|
||||
public:
|
||||
PIMultiProtocol() {;}
|
||||
virtual ~PIMultiProtocol() {clear();}
|
||||
|
||||
void addProtocol(PIProtocol & prot) {prots.push_back(&prot); prot.setMultiProtocolOwner(this); prot.new_mp_prot = false;}
|
||||
void addProtocol(PIProtocol * prot) {prots.push_back(prot); prot->setMultiProtocolOwner(this); prot->new_mp_prot = false;}
|
||||
void addProtocol(const PIString & config, const PIString & name, void * recHeaderPtr = 0, int recHeaderSize = 0,
|
||||
void * recDataPtr = 0, int recDataSize = 0, void * sendDataPtr = 0, int sendDataSize = 0) {;
|
||||
prots.push_back(new PIProtocol(config, name, recHeaderPtr, recHeaderSize, recDataPtr, recDataSize, sendDataPtr, sendDataSize));
|
||||
prots.back()->setMultiProtocolOwner(this);
|
||||
prots.back()->new_mp_prot = true;
|
||||
}
|
||||
PIProtocol * protocol(const PIString & name) {piForeach (PIProtocol * i, prots) if (i->name() == name) return i; return 0;}
|
||||
PIProtocol * protocol(const int index) {return prots[index];}
|
||||
PIProtocol * operator [](const int index) {return prots[index];}
|
||||
|
||||
void startSend() {piForeach (PIProtocol * i, prots) i->startSend();}
|
||||
void startReceive() {piForeach (PIProtocol * i, prots) i->startReceive();}
|
||||
void start() {piForeach (PIProtocol * i, prots) i->start();}
|
||||
|
||||
void stopSend() {piForeach (PIProtocol * i, prots) i->stopSend();}
|
||||
void stopReceive() {piForeach (PIProtocol * i, prots) i->stopReceive();}
|
||||
void stop() {piForeach (PIProtocol * i, prots) i->stop();}
|
||||
|
||||
PIProtocol::Quality worseQuality() const {PIProtocol::Quality cq = PIProtocol::Good; piForeachC (PIProtocol * i, prots) if (cq > i->quality()) cq = i->quality(); return cq;}
|
||||
PIProtocol::Quality bestQuality() const {PIProtocol::Quality cq = PIProtocol::Unknown; piForeachC (PIProtocol * i, prots) if (cq < i->quality()) cq = i->quality(); return cq;}
|
||||
|
||||
int count() const {return prots.size_s();}
|
||||
void clear() {stop(); piForeach (PIProtocol * i, prots) if (i->new_mp_prot) delete i; prots.clear();}
|
||||
|
||||
private:
|
||||
PIVector<PIProtocol * > prots;
|
||||
|
||||
};
|
||||
|
||||
class PIRepeater: public PIMultiProtocol {
|
||||
public:
|
||||
PIRepeater(const PIString & config, const PIString & name_) {
|
||||
PIConfig conf(config, PIIODevice::ReadOnly);
|
||||
if (!conf.isOpened()) {
|
||||
piCoutObj << "[PIRepeater \"" << name_ << "\"] Can`t open \"" << config << "\"!";
|
||||
return;
|
||||
}
|
||||
PIConfig::Entry & b(conf.getValue(name_));
|
||||
if (b.childCount() != 2) {
|
||||
piCoutObj << "[PIRepeater \"" << name_ << "\"] \"" << config << "\" should consist 2 nodes!";
|
||||
return;
|
||||
}
|
||||
addProtocol(config, b.child(0)->fullName());
|
||||
addProtocol(config, b.child(1)->fullName());
|
||||
start();
|
||||
}
|
||||
|
||||
PIString firstChannelName() {if (count() == 2) return protocol(0)->receiverDeviceName() + " -> " + protocol(1)->senderDeviceName(); return "Config error";}
|
||||
PIString secondChannelName() {if (count() == 2) return protocol(1)->receiverDeviceName() + " -> " + protocol(0)->senderDeviceName(); return "Config error";}
|
||||
|
||||
ullong receiveCount() {if (count() == 2) return protocol(0)->receiveCount(); return 0;}
|
||||
const ullong * receiveCount_ptr() {if (count() == 2) return protocol(0)->receiveCount_ptr(); return 0;}
|
||||
ullong sendCount() {if (count() == 2) return protocol(0)->sendCount(); return 0;}
|
||||
const ullong * sendCount_ptr() {if (count() == 2) return protocol(0)->sendCount_ptr(); return 0;}
|
||||
|
||||
private:
|
||||
void received(PIProtocol * prot, bool , uchar * data, int size) {if (prot == protocol(0)) protocol(1)->send(data, size); else protocol(0)->send(data, size);}
|
||||
|
||||
};
|
||||
|
||||
#endif // PIMULTIPROTOCOL_H
|
||||
59
pimutex.cpp
59
pimutex.cpp
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Mutex
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pimutex.h"
|
||||
|
||||
|
||||
/** \class PIMutex
|
||||
* \brief Mutex
|
||||
* \details
|
||||
* \section PIMutex_sec0 Synopsis
|
||||
* %PIMutex provides synchronization blocks between several threads.
|
||||
* Using mutex guarantees execution of some code only one of threads.
|
||||
* Mutex contains logic state and functions to change it: \a lock(),
|
||||
* \a unlock() and \a tryLock().
|
||||
*
|
||||
* \section PIMutex_sec1 Usage
|
||||
* Block of code that should to be executed only one thread simultaniously
|
||||
* should to be started with \a lock() and ended with \a unlock().
|
||||
* \snippet pimutex.cpp main
|
||||
* "mutex" in this example is one for all threads.
|
||||
*
|
||||
* */
|
||||
|
||||
|
||||
PIMutex::PIMutex() {
|
||||
#ifdef WINDOWS
|
||||
mutex = CreateMutex(0, false, 0);
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutex_init(&mutex, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PIMutex::~PIMutex() {
|
||||
#ifdef WINDOWS
|
||||
if (mutex != 0) CloseHandle(mutex);
|
||||
#else
|
||||
pthread_mutex_destroy(&mutex);
|
||||
#endif
|
||||
}
|
||||
93
pimutex.h
93
pimutex.h
@@ -1,93 +0,0 @@
|
||||
/*! \file pimutex.h
|
||||
* \brief Mutex
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Mutex
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIMUTEX_H
|
||||
#define PIMUTEX_H
|
||||
|
||||
#include "piincludes.h"
|
||||
|
||||
class PIP_EXPORT PIMutex
|
||||
{
|
||||
public:
|
||||
|
||||
//! Constructs unlocked mutex
|
||||
PIMutex();
|
||||
|
||||
~PIMutex();
|
||||
|
||||
|
||||
//! \brief Lock mutex
|
||||
//! \details If mutex is unlocked it set to locked state and returns immediate.
|
||||
//! If mutex is already locked function blocks until mutex will be unlocked
|
||||
void lock() {
|
||||
#ifdef WINDOWS
|
||||
WaitForSingleObject(mutex, INFINITE);
|
||||
#else
|
||||
pthread_mutex_lock(&mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//! \brief Unlock mutex
|
||||
//! \details In any case this function returns immediate
|
||||
void unlock() {
|
||||
#ifdef WINDOWS
|
||||
ReleaseMutex(mutex);
|
||||
#else
|
||||
pthread_mutex_unlock(&mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//! \brief Try to lock mutex
|
||||
//! \details If mutex is unlocked it set to locked state and returns "true" immediate.
|
||||
//! If mutex is already locked function returns immediate an returns "false"
|
||||
bool tryLock() {
|
||||
#ifdef WINDOWS
|
||||
return (WaitForSingleObject(mutex, 0) == WAIT_OBJECT_0);
|
||||
#else
|
||||
return (pthread_mutex_trylock(&mutex) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef WINDOWS
|
||||
void *
|
||||
#else
|
||||
pthread_mutex_t
|
||||
#endif
|
||||
mutex;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class PIP_EXPORT PIMutexLocker
|
||||
{
|
||||
public:
|
||||
PIMutexLocker(PIMutex * m): mutex(m) {mutex->lock();}
|
||||
PIMutexLocker(PIMutex & m): mutex(&m) {mutex->lock();}
|
||||
~PIMutexLocker() {mutex->unlock();}
|
||||
private:
|
||||
PIMutex * mutex;
|
||||
};
|
||||
|
||||
#endif // PIMUTEX_H
|
||||
115
piobject.cpp
115
piobject.cpp
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Object, base class of some PIP classes, provide EVENT -> EVENT_HANDLER mechanism
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piobject.h"
|
||||
|
||||
PIVector<PIObject * > PIObject::objects;
|
||||
|
||||
|
||||
/** \class PIObject
|
||||
* \brief This is base class for any classes which use events -> handlers mechanism.
|
||||
* \details
|
||||
* \section PIObject_sec0 Events and Event handlers
|
||||
* %PIObject provide notification mechanism similar Qt but implemented
|
||||
* on language capabilities without any special preprocessors or compilers.
|
||||
* Any class inherits PIObject should use macro \a PIOBJECT() immediate
|
||||
* after declaration to proper compile.
|
||||
*
|
||||
* Event is a some abstract event that can be raised at any time.
|
||||
* Event is a function but declared with special macro \a EVENT().
|
||||
* To raise event simply execute event function.
|
||||
*
|
||||
* Event handler is a function but declared with special macro
|
||||
* \a EVENT_HANDLER(). You can use event handlers as ordinary functions.
|
||||
*
|
||||
* Main goal of this mechanism is perform abstract connections between
|
||||
* various objects. This functionality provide macro \a CONNECT() which
|
||||
* connect some event of first object to some event handler or event of
|
||||
* second object. Each event can be connected any times to any event handlers.
|
||||
*
|
||||
* \image html events_handlers.png
|
||||
*
|
||||
* Example: \snippet piobject.cpp main
|
||||
* Result:
|
||||
\code{.cpp}
|
||||
handler B: 2 , 0.5
|
||||
handler A: event to handler
|
||||
handler A: event to event
|
||||
\endcode
|
||||
*/
|
||||
|
||||
|
||||
PIObject::PIObject(const PIString & name): emitter_(0) {
|
||||
piMonitor.objects++;
|
||||
setName(name);
|
||||
setDebug(true);
|
||||
objects << this;
|
||||
}
|
||||
|
||||
|
||||
void PIObject::piConnect(const PIString & src, const PIString & sig, void * dest, void * ev_h) {
|
||||
PIObject * o = findByName(src);
|
||||
if (o == 0) {
|
||||
piCout << "[PIObject] Can`t find object with name \"" << src << "\"!";
|
||||
return;
|
||||
}
|
||||
o->connections << Connection(ev_h, 0, sig, dest);
|
||||
}
|
||||
|
||||
|
||||
void PIObject::piConnect(PIObject * src, const PIString & sig, const PIString & dest, void * ev_h) {
|
||||
PIObject * o = findByName(dest);
|
||||
if (o == 0) {
|
||||
piCout << "[PIObject] Can`t find object with name \"" << dest << "\"!";
|
||||
return;
|
||||
}
|
||||
src->connections << Connection(ev_h, 0, sig, o);
|
||||
}
|
||||
|
||||
|
||||
void PIObject::piConnect(const PIString & src, const PIString & sig, const PIString & dest, void * ev_h) {
|
||||
PIObject * s = findByName(src);
|
||||
if (s == 0) {
|
||||
piCout << "[PIObject] Can`t find object with name \"" << src << "\"!";
|
||||
return;
|
||||
}
|
||||
PIObject * d = findByName(dest);
|
||||
if (d == 0) {
|
||||
piCout << "[PIObject] Can`t find object with name \"" << dest << "\"!";
|
||||
return;
|
||||
}
|
||||
s->connections << Connection(ev_h, 0, sig, d);
|
||||
}
|
||||
|
||||
/*
|
||||
PIStringList PIObject::events() {
|
||||
PIStringList l;
|
||||
for (PIMap<NamedFunction, PIString>::const_iterator i = signals_.begin(); i != signals_.end(); i++)
|
||||
l << (*i).first;
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
PIStringList PIObject::eventHandlers() {
|
||||
PIStringList l;
|
||||
for (PIMap<NamedFunction, PIString>::const_iterator i = slots_.begin(); i != slots_.end(); i++)
|
||||
l << (*i).first;
|
||||
return l;
|
||||
}
|
||||
*/
|
||||
535
piobject.h
535
piobject.h
@@ -1,535 +0,0 @@
|
||||
/*! \file piobject.h
|
||||
* \brief Base object
|
||||
*
|
||||
* This file declare PIObject class and associated macros
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Object, base class of some PIP classes, provide EVENT -> EVENT_HANDLER mechanism
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIOBJECT_H
|
||||
#define PIOBJECT_H
|
||||
|
||||
#include "pivariant.h"
|
||||
#include "pimutex.h"
|
||||
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief you should use this macro after class declaration to use EVENT and EVENT_HANDLER and correct piCoutObj output
|
||||
#define PIOBJECT(name)
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name()
|
||||
#define EVENT_HANDLER0(ret, name) ret name()
|
||||
|
||||
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0)
|
||||
#define EVENT_HANDLER1(ret, name, type0, var0) ret name(type0 var0)
|
||||
|
||||
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1)
|
||||
#define EVENT_HANDLER2(ret, name, type0, var0, type1, var1) ret name(type0 var0, type1 var1)
|
||||
|
||||
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1, type2 var2)
|
||||
#define EVENT_HANDLER3(ret, name, type0, var0, type1, var1, type2, var2) ret name(type0 var0, type1 var1, type2 var2)
|
||||
|
||||
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1, type2 var2, type3 var3)
|
||||
#define EVENT_HANDLER4(ret, name, type0, var0, type1, var1, type2, var2, type3, var3) ret name(type0 var0, type1 var1, type2 var2, type3 var3)
|
||||
|
||||
/// \relatesalso PIObject \brief EVENT_HANDLER is synonym of EVENT_HANDLER0
|
||||
#define EVENT_HANDLER EVENT_HANDLER0
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name()
|
||||
#define EVENT_VHANDLER0(ret, name) virtual ret name()
|
||||
|
||||
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0)
|
||||
#define EVENT_VHANDLER1(ret, name, type0, var0) virtual ret name(type0 var0)
|
||||
|
||||
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1)
|
||||
#define EVENT_VHANDLER2(ret, name, type0, var0, type1, var1) virtual ret name(type0 var0, type1 var1)
|
||||
|
||||
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1, type2 var2)
|
||||
#define EVENT_VHANDLER3(ret, name, type0, var0, type1, var1, type2, var2) virtual ret name(type0 var0, type1 var1, type2 var2)
|
||||
|
||||
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3)
|
||||
#define EVENT_VHANDLER4(ret, name, type0, var0, type1, var1, type2, var2, type3, var3) virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3)
|
||||
|
||||
/// \relatesalso PIObject \brief EVENT_VHANDLER is synonym of EVENT_VHANDLER0
|
||||
#define EVENT_VHANDLER EVENT_VHANDLER0
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name();
|
||||
#define EVENT0(name) void name();
|
||||
|
||||
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0);
|
||||
#define EVENT1(name, type0, var0) void name(type0 var0);
|
||||
|
||||
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1);
|
||||
#define EVENT2(name, type0, var0, type1, var1) void name(type0 var0, type1 var1);
|
||||
|
||||
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1, type2 var2);
|
||||
#define EVENT3(name, type0, var0, type1, var1, type2, var2) void name(type0 var0, type1 var1, type2 var2);
|
||||
|
||||
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1, type2 var2, type3 var3);
|
||||
#define EVENT4(name, type0, var0, type1, var1, type2, var2, type3, var3) void name(type0 var0, type1 var1, type2 var2, type3 var3);
|
||||
|
||||
/// \relatesalso PIObject \brief EVENT is synonym of EVENT0
|
||||
#define EVENT EVENT0
|
||||
|
||||
|
||||
#define RAISE_EVENT0(src, event)
|
||||
#define RAISE_EVENT1(src, event, v0)
|
||||
#define RAISE_EVENT2(src, event, v0, v1)
|
||||
#define RAISE_EVENT3(src, event, v0, v1, v2)
|
||||
#define RAISE_EVENT4(src, event, v0, v1, v2, v3)
|
||||
#define RAISE_EVENT RAISE_EVENT0
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
|
||||
#define CONNECT0(ret, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
|
||||
#define CONNECT1(ret, type0, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
|
||||
#define CONNECT2(ret, type0, type1, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
|
||||
#define CONNECT3(ret, type0, type1, type2, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
|
||||
#define CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief CONNECT is synonym of CONNECT0
|
||||
#define CONNECT CONNECT0
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
|
||||
#define WEAK_CONNECT0(ret, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
|
||||
#define WEAK_CONNECT1(ret, type0, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
|
||||
#define WEAK_CONNECT2(ret, type0, type1, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
|
||||
#define WEAK_CONNECT3(ret, type0, type1, type2, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
|
||||
#define WEAK_CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief WEAK_CONNECT is synonym of WEAK_CONNECT0
|
||||
#define WEAK_CONNECT WEAK_CONNECT0
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
|
||||
#define DISCONNECT0(ret, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
|
||||
#define DISCONNECT1(ret, type0, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
|
||||
#define DISCONNECT2(ret, type0, type1, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
|
||||
#define DISCONNECT3(ret, type0, type1, type2, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
|
||||
#define DISCONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief DISCONNECT is synonym of DISCONNECT0
|
||||
#define DISCONNECT DISCONNECT0
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief Returns pointer to events handler \"handler\"
|
||||
#define HANDLER(handler)
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#define PIOBJECT(obj) typedef obj __PIObject__; public: virtual const char * className() const {return #obj;} private:
|
||||
|
||||
#define EVENT_HANDLER0(ret, name) static ret __stat_eh_##name##__(void * o) {return ((__PIObject__*)o)->name();} ret name()
|
||||
#define EVENT_HANDLER1(ret, name, a0, n0) static ret __stat_eh_##name##__(void * o, a0 n0) {return ((__PIObject__*)o)->name(n0);} ret name(a0 n0)
|
||||
#define EVENT_HANDLER2(ret, name, a0, n0, a1, n1) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1) {return ((__PIObject__*)o)->name(n0, n1);} ret name(a0 n0, a1 n1)
|
||||
#define EVENT_HANDLER3(ret, name, a0, n0, a1, n1, a2, n2) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2) {return ((__PIObject__*)o)->name(n0, n1, n2);} ret name(a0 n0, a1 n1, a2 n2)
|
||||
#define EVENT_HANDLER4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2, a3 n3) {return ((__PIObject__*)o)->name(n0, n1, n2, n3);} ret name(a0 n0, a1 n1, a2 n2, a3 n3)
|
||||
#define EVENT_HANDLER EVENT_HANDLER0
|
||||
|
||||
#define EVENT_VHANDLER0(ret, name) static ret __stat_eh_##name##__(void * o) {return ((__PIObject__*)o)->name();} virtual ret name()
|
||||
#define EVENT_VHANDLER1(ret, name, a0, n0) static ret __stat_eh_##name##__(void * o, a0 n0) {return ((__PIObject__*)o)->name(n0);} virtual ret name(a0 n0)
|
||||
#define EVENT_VHANDLER2(ret, name, a0, n0, a1, n1) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1) {return ((__PIObject__*)o)->name(n0, n1);} virtual ret name(a0 n0, a1 n1)
|
||||
#define EVENT_VHANDLER3(ret, name, a0, n0, a1, n1, a2, n2) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2) {return ((__PIObject__*)o)->name(n0, n1, n2);} virtual ret name(a0 n0, a1 n1, a2 n2)
|
||||
#define EVENT_VHANDLER4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2, a3 n3) {return ((__PIObject__*)o)->name(n0, n1, n2, n3);} virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3)
|
||||
#define EVENT_VHANDLER EVENT_VHANDLER0
|
||||
|
||||
#define EVENT0(name) EVENT_HANDLER0(void, name) {PIObject::raiseEvent(this, #name);}
|
||||
#define EVENT1(name, a0, n0) EVENT_HANDLER1(void, name, a0, n0) {PIObject::raiseEvent(this, #name, n0);}
|
||||
#define EVENT2(name, a0, n0, a1, n1) EVENT_HANDLER2(void, name, a0, n0, a1, n1) {PIObject::raiseEvent(this, #name, n0, n1);}
|
||||
#define EVENT3(name, a0, n0, a1, n1, a2, n2) EVENT_HANDLER3(void, name, a0, n0, a1, n1, a2, n2) {PIObject::raiseEvent(this, #name, n0, n1, n2);}
|
||||
#define EVENT4(name, a0, n0, a1, n1, a2, n2, a3, n3) EVENT_HANDLER4(void, name, a0, n0, a1, n1, a2, n2, a3, n3) {PIObject::raiseEvent(this, #name, n0, n1, n2, n3);}
|
||||
#define EVENT EVENT0
|
||||
|
||||
#define RAISE_EVENT0(src, event) (src)->event();
|
||||
#define RAISE_EVENT1(src, event, v0) (src)->event(v0);
|
||||
#define RAISE_EVENT2(src, event, v0, v1) (src)->event(v0, v1);
|
||||
#define RAISE_EVENT3(src, event, v0, v1, v2) (src)->event(v0, v1, v2);
|
||||
#define RAISE_EVENT4(src, event, v0, v1, v2, v3) (src)->event(v0, v1, v2, v3);
|
||||
#define RAISE_EVENT RAISE_EVENT0
|
||||
|
||||
#define CONNECT0(ret, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*))(&(src)->__stat_eh_##event##__));
|
||||
#define CONNECT1(ret, a0, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0))(&(src)->__stat_eh_##event##__));
|
||||
#define CONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1))(&(src)->__stat_eh_##event##__));
|
||||
#define CONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1, a2))(&(src)->__stat_eh_##event##__));
|
||||
#define CONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1, a2, a3))(&(src)->__stat_eh_##event##__));
|
||||
#define CONNECT CONNECT0
|
||||
|
||||
#define WEAK_CONNECT0(ret, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__));
|
||||
#define WEAK_CONNECT1(ret, a0, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__));
|
||||
#define WEAK_CONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__));
|
||||
#define WEAK_CONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__));
|
||||
#define WEAK_CONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__));
|
||||
#define WEAK_CONNECT WEAK_CONNECT0
|
||||
|
||||
#define DISCONNECT0(ret, src, event, dest, handler) PIObject::piDisconnect(src, #event, dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__));
|
||||
#define DISCONNECT1(ret, a0, src, event, dest, handler) PIObject::piDisconnect(src, #event, dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__));
|
||||
#define DISCONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piDisconnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__));
|
||||
#define DISCONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piDisconnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__));
|
||||
#define DISCONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piDisconnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__));
|
||||
#define DISCONNECT DISCONNECT0
|
||||
|
||||
#define HANDLER(handler) __stat_eh_##handler##__
|
||||
|
||||
#endif
|
||||
|
||||
typedef void (*Handler)(void * );
|
||||
|
||||
class PIP_EXPORT PIObject
|
||||
{
|
||||
friend class PIObjectManager;
|
||||
public:
|
||||
|
||||
//! Contructs PIObject with name "name"
|
||||
PIObject(const PIString & name = PIString());
|
||||
|
||||
virtual ~PIObject() {piMonitor.objects--; objects.removeAll(this);}
|
||||
|
||||
|
||||
//! Returns object name
|
||||
PIString name() const {return property("name").toString();}
|
||||
|
||||
//! Returns object class name
|
||||
virtual const char * className() const {return "PIObject";}
|
||||
|
||||
//! Return if debug of this object is active
|
||||
bool debug() const {return property("debug").toBool();}
|
||||
|
||||
|
||||
//! Set object name
|
||||
void setName(const PIString & name) {setProperty("name", name);}
|
||||
|
||||
//! Set object debug active
|
||||
void setDebug(bool debug) {setProperty("debug", debug);}
|
||||
|
||||
//! Returns properties of the object
|
||||
const PIMap<PIString, PIVariant> & properties() const {return properties_;}
|
||||
|
||||
//! Returns properties count of the object
|
||||
int propertiesCount() const {return properties_.size_s();}
|
||||
|
||||
//! Returns property with name "name"
|
||||
PIVariant property(const PIString & name) const {if (!properties_.contains(name)) return PIVariant(); return properties_.value(name);}
|
||||
|
||||
//! Set property with name "name" to "value". If there is no such property in object it will be added
|
||||
void setProperty(const PIString & name, const PIVariant & value) {properties_[name] = value; propertyChanged(name);}
|
||||
|
||||
//! Returns if property with name "name" exists
|
||||
bool isPropertyExists(const PIString & name) const {return properties_.contains(name);}
|
||||
|
||||
/*
|
||||
PIStringList events();
|
||||
PIStringList eventHandlers();
|
||||
|
||||
/// Events
|
||||
void addEvent(const PIString & name) {
|
||||
signals_.insert(NamedFunction(0, name, PIStringList()), name);
|
||||
}
|
||||
template <typename T0>
|
||||
void addEvent(const PIString & name) {
|
||||
signals_.insert(NamedFunction(0, name, PIStringList(typeid(T0).name())), name);
|
||||
}
|
||||
template <typename T0, typename T1>
|
||||
void addEvent(const PIString & name) {
|
||||
signals_.insert(NamedFunction(0, name, PIStringList(typeid(T0).name(), typeid(T1).name())), name);
|
||||
}
|
||||
template <typename T0, typename T1, typename T2>
|
||||
void addEvent(const PIString & name) {
|
||||
signals_.insert(NamedFunction(0, name, PIStringList(typeid(T0).name(), typeid(T1).name(), typeid(T2).name())), name);
|
||||
}
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
void addEvent(const PIString & name) {
|
||||
signals_.insert(NamedFunction(0, name, PIStringList(typeid(T0).name(), typeid(T1).name(), typeid(T2).name(), typeid(T3).name())), name);
|
||||
}
|
||||
|
||||
/// Event handlers
|
||||
void addEventHandler(const PIString & name, void * func) {
|
||||
slots_.insert(NamedFunction(func, name, PIStringList()), name);
|
||||
}
|
||||
template <typename T0>
|
||||
void addEventHandler(const PIString & name, void * func) {
|
||||
slots_.insert(NamedFunction(func, name, PIStringList(typeid(T0).name())), name);
|
||||
}
|
||||
template <typename T0, typename T1>
|
||||
void addEventHandler(const PIString & name, void * func) {
|
||||
slots_.insert(NamedFunction(func, name, PIStringList(typeid(T0).name(), typeid(T1).name())), name);
|
||||
}
|
||||
template <typename T0, typename T1, typename T2>
|
||||
void addEventHandler(const PIString & name, void * func) {
|
||||
slots_.insert(NamedFunction(func, name, PIStringList(typeid(T0).name(), typeid(T1).name(), typeid(T2).name())), name);
|
||||
}
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
void addEventHandler(const PIString & name, void * func) {
|
||||
slots_.insert(NamedFunction(func, name, PIStringList(typeid(T0).name(), typeid(T1).name(), typeid(T2).name(), typeid(T3).name())), name);
|
||||
}
|
||||
*/
|
||||
// / Direct connect
|
||||
static void piConnect(PIObject * src, const PIString & sig, void * dest, void * ev_h) {src->connections << Connection(ev_h, 0, sig, dest);}
|
||||
static void piConnect(PIObject * src, const PIString & sig, void * dest, void * ev_h, void * e_h) {src->connections << Connection(ev_h, e_h, sig, dest);}
|
||||
|
||||
static void piConnect(const PIString & src, const PIString & sig, void * dest, void * ev_h);
|
||||
static void piConnect(PIObject * src, const PIString & sig, const PIString & dest, void * ev_h);
|
||||
static void piConnect(const PIString & src, const PIString & sig, const PIString & dest, void * ev_h);
|
||||
|
||||
static void piDisconnect(PIObject * src, const PIString & sig, void * dest, void * ev_h) {
|
||||
for (int i = 0; i < src->connections.size_s(); ++i) {
|
||||
Connection & cc(src->connections[i]);
|
||||
if (cc.event == sig && cc.dest == dest && cc.slot == ev_h) {
|
||||
src->connections.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void piDisconnect(PIObject * src, const PIString & sig, void * dest) {
|
||||
for (int i = 0; i < src->connections.size_s(); ++i) {
|
||||
Connection & cc(src->connections[i]);
|
||||
if (cc.event == sig && cc.dest == dest) {
|
||||
src->connections.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Disconnect object "src" from all connections with event name "sig"
|
||||
static void piDisconnect(PIObject * src, const PIString & sig) {
|
||||
for (int i = 0; i < src->connections.size_s(); ++i) {
|
||||
Connection & cc(src->connections[i]);
|
||||
if (cc.event == sig) {
|
||||
src->connections.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Disconnect object "src" from all connections, i.e. all connections where object "src" is emitter
|
||||
static void piDisconnect(PIObject * src) {src->connections.clear();}
|
||||
//static void piConnect(PIObject & src, const PIString & sig, PIObject * dest, void * ev_h) {src.connections << Connection(ev_h, sig, dest);}
|
||||
//static void piConnect(PIObject * src, const PIString & sig, PIObject & dest, void * ev_h) {src->connections << Connection(ev_h, sig, &dest);}
|
||||
//static void piConnect(PIObject & src, const PIString & sig, PIObject & dest, void * ev_h) {src.connections << Connection(ev_h, sig, &dest);}
|
||||
|
||||
/*/// Connect through manager
|
||||
static bool piConnect(const PIString & srcObject, const PIString & event, const PIString & destObject, const PIString & handler, bool force = false) {
|
||||
PIObject * src = findByName(srcObject);
|
||||
if (src == 0) {
|
||||
cout << "PIObject::piConnect: can`t find PIObject with \"" << srcObject << "\" name!" << endl;
|
||||
return false;
|
||||
}
|
||||
PIObject * dest = findByName(destObject);
|
||||
if (dest == 0) {
|
||||
cout << "PIObject::piConnect: can`t find PIObject with \"" << destObject << "\" name!" << endl;
|
||||
return false;
|
||||
}
|
||||
return PIObject::piConnect(src, event, dest, handler, force);
|
||||
}*/
|
||||
|
||||
// / Raise events
|
||||
static void raiseEvent(PIObject * sender, const PIString & event) {
|
||||
for (int j = 0; j < sender->connections.size_s(); ++j) {
|
||||
Connection & i(sender->connections[j]);
|
||||
if (i.event != event) continue;
|
||||
//((PIObject*)(i.dest))->mutex_.lock();
|
||||
((PIObject*)(i.dest))->emitter_ = sender;
|
||||
((void(*)(void * ))i.slot)(i.dest);
|
||||
((PIObject*)(i.dest))->emitter_ = 0;
|
||||
//((PIObject*)(i.dest))->mutex_.unlock();
|
||||
}
|
||||
}
|
||||
template <typename T0>
|
||||
static void raiseEvent(PIObject * sender, const PIString & event, const T0 & v0 = T0()) {
|
||||
for (int j = 0; j < sender->connections.size_s(); ++j) {
|
||||
Connection & i(sender->connections[j]);
|
||||
if (i.event != event) continue;
|
||||
//((PIObject*)(i.dest))->mutex_.lock();
|
||||
((PIObject*)(i.dest))->emitter_ = sender;
|
||||
((void(*)(void * , T0))i.slot)(i.dest, v0);
|
||||
((PIObject*)(i.dest))->emitter_ = 0;
|
||||
//((PIObject*)(i.dest))->mutex_.unlock();
|
||||
}
|
||||
}
|
||||
template <typename T0, typename T1>
|
||||
static void raiseEvent(PIObject * sender, const PIString & event, const T0 & v0 = T0(), const T1 & v1 = T1()) {
|
||||
for (int j = 0; j < sender->connections.size_s(); ++j) {
|
||||
Connection & i(sender->connections[j]);
|
||||
if (i.event != event) continue;
|
||||
//((PIObject*)(i.dest))->mutex_.lock();
|
||||
((PIObject*)(i.dest))->emitter_ = sender;
|
||||
((void(*)(void * , T0, T1))i.slot)(i.dest, v0, v1);
|
||||
((PIObject*)(i.dest))->emitter_ = 0;
|
||||
//((PIObject*)(i.dest))->mutex_.unlock();
|
||||
}
|
||||
}
|
||||
template <typename T0, typename T1, typename T2>
|
||||
static void raiseEvent(PIObject * sender, const PIString & event, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2()) {
|
||||
for (int j = 0; j < sender->connections.size_s(); ++j) {
|
||||
Connection & i(sender->connections[j]);
|
||||
if (i.event != event) continue;
|
||||
//((PIObject*)(i.dest))->mutex_.lock();
|
||||
((PIObject*)(i.dest))->emitter_ = sender;
|
||||
((void(*)(void * , T0, T1, T2))i.slot)(i.dest, v0, v1, v2);
|
||||
((PIObject*)(i.dest))->emitter_ = 0;
|
||||
//((PIObject*)(i.dest))->mutex_.unlock();
|
||||
}
|
||||
}
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
static void raiseEvent(PIObject * sender, const PIString & event, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2(), const T3 & v3 = T3()) {
|
||||
for (int j = 0; j < sender->connections.size_s(); ++j) {
|
||||
Connection & i(sender->connections[j]);
|
||||
if (i.event != event) continue;
|
||||
//((PIObject*)(i.dest))->mutex_.lock();
|
||||
((PIObject*)(i.dest))->emitter_ = sender;
|
||||
((void(*)(void * , T0, T1, T2, T3))i.slot)(i.dest, v0, v1, v2, v3);
|
||||
((PIObject*)(i.dest))->emitter_ = 0;
|
||||
//((PIObject*)(i.dest))->mutex_.unlock();
|
||||
}
|
||||
}
|
||||
/*
|
||||
/// Raise events (static)
|
||||
static void raiseEvent(PIObject * destObject, const PIString & name) {
|
||||
destObject->raiseEvent(name);
|
||||
}
|
||||
template <typename T0>
|
||||
static void raiseEvent(PIObject * destObject, const PIString & name, const T0 & v0 = T0()) {
|
||||
destObject->raiseEvent<T0>(name, v0);
|
||||
}
|
||||
template <typename T0, typename T1>
|
||||
static void raiseEvent(PIObject * destObject, const PIString & name, const T0 & v0 = T0(), const T1 & v1 = T1()) {
|
||||
destObject->raiseEvent<T0, T1>(name, v0, v1);
|
||||
}
|
||||
template <typename T0, typename T1, typename T2>
|
||||
static void raiseEvent(PIObject * destObject, const PIString & name, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2()) {
|
||||
destObject->raiseEvent<T0, T1, T2>(name, v0, v1, v2);
|
||||
}
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
static void raiseEvent(PIObject * destObject, const PIString & name, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2(), const T3 & v3 = T3()) {
|
||||
destObject->raiseEvent<T0, T1, T2, T3>(name, v0, v1, v2, v3);
|
||||
}
|
||||
*/
|
||||
// / Raise events through manager
|
||||
static void raiseEvent(const PIString & destObject, const PIString & name) {
|
||||
PIObject * dest = findByName(destObject);
|
||||
if (dest == 0) {
|
||||
cout << "PIObject::piConnect: can`t find PIObject with \"" << destObject << "\" name!" << endl;
|
||||
return;
|
||||
}
|
||||
raiseEvent(dest, name);
|
||||
}
|
||||
template <typename T0>
|
||||
static void raiseEvent(const PIString & destObject, const PIString & name, const T0 & v0 = T0()) {
|
||||
PIObject * dest = findByName(destObject);
|
||||
if (dest == 0) {
|
||||
cout << "PIObject::piConnect: can`t find PIObject with \"" << destObject << "\" name!" << endl;
|
||||
return;
|
||||
}
|
||||
raiseEvent<T0>(dest, name, v0);
|
||||
}
|
||||
template <typename T0, typename T1>
|
||||
static void raiseEvent(const PIString & destObject, const PIString & name, const T0 & v0 = T0(), const T1 & v1 = T1()) {
|
||||
PIObject * dest = findByName(destObject);
|
||||
if (dest == 0) {
|
||||
cout << "PIObject::piConnect: can`t find PIObject with \"" << destObject << "\" name!" << endl;
|
||||
return;
|
||||
}
|
||||
raiseEvent<T0, T1>(dest, name, v0, v1);
|
||||
}
|
||||
template <typename T0, typename T1, typename T2>
|
||||
static void raiseEvent(const PIString & destObject, const PIString & name, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2()) {
|
||||
PIObject * dest = findByName(destObject);
|
||||
if (dest == 0) {
|
||||
cout << "PIObject::piConnect: can`t find PIObject with \"" << destObject << "\" name!" << endl;
|
||||
return;
|
||||
}
|
||||
raiseEvent<T0, T1, T2>(name, dest, v0, v1, v2);
|
||||
}
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
static void raiseEvent(const PIString & destObject, const PIString & name, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2(), const T3 & v3 = T3()) {
|
||||
PIObject * dest = findByName(destObject);
|
||||
if (dest == 0) {
|
||||
cout << "PIObject::piConnect: can`t find PIObject with \"" << destObject << "\" name!" << endl;
|
||||
return;
|
||||
}
|
||||
raiseEvent<T0, T1, T2, T3>(name,dest , v0, v1, v2, v3);
|
||||
}
|
||||
|
||||
//! Returns PIObject* with name "name" or 0, if there is no object found
|
||||
static PIObject * findByName(const PIString & name) {
|
||||
piForeach (PIObject * i, PIObject::objects) {
|
||||
if (i->name() != name) continue;
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
//! Returns PIObject* which has raised an event. This value is correct only in definition of some event handler
|
||||
PIObject * emitter() const {return emitter_;}
|
||||
|
||||
//! Virtual function executes after property with name "name" has been changed
|
||||
virtual void propertyChanged(const PIString & name) {}
|
||||
|
||||
private:
|
||||
struct Connection {
|
||||
Connection(void * sl = 0, void * si = 0, const PIString & e = PIString(), void * o = 0) {slot = sl; signal = si; event = e; dest = o;}
|
||||
void * slot;
|
||||
void * signal;
|
||||
PIString event;
|
||||
void * dest;
|
||||
};
|
||||
|
||||
PIVector<Connection> connections;
|
||||
PIMap<PIString, PIVariant> properties_;
|
||||
|
||||
static PIVector<PIObject * > objects;
|
||||
PIMutex mutex_;
|
||||
PIObject * emitter_;
|
||||
|
||||
};
|
||||
|
||||
#endif // PIOBJECT_H
|
||||
663
pip.cbp
Normal file
663
pip.cbp
Normal file
@@ -0,0 +1,663 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<CodeBlocks_project_file>
|
||||
<FileVersion major="1" minor="6" />
|
||||
<Project>
|
||||
<Option title="pip" />
|
||||
<Option makefile_is_custom="1" />
|
||||
<Option compiler="gcc" />
|
||||
<Option virtualFolders="CMake Files\;CMake Files\utils\;CMake Files\utils\system_test\;CMake Files\utils\remote_console\;CMake Files\utils\code_model_generator\;CMake Files\utils\system_daemon\;" />
|
||||
<Build>
|
||||
<Target title="all">
|
||||
<Option working_dir="C:/libs/pip" />
|
||||
<Option type="4" />
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 all" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="edit_cache">
|
||||
<Option working_dir="C:/libs/pip" />
|
||||
<Option type="4" />
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 edit_cache" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="install">
|
||||
<Option working_dir="C:/libs/pip" />
|
||||
<Option type="4" />
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 install" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="install/local">
|
||||
<Option working_dir="C:/libs/pip" />
|
||||
<Option type="4" />
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 install/local" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="install/strip">
|
||||
<Option working_dir="C:/libs/pip" />
|
||||
<Option type="4" />
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 install/strip" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="list_install_components">
|
||||
<Option working_dir="C:/libs/pip" />
|
||||
<Option type="4" />
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 list_install_components" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="pip">
|
||||
<Option output="C:/libs/pip/libpip.dll" prefix_auto="0" extension_auto="0" />
|
||||
<Option working_dir="C:/libs/pip" />
|
||||
<Option object_output="./" />
|
||||
<Option type="3" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add directory="C:/libs/pip" />
|
||||
<Add directory="C:/libs/pip/src" />
|
||||
<Add directory="C:/libs/pip/src/." />
|
||||
<Add directory="C:/libs/pip/src/code" />
|
||||
<Add directory="C:/libs/pip/src/containers" />
|
||||
<Add directory="C:/libs/pip/src/core" />
|
||||
<Add directory="C:/libs/pip/src/io" />
|
||||
<Add directory="C:/libs/pip/src/math" />
|
||||
<Add directory="C:/libs/pip/src/system" />
|
||||
<Add directory="C:/libs/pip/src/thread" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/../../../../i686-w64-mingw32/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include-fixed" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/backward" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/i686-w64-mingw32" />
|
||||
</Compiler>
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 pip" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="pip/fast">
|
||||
<Option output="C:/libs/pip/libpip.dll" prefix_auto="0" extension_auto="0" />
|
||||
<Option working_dir="C:/libs/pip" />
|
||||
<Option object_output="./" />
|
||||
<Option type="3" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add directory="C:/libs/pip" />
|
||||
<Add directory="C:/libs/pip/src" />
|
||||
<Add directory="C:/libs/pip/src/." />
|
||||
<Add directory="C:/libs/pip/src/code" />
|
||||
<Add directory="C:/libs/pip/src/containers" />
|
||||
<Add directory="C:/libs/pip/src/core" />
|
||||
<Add directory="C:/libs/pip/src/io" />
|
||||
<Add directory="C:/libs/pip/src/math" />
|
||||
<Add directory="C:/libs/pip/src/system" />
|
||||
<Add directory="C:/libs/pip/src/thread" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/../../../../i686-w64-mingw32/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include-fixed" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/backward" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/i686-w64-mingw32" />
|
||||
</Compiler>
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 pip/fast" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="pip_test">
|
||||
<Option output="C:/libs/pip/pip_test.exe" prefix_auto="0" extension_auto="0" />
|
||||
<Option working_dir="C:/libs/pip" />
|
||||
<Option object_output="./" />
|
||||
<Option type="1" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add directory="C:/libs/pip" />
|
||||
<Add directory="C:/libs/pip/src" />
|
||||
<Add directory="C:/libs/pip/src/." />
|
||||
<Add directory="C:/libs/pip/src/code" />
|
||||
<Add directory="C:/libs/pip/src/containers" />
|
||||
<Add directory="C:/libs/pip/src/core" />
|
||||
<Add directory="C:/libs/pip/src/io" />
|
||||
<Add directory="C:/libs/pip/src/math" />
|
||||
<Add directory="C:/libs/pip/src/system" />
|
||||
<Add directory="C:/libs/pip/src/thread" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/../../../../i686-w64-mingw32/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include-fixed" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/backward" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/i686-w64-mingw32" />
|
||||
</Compiler>
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 pip_test" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="pip_test/fast">
|
||||
<Option output="C:/libs/pip/pip_test.exe" prefix_auto="0" extension_auto="0" />
|
||||
<Option working_dir="C:/libs/pip" />
|
||||
<Option object_output="./" />
|
||||
<Option type="1" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add directory="C:/libs/pip" />
|
||||
<Add directory="C:/libs/pip/src" />
|
||||
<Add directory="C:/libs/pip/src/." />
|
||||
<Add directory="C:/libs/pip/src/code" />
|
||||
<Add directory="C:/libs/pip/src/containers" />
|
||||
<Add directory="C:/libs/pip/src/core" />
|
||||
<Add directory="C:/libs/pip/src/io" />
|
||||
<Add directory="C:/libs/pip/src/math" />
|
||||
<Add directory="C:/libs/pip/src/system" />
|
||||
<Add directory="C:/libs/pip/src/thread" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/../../../../i686-w64-mingw32/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include-fixed" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/backward" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/i686-w64-mingw32" />
|
||||
</Compiler>
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 pip_test/fast" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="rebuild_cache">
|
||||
<Option working_dir="C:/libs/pip" />
|
||||
<Option type="4" />
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 rebuild_cache" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="pip_system_test">
|
||||
<Option output="C:/libs/pip/utils/system_test/pip_system_test.exe" prefix_auto="0" extension_auto="0" />
|
||||
<Option working_dir="C:/libs/pip/utils/system_test" />
|
||||
<Option object_output="./" />
|
||||
<Option type="1" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add directory="C:/libs/pip" />
|
||||
<Add directory="C:/libs/pip/src" />
|
||||
<Add directory="C:/libs/pip/src/." />
|
||||
<Add directory="C:/libs/pip/src/code" />
|
||||
<Add directory="C:/libs/pip/src/containers" />
|
||||
<Add directory="C:/libs/pip/src/core" />
|
||||
<Add directory="C:/libs/pip/src/io" />
|
||||
<Add directory="C:/libs/pip/src/math" />
|
||||
<Add directory="C:/libs/pip/src/system" />
|
||||
<Add directory="C:/libs/pip/src/thread" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/../../../../i686-w64-mingw32/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include-fixed" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/backward" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/i686-w64-mingw32" />
|
||||
</Compiler>
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_test/Makefile" VERBOSE=1 pip_system_test" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_test/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_test/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_test/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="pip_system_test/fast">
|
||||
<Option output="C:/libs/pip/utils/system_test/pip_system_test.exe" prefix_auto="0" extension_auto="0" />
|
||||
<Option working_dir="C:/libs/pip/utils/system_test" />
|
||||
<Option object_output="./" />
|
||||
<Option type="1" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add directory="C:/libs/pip" />
|
||||
<Add directory="C:/libs/pip/src" />
|
||||
<Add directory="C:/libs/pip/src/." />
|
||||
<Add directory="C:/libs/pip/src/code" />
|
||||
<Add directory="C:/libs/pip/src/containers" />
|
||||
<Add directory="C:/libs/pip/src/core" />
|
||||
<Add directory="C:/libs/pip/src/io" />
|
||||
<Add directory="C:/libs/pip/src/math" />
|
||||
<Add directory="C:/libs/pip/src/system" />
|
||||
<Add directory="C:/libs/pip/src/thread" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/../../../../i686-w64-mingw32/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include-fixed" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/backward" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/i686-w64-mingw32" />
|
||||
</Compiler>
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_test/Makefile" VERBOSE=1 pip_system_test/fast" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_test/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_test/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_test/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="pip_remote_console">
|
||||
<Option output="C:/libs/pip/utils/remote_console/pip_remote_console.exe" prefix_auto="0" extension_auto="0" />
|
||||
<Option working_dir="C:/libs/pip/utils/remote_console" />
|
||||
<Option object_output="./" />
|
||||
<Option type="1" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add directory="C:/libs/pip" />
|
||||
<Add directory="C:/libs/pip/src" />
|
||||
<Add directory="C:/libs/pip/src/." />
|
||||
<Add directory="C:/libs/pip/src/code" />
|
||||
<Add directory="C:/libs/pip/src/containers" />
|
||||
<Add directory="C:/libs/pip/src/core" />
|
||||
<Add directory="C:/libs/pip/src/io" />
|
||||
<Add directory="C:/libs/pip/src/math" />
|
||||
<Add directory="C:/libs/pip/src/system" />
|
||||
<Add directory="C:/libs/pip/src/thread" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/../../../../i686-w64-mingw32/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include-fixed" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/backward" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/i686-w64-mingw32" />
|
||||
</Compiler>
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/remote_console/Makefile" VERBOSE=1 pip_remote_console" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/remote_console/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/remote_console/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/remote_console/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="pip_remote_console/fast">
|
||||
<Option output="C:/libs/pip/utils/remote_console/pip_remote_console.exe" prefix_auto="0" extension_auto="0" />
|
||||
<Option working_dir="C:/libs/pip/utils/remote_console" />
|
||||
<Option object_output="./" />
|
||||
<Option type="1" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add directory="C:/libs/pip" />
|
||||
<Add directory="C:/libs/pip/src" />
|
||||
<Add directory="C:/libs/pip/src/." />
|
||||
<Add directory="C:/libs/pip/src/code" />
|
||||
<Add directory="C:/libs/pip/src/containers" />
|
||||
<Add directory="C:/libs/pip/src/core" />
|
||||
<Add directory="C:/libs/pip/src/io" />
|
||||
<Add directory="C:/libs/pip/src/math" />
|
||||
<Add directory="C:/libs/pip/src/system" />
|
||||
<Add directory="C:/libs/pip/src/thread" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/../../../../i686-w64-mingw32/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include-fixed" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/backward" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/i686-w64-mingw32" />
|
||||
</Compiler>
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/remote_console/Makefile" VERBOSE=1 pip_remote_console/fast" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/remote_console/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/remote_console/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/remote_console/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="pip_cmg">
|
||||
<Option output="C:/libs/pip/utils/code_model_generator/pip_cmg.exe" prefix_auto="0" extension_auto="0" />
|
||||
<Option working_dir="C:/libs/pip/utils/code_model_generator" />
|
||||
<Option object_output="./" />
|
||||
<Option type="1" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add directory="C:/libs/pip" />
|
||||
<Add directory="C:/libs/pip/src" />
|
||||
<Add directory="C:/libs/pip/src/." />
|
||||
<Add directory="C:/libs/pip/src/code" />
|
||||
<Add directory="C:/libs/pip/src/containers" />
|
||||
<Add directory="C:/libs/pip/src/core" />
|
||||
<Add directory="C:/libs/pip/src/io" />
|
||||
<Add directory="C:/libs/pip/src/math" />
|
||||
<Add directory="C:/libs/pip/src/system" />
|
||||
<Add directory="C:/libs/pip/src/thread" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/../../../../i686-w64-mingw32/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include-fixed" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/backward" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/i686-w64-mingw32" />
|
||||
</Compiler>
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/code_model_generator/Makefile" VERBOSE=1 pip_cmg" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/code_model_generator/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/code_model_generator/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/code_model_generator/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="pip_cmg/fast">
|
||||
<Option output="C:/libs/pip/utils/code_model_generator/pip_cmg.exe" prefix_auto="0" extension_auto="0" />
|
||||
<Option working_dir="C:/libs/pip/utils/code_model_generator" />
|
||||
<Option object_output="./" />
|
||||
<Option type="1" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add directory="C:/libs/pip" />
|
||||
<Add directory="C:/libs/pip/src" />
|
||||
<Add directory="C:/libs/pip/src/." />
|
||||
<Add directory="C:/libs/pip/src/code" />
|
||||
<Add directory="C:/libs/pip/src/containers" />
|
||||
<Add directory="C:/libs/pip/src/core" />
|
||||
<Add directory="C:/libs/pip/src/io" />
|
||||
<Add directory="C:/libs/pip/src/math" />
|
||||
<Add directory="C:/libs/pip/src/system" />
|
||||
<Add directory="C:/libs/pip/src/thread" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/../../../../i686-w64-mingw32/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include-fixed" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/backward" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/i686-w64-mingw32" />
|
||||
</Compiler>
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/code_model_generator/Makefile" VERBOSE=1 pip_cmg/fast" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/code_model_generator/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/code_model_generator/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/code_model_generator/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="pisd">
|
||||
<Option output="C:/libs/pip/utils/system_daemon/pisd.exe" prefix_auto="0" extension_auto="0" />
|
||||
<Option working_dir="C:/libs/pip/utils/system_daemon" />
|
||||
<Option object_output="./" />
|
||||
<Option type="1" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add directory="C:/libs/pip" />
|
||||
<Add directory="C:/libs/pip/src" />
|
||||
<Add directory="C:/libs/pip/src/." />
|
||||
<Add directory="C:/libs/pip/src/code" />
|
||||
<Add directory="C:/libs/pip/src/containers" />
|
||||
<Add directory="C:/libs/pip/src/core" />
|
||||
<Add directory="C:/libs/pip/src/io" />
|
||||
<Add directory="C:/libs/pip/src/math" />
|
||||
<Add directory="C:/libs/pip/src/system" />
|
||||
<Add directory="C:/libs/pip/src/thread" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/../../../../i686-w64-mingw32/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include-fixed" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/backward" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/i686-w64-mingw32" />
|
||||
</Compiler>
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_daemon/Makefile" VERBOSE=1 pisd" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_daemon/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_daemon/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_daemon/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
<Target title="pisd/fast">
|
||||
<Option output="C:/libs/pip/utils/system_daemon/pisd.exe" prefix_auto="0" extension_auto="0" />
|
||||
<Option working_dir="C:/libs/pip/utils/system_daemon" />
|
||||
<Option object_output="./" />
|
||||
<Option type="1" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add directory="C:/libs/pip" />
|
||||
<Add directory="C:/libs/pip/src" />
|
||||
<Add directory="C:/libs/pip/src/." />
|
||||
<Add directory="C:/libs/pip/src/code" />
|
||||
<Add directory="C:/libs/pip/src/containers" />
|
||||
<Add directory="C:/libs/pip/src/core" />
|
||||
<Add directory="C:/libs/pip/src/io" />
|
||||
<Add directory="C:/libs/pip/src/math" />
|
||||
<Add directory="C:/libs/pip/src/system" />
|
||||
<Add directory="C:/libs/pip/src/thread" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/../../../../i686-w64-mingw32/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include" />
|
||||
<Add directory="C:/mingw/x32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/include-fixed" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/backward" />
|
||||
<Add directory="C:/mingw/x32/lib/gcc/../../i686-w64-mingw32/include/c++/i686-w64-mingw32" />
|
||||
</Compiler>
|
||||
<MakeCommands>
|
||||
<Build command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_daemon/Makefile" VERBOSE=1 pisd/fast" />
|
||||
<CompileFile command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_daemon/Makefile" VERBOSE=1 "$file"" />
|
||||
<Clean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_daemon/Makefile" VERBOSE=1 clean" />
|
||||
<DistClean command="C:/mingw/x32/bin/mingw32-make.exe -f "C:/libs/pip/utils/system_daemon/Makefile" VERBOSE=1 clean" />
|
||||
</MakeCommands>
|
||||
</Target>
|
||||
</Build>
|
||||
<Unit filename="C:/libs/pip/main.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/code/picodeinfo.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/code/picodeparser.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/containers/picontainers.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/pibytearray.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/picli.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/picollection.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/piincludes.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/piinit.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/piobject.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/pistring.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/pitime.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/pivariant.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pibinarylog.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piconfig.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piconnection.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pidiagnostics.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pidir.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piethernet.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pifile.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pifiletransfer.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piiodevice.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piiostring.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pimultiprotocol.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pipacketextractor.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pipeer.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piprotocol.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piserial.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piusb.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/math/pievaluator.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/math/pifft.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/math/pimathbase.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/math/pimathsolver.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/picodec.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/piconsole.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/pikbdlistener.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/pimonitor.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/piprocess.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/pisignals.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/pisystemmonitor.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/pisystemtests.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/thread/pimutex.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/thread/pithread.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/thread/pitimer.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/utils/code_model_generator/main.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/utils/remote_console/main.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/utils/system_daemon/daemon.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/utils/system_daemon/file_manager.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/utils/system_daemon/main.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/utils/system_test/main.cpp">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/pip_resource_win.rc">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/code/picodeinfo.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/code/picodeparser.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/containers/picontainers.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/pibytearray.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/picli.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/picollection.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/piincludes.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/piinit.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/piobject.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/pistring.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/pitime.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/core/pivariant.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pibinarylog.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piconfig.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piconnection.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pidiagnostics.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pidir.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piethernet.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pifile.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pifiletransfer.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piiodevice.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piiostring.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pimultiprotocol.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pipacketextractor.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/pipeer.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piprotocol.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piserial.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/io/piusb.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/math/pievaluator.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/math/pifft.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/math/pimathbase.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/math/pimathsolver.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/picodec.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/piconsole.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/pikbdlistener.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/pimonitor.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/piprocess.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/pisignals.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/pisystemmonitor.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/system/pisystemtests.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/thread/pimutex.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/thread/pithread.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/src/thread/pitimer.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/utils/system_daemon/daemon.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/utils/system_daemon/file_manager.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/utils/system_daemon/shared.h">
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/CMakeLists.txt">
|
||||
<Option virtualFolder="CMake Files\" />
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/utils/system_test/CMakeLists.txt">
|
||||
<Option virtualFolder="CMake Files\utils\system_test\" />
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/utils/remote_console/CMakeLists.txt">
|
||||
<Option virtualFolder="CMake Files\utils\remote_console\" />
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/utils/code_model_generator/CMakeLists.txt">
|
||||
<Option virtualFolder="CMake Files\utils\code_model_generator\" />
|
||||
</Unit>
|
||||
<Unit filename="C:/libs/pip/utils/system_daemon/CMakeLists.txt">
|
||||
<Option virtualFolder="CMake Files\utils\system_daemon\" />
|
||||
</Unit>
|
||||
</Project>
|
||||
</CodeBlocks_project_file>
|
||||
36
pip.h
36
pip.h
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
All includes
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pitimer.h"
|
||||
#include "pivariant.h"
|
||||
#include "piconsole.h"
|
||||
#include "picli.h"
|
||||
#include "pievaluator.h"
|
||||
#include "pimultiprotocol.h"
|
||||
#include "picodec.h"
|
||||
#include "pisignals.h"
|
||||
#include "piobject.h"
|
||||
#include "pisystemmonitor.h"
|
||||
#include "pipeer.h"
|
||||
#include "picrc.h"
|
||||
#include "pistatemachine.h"
|
||||
#include "picollection.h"
|
||||
#include "piserial.h"
|
||||
#include "pibinarylog.h"
|
||||
#include "piusb.h"
|
||||
130
pip.pro
130
pip.pro
@@ -1,130 +0,0 @@
|
||||
######################################################################
|
||||
# Automatically generated by qmake (2.01a) ?? ???. 5 22:55:18 2011
|
||||
######################################################################
|
||||
|
||||
TEMPLATE = lib
|
||||
TARGET = pip
|
||||
DEPENDPATH += .
|
||||
INCLUDEPATH += .
|
||||
QT -= core gui
|
||||
CONFIG -= qt
|
||||
CONFIG += dll
|
||||
VERSION = 0.4.0
|
||||
|
||||
# Input
|
||||
HEADERS += \
|
||||
pivariant.h \
|
||||
pitimer.h \
|
||||
pithread.h \
|
||||
pisystemtests.h \
|
||||
pisystemmonitor.h \
|
||||
pistring.h \
|
||||
pisignals.h \
|
||||
piserial.h \
|
||||
piprotocol.h \
|
||||
piprocess.h \
|
||||
pipeer.h \
|
||||
pipacketextractor.h \
|
||||
pip.h \
|
||||
piobject.h \
|
||||
pimutex.h \
|
||||
pimultiprotocol.h \
|
||||
pimonitor.h \
|
||||
pimath.h \
|
||||
pikbdlistener.h \
|
||||
piiodevice.h \
|
||||
piincludes.h \
|
||||
pigeometry.h \
|
||||
pifile.h \
|
||||
pievaluator.h \
|
||||
piethernet.h \
|
||||
pidir.h \
|
||||
picrc.h \
|
||||
picontainers.h \
|
||||
piconsole.h \
|
||||
piconfig.h \
|
||||
picodec.h \
|
||||
picli.h \
|
||||
pichar.h \
|
||||
pibytearray.h \
|
||||
pibitarray.h \
|
||||
picollection.h \
|
||||
pidiagnostics.h \
|
||||
pibinarylog.h \
|
||||
picodeparser.h \
|
||||
picodeinfo.h \
|
||||
piusb.h \
|
||||
piconnection.h
|
||||
SOURCES += main.cpp \
|
||||
pivariant.cpp \
|
||||
pitimer.cpp \
|
||||
pithread.cpp \
|
||||
pisystemtests.cpp \
|
||||
pisystemmonitor.cpp \
|
||||
pistring.cpp \
|
||||
pisignals.cpp \
|
||||
piserial.cpp \
|
||||
piprotocol.cpp \
|
||||
piprocess.cpp \
|
||||
pipeer.cpp \
|
||||
pipacketextractor.cpp \
|
||||
piobject.cpp \
|
||||
pimonitor.cpp \
|
||||
pimath.cpp \
|
||||
pikbdlistener.cpp \
|
||||
piiodevice.cpp \
|
||||
piincludes.cpp \
|
||||
pifile.cpp \
|
||||
pievaluator.cpp \
|
||||
piethernet.cpp \
|
||||
pidir.cpp \
|
||||
piconsole.cpp \
|
||||
piconfig.cpp \
|
||||
picodec.cpp \
|
||||
picli.cpp \
|
||||
pibytearray.cpp \
|
||||
picollection.cpp \
|
||||
pidiagnostics.cpp \
|
||||
pibinarylog.cpp \
|
||||
picodeparser.cpp \
|
||||
picodeinfo.cpp \
|
||||
piusb.cpp \
|
||||
piconnection.cpp
|
||||
win32 {
|
||||
LIBS += -lws2_32 -lIphlpapi
|
||||
} else {
|
||||
android {
|
||||
} else {
|
||||
LIBS = -lpthread -lrt
|
||||
}
|
||||
}
|
||||
|
||||
OTHER_FILES += \
|
||||
android/AndroidManifest.xml \
|
||||
android/res/layout/splash.xml \
|
||||
android/res/values/libs.xml \
|
||||
android/res/values/strings.xml \
|
||||
android/res/values-de/strings.xml \
|
||||
android/res/values-el/strings.xml \
|
||||
android/res/values-es/strings.xml \
|
||||
android/res/values-et/strings.xml \
|
||||
android/res/values-fa/strings.xml \
|
||||
android/res/values-fr/strings.xml \
|
||||
android/res/values-id/strings.xml \
|
||||
android/res/values-it/strings.xml \
|
||||
android/res/values-ja/strings.xml \
|
||||
android/res/values-ms/strings.xml \
|
||||
android/res/values-nb/strings.xml \
|
||||
android/res/values-nl/strings.xml \
|
||||
android/res/values-pl/strings.xml \
|
||||
android/res/values-pt-rBR/strings.xml \
|
||||
android/res/values-ro/strings.xml \
|
||||
android/res/values-rs/strings.xml \
|
||||
android/res/values-ru/strings.xml \
|
||||
android/res/values-zh-rCN/strings.xml \
|
||||
android/res/values-zh-rTW/strings.xml \
|
||||
android/src/org/kde/necessitas/ministro/IMinistro.aidl \
|
||||
android/src/org/kde/necessitas/ministro/IMinistroCallback.aidl \
|
||||
android/src/org/qtproject/qt5/android/bindings/QtActivity.java \
|
||||
android/src/org/qtproject/qt5/android/bindings/QtApplication.java \
|
||||
android/version.xml
|
||||
215
pip.pro.user
215
pip.pro.user
@@ -1,215 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by Qt Creator 2.4.1, 2013-04-09T20:11:21. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="int">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QString" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QString" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap"/>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Target.DesktopTarget</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Mingw:C:/MinGW/bin//g++.exe.x86-windows-msys-pe-32bit.C:/Qt/qtcreator-2.4.1/pythongdb/gdb-i686-pc-mingw32.exe</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
|
||||
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.8.0 (4.8.0) Релиз</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
|
||||
<value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">E:/pprojects/pip</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId">6</value>
|
||||
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">false</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Установка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Без установки</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Project.UseGlobal">true</value>
|
||||
<value type="bool" key="Analyzer.Project.UseGlobal">true</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
|
||||
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
|
||||
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
|
||||
<value type="int">0</value>
|
||||
<value type="int">1</value>
|
||||
<value type="int">2</value>
|
||||
<value type="int">3</value>
|
||||
<value type="int">4</value>
|
||||
<value type="int">5</value>
|
||||
<value type="int">6</value>
|
||||
<value type="int">7</value>
|
||||
<value type="int">8</value>
|
||||
<value type="int">9</value>
|
||||
<value type="int">10</value>
|
||||
<value type="int">11</value>
|
||||
<value type="int">12</value>
|
||||
<value type="int">13</value>
|
||||
<value type="int">14</value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
|
||||
<value type="int">0</value>
|
||||
<value type="int">1</value>
|
||||
<value type="int">2</value>
|
||||
<value type="int">3</value>
|
||||
<value type="int">4</value>
|
||||
<value type="int">5</value>
|
||||
<value type="int">6</value>
|
||||
<value type="int">7</value>
|
||||
<value type="int">8</value>
|
||||
<value type="int">9</value>
|
||||
<value type="int">10</value>
|
||||
<value type="int">11</value>
|
||||
<value type="int">12</value>
|
||||
<value type="int">13</value>
|
||||
<value type="int">14</value>
|
||||
</valuelist>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">pip</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4RunConfiguration.BaseEnvironmentBase">2</value>
|
||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">pip.pro</value>
|
||||
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value>
|
||||
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal">false</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.Qt4RunConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
|
||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">false</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="int">1</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
|
||||
<value type="QString">{e0680b61-7ce7-4775-a872-e83c6b7b3dfe}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||
<value type="int">10</value>
|
||||
</data>
|
||||
</qtcreator>
|
||||
35
pip_export.h
35
pip_export.h
@@ -1,35 +0,0 @@
|
||||
|
||||
#ifndef PIP_EXPORT_H
|
||||
#define PIP_EXPORT_H
|
||||
|
||||
#ifdef PIP_STATIC_DEFINE
|
||||
# define PIP_EXPORT
|
||||
# define PIP_NO_EXPORT
|
||||
#else
|
||||
# ifndef PIP_EXPORT
|
||||
# ifdef pip_EXPORTS
|
||||
/* We are building this library */
|
||||
# define PIP_EXPORT __attribute__((visibility("default")))
|
||||
# else
|
||||
/* We are using this library */
|
||||
# define PIP_EXPORT __attribute__((visibility("default")))
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef PIP_NO_EXPORT
|
||||
# define PIP_NO_EXPORT __attribute__((visibility("hidden")))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef PIP_DEPRECATED
|
||||
# define PIP_DEPRECATED __attribute__ ((__deprecated__))
|
||||
# define PIP_DEPRECATED_EXPORT PIP_EXPORT __attribute__ ((__deprecated__))
|
||||
# define PIP_DEPRECATED_NO_EXPORT PIP_NO_EXPORT __attribute__ ((__deprecated__))
|
||||
#endif
|
||||
|
||||
#define DEFINE_NO_DEPRECATED 0
|
||||
#if DEFINE_NO_DEPRECATED
|
||||
# define PIP_NO_DEPRECATED
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,12 +1,14 @@
|
||||
# if defined(UNDER_CE)
|
||||
#if defined(UNDER_CE)
|
||||
# include <winbase.h>
|
||||
# else
|
||||
#else
|
||||
# include <winver.h>
|
||||
# endif
|
||||
#endif
|
||||
#include <src/piversion.h>
|
||||
#include <src/pip_version_str.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,4,0,0
|
||||
PRODUCTVERSION 0,4,0,0
|
||||
FILEVERSION PIP_VERSION_MAJOR,PIP_VERSION_MINOR,PIP_VERSION_REVISION,0
|
||||
PRODUCTVERSION PIP_VERSION_MAJOR,PIP_VERSION_MINOR,PIP_VERSION_REVISION,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS VOS__WINDOWS32
|
||||
@@ -19,7 +21,7 @@ VS_VERSION_INFO VERSIONINFO
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Peri4\0"
|
||||
VALUE "FileDescription", "Platform-Independent Primitives\0"
|
||||
VALUE "FileVersion", "0.4.0_beta2\0"
|
||||
VALUE "FileVersion", __PIP_VERSION_STR__
|
||||
VALUE "LegalCopyright", "\0"
|
||||
VALUE "OriginalFilename", "libpip.dll\0"
|
||||
VALUE "ProductName", "PIP\0"
|
||||
|
||||
@@ -1,301 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Packets extractor
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pipacketextractor.h"
|
||||
|
||||
|
||||
/** \class PIPacketExtractor
|
||||
* \brief Packets extractor
|
||||
* \details
|
||||
* \section PIPacketExtractor_main Synopsis
|
||||
* This class implements packet recognition by various algorithms and custom
|
||||
* validating from data stream. Stream is formed from child %PIIODevice
|
||||
* passed from contructor or with function \a setDevice().
|
||||
*
|
||||
* \section PIPacketExtractor_work Principle of work
|
||||
* %PIPacketExtractor works with child %PIIODevice. \a read and \a write
|
||||
* functions directly call child device functions. You should start threaded
|
||||
* read of \b extractor (not child device) to proper work. Extractor read data
|
||||
* from child device, try to detect packet from readed data and raise
|
||||
* \a packetReceived() event on success.
|
||||
*
|
||||
* \section PIPacketExtractor_algorithms Algorithms
|
||||
* There are 6 algorithms: \n
|
||||
* * PIPacketExtractor::None \n
|
||||
* Packet is successfully received on every read without any validation. \n \n
|
||||
* * PIPacketExtractor::Header \n
|
||||
* Wait for at least \a header() bytes + \a payloadSize(), then validate
|
||||
* header with virtual function \a validateHeader() and if it fail, shifts
|
||||
* for next 1 byte. If header is successfully validated check payload with
|
||||
* function \a validatePayload() and if it fail, shifts for next 1 byte. If
|
||||
* all validations were successful raise \a packetReceived() event. \n \n
|
||||
* * PIPacketExtractor::Footer \n
|
||||
* This algorithm similar to previous, but instead of \a header() first validate
|
||||
* \a footer() at after \a payloadSize() bytes with function \a validateFooter(). \n \n
|
||||
* * PIPacketExtractor::HeaderAndFooter \n
|
||||
* Wait for at least \a header() bytes + \a footer() bytes, then validate
|
||||
* header with virtual function \a validateHeader() and if it fail, shifts
|
||||
* for next 1 byte. If header is successfully validated check footer with
|
||||
* function \a validateFooter() and if it fail, shifts footer position for
|
||||
* next 1 byte. Then validate payload and if it fail, search header again,
|
||||
* starts from next byte of previous header. If all validations were successful
|
||||
* raise \a packetReceived() event. \n \n
|
||||
* * PIPacketExtractor::Size \n
|
||||
* Wait for at least \a packetSize() bytes, then validate packet with function
|
||||
* \a validatePayload() and if it fail, shifts for next 1 byte. If validating
|
||||
* was successfull raise \a packetReceived() event. \n \n
|
||||
* * PIPacketExtractor::Timeout \n
|
||||
* Wait for first read, then read for \a timeout() milliseconds and raise
|
||||
* \a packetReceived() event. \n
|
||||
*
|
||||
* \section PIPacketExtractor_control Control validating
|
||||
* There are three parameters:
|
||||
* * header content
|
||||
* * header size
|
||||
* * payload size
|
||||
*
|
||||
* Extractor can detect packet with compare your header with readed data.
|
||||
* It is default implementation of function \a packetHeaderValidate().
|
||||
* If header validating passed, function \a packetValidate() will be called.
|
||||
* If either of this function return \b false extractor shifts by one byte
|
||||
* and takes next header. If both functions returns \b true extractor shifts
|
||||
* by whole packet size.
|
||||
* \image html packet_detection.png
|
||||
*
|
||||
* */
|
||||
|
||||
REGISTER_DEVICE(PIPacketExtractor);
|
||||
|
||||
|
||||
PIPacketExtractor::PIPacketExtractor(PIIODevice * device_, PIPacketExtractor::SplitMode mode) {
|
||||
init_();
|
||||
setDevice(device_);
|
||||
setSplitMode(mode);
|
||||
}
|
||||
|
||||
|
||||
void PIPacketExtractor::init_() {
|
||||
ret_func_header = ret_func_footer = 0;
|
||||
setPayloadSize(0);
|
||||
setTimeout(100);
|
||||
setThreadedReadBufferSize(65536);
|
||||
setBufferSize(65536);
|
||||
setDevice(0);
|
||||
setPacketSize(0);
|
||||
setSplitMode(None);
|
||||
allReaded = addSize = curInd = missed = footerInd = 0;
|
||||
header_found = false;
|
||||
}
|
||||
|
||||
|
||||
void PIPacketExtractor::propertyChanged(const PIString &) {
|
||||
packetSize_ = property("packetSize").toInt();
|
||||
mode_ = (SplitMode)(property("splitMode").toInt());
|
||||
dataSize = property("payloadSize").toInt();
|
||||
src_header = property("header").toByteArray();
|
||||
src_footer = property("footer").toByteArray();
|
||||
packetSize_hf = src_header.size_s() + src_footer.size_s() + payloadSize();
|
||||
}
|
||||
|
||||
|
||||
void PIPacketExtractor::setDevice(PIIODevice * device_) {
|
||||
dev = device_;
|
||||
if (dev == 0) return;
|
||||
}
|
||||
|
||||
|
||||
void PIPacketExtractor::setPayloadSize(int size) {
|
||||
setProperty("payloadSize", size);
|
||||
dataSize = size;
|
||||
packetSize_hf = src_header.size_s() + src_footer.size_s() + payloadSize();
|
||||
}
|
||||
|
||||
|
||||
void PIPacketExtractor::setHeader(const PIByteArray & data) {
|
||||
setProperty("header", data);
|
||||
src_header = data;
|
||||
packetSize_hf = src_header.size_s() + src_footer.size_s() + payloadSize();
|
||||
}
|
||||
|
||||
|
||||
void PIPacketExtractor::setFooter(const PIByteArray & data) {
|
||||
setProperty("footer", data);
|
||||
src_footer = data;
|
||||
packetSize_hf = src_header.size_s() + src_footer.size_s() + payloadSize();
|
||||
}
|
||||
|
||||
|
||||
bool PIPacketExtractor::threadedRead(uchar * readed, int size_) {
|
||||
//piCoutObj << "readed" << size_;
|
||||
int ss;
|
||||
switch (mode_) {
|
||||
case PIPacketExtractor::None:
|
||||
if (validatePayload(readed, size_))
|
||||
packetReceived(readed, size_);
|
||||
break;
|
||||
case PIPacketExtractor::Header:
|
||||
tmpbuf.append(readed, size_);
|
||||
ss = src_header.size_s() + dataSize;
|
||||
while (tmpbuf.size_s() >= ss) {
|
||||
while (!validateHeader(src_header.data(), tmpbuf.data(), src_header.size_s())) {
|
||||
tmpbuf.pop_front();
|
||||
++missed;
|
||||
if (tmpbuf.size_s() < ss) return true;
|
||||
}
|
||||
while (!validatePayload(tmpbuf.data(src_header.size_s()), dataSize)) {
|
||||
tmpbuf.pop_front();
|
||||
++missed;
|
||||
if (tmpbuf.size_s() < ss) return true;
|
||||
}
|
||||
packetReceived(tmpbuf.data(), ss);
|
||||
tmpbuf.remove(0, ss);
|
||||
}
|
||||
break;
|
||||
case PIPacketExtractor::Footer:
|
||||
/*memcpy(buffer.data(allReaded), readed, size_);
|
||||
allReaded += size_;
|
||||
footer_ = (mode_ == PIPacketExtractor::Footer);
|
||||
while (allReaded >= packetSize_hf + addSize && allReaded > 0) {
|
||||
if (!src_header.isEmpty()) {
|
||||
if (allReaded + curInd >= buffer_size) {
|
||||
memcpy(sbuffer.data(), buffer.data(), buffer_size);
|
||||
memcpy(buffer.data(), sbuffer.data(buffer_size - packetSize_hf), allReaded);
|
||||
allReaded = packetSize_hf;
|
||||
addSize = curInd = 0;
|
||||
}
|
||||
bool brk = false;
|
||||
while (!validateHeader((uchar * )(footer_ ? src_footer.data() : src_header.data()), buffer.data(curInd + (footer_ ? dataSize : 0)), footer_ ? src_footer.size_s() : src_header.size_s())) {
|
||||
++curInd; ++missed;
|
||||
if (packetSize_hf > 0) missed_packets = missed / packetSize_hf;
|
||||
if (curInd > addSize) {
|
||||
addSize += packetSize_hf;
|
||||
brk = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (brk) continue;
|
||||
//memcpy(mheader.data(), buffer.data(curInd + (footer_ ? dataSize : 0)), src_header.size_s());
|
||||
if (!src_header.isEmpty()) memcpy(src_header.data(), buffer.data(curInd), src_header.size_s());
|
||||
if (!validatePayload(buffer.data(curInd + src_header.size_s()), dataSize)) {
|
||||
++curInd; ++missed;
|
||||
if (packetSize_hf > 0) missed_packets = missed / packetSize_hf;
|
||||
continue;
|
||||
}
|
||||
packetReceived(buffer.data(curInd), packetSize_hf);
|
||||
memcpy(sbuffer.data(), buffer.data(), allReaded);
|
||||
memcpy(buffer.data(), sbuffer.data(packetSize_hf + curInd), allReaded);
|
||||
allReaded -= packetSize_hf + curInd;
|
||||
curInd = addSize = 0;
|
||||
} else {
|
||||
if (dataSize == 0) {
|
||||
if (validatePayload(buffer.data(), size_))
|
||||
packetReceived(buffer.data(), size_);
|
||||
memcpy(sbuffer.data(), buffer.data(), allReaded);
|
||||
memcpy(buffer.data(), sbuffer.data(size_), allReaded);
|
||||
allReaded -= size_;
|
||||
} else {
|
||||
if (validatePayload(buffer.data(), dataSize))
|
||||
packetReceived(buffer.data(), dataSize);
|
||||
memcpy(sbuffer.data(), buffer.data(), allReaded);
|
||||
memcpy(buffer.data(), sbuffer.data(packetSize_hf), allReaded);
|
||||
allReaded -= packetSize_hf;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
tmpbuf.append(readed, size_);
|
||||
ss = src_footer.size_s() + dataSize;
|
||||
while (tmpbuf.size_s() >= ss) {
|
||||
while (!validateFooter(src_footer.data(), tmpbuf.data(dataSize), src_footer.size_s())) {
|
||||
tmpbuf.pop_front();
|
||||
++missed;
|
||||
if (tmpbuf.size_s() < ss) return true;
|
||||
}
|
||||
while (!validatePayload(tmpbuf.data(), dataSize)) {
|
||||
tmpbuf.pop_front();
|
||||
++missed;
|
||||
if (tmpbuf.size_s() < ss) return true;
|
||||
}
|
||||
packetReceived(tmpbuf.data(), ss);
|
||||
tmpbuf.remove(0, ss);
|
||||
}
|
||||
break;
|
||||
case PIPacketExtractor::HeaderAndFooter:
|
||||
tmpbuf.append(readed, size_);
|
||||
ss = src_header.size_s() + src_footer.size_s();
|
||||
while (tmpbuf.size_s() >= ss) {
|
||||
if (!header_found) {
|
||||
if (tmpbuf.size_s() < ss) return true;
|
||||
while (!validateHeader(src_header.data(), tmpbuf.data(), src_header.size_s())) {
|
||||
tmpbuf.pop_front();
|
||||
++missed;
|
||||
if (tmpbuf.size_s() < ss) return true;
|
||||
}
|
||||
header_found = true;
|
||||
footerInd = src_header.size_s();
|
||||
} else {
|
||||
if (tmpbuf.size_s() < footerInd + src_footer.size_s()) return true;
|
||||
while (!validateFooter(src_footer.data(), tmpbuf.data(footerInd), src_footer.size_s())) {
|
||||
++footerInd;
|
||||
if (tmpbuf.size_s() < footerInd + src_footer.size_s()) return true;
|
||||
}
|
||||
//piCout << "footer found at" << footerInd;
|
||||
header_found = false;
|
||||
if (!validatePayload(tmpbuf.data(src_header.size_s()), footerInd - src_header.size_s())) {
|
||||
tmpbuf.pop_front();
|
||||
++missed;
|
||||
continue;
|
||||
}
|
||||
packetReceived(tmpbuf.data(), footerInd + src_footer.size_s());
|
||||
tmpbuf.remove(0, footerInd + src_footer.size_s());
|
||||
footerInd = src_header.size_s();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PIPacketExtractor::Size:
|
||||
tmpbuf.append(readed, size_);
|
||||
if (packetSize_ <= 0) {
|
||||
tmpbuf.clear();
|
||||
return true;
|
||||
}
|
||||
while (tmpbuf.size_s() >= packetSize_) {
|
||||
if (!validatePayload(tmpbuf.data(), packetSize_)) {
|
||||
tmpbuf.pop_front();
|
||||
++missed;
|
||||
missed_packets = missed / packetSize_;
|
||||
continue;
|
||||
}
|
||||
packetReceived(tmpbuf.data(), packetSize_);
|
||||
tmpbuf.remove(0, packetSize_);
|
||||
}
|
||||
break;
|
||||
case PIPacketExtractor::Timeout:
|
||||
memcpy(buffer.data(), readed, size_);
|
||||
trbuf = dev->readForTime(time_);
|
||||
memcpy(buffer.data(size_), trbuf.data(), trbuf.size());
|
||||
if (size_ + trbuf.size() > 0)
|
||||
packetReceived(buffer.data(), size_ + trbuf.size());
|
||||
break;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PIString PIPacketExtractor::constructFullPath() const {
|
||||
return fullPathPrefix() + "://";
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
/*! \file pipacketextractor.h
|
||||
* \brief Packets extractor
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Packets extractor
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PIPACKETEXTRACTOR_H
|
||||
#define PIPACKETEXTRACTOR_H
|
||||
|
||||
#include "piiodevice.h"
|
||||
|
||||
// Pass data, recHeaderPtr, received_data, recHeaderSize. Return true if packet is correct nor return false.
|
||||
typedef bool (*PacketExtractorCheckFunc)(void * , uchar * , uchar * , int );
|
||||
|
||||
class PIP_EXPORT PIPacketExtractor: public PIIODevice
|
||||
{
|
||||
PIIODEVICE(PIPacketExtractor)
|
||||
friend class PIConnection;
|
||||
public:
|
||||
|
||||
//! Extract algorithms
|
||||
enum SplitMode {
|
||||
None /** No data processing */ ,
|
||||
Header /** Detect packets with \a header() and following \a payloadSize() */ ,
|
||||
Footer /** Detect packets with \a footer() and leading \a payloadSize() */ ,
|
||||
HeaderAndFooter /** Detect packets with \a header() and \a footer() without \a payloadSize() */ ,
|
||||
Size /** Detect packets with \a packetSize() */ ,
|
||||
Timeout /** Wait for first read, then read for \a timeout() milliseconds */
|
||||
};
|
||||
|
||||
//! Contructs extractor with child device "device_" and extract algorithm "mode"
|
||||
PIPacketExtractor(PIIODevice * device_ = 0, SplitMode mode = None);
|
||||
|
||||
virtual ~PIPacketExtractor() {stop();}
|
||||
|
||||
|
||||
//! Returns child %device
|
||||
PIIODevice * device() {return dev;}
|
||||
|
||||
//! Set child %device to "device_"
|
||||
void setDevice(PIIODevice * device_);
|
||||
|
||||
|
||||
//! Returns buffer size
|
||||
int bufferSize() const {return buffer_size;}
|
||||
|
||||
//! Set buffer size to "new_size" bytes, should be at least greater than whole packet size
|
||||
void setBufferSize(int new_size) {buffer_size = new_size; buffer.resize(buffer_size); sbuffer.resize(buffer_size); memset(buffer.data(), 0, buffer.size()); memset(sbuffer.data(), 0, sbuffer.size());}
|
||||
|
||||
void setHeaderCheckSlot(PacketExtractorCheckFunc f) {ret_func_header = f;}
|
||||
void setFooterCheckSlot(PacketExtractorCheckFunc f) {ret_func_footer = f;}
|
||||
void setPayloadCheckSlot(ReadRetFunc f) {ret_func_ = f;}
|
||||
|
||||
|
||||
//! Set extract algorithm
|
||||
void setSplitMode(SplitMode mode) {setProperty("splitMode", int(mode)); mode_ = mode;}
|
||||
|
||||
//! Set payload size, used for PIPacketExtractor::Header and PIPacketExtractor::Footer algorithms
|
||||
void setPayloadSize(int size);
|
||||
|
||||
//! Set header data, used for PIPacketExtractor::Header and PIPacketExtractor::HeaderAndFooter algorithms
|
||||
void setHeader(const PIByteArray & data);
|
||||
|
||||
//! Set footer data, used for PIPacketExtractor::Footer and PIPacketExtractor::HeaderAndFooter algorithms
|
||||
void setFooter(const PIByteArray & data);
|
||||
|
||||
//! Set packet size, used for PIPacketExtractor::Size algorithm
|
||||
void setPacketSize(int size) {setProperty("packetSize", size); packetSize_ = size;}
|
||||
|
||||
//! Set timeout in milliseconds, used for PIPacketExtractor::Timeout algorithm
|
||||
void setTimeout(double msecs) {setProperty("timeout", msecs); time_ = msecs;}
|
||||
|
||||
|
||||
//! Returns current extract algorithm
|
||||
SplitMode splitMode() const {return (SplitMode)(property("splitMode").toInt());}
|
||||
|
||||
//! Returns current payload size, used for PIPacketExtractor::Header and PIPacketExtractor::Footer algorithms
|
||||
int payloadSize() const {return property("payloadSize").toInt();}
|
||||
|
||||
//! Returns current header data, used for PIPacketExtractor::Header and PIPacketExtractor::HeaderAndFooter algorithms
|
||||
PIByteArray header() const {return src_header;}
|
||||
|
||||
//! Returns current footer data, used for PIPacketExtractor::Footer and PIPacketExtractor::HeaderAndFooter algorithms
|
||||
PIByteArray footer() const {return src_footer;}
|
||||
|
||||
//! Returns current packet size, used for PIPacketExtractor::Size algorithm
|
||||
int packetSize() const {return property("packetSize").toInt();}
|
||||
|
||||
//! Returns current timeout in milliseconds, used for PIPacketExtractor::Timeout algorithm
|
||||
double timeout() const {return property("timeout").toDouble();}
|
||||
|
||||
|
||||
//! Returns missed by validating functions bytes count
|
||||
ullong missedBytes() const {return missed;}
|
||||
|
||||
// //! Returns missed by validating functions packets count, = missedBytes() / packetSize
|
||||
ullong missedPackets() const {/*if (packetSize_hf == 0) return missed; return missed / packetSize_hf*/; return missed_packets;}
|
||||
|
||||
//! Returns pointer to \a missedBytes() count. Useful for output to PIConsole
|
||||
const ullong * missedBytes_ptr() const {return &missed;}
|
||||
|
||||
// //! Returns pointer to \a missedPackets() count. Useful for output to PIConsole
|
||||
const ullong * missedPackets_ptr() const {return &missed_packets;}
|
||||
|
||||
|
||||
// //! Returns last successfully validated header as byte array
|
||||
PIByteArray lastHeader() {return mheader;}
|
||||
|
||||
|
||||
//! Directly call \a read() function of child %device
|
||||
int read(void * read_to, int max_size) {if (dev == 0) return -1; return dev->read(read_to, max_size);}
|
||||
|
||||
//! Directly call \a write() function of child %device
|
||||
int write(const void * data, int max_size) {if (dev == 0) return -1; return dev->write(data, max_size);}
|
||||
|
||||
PIString constructFullPath() const;
|
||||
|
||||
EVENT2(packetReceived, uchar * , data, int, size)
|
||||
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void packetReceived(uchar * data, int size)
|
||||
//! \brief Raise on successfull \a packetValidate() function
|
||||
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
|
||||
/** \brief Function to validate header
|
||||
* \param src Your header content
|
||||
* \param rec Received header
|
||||
* \param size Header size
|
||||
* \details Default implementation returns by-byte "src" with "rec" compare result */
|
||||
virtual bool validateHeader(uchar * src, uchar * rec, int size) {if (ret_func_header != 0) return ret_func_header(ret_data_, src, rec, size); for (int i = 0; i < size; ++i) if (src[i] != rec[i]) return false; return true;}
|
||||
|
||||
/** \brief Function to validate footer
|
||||
* \param src Your footer content
|
||||
* \param rec Received footer
|
||||
* \param size Footer size
|
||||
* \details Default implementation returns by-byte "src" with "rec" compare result */
|
||||
virtual bool validateFooter(uchar * src, uchar * rec, int size) {if (ret_func_footer != 0) return ret_func_footer(ret_data_, src, rec, size); for (int i = 0; i < size; ++i) if (src[i] != rec[i]) return false; return true;}
|
||||
|
||||
/** \brief Function to validate payload
|
||||
* \param rec Received payload
|
||||
* \param size payload size
|
||||
* \details Default implementation returns \b true */
|
||||
virtual bool validatePayload(uchar * rec, int size) {if (ret_func_ != 0) return ret_func_(ret_data_, rec, size); return true;}
|
||||
|
||||
private:
|
||||
void init_();
|
||||
void propertyChanged(const PIString & );
|
||||
bool threadedRead(uchar * readed, int size);
|
||||
PIString fullPathPrefix() const {return "pckext";}
|
||||
bool openDevice() {if (dev == 0) return false; return dev->open();}
|
||||
|
||||
PIIODevice * dev;
|
||||
PIByteArray mheader, buffer, sbuffer, tmpbuf, src_header, src_footer, trbuf;
|
||||
PacketExtractorCheckFunc ret_func_header, ret_func_footer;
|
||||
SplitMode mode_;
|
||||
void * data;
|
||||
int buffer_size, dataSize, packetSize_hf, allReaded, addSize, curInd, footerInd, packetSize_;
|
||||
double time_;
|
||||
bool header_found;
|
||||
ullong missed, missed_packets;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // PIPACKETEXTRACTOR_H
|
||||
515
pipeer.cpp
515
pipeer.cpp
@@ -1,515 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Peer - named I/O ethernet node
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pipeer.h"
|
||||
|
||||
#define _PIPEER_PORT_SYNC_START 13313
|
||||
#define _PIPEER_PORT_SYNC_END 13353
|
||||
#define _PIPEER_IP_MULTICAST "230.13.3.12"
|
||||
#define _PIPEER_MSG_SIZE 8192
|
||||
|
||||
PIPeer::PIPeer(const PIString & name_): PIObject() {
|
||||
rec_mc = rec_bc = false;
|
||||
setName(name_);
|
||||
self_info.name = name_;
|
||||
self_info.dist = 0;
|
||||
eth_send = 0;
|
||||
//joinMulticastGroup("239.240.241.242");
|
||||
srand(uint(PITimer::elapsed_system_m()));
|
||||
//id_ = name() + "_" + PIString::fromNumber(rand());
|
||||
CONNECT2(void, void * , int, &timer, timeout, this, timerEvent);
|
||||
PIStringList sl = PIEthernet::allAddresses();
|
||||
sl.removeAll("127.0.0.1"); sl << "127.0.0.1";
|
||||
initMulticasts(sl);
|
||||
initEths(sl);
|
||||
sendSelfInfo();
|
||||
timer.addDelimiter(5);
|
||||
timer.start(1000);
|
||||
}
|
||||
|
||||
|
||||
PIPeer::~PIPeer() {
|
||||
piForeach (PIEthernet * i, mc_eths)
|
||||
i->stopThreadedRead();
|
||||
if (eth_send != 0)
|
||||
eth_send->stopThreadedRead();
|
||||
sendSelfRemove();
|
||||
destroyMulticasts();
|
||||
piForeach (PIEthernet * i, eths)
|
||||
delete i;
|
||||
eths.clear();
|
||||
if (eth_send != 0)
|
||||
delete eth_send;
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::timerEvent(void * data, int delim) {
|
||||
switch (delim) {
|
||||
case 5: // 5 s
|
||||
syncPeers();
|
||||
break;
|
||||
}
|
||||
//send("broadcast", 9);
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::initEths(const PIStringList & al) {
|
||||
PIEthernet * ce;
|
||||
PIEthernet::InterfaceList il = PIEthernet::interfaces();
|
||||
const PIEthernet::Interface * cint = 0;
|
||||
piForeachC (PIString & a, al) {
|
||||
ce = new PIEthernet();
|
||||
ce->setParameters(0);
|
||||
ce->setDebug(false);
|
||||
for (int p = _PIPEER_PORT_SYNC_START; p < 65536; ++p) {
|
||||
ce->setReadAddress(a, p);
|
||||
if (ce->open()) {
|
||||
eths << ce;
|
||||
cint = il.getByAddress(a);
|
||||
self_info.addresses << ce->path();
|
||||
self_info.netmasks << (cint == 0 ? "255.255.255.0" : cint->netmask);
|
||||
CONNECT2(bool, void * , int, ce, threadedReadEvent, this, dataRead);
|
||||
ce->startThreadedRead();
|
||||
//piCout << "dc binded to" << ce->path();
|
||||
//piCout << "add eth" << ta;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
eth_send = new PIEthernet();
|
||||
eth_send->setParameters(0);
|
||||
eth_send->setDebug(false);
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::initMulticasts(const PIStringList & al) {
|
||||
destroyMulticasts();
|
||||
PIEthernet * ce;
|
||||
PIEthernet::InterfaceList il = PIEthernet::interfaces();
|
||||
const PIEthernet::Interface * cint;
|
||||
PIStringList nal = al;
|
||||
PIString nm;
|
||||
nal << "main" << "bc";
|
||||
rec_mc = rec_bc = false;
|
||||
piForeachC (PIString & a, nal) {
|
||||
bool is_main = (a == "main");
|
||||
bool is_bc = (a == "bc");
|
||||
ce = new PIEthernet();
|
||||
ce->setParameters((is_main || is_bc) ? PIEthernet::Broadcast : 0);
|
||||
ce->setDebug(false);
|
||||
//cint = il.getByAddress(a);
|
||||
//nm = (cint == 0) ? "255.255.255.0" : cint->netmask;
|
||||
ce->setSendIP(is_bc ? "255.255.255.255" : _PIPEER_IP_MULTICAST);
|
||||
//piCout << "mc try" << a << nm << ce->sendIP();
|
||||
for (int p = _PIPEER_PORT_SYNC_START; p < _PIPEER_PORT_SYNC_END; ++p) {
|
||||
ce->setReadAddress(((is_main || is_bc) ? "255.255.255.255" : a) + ":" + PIString::fromNumber(p));
|
||||
ce->close();
|
||||
if (!ce->open()) continue;
|
||||
if (is_main) if (!ce->joinMulticastGroup(_PIPEER_IP_MULTICAST)) continue;
|
||||
//piCout << "mc binded to" << ce->path();
|
||||
ce->setName(is_main ? "no_send" : "");
|
||||
mc_eths << ce;
|
||||
if (is_main || is_bc) {
|
||||
if (is_main) rec_mc = true;
|
||||
if (is_bc) rec_bc = true;
|
||||
CONNECT2(bool, void * , int, ce, threadedReadEvent, this, multicastRead);
|
||||
ce->startThreadedRead();
|
||||
if (is_bc) ce->setParameter(PIEthernet::Broadcast, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
piForeachC (PIString & a, al) {
|
||||
ce = new PIEthernet();
|
||||
ce->setParameters(PIEthernet::Broadcast);
|
||||
ce->setDebug(false);
|
||||
cint = il.getByAddress(a);
|
||||
nm = (cint == 0) ? "255.255.255.0" : cint->netmask;
|
||||
ce->setSendIP(PIEthernet::getBroadcast(a, nm));
|
||||
//piCout << "mc BC try" << a << nm << ce->sendIP();
|
||||
for (int p = _PIPEER_PORT_SYNC_START; p < _PIPEER_PORT_SYNC_END; ++p) {
|
||||
ce->setReadAddress(a + ":" + PIString::fromNumber(p));
|
||||
ce->close();
|
||||
if (!ce->open()) continue;
|
||||
//piCout << "BC binded to" << ce->path();
|
||||
mc_eths << ce;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!rec_mc) piCoutObj << "Can`t find suitable network interface for multicast receive, check for exists at least one interface with multicasting enabled!";
|
||||
if (!rec_bc) piCoutObj << "Can`t find suitable network interface for broadcast receive, check for exists at least one interface with broadcasting enabled!";
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::destroyMulticasts() {
|
||||
piForeach (PIEthernet * i, mc_eths) {
|
||||
i->leaveMulticastGroup(_PIPEER_IP_MULTICAST);
|
||||
delete i;
|
||||
}
|
||||
mc_eths.clear();
|
||||
}
|
||||
|
||||
|
||||
PIPeer::PeerInfo * PIPeer::quickestPeer(const PIString & to) {
|
||||
if (!addresses_map.contains(to)) return 0;
|
||||
//piCout << "*** search quickest peer" << to;
|
||||
PIVector<PeerInfo * > tp = addresses_map[to];
|
||||
PeerInfo * dp = 0;
|
||||
int mping = 99999;
|
||||
for (int i = 0; i < tp.size_s(); ++i) {
|
||||
if (mping > tp[i]->ping) {
|
||||
mping = tp[i]->ping;
|
||||
dp = tp[i];
|
||||
}
|
||||
}
|
||||
//piCout << "*** search quickest peer: found" << dp->name;
|
||||
return dp;
|
||||
}
|
||||
|
||||
|
||||
bool PIPeer::send(const PIString & to, const void * data, int size) {
|
||||
PeerInfo * dp = quickestPeer(to);
|
||||
if (dp == 0) {
|
||||
//piCoutObj << "Can`t find peer \"" << to << "\"!";
|
||||
return false;
|
||||
}
|
||||
PIByteArray ba;
|
||||
ba << int(4) << self_info.name << to << int(0) << size;
|
||||
PIByteArray fmsg(data, size), cmsg;
|
||||
int msg_count = (size - 1) / _PIPEER_MSG_SIZE + 1;
|
||||
//piCout << "[PIPeer] send" << size << "bytes in" << msg_count << "packets ...";
|
||||
for (int i = 0; i < msg_count; ++i) {
|
||||
int csize = (i == msg_count - 1) ? ((size - 1) % _PIPEER_MSG_SIZE + 1) : _PIPEER_MSG_SIZE;
|
||||
cmsg.clear();
|
||||
cmsg.append(ba);
|
||||
cmsg << msg_count << i;
|
||||
cmsg.append(fmsg.data(i * _PIPEER_MSG_SIZE), csize);
|
||||
if (!sendToNeighbour(dp, cmsg)) return false;
|
||||
}
|
||||
//piCout << "[PIPeer] send" << size << "bytes ok";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIPeer::dataRead(uchar * readed, int size) {
|
||||
if (size < 16) return true;
|
||||
PIByteArray ba(readed, size), sba;
|
||||
int type, cnt, rec_size;
|
||||
PIString from, to;
|
||||
ba >> type;
|
||||
//piCout << "[PIPeer \"" + name_ + "\"] Received packet" << type;
|
||||
if (type != 4) return true;
|
||||
PIMutexLocker locker(eth_mutex);
|
||||
diag_d.received(size);
|
||||
ba >> from >> to >> cnt >> rec_size;
|
||||
//piCout << "[PIPeer \"" + name_ + "\"] Received packet" << /*type << from << to << cnt <<*/ rec_size;
|
||||
if (type == 4) { // data packet
|
||||
if (to == self_info.name) { // my packet
|
||||
int msg_count, cmsg;
|
||||
ba >> msg_count >> cmsg;
|
||||
//piCout << "[PIPeer \"" + name_ + "\"] Received packet" << type << from << to << cnt << rec_size << msg_count << cmsg;
|
||||
if (cmsg == 0 && msg_count == 1) {
|
||||
dataReceived(from, ba);
|
||||
dataReceivedEvent(from, ba);
|
||||
return true;
|
||||
}
|
||||
PeerInfo * fp = const_cast<PeerInfo * >(getPeerByName(from));
|
||||
if (fp == 0) return true;
|
||||
PeerData & pd(fp->_data);
|
||||
if (cmsg == 0) {
|
||||
//piCout << "[PIPeer \"" + name_ + "\"] Packet clear" << rec_size;
|
||||
pd.clear();
|
||||
pd.msg_count = msg_count;
|
||||
}
|
||||
//piCout << "[PIPeer \"" + name_ + "\"] Packet add" << cmsg << ba.size_s();
|
||||
pd.addData(ba);
|
||||
if (pd.isFullReceived()) {
|
||||
dataReceived(from, pd.data);
|
||||
dataReceivedEvent(from, pd.data);
|
||||
//piCout << "[PIPeer \"" + name_ + "\"] Packet received" << pd.data.size_s();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
PeerInfo * dp = quickestPeer(to);
|
||||
if (dp == 0) {
|
||||
//piCoutObj << "Can`t find peer \"" << to << "\"!";
|
||||
return true;
|
||||
}
|
||||
cnt++;
|
||||
if (cnt > 100 || from == dp->name) return true;
|
||||
sba << type << from << to << cnt << rec_size;
|
||||
sba.append(ba);
|
||||
//piCoutObj << "Translate data packet" << type << from << to << cnt << rec_size;
|
||||
sendToNeighbour(dp, sba);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIPeer::multicastRead(uchar * data, int size) {
|
||||
if (size < 8) return true;
|
||||
int type;
|
||||
PIByteArray ba(data, size);
|
||||
ba >> type;
|
||||
if (type <= 0 || type >= 4) return true;
|
||||
PeerInfo pi;
|
||||
PIVector<PeerInfo> rpeers;
|
||||
ba >> pi.name;
|
||||
//piCout << "read type" << type << "from" << pi.name;
|
||||
if (pi.name == name()) return true;
|
||||
PIMutexLocker locker(mc_mutex);
|
||||
diag_s.received(size);
|
||||
//piCout << "analyz ...";
|
||||
switch (type) {
|
||||
case 1: // new peer accepted
|
||||
//piCout << "new peer packet ...";
|
||||
if (hasPeer(pi.name)) break;
|
||||
ba >> pi.dist >> pi.addresses >> pi.netmasks >> pi.neighbours;
|
||||
pi.sync = 0;
|
||||
if (pi.dist == 0) {
|
||||
pi.addNeighbour(self_info.name);
|
||||
self_info.addNeighbour(pi.name);
|
||||
}
|
||||
peers << pi;
|
||||
//piCoutObj << "new peer \"" << pi.name << "\"" << " dist " << pi.dist;
|
||||
pi.dist++;
|
||||
sendSelfInfo();
|
||||
sendPeerInfo(pi);
|
||||
findNearestAddresses();
|
||||
peerConnected(pi.name);
|
||||
peerConnectedEvent(pi.name);
|
||||
//piCout << "new peer packet ok";
|
||||
break;
|
||||
case 2: // remove peer accepted
|
||||
//piCout << "remove peer packet ...";
|
||||
if (removePeer(pi.name)) {
|
||||
//piCoutObj << "remove peer \"" << pi.name << "\"";
|
||||
if (pi.dist == 0) {
|
||||
pi.removeNeighbour(self_info.name);
|
||||
self_info.removeNeighbour(pi.name);
|
||||
}
|
||||
sendPeerRemove(pi.name);
|
||||
findNearestAddresses();
|
||||
peerDisconnected(pi.name);
|
||||
peerDisconnectedEvent(pi.name);
|
||||
}
|
||||
//piCout << "remove peer packet ok";
|
||||
break;
|
||||
case 3: // sync peers
|
||||
//piCout << "sync packet ...";
|
||||
ba >> pi.addresses >> pi.netmasks >> pi.neighbours >> rpeers;
|
||||
rpeers << pi;
|
||||
//piCout << "[PIPeer \"" + name_ + "\"] rec sync " << rpeers.size_s() << " peers";
|
||||
for (uint i = 0; i < rpeers.size(); ++i) {
|
||||
PeerInfo & rpeer(rpeers[i]);
|
||||
//piCout << " to sync " << rpeer.name;
|
||||
if (rpeer.name == name()) continue;
|
||||
bool exist = false;
|
||||
for (uint j = 0; j < peers.size(); ++j) {
|
||||
PeerInfo & peer(peers[j]);
|
||||
if (peer.name == rpeer.name) {
|
||||
//piCout << "synced " << peer.name;
|
||||
peer.addresses = rpeer.addresses;
|
||||
peer.netmasks = rpeer.netmasks;
|
||||
peer.addNeighbours(rpeer.neighbours);
|
||||
rpeer.neighbours = peer.neighbours;
|
||||
if (peer.name == pi.name) peer.sync = 0;
|
||||
exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exist) continue;
|
||||
peers << rpeer;
|
||||
peers.back().dist++;
|
||||
findNearestAddresses();
|
||||
peerConnected(rpeer.name);
|
||||
peerConnectedEvent(rpeer.name);
|
||||
}
|
||||
//piCout << "***";;
|
||||
//piCout << self_info.name << self_info.neighbours;
|
||||
piForeach (PeerInfo & i, peers) {
|
||||
if (i.dist == 0) {
|
||||
self_info.addNeighbour(i.name);
|
||||
i.addNeighbour(self_info.name);
|
||||
}
|
||||
//piCout << i.name << i.neighbours;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIPeer::sendToNeighbour(PIPeer::PeerInfo * peer, const PIByteArray & ba) {
|
||||
if (peer->_neth == 0) return false;
|
||||
//piCout << "[PIPeer] sendToNeighbour" << (eth_send->readAddress()) << peer->_naddress << ba.size_s() << "bytes ...";
|
||||
//bool ok = peer->_neth->send(peer->_naddress, ba.data(), ba.size_s());
|
||||
bool ok = eth_send->send(peer->_naddress, ba.data(), ba.size_s());
|
||||
//piCout << "[PIPeer] sendToNeighbour" << (ok ? "ok" : "fail");
|
||||
if (ok) diag_d.sended(ba.size_s());
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::sendMulticast(const PIByteArray & ba) {
|
||||
//piCout << "send muticast ...";
|
||||
piForeach (PIEthernet * e, mc_eths) {
|
||||
if (e->name() == "no_send") continue;
|
||||
for (int p = _PIPEER_PORT_SYNC_START; p < _PIPEER_PORT_SYNC_END; ++p) {
|
||||
e->setSendPort(p);
|
||||
//errorClear();
|
||||
//piCout << "send to" << e->path() << e->sendAddress();// << e->send(ba);
|
||||
//piCout << PIEthernet::ethErrorString();
|
||||
e->send(ba);
|
||||
diag_s.sended(ba.size_s());
|
||||
}
|
||||
}
|
||||
//piCout << "send muticast ok";
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::sendPeerInfo(const PeerInfo & info) {
|
||||
PIByteArray ba;
|
||||
ba << int(1) << info.name << info.dist << info.addresses << info.netmasks << info.neighbours;
|
||||
sendMulticast(ba);
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::sendPeerRemove(const PIString & peer) {
|
||||
PIByteArray ba;
|
||||
ba << int(2) << peer;
|
||||
sendMulticast(ba);
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::syncPeers() {
|
||||
//piCout << "[PIPeer \"" + name_ + "\"] sync " << peers.size_s() << " peers";
|
||||
PIString pn;
|
||||
bool change = false;
|
||||
for (uint i = 0; i < peers.size(); ++i) {
|
||||
PeerInfo & cp(peers[i]);
|
||||
if (cp.sync > 3 && cp.dist == 0) {
|
||||
pn = cp.name;
|
||||
//piCoutObj << "sync: remove " << pn;
|
||||
peers.remove(i);
|
||||
sendPeerRemove(pn);
|
||||
--i;
|
||||
piForeach (PeerInfo & p, peers)
|
||||
p.removeNeighbour(pn);
|
||||
self_info.removeNeighbour(pn);
|
||||
peerDisconnected(pn);
|
||||
peerDisconnectedEvent(pn);
|
||||
change = true;
|
||||
continue;
|
||||
}
|
||||
cp.sync++;
|
||||
}
|
||||
if (change) findNearestAddresses();
|
||||
PIByteArray ba;
|
||||
ba << int(3) << self_info.name << self_info.addresses << self_info.netmasks << self_info.neighbours << peers;
|
||||
sendMulticast(ba);
|
||||
}
|
||||
|
||||
|
||||
void PIPeer::findNearestAddresses() {
|
||||
//piCout << "[PIPeer \"" + name_ + "\"] findNearestAddresses";
|
||||
addresses_map.clear();
|
||||
int max_dist = -1;
|
||||
static PIMap<PIString, PeerInfo * > peers_;
|
||||
peers_.clear();
|
||||
self_info._nuses.resize(self_info.neighbours.size());
|
||||
self_info._nuses.fill(0);
|
||||
self_info._first = &self_info;
|
||||
peers_[self_info.name] = &self_info;
|
||||
piForeach (PeerInfo & i, peers) {
|
||||
i._nuses.resize(i.neighbours.size());
|
||||
i._nuses.fill(0);
|
||||
i._first = 0;
|
||||
peers_[i.name] = &i;
|
||||
if (max_dist < i.dist)
|
||||
max_dist = i.dist;
|
||||
if (i.dist > 0) continue;
|
||||
i._naddress.clear();
|
||||
i._neth = 0;
|
||||
PIString mma, ma;
|
||||
bool af = false;
|
||||
for (int mi = 0; mi < self_info.addresses.size_s(); ++mi) {
|
||||
PIString & m(self_info.addresses[mi]), & mmask(self_info.netmasks[mi]);
|
||||
if (af) break;
|
||||
ma = m;
|
||||
//mma = m.left(m.findLast("."));
|
||||
mma = PIEthernet::applyMask(m, mmask);
|
||||
for (int ii = 0; ii < i.addresses.size_s(); ++ii) {
|
||||
PIString & r(i.addresses[ii]), & rmask(i.netmasks[ii]);
|
||||
if (mma == PIEthernet::applyMask(r, rmask)) {
|
||||
i._naddress = r;
|
||||
//piCout << "_naddress" << i.name << "=" << r;
|
||||
af = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!af) continue;
|
||||
//piCout << " peer" << i.name << ma;
|
||||
piForeach (PIEthernet * e, eths)
|
||||
if (e->readAddress() == ma) {
|
||||
i._neth = e;
|
||||
break;
|
||||
}
|
||||
//piCout << i.name << i._naddress;
|
||||
}
|
||||
PIVector<PeerInfo * > cwave, nwave;
|
||||
PeerInfo * npeer;
|
||||
cwave << &self_info;
|
||||
for (int d = 0; d <= max_dist; ++d) {
|
||||
if (cwave.isEmpty()) break;
|
||||
nwave.clear();
|
||||
piForeach (PeerInfo * p, cwave) {
|
||||
int ns = p->neighbours.size_s();
|
||||
for (int n = 0; n < ns; ++n) {
|
||||
if (p->_nuses[n] >= ns) continue;
|
||||
p->_nuses[n]++;
|
||||
npeer = peers_[p->neighbours[n]];
|
||||
if (npeer == 0) continue;
|
||||
if (d == 0) npeer->_first = npeer;
|
||||
else {
|
||||
if (d == 1) npeer->_first = p;
|
||||
else npeer->_first = p->_first;
|
||||
}
|
||||
nwave << npeer;
|
||||
}
|
||||
}
|
||||
cwave = nwave;
|
||||
//piCout << "wave" << d;
|
||||
for (int i = 0; i < cwave.size_s(); ++i) {
|
||||
//piCout << " peer" << cwave[i]->name << Hex << (uint)(cwave[i]->_first);
|
||||
if (cwave[i]->_first == 0) {cwave.remove(i); --i; continue;}
|
||||
if (addresses_map.contains(cwave[i]->name)) {cwave.remove(i); --i; continue;}
|
||||
}
|
||||
for (int i = 0; i < cwave.size_s(); ++i) {
|
||||
PIVector<PeerInfo * > & pl(addresses_map[cwave[i]->name]);
|
||||
if (!pl.contains(cwave[i]->_first))
|
||||
pl << cwave[i]->_first;
|
||||
}
|
||||
}
|
||||
/*piCout << " ** addresses map **";
|
||||
piForeachC (napair & i, addresses_map)
|
||||
piCout << i.first << i.second;
|
||||
piCout << " ** addresses map end **";*/
|
||||
}
|
||||
167
pipeer.h
167
pipeer.h
@@ -1,167 +0,0 @@
|
||||
/*! \file pipeer.h
|
||||
* \brief Peering net node
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Peer - named I/O ethernet node, forming self-organized peering network
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIPEER_H
|
||||
#define PIPEER_H
|
||||
|
||||
#include "piethernet.h"
|
||||
#include "pidiagnostics.h"
|
||||
|
||||
class PIP_EXPORT PIPeer: public PIObject
|
||||
{
|
||||
PIOBJECT(PIPeer)
|
||||
private:
|
||||
struct PeerData {
|
||||
PeerData() {msg_count = msg_rec = 0;}
|
||||
void clear() {msg_count = msg_rec = 0; data.clear();}
|
||||
bool isEmpty() const {return msg_count == 0;}
|
||||
bool isFullReceived() const {return msg_count == msg_rec;}
|
||||
void addData(const PIByteArray & ba) {data.append(ba); msg_rec++;}
|
||||
void setData(const PIByteArray & ba) {data = ba; msg_rec = 0; msg_count = (data.size_s() - 1) / 4096 + 1;}
|
||||
PIByteArray data;
|
||||
int msg_count;
|
||||
int msg_rec;
|
||||
};
|
||||
|
||||
public:
|
||||
PIPeer(const PIString & name);
|
||||
virtual ~PIPeer();
|
||||
|
||||
class PeerInfo {
|
||||
friend class PIPeer;
|
||||
friend PIByteArray & operator <<(PIByteArray & s, const PIPeer::PeerInfo & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & s, PIPeer::PeerInfo & v);
|
||||
public:
|
||||
PeerInfo() {dist = sync = ping = 0; _neth = 0; _first = 0;}
|
||||
|
||||
PIString name;
|
||||
PIStringList addresses;
|
||||
int dist;
|
||||
int ping;
|
||||
|
||||
bool isNeighbour() const {return dist == 0;}
|
||||
|
||||
protected:
|
||||
void addNeighbour(const PIString & n) {if (!neighbours.contains(n)) neighbours << n;}
|
||||
void addNeighbours(const PIStringList & l) {piForeachC (PIString & n, l) if (!neighbours.contains(n)) neighbours << n;}
|
||||
void removeNeighbour(const PIString & n) {neighbours.removeAll(n);}
|
||||
|
||||
PIString nearest_address;
|
||||
PIStringList netmasks;
|
||||
PIStringList neighbours;
|
||||
int sync;
|
||||
PIString _naddress;
|
||||
PIEthernet * _neth;
|
||||
PIVector<uchar> _nuses;
|
||||
PeerInfo * _first;
|
||||
PeerData _data;
|
||||
|
||||
};
|
||||
|
||||
friend PIByteArray & operator <<(PIByteArray & s, const PIPeer::PeerInfo & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & s, PIPeer::PeerInfo & v);
|
||||
|
||||
bool send(const PIString & to, const PIByteArray & data) {return send(to, data.data(), data.size_s());}
|
||||
bool send(const PIString & to, const PIString & data) {return send(to, data.data(), data.size_s());}
|
||||
bool send(const PIString & to, const void * data, int size);
|
||||
bool send(const PeerInfo & to, const PIByteArray & data) {return send(to.name, data.data(), data.size_s());}
|
||||
bool send(const PeerInfo & to, const PIString & data) {return send(to.name, data.data(), data.size_s());}
|
||||
bool send(const PeerInfo & to, const void * data, int size) {return send(to.name, data, size);}
|
||||
bool send(const PeerInfo * to, const PIByteArray & data) {if (to == 0) return false; return send(to->name, data.data(), data.size_s());}
|
||||
bool send(const PeerInfo * to, const PIString & data) {if (to == 0) return false; return send(to->name, data.data(), data.size_s());}
|
||||
bool send(const PeerInfo * to, const void * data, int size) {if (to == 0) return false; return send(to->name, data, size);}
|
||||
void sendToAll(const PIByteArray & data) {piForeachC (PeerInfo & i, peers) send(i.name, data.data(), data.size_s());}
|
||||
void sendToAll(const PIString & data) {piForeachC (PeerInfo & i, peers) send(i.name, data.data(), data.size_s());}
|
||||
void sendToAll(const void * data, int size) {piForeachC (PeerInfo & i, peers) send(i.name, data, size);}
|
||||
|
||||
bool isMulticastReceive() const {return rec_mc;}
|
||||
bool isBroadcastReceive() const {return rec_bc;}
|
||||
|
||||
PIDiagnostics & diagnosticService() {return diag_s;}
|
||||
PIDiagnostics & diagnosticData() {return diag_d;}
|
||||
|
||||
const PIVector<PIPeer::PeerInfo> & allPeers() const {return peers;}
|
||||
bool isPeerExists(const PIString & name) const {return getPeerByName(name) != 0;}
|
||||
|
||||
const PeerInfo * getPeerByName(const PIString & name) const {piForeachC (PeerInfo & i, peers) if (i.name == name) return &i; return 0;}
|
||||
|
||||
void lock() {mc_mutex.lock();}
|
||||
void unlock() {mc_mutex.unlock();}
|
||||
|
||||
EVENT2(dataReceivedEvent, const PIString &, from, const PIByteArray &, data);
|
||||
EVENT1(peerConnectedEvent, const PIString &, name);
|
||||
EVENT1(peerDisconnectedEvent, const PIString &, name);
|
||||
|
||||
protected:
|
||||
virtual void dataReceived(const PIString & from, const PIByteArray & data) {;}
|
||||
virtual void peerConnected(const PIString & name) {;}
|
||||
virtual void peerDisconnected(const PIString & name) {;}
|
||||
|
||||
EVENT_HANDLER2(bool, dataRead, uchar *, readed, int, size);
|
||||
EVENT_HANDLER2(bool, multicastRead, uchar *, readed, int, size);
|
||||
|
||||
private:
|
||||
EVENT_HANDLER2(void, timerEvent, void * , data, int, delim);
|
||||
|
||||
bool hasPeer(const PIString & name) {piForeachC (PeerInfo & i, peers) if (i.name == name) return true; return false;}
|
||||
bool removePeer(const PIString & name) {for (uint i = 0; i < peers.size(); ++i) if (peers[i].name == name) {peers.remove(i); return true;} return false;}
|
||||
|
||||
void sendPeerInfo(const PeerInfo & info);
|
||||
void sendPeerRemove(const PIString & peer);
|
||||
void sendSelfInfo() {sendPeerInfo(self_info);}
|
||||
void sendSelfRemove() {sendPeerRemove(name());}
|
||||
void syncPeers();
|
||||
void findNearestAddresses();
|
||||
void initEths(const PIStringList & al);
|
||||
void initMulticasts(const PIStringList & al);
|
||||
void destroyMulticasts();
|
||||
void sendMulticast(const PIByteArray & ba);
|
||||
|
||||
PeerInfo * quickestPeer(const PIString & to);
|
||||
bool sendToNeighbour(PeerInfo * peer, const PIByteArray & ba);
|
||||
|
||||
struct PeerPacket {
|
||||
int header; // 1 - new peer, 2 - remove peer, 3 - sync peers, 4 - data
|
||||
// Data packet: 4, from, to, ticks, data_size, data
|
||||
};
|
||||
|
||||
typedef std::pair<PIString, PIVector<PeerInfo * > > napair;
|
||||
|
||||
PIVector<PIEthernet * > eths;
|
||||
PIVector<PIEthernet * > mc_eths;
|
||||
PIEthernet * eth_send;
|
||||
PITimer timer;
|
||||
PIMutex mc_mutex, eth_mutex;
|
||||
bool rec_mc, rec_bc;
|
||||
|
||||
PeerInfo self_info;
|
||||
PIVector<PeerInfo> peers;
|
||||
PIMap<PIString, PIVector<PeerInfo * > > addresses_map; // map {"to" = list of nearest peers}
|
||||
PIDiagnostics diag_s, diag_d;
|
||||
//PIString id_;
|
||||
|
||||
};
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIPeer::PeerInfo & v) {s << v.name << v.addresses << v.netmasks << v.dist << v.neighbours; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIPeer::PeerInfo & v) {s >> v.name >> v.addresses >> v.netmasks >> v.dist >> v.neighbours; return s;}
|
||||
|
||||
#endif // PIPEER_H
|
||||
199
piprocess.cpp
199
piprocess.cpp
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Process
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piprocess.h"
|
||||
|
||||
|
||||
PIProcess::PIProcess(): PIThread() {
|
||||
exit_code = -1;
|
||||
#ifdef WINDOWS
|
||||
pi.dwProcessId = 0;
|
||||
#else
|
||||
pid = 0;
|
||||
#endif
|
||||
is_exec = false;
|
||||
g_in = g_out = g_err = false;
|
||||
t_in = t_out = t_err = false;
|
||||
env = PIProcess::currentEnvironment();
|
||||
}
|
||||
|
||||
|
||||
PIProcess::~PIProcess() {
|
||||
if (t_in) f_in.remove();
|
||||
if (t_out) f_out.remove();
|
||||
if (t_err) f_err.remove();
|
||||
}
|
||||
|
||||
|
||||
void PIProcess::exec_() {
|
||||
is_exec = false;
|
||||
startOnce();
|
||||
//cout << "exec wait" << endl;
|
||||
while (!is_exec)
|
||||
msleep(1);
|
||||
//cout << "exec end" << endl;
|
||||
}
|
||||
|
||||
|
||||
void PIProcess::run() {
|
||||
//cout << "run" << endl;
|
||||
string str;
|
||||
/// arguments convertion
|
||||
as = 0;
|
||||
#ifdef WINDOWS
|
||||
//args.pop_front();
|
||||
piForeachC (PIString & i, args)
|
||||
as += i.lengthAscii() + 1;
|
||||
char * a = new char[as];
|
||||
memset(a, ' ', as - 1);
|
||||
as = 0;
|
||||
for (int i = 0; i < args.size_s(); ++i) {
|
||||
str = args[i].stdString();
|
||||
memcpy(&a[as], str.c_str(), str.size());
|
||||
as += str.length() + 1;
|
||||
}
|
||||
a[as - 1] = 0;
|
||||
#else
|
||||
char * a[args.size_s() + 1];
|
||||
for (int i = 0; i < args.size_s(); ++i) {
|
||||
str = args[i].stdString();
|
||||
a[i] = new char[str.size() + 1];
|
||||
memcpy(a[i], str.c_str(), str.size());
|
||||
a[i][str.size()] = 0;
|
||||
//cout << a[i] << endl;
|
||||
}
|
||||
a[args.size_s()] = 0;
|
||||
#endif
|
||||
/// environment convertion
|
||||
char ** e = new char*[env.size_s() + 1];
|
||||
for (int i = 0; i < env.size_s(); ++i) {
|
||||
str = env[i].stdString();
|
||||
e[i] = new char[str.size() + 1];
|
||||
memcpy(e[i], str.c_str(), str.size());
|
||||
e[i][str.size()] = 0;
|
||||
//cout << e[i] << endl;
|
||||
}
|
||||
e[env.size_s()] = 0;
|
||||
/// files for stdin/out/err
|
||||
t_in = t_out = t_err = false;
|
||||
if (f_in.path().isEmpty()) {
|
||||
f_in = PIFile::openTemporary(PIIODevice::ReadWrite);
|
||||
t_in = true;
|
||||
}
|
||||
//f_in.open(PIIODevice::ReadWrite); f_in.close();
|
||||
if (f_out.path().isEmpty()) {
|
||||
f_out = PIFile::openTemporary(PIIODevice::ReadWrite);
|
||||
t_out = true;
|
||||
}
|
||||
//f_out.open(PIIODevice::WriteOnly); f_out.close();
|
||||
if (f_err.path().isEmpty()) {
|
||||
f_err = PIFile::openTemporary(PIIODevice::ReadWrite);
|
||||
t_err = true;
|
||||
}
|
||||
//f_err.open(PIIODevice::WriteOnly); f_err.close();
|
||||
|
||||
str = args.front().stdString();
|
||||
is_exec = true;
|
||||
execStarted(PIString(str));
|
||||
#ifndef WINDOWS
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
#endif
|
||||
tf_in = tf_out = tf_err = 0;
|
||||
//cout << "exec " << tf_in << ", " << tf_out << ", " << tf_err << endl;
|
||||
//cout << f_out.path() << endl;
|
||||
if (g_in) tf_in = freopen(f_in.path().data(), "r", stdin);
|
||||
if (g_out) tf_out = freopen(f_out.path().data(), "w", stdout);
|
||||
if (g_err) tf_err = freopen(f_err.path().data(), "w", stderr);
|
||||
#ifndef WINDOWS
|
||||
if (!wd.isEmpty()) as = chdir(wd.data());
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
GetStartupInfoA(&si);
|
||||
memset(&pi, 0, sizeof(pi));
|
||||
if(CreateProcessA(0, // No module name (use command line)
|
||||
a, // Command line
|
||||
0, // Process handle not inheritable
|
||||
0, // Thread handle not inheritable
|
||||
false, // Set handle inheritance to FALSE
|
||||
0, // No creation flags
|
||||
0,//e, // Use environment
|
||||
wd.isEmpty() ? 0 : wd.data(), // Use working directory
|
||||
&si, // Pointer to STARTUPINFO structure
|
||||
&pi)) // Pointer to PROCESS_INFORMATION structure
|
||||
{
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
CloseHandle(pi.hProcess);
|
||||
} else
|
||||
piCoutObj << "\"CreateProcess\" error, " << errorString();
|
||||
#else
|
||||
|
||||
//cout << "exec " << tf_in << ", " << tf_out << ", " << tf_err << endl;
|
||||
if (execve(str.c_str(), a, e) < 0)
|
||||
piCoutObj << "\"execve\" error, " << errorString();
|
||||
} else {
|
||||
msleep(1);
|
||||
//cout << "wait" << endl;
|
||||
wait(&exit_code);
|
||||
/*if (tf_in != 0) fclose(tf_in);
|
||||
if (tf_out != 0) fclose(tf_out);
|
||||
if (tf_err != 0) fclose(tf_err);*/
|
||||
pid = 0;
|
||||
//cout << "wait done" << endl;
|
||||
}
|
||||
#endif
|
||||
execFinished(PIString(str), exit_code);
|
||||
is_exec = false;
|
||||
for (int i = 0; i < env.size_s(); ++i)
|
||||
delete e[i];
|
||||
delete e;
|
||||
#ifdef WINDOWS
|
||||
delete a;
|
||||
#else
|
||||
for (int i = 0; i < args.size_s(); ++i)
|
||||
delete a[i];
|
||||
#endif
|
||||
//cout << "end " << tf_in << ", " << tf_out << ", " << tf_err << endl;
|
||||
}
|
||||
|
||||
|
||||
void PIProcess::removeEnvironmentVariable(const PIString & variable) {
|
||||
PIString s;
|
||||
for (int i = 0; i < env.size_s(); ++i) {
|
||||
s = env[i];
|
||||
if (s.left(s.find("=")).trimmed() == variable) {
|
||||
env.remove(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIProcess::setEnvironmentVariable(const PIString & variable, const PIString & value) {
|
||||
PIString s, v;
|
||||
for (int i = 0; i < env.size_s(); ++i) {
|
||||
s = env[i];
|
||||
v = s.left(s.find("=")).trimmed();
|
||||
if (v == variable) {
|
||||
env[i] = v + "=" + value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
env << variable + "=" + value;
|
||||
}
|
||||
130
piprocess.h
130
piprocess.h
@@ -1,130 +0,0 @@
|
||||
/*! \file piprocess.h
|
||||
* \brief Process
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Process
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIPROCESS_H
|
||||
#define PIPROCESS_H
|
||||
|
||||
#include "pithread.h"
|
||||
#include "pifile.h"
|
||||
#ifdef WINDOWS
|
||||
//# include <.h>
|
||||
#else
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
/// events:
|
||||
/// execStarted(PIString program)
|
||||
/// execFinished(PIString program, int exit_code)
|
||||
///
|
||||
/// handlers:
|
||||
/// bool exec(const PIString & program)
|
||||
/// bool exec(const PIString & program, const PIString & arg1)
|
||||
/// bool exec(const PIString & program, const PIString & arg1, const PIString & arg2)
|
||||
/// bool exec(const PIString & program, const PIString & arg1, const PIString & arg2, const PIString & arg3)
|
||||
/// bool exec(const PIString & program, const PIStringList & args)
|
||||
/// void terminate()
|
||||
/// bool waitForFinish(int timeout_msecs = 60000)
|
||||
class PIP_EXPORT PIProcess: private PIThread
|
||||
{
|
||||
PIOBJECT(PIProcess)
|
||||
public:
|
||||
PIProcess();
|
||||
virtual ~PIProcess();
|
||||
|
||||
int exitCode() const {return exit_code;}
|
||||
int pID() const {
|
||||
#ifdef WINDOWS
|
||||
return pi.dwProcessId;
|
||||
#else
|
||||
return pid;
|
||||
#endif
|
||||
}
|
||||
|
||||
void setGrabInput(bool yes) {g_in = yes;}
|
||||
void setGrabOutput(bool yes) {g_out = yes;}
|
||||
void setGrabError(bool yes) {g_err = yes;}
|
||||
void setInputFile(const PIString & path) {f_in.setPath(path);}
|
||||
void setOutputFile(const PIString & path) {f_out.setPath(path);}
|
||||
void setErrorFile(const PIString & path) {f_err.setPath(path);}
|
||||
void unsetInputFile() {f_in.setPath("");}
|
||||
void unsetOutputFile() {f_out.setPath("");}
|
||||
void unsetErrorFile() {f_err.setPath("");}
|
||||
PIString workingDirectory() const {return wd;}
|
||||
void setWorkingDirectory(const PIString & path) {wd = path;}
|
||||
void resetWorkingDirectory() {wd.clear();}
|
||||
PIByteArray readOutput() {f_out.open(PIIODevice::ReadOnly); return f_out.readAll();}
|
||||
PIByteArray readError() {f_err.open(PIIODevice::ReadOnly); return f_err.readAll();}
|
||||
|
||||
PIStringList environment() {return env;}
|
||||
void clearEnvironment() {env.clear();}
|
||||
void removeEnvironmentVariable(const PIString & variable);
|
||||
void setEnvironmentVariable(const PIString & variable, const PIString & value);
|
||||
|
||||
EVENT_HANDLER1(void, exec, const PIString & , program) {args.clear(); args << program; exec_();}
|
||||
EVENT_HANDLER2(void, exec, const PIString & , program, const PIString & , arg) {args.clear(); args << program << arg; exec_();}
|
||||
EVENT_HANDLER3(void, exec, const PIString & , program, const PIString & , arg1, const PIString & , arg2) {args.clear(); args << program << arg1 << arg2; exec_();}
|
||||
EVENT_HANDLER4(void, exec, const PIString & , program, const PIString & , arg1, const PIString & , arg2, const PIString & , arg3) {args.clear(); args << program << arg1 << arg2 << arg3; exec_();}
|
||||
EVENT_HANDLER2(void, exec, const PIString & , program, const PIStringList & , args_) {args << program << args_; exec_();}
|
||||
EVENT_HANDLER(void, terminate) {
|
||||
#ifdef WINDOWS
|
||||
if (is_exec) if (!TerminateProcess(pi.hProcess, 0)) return; pi.dwProcessId = 0;
|
||||
#else
|
||||
if (is_exec) kill(pid, SIGKILL); pid = 0;
|
||||
#endif
|
||||
}
|
||||
EVENT_HANDLER(bool, waitForFinish) {return waitForFinish(60000);}
|
||||
EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs) {return PIThread::waitForFinish(timeout_msecs);}
|
||||
|
||||
EVENT1(execStarted, PIString, program)
|
||||
EVENT2(execFinished, PIString, program, int, exit_code)
|
||||
|
||||
static PIStringList currentEnvironment() {PIStringList l; int i = 0; while (environ[i] != 0) {l << environ[i]; ++i;} return l;}
|
||||
static int currentPID() {
|
||||
#ifdef WINDOWS
|
||||
return GetCurrentProcessId();
|
||||
#else
|
||||
return getpid();
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void run();
|
||||
void exec_();
|
||||
|
||||
PIStringList args, env;
|
||||
PIString wd;
|
||||
PIByteArray out;
|
||||
PIFile f_in, f_out, f_err;
|
||||
bool g_in, g_out, g_err, t_in, t_out, t_err;
|
||||
#ifdef WINDOWS
|
||||
STARTUPINFOA si;
|
||||
PROCESS_INFORMATION pi;
|
||||
#else
|
||||
pid_t pid;
|
||||
#endif
|
||||
FILE * tf_in, * tf_out, * tf_err;
|
||||
int exit_code, sz, as;
|
||||
bool is_exec;
|
||||
|
||||
};
|
||||
|
||||
#endif // PIPROCESS_H
|
||||
777
piprotocol.cpp
777
piprotocol.cpp
@@ -1,777 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Protocol, input/output channel (COM, UDP)
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com, Bychkov Andrey wapmobil@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piprotocol.h"
|
||||
|
||||
|
||||
/** \class PIProtocol
|
||||
* \brief
|
||||
* \details
|
||||
* \section PIProtocol_sec0 Synopsis
|
||||
*
|
||||
*
|
||||
*
|
||||
* */
|
||||
|
||||
|
||||
PIProtocol::PIProtocol(const PIString & config, const PIString & name_, void * recHeaderPtr, int recHeaderSize, void * recDataPtr, int recDataSize, void * sendDataPtr_, int sendDataSize_): PIObject() {
|
||||
init();
|
||||
protName = name_;
|
||||
PIObject::setName(name_);
|
||||
PIConfig conf(config, PIIODevice::ReadOnly);
|
||||
if (!conf.isOpened()) {
|
||||
piCoutObj << "Can`t open \"" << config << "\"!";
|
||||
devReceiverState = devSenderState = "Config error";
|
||||
return;
|
||||
}
|
||||
PIConfig::Entry & b(conf.getValue(name_)),
|
||||
& rb(b.getValue("receiver")),
|
||||
& sb(b.getValue("sender"));
|
||||
|
||||
init_receiver(b, rb, config);
|
||||
init_sender(b, sb, config);
|
||||
|
||||
headerPtr = (uchar * )recHeaderPtr;
|
||||
headerSize = recHeaderSize;
|
||||
dataPtr = (uchar * )recDataPtr;
|
||||
dataSize = recDataSize;
|
||||
sendDataPtr = (uchar * )sendDataPtr_;
|
||||
sendDataSize = sendDataSize_;
|
||||
packet_ext->setHeader(PIByteArray(recHeaderPtr, recHeaderSize));
|
||||
packet_ext->setPayloadSize(recDataSize);
|
||||
packet_ext->setPacketSize(recDataSize);
|
||||
packet_ext->setSplitMode(PIPacketExtractor::Header);
|
||||
bool null_h = (recHeaderPtr == 0 || recHeaderSize == 0), null_d = (recDataPtr == 0 || recDataSize == 0);
|
||||
if (null_h && null_d) packet_ext->setSplitMode(PIPacketExtractor::None);
|
||||
else {
|
||||
if (null_h) packet_ext->setSplitMode(PIPacketExtractor::Size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIProtocol::~PIProtocol() {
|
||||
//cout << "prot " << protName << " delete\n";
|
||||
if (history_write_rec) {
|
||||
if (history_file_rec.isEmpty()) {
|
||||
history_file_rec.close();
|
||||
history_file_rec.remove();
|
||||
}
|
||||
history_file_rec.close();
|
||||
}
|
||||
if (history_write_send) {
|
||||
if (history_file_send.isEmpty()) {
|
||||
history_file_send.close();
|
||||
history_file_send.remove();
|
||||
}
|
||||
history_file_send.close();
|
||||
}
|
||||
delete diagTimer;
|
||||
delete sendTimer;
|
||||
delete secTimer;
|
||||
delete packet_ext;
|
||||
if (eth != 0) delete eth;
|
||||
if (ser != 0) delete ser;
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::init() {
|
||||
packet_ext = new PIPacketExtractor(0, PIPacketExtractor::Header);
|
||||
packet_ext->setThreadedReadData(this);
|
||||
packet_ext->setThreadedReadSlot(receiveEvent);
|
||||
packet_ext->setHeaderCheckSlot(headerValidateEvent);
|
||||
work = new_mp_prot = history_write_rec = history_write_send = false;
|
||||
eth = 0;
|
||||
ser = 0;
|
||||
ret_func = 0;
|
||||
mp_owner = 0;
|
||||
net_diag = PIProtocol::Unknown;
|
||||
cur_pckt = 0;
|
||||
packets[0] = packets[1] = pckt_cnt = pckt_cnt_max = 0;
|
||||
diagTimer = 0;
|
||||
timeout_ = 3.f;
|
||||
sendTimer = new PITimer(sendEvent, this);
|
||||
diagTimer = new PITimer(diagEvent, this);
|
||||
secTimer = new PITimer(secEvent, this);
|
||||
wrong_count = receive_count = send_count = missed_count = 0;
|
||||
packets_in_sec = packets_out_sec = bytes_in_sec = bytes_out_sec = 0;
|
||||
immediate_freq = integral_freq = ifreq = 0.f;
|
||||
headerPtr = dataPtr = sendDataPtr = 0;
|
||||
headerSize = dataSize = sendDataSize = 0;
|
||||
type_rec = type_send = PIProtocol::None;
|
||||
devSenderState = devReceiverState = "Unknown";
|
||||
devSenderName = devReceiverName = "no device";
|
||||
history_rsize_rec = history_rsize_send = "no file";
|
||||
secTimer->start(1000.);
|
||||
/*addEvent("receiver started");
|
||||
addEvent("receiver stopped");
|
||||
addEvent("sender started");
|
||||
addEvent("sender stopped");
|
||||
addEvent<bool>("received");
|
||||
addEvent<PIProtocol::Quality>("quality changed");
|
||||
addEventHandler<float>(HANDLER(PIProtocol, startReceive));
|
||||
addEventHandler<float>(HANDLER(PIProtocol, startSend));
|
||||
addEventHandler(HANDLER(PIProtocol, start));
|
||||
addEventHandler(HANDLER(PIProtocol, stopReceive));
|
||||
addEventHandler(HANDLER(PIProtocol, stopSend));
|
||||
addEventHandler(HANDLER(PIProtocol, stop));*/
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::init_sender(PIConfig::Entry & b, PIConfig::Entry & sb, const PIString & config) {
|
||||
int ps, gps;
|
||||
bool ok, gok, flag, gflag, has_dev = false;
|
||||
float freq, gfreq;
|
||||
PIFlags<PISerial::Parameters> pp(0);
|
||||
PIString dev, gdev;
|
||||
|
||||
if (sb.isEntryExists("ip") && sb.isEntryExists("device")) {
|
||||
piCoutObj << "Ambiguous sender type in \"" << config << "\"!";
|
||||
devSenderState = "Config error";
|
||||
return;
|
||||
}
|
||||
dev = sb.getValue("ip", "", &ok);
|
||||
gdev = b.getValue("ip", "", &gok);
|
||||
has_dev = false;
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) dev = gdev;
|
||||
if (gok && ok && (dev != gdev)) {
|
||||
piCoutObj << "Ambiguous sender type in \"" << config << "\"!";
|
||||
devSenderState = "Config error";
|
||||
return;
|
||||
}
|
||||
ps = sb.getValue("port", 0, &ok);
|
||||
gps = b.getValue("port", 0, &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) ps = gps;
|
||||
if (gok && ok && (ps != gps)) {
|
||||
piCoutObj << "Ambiguous send port in \"" << config << "\"!";
|
||||
devSenderState = "Config error";
|
||||
return;
|
||||
}
|
||||
type_send = PIProtocol::Ethernet;
|
||||
if (eth == 0) eth = new PIEthernet();
|
||||
setSenderAddress(dev, ps);
|
||||
//setReceiverAddress(dev, ps);
|
||||
has_dev = true;
|
||||
flag = sb.getValue("reconnectEnabled", true, &ok);
|
||||
gflag = b.getValue("reconnectEnabled", true, &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) flag = gflag;
|
||||
if (gok && ok && (flag != gflag)) {
|
||||
piCoutObj << "Ambiguous \"reconnectEnabled\" flag in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
eth->setReopenEnabled(flag);
|
||||
}
|
||||
freq = sb.getValue("reconnectTimeout", 1., &ok);
|
||||
gfreq = b.getValue("reconnectTimeout", 1., &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) freq = gfreq;
|
||||
if (gok && ok && (freq != gfreq)) {
|
||||
piCoutObj << "Ambiguous \"reconnectTimeout\" value in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
eth->setReopenTimeout(freq * 1000);
|
||||
}
|
||||
/*if (sendDataPtr_ == 0)
|
||||
piCoutObj << "Warning: null send data pointer!";
|
||||
if (sendDataSize_ == 0)
|
||||
piCoutObj << "Warning: null send data size!";*/
|
||||
} else {
|
||||
piCoutObj << "Can`t find \"" << name() << ".sender.port\" or \"" << name() << ".port\" in \"" << config << "\"!";
|
||||
devSenderState = "Config error";
|
||||
return;
|
||||
}
|
||||
}
|
||||
dev = sb.getValue("device", "", &ok);
|
||||
gdev = b.getValue("device", "", &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) dev = gdev;
|
||||
if (gok && ok && (dev != gdev)) {
|
||||
piCoutObj << "Ambiguous sender type in \"" << config << "\"!";
|
||||
devSenderState = "Config error";
|
||||
return;
|
||||
}
|
||||
ps = sb.getValue("speed", 0, &ok);
|
||||
gps = b.getValue("speed", 0, &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) ps = gps;
|
||||
if (gok && ok && (ps != gps)) {
|
||||
piCoutObj << "Ambiguous send \"speed\" in \"" << config << "\"!";
|
||||
devSenderState = "Config error";
|
||||
return;
|
||||
}
|
||||
flag = sb.getValue("parity", false, &ok);
|
||||
gflag = b.getValue("parity", false, &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) flag = gflag;
|
||||
if (gok && ok && (flag != gflag)) {
|
||||
piCoutObj << "Ambiguous send \"parity\" in \"" << config << "\"!";
|
||||
devSenderState = "Config error";
|
||||
return;
|
||||
}
|
||||
pp.setFlag(PISerial::ParityControl, flag);
|
||||
}
|
||||
flag = sb.getValue("twoStopBits", false, &ok);
|
||||
gflag = b.getValue("twoStopBits", false, &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) flag = gflag;
|
||||
if (gok && ok && (flag != gflag)) {
|
||||
piCoutObj << "Ambiguous send \"twoStopBits\" parity in \"" << config << "\"!";
|
||||
devSenderState = "Config error";
|
||||
return;
|
||||
}
|
||||
pp.setFlag(PISerial::TwoStopBits, flag);
|
||||
}
|
||||
} else {
|
||||
piCoutObj << "Can`t find \"" << name() << ".sender.speed\" or \"" << name() << ".speed\" in \"" << config << "\"!";
|
||||
devSenderState = "Config error";
|
||||
return;
|
||||
}
|
||||
type_send = PIProtocol::Serial;
|
||||
if (ser == 0) ser = new PISerial(dev);
|
||||
setSenderDevice(dev, (PISerial::Speed)ps);
|
||||
ser->setOutSpeed((PISerial::Speed)ps);
|
||||
ser->setParameters(pp);
|
||||
has_dev = true;
|
||||
/*if (sendDataPtr_ == 0)
|
||||
piCoutObj << "Warning: null send data pointer!";
|
||||
if (sendDataSize_ == 0)
|
||||
piCoutObj << "Warning: null send data size!";*/
|
||||
}
|
||||
history_write_send = sb.getValue("writeHistory", false, &ok);
|
||||
bool ghist = b.getValue("writeHistory", false, &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) history_write_send = ghist;
|
||||
if (gok && ok && (history_write_send != ghist)) {
|
||||
piCoutObj << "Ambiguous sender history in \"" << config << "\"!";
|
||||
devSenderState = "Config error";
|
||||
return;
|
||||
}
|
||||
if (history_write_send) {
|
||||
history_path_send = sb.getValue("historyFile", "./history_" + protName + "_send_" +
|
||||
PIDate::current().toString("__dd_mm_yyyy_") +
|
||||
PITime::current().toString("_hh_mm_ss_")).value();
|
||||
history_id_send = sb.getValue("historyID", 0, &ok);
|
||||
if (!ok) {
|
||||
history_id_send = ushort(protName.toByteArray().checksumPlain32()) + 1;
|
||||
piCoutObj << "Warning: no sender history ID defined, write with ID = " << history_id_send;
|
||||
}
|
||||
history_file_send.open(history_path_send, PIIODevice::WriteOnly);
|
||||
}
|
||||
}
|
||||
freq = sb.getValue("frequency", -1.f, &ok);
|
||||
gfreq = b.getValue("frequency", -1.f, &gok);
|
||||
if (gok && !ok) freq = gfreq;
|
||||
if (gok && ok && (freq != gfreq)) {
|
||||
piCoutObj << "Ambiguous sender frequency in \"" << config << "\"!";
|
||||
devSenderState = "Config error";
|
||||
return;
|
||||
}
|
||||
if (freq > 0.f && !has_dev)
|
||||
piCoutObj << "Warning: no sender device and not null send frequency!";
|
||||
setSenderFrequency(freq);
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::init_receiver(PIConfig::Entry & b, PIConfig::Entry & rb, const PIString & config) {
|
||||
int ps, gps;
|
||||
bool ok, gok, flag, gflag, has_dev = false;
|
||||
float freq, gfreq;
|
||||
PIFlags<PISerial::Parameters> pp(0);
|
||||
PIString dev, gdev;
|
||||
|
||||
if (rb.isEntryExists("ip") && rb.isEntryExists("device")) {
|
||||
piCoutObj << "Ambiguous receiver type in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
dev = rb.getValue("ip", "", &ok);
|
||||
gdev = b.getValue("ip", "", &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) dev = gdev;
|
||||
if (gok && ok && (dev != gdev)) {
|
||||
piCoutObj << "Ambiguous receiver type in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
ps = rb.getValue("port", 0, &ok);
|
||||
gps = b.getValue("port", 0, &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) ps = gps;
|
||||
if (gok && ok && (ps != gps)) {
|
||||
piCoutObj << "Ambiguous receive port in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
type_rec = PIProtocol::Ethernet;
|
||||
eth = new PIEthernet();
|
||||
packet_ext->setDevice(eth);
|
||||
//setSenderAddress(dev, ps);
|
||||
setReceiverAddress(dev, ps);
|
||||
has_dev = true;
|
||||
flag = rb.getValue("reconnectEnabled", true, &ok);
|
||||
gflag = b.getValue("reconnectEnabled", true, &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) flag = gflag;
|
||||
if (gok && ok && (flag != gflag)) {
|
||||
piCoutObj << "Ambiguous \"reconnectEnabled\" flag in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
eth->setReopenEnabled(flag);
|
||||
}
|
||||
freq = rb.getValue("reconnectTimeout", 1., &ok);
|
||||
gfreq = b.getValue("reconnectTimeout", 1., &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) freq = gfreq;
|
||||
if (gok && ok && (freq != gfreq)) {
|
||||
piCoutObj << "Ambiguous \"reconnectTimeout\" value in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
eth->setReopenTimeout(freq * 1000);
|
||||
}
|
||||
/*if (recDataPtr == 0)
|
||||
piCoutObj << "Warning: null receive data pointer!";
|
||||
if (recDataSize == 0)
|
||||
piCoutObj << "Warning: null receive data size!";*/
|
||||
} else {
|
||||
piCoutObj << "Can`t find \"" << name() << ".receiver.port\" or \"" << name() << ".port\" in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
}
|
||||
dev = rb.getValue("device", "", &ok);
|
||||
gdev = b.getValue("device", "", &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) dev = gdev;
|
||||
if (gok && ok && (dev != gdev)) {
|
||||
piCoutObj << "Ambiguous receiver type in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
ps = rb.getValue("speed", 0, &ok);
|
||||
gps = b.getValue("speed", 0, &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) ps = gps;
|
||||
if (gok && ok && (ps != gps)) {
|
||||
piCoutObj << "Ambiguous receive \"speed\" in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
flag = rb.getValue("parity", false, &ok);
|
||||
gflag = b.getValue("parity", false, &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) flag = gflag;
|
||||
if (gok && ok && (flag != gflag)) {
|
||||
piCoutObj << "Ambiguous receive \"parity\" in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
pp.setFlag(PISerial::ParityControl, flag);
|
||||
}
|
||||
flag = rb.getValue("twoStopBits", false, &ok);
|
||||
gflag = b.getValue("twoStopBits", false, &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) flag = gflag;
|
||||
if (gok && ok && (flag != gflag)) {
|
||||
piCoutObj << "Ambiguous receive \"twoStopBits\" parity in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
pp.setFlag(PISerial::TwoStopBits, flag);
|
||||
}
|
||||
type_rec = PIProtocol::Serial;
|
||||
type_send = PIProtocol::Serial;
|
||||
ser = new PISerial(dev);
|
||||
packet_ext->setDevice(ser);
|
||||
//setSenderDevice(dev, (PISerial::Speed)ps);
|
||||
setReceiverDevice(dev, (PISerial::Speed)ps);
|
||||
ser->setInSpeed((PISerial::Speed)ps);
|
||||
ser->setParameters(pp);
|
||||
ps = rb.getValue("vtime", 1, &ok);
|
||||
gps = b.getValue("vtime", 1, &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) ps = gps;
|
||||
if (gok && ok && (ps != gps)) {
|
||||
piCoutObj << "Ambiguous receive \"vtime\" in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
ser->setVTime(ps);
|
||||
}
|
||||
has_dev = true;
|
||||
/*if (recDataPtr == 0)
|
||||
piCoutObj << "Warning: null receive data pointer!";
|
||||
if (recDataSize == 0)
|
||||
piCoutObj << "Warning: null receive data size!";*/
|
||||
} else {
|
||||
piCoutObj << "Can`t find \"" << name() << ".receiver.speed\" or \"" << name() << ".speed\" in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
}
|
||||
history_write_rec = rb.getValue("writeHistory", false, &ok);
|
||||
bool ghist = b.getValue("writeHistory", false, &gok);
|
||||
if (ok || gok) {
|
||||
if (gok && !ok) history_write_rec = ghist;
|
||||
if (gok && ok && (history_write_rec != ghist)) {
|
||||
piCoutObj << "Ambiguous receiver history in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
if (history_write_rec) {
|
||||
history_path_rec = rb.getValue("historyFile", "./history_" + protName + "_rec_" +
|
||||
PIDate::current().toString("__dd_mm_yyyy_") +
|
||||
PITime::current().toString("_hh_mm_ss_")).value();
|
||||
history_id_rec = rb.getValue("historyID", 0, &ok);
|
||||
if (!ok) {
|
||||
history_id_rec = ushort(protName.toByteArray().checksumPlain32());
|
||||
piCoutObj << "Warning: no receiver history ID defined, write with ID = " << history_id_rec;
|
||||
}
|
||||
history_file_rec.open(history_path_rec, PIIODevice::WriteOnly);
|
||||
}
|
||||
}
|
||||
freq = rb.getValue("frequency", -1.f, &ok);
|
||||
gfreq = b.getValue("frequency", -1.f, &gok);
|
||||
if (gok && !ok) freq = gfreq;
|
||||
if (gok && ok && (freq != gfreq)) {
|
||||
piCoutObj << "Ambiguous expected frequency in \"" << config << "\"!";
|
||||
devReceiverState = "Config error";
|
||||
return;
|
||||
}
|
||||
if (freq > 0.f && !has_dev)
|
||||
piCoutObj << "Warning: no receiver device and not null expected frequency!";
|
||||
float tm = b.getValue("disconnectTimeout", 3.f);
|
||||
if (tm <= 0.f)
|
||||
piCoutObj << "Warning: diconnect timeout <= 0 s!";
|
||||
timeout_ = (tm < 0.f) ? 0.f : tm;
|
||||
setExpectedFrequency(freq);
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::setReceiverDevice(const PIString & device, PISerial::Speed speed, bool force) {
|
||||
if (force) {
|
||||
type_send = type_rec = PIProtocol::Serial;
|
||||
if (ser == 0) {
|
||||
ser = new PISerial();
|
||||
packet_ext->setDevice(ser);
|
||||
}
|
||||
}
|
||||
if (type_rec == PIProtocol::Serial && ser != 0) {
|
||||
ser->setDevice(device);
|
||||
ser->setSpeed(speed);
|
||||
devReceiverName = device;
|
||||
devSenderName = device;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::setReceiverAddress(const PIString & ip, int port, bool force) {
|
||||
if (force) {
|
||||
type_rec = PIProtocol::Ethernet;
|
||||
if (eth == 0) {
|
||||
eth = new PIEthernet();
|
||||
packet_ext->setDevice(eth);
|
||||
}
|
||||
}
|
||||
if (type_rec == PIProtocol::Ethernet && eth != 0) {
|
||||
eth->setReadAddress(ip, port);
|
||||
if (ip.trimmed().isEmpty()) devReceiverName = "no ip";
|
||||
else devReceiverName = ip + ":" + PIString::fromNumber(port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::setSenderDevice(const PIString & device, PISerial::Speed speed, bool force) {
|
||||
if (force) {
|
||||
type_send = type_rec = PIProtocol::Serial;
|
||||
if (ser == 0) ser = new PISerial();
|
||||
}
|
||||
if (type_send == PIProtocol::Serial && ser != 0) {
|
||||
ser->setDevice(device);
|
||||
ser->setSpeed(speed);
|
||||
ser->open();
|
||||
devSenderName = device;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::setSenderAddress(const PIString & ip, int port, bool force) {
|
||||
if (force) {
|
||||
type_send = PIProtocol::Ethernet;
|
||||
if (eth == 0) eth = new PIEthernet();
|
||||
}
|
||||
if (type_send == PIProtocol::Ethernet && eth != 0) {
|
||||
eth->setSendAddress(ip, port);
|
||||
if (ip.isEmpty()) devSenderName = "no ip";
|
||||
else devSenderName = ip + ":" + PIString::fromNumber(port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::setSenderIP(const PIString & ip, bool force) {
|
||||
if (force) {
|
||||
type_send = PIProtocol::Ethernet;
|
||||
if (eth == 0) eth = new PIEthernet();
|
||||
}
|
||||
if (type_send == PIProtocol::Ethernet && eth != 0) {
|
||||
eth->setSendIP(ip);
|
||||
if (ip.isEmpty()) devSenderName = "no ip";
|
||||
else devSenderName = ip + ":" + PIString::fromNumber(eth->sendPort());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::setSenderPort(int port, bool force) {
|
||||
if (force) {
|
||||
type_send = PIProtocol::Ethernet;
|
||||
if (eth == 0) eth = new PIEthernet();
|
||||
}
|
||||
if (type_send == PIProtocol::Ethernet && eth != 0) {
|
||||
eth->setSendPort(port);
|
||||
if (eth->sendIP().isEmpty()) devSenderName = "no ip";
|
||||
else devSenderName = eth->sendIP() + ":" + PIString::fromNumber(port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::setExpectedFrequency(float frequency) {
|
||||
exp_freq = frequency;
|
||||
changeDisconnectTimeout();
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::changeDisconnectTimeout() {
|
||||
pckt_cnt_max = int(round(timeout_ * exp_freq));
|
||||
if (pckt_cnt_max < 3) pckt_cnt_max = 3;
|
||||
last_packets.resize(pckt_cnt_max);
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::startReceive(float exp_frequency) {
|
||||
if (exp_frequency > 0.f) exp_freq = exp_frequency;
|
||||
//if (type_rec == PIProtocol::Serial) ser->start();
|
||||
//if (type_rec == PIProtocol::Ethernet) eth->start();
|
||||
packet_ext->startThreadedRead();
|
||||
msleep(1);
|
||||
check_state();
|
||||
if (exp_freq <= 0.f) return;
|
||||
setExpectedFrequency(exp_freq);
|
||||
diagTimer->start(1000. / exp_freq);
|
||||
diagTimer->reset();
|
||||
receiverStarted();
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::startSend(float frequency) {
|
||||
//cout << "** start send " << send_freq << ", " << frequency << endl;
|
||||
if (frequency > 0.f) send_freq = frequency;
|
||||
msleep(1);
|
||||
check_state();
|
||||
if (send_freq <= 0.f) return;
|
||||
sendTimer->start(1000. / send_freq);
|
||||
diagTimer->reset();
|
||||
senderStarted();
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::stopReceive() {
|
||||
//if (type_rec == PIProtocol::Serial) ser->stop();
|
||||
//if (type_rec == PIProtocol::Ethernet) eth->stop();
|
||||
packet_ext->stop();
|
||||
diagTimer->stop();
|
||||
receiverStopped();
|
||||
}
|
||||
|
||||
|
||||
bool PIProtocol::receiveEvent(void * t, uchar * data, int size) {
|
||||
PIProtocol * p = (PIProtocol * )t;
|
||||
if (!p->receive(data, size)) return false;
|
||||
p->work = true;
|
||||
//p->lock();
|
||||
if (p->validate()) {
|
||||
if (p->history_write_rec) {
|
||||
p->history_file_rec.writeToBinLog(p->history_id_rec, data, size);
|
||||
p->history_rsize_rec.setReadableSize(p->history_file_rec.pos());
|
||||
}
|
||||
p->received(true);
|
||||
//p->unlock();
|
||||
p->ifreq = p->diagTimer->elapsed_m();
|
||||
if (p->ifreq > 0.) p->ifreq = 1000. / p->ifreq;
|
||||
p->diagTimer->reset();
|
||||
p->receive_count++;
|
||||
p->packets_in_sec++;
|
||||
p->bytes_in_sec += size;
|
||||
p->cur_pckt = 1;
|
||||
if (p->ret_func != 0) p->ret_func(p);
|
||||
if (p->mp_owner != 0) PIMultiProtocolBase::receiveEvent(p->mp_owner, p, true, data, size);
|
||||
return true;
|
||||
}
|
||||
p->received(false);
|
||||
//p->unlock();
|
||||
p->wrong_count++;
|
||||
if (p->mp_owner != 0) PIMultiProtocolBase::receiveEvent(p->mp_owner, p, false, data, size);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::diagEvent(void * t, int) {
|
||||
PIProtocol * p = (PIProtocol * )t;
|
||||
p->calc_freq();
|
||||
p->calc_diag();
|
||||
p->check_state();
|
||||
if (p->ser != 0) p->missed_count = p->packet_ext->missedPackets();
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::secEvent(void * t, int ) {
|
||||
PIProtocol * p = (PIProtocol * )t;
|
||||
p->speedIn = PIString::readableSize(p->bytes_in_sec) + "/s";
|
||||
p->speedOut = PIString::readableSize(p->bytes_out_sec) + "/s";
|
||||
p->bytes_in_sec = p->bytes_out_sec = p->packets_in_sec = p->packets_out_sec = 0;
|
||||
if (p->ser != 0) p->missed_count = p->packet_ext->missedPackets();
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::calc_diag() {
|
||||
PIProtocol::Quality diag;
|
||||
if (!work) {
|
||||
diag = PIProtocol::Unknown;
|
||||
return;
|
||||
}
|
||||
if (pckt_cnt < pckt_cnt_max) {
|
||||
last_packets[pckt_cnt] = cur_pckt;
|
||||
pckt_cnt++;
|
||||
} else {
|
||||
packets[(int)last_packets.back()]--;
|
||||
if (!last_packets.isEmpty()) last_packets.pop_back();
|
||||
last_packets.push_front(cur_pckt);
|
||||
}
|
||||
packets[(int)cur_pckt]++;
|
||||
cur_pckt = 0;
|
||||
float good_percents;
|
||||
good_percents = (float)packets[1] / pckt_cnt * 100.f;
|
||||
if (good_percents == 0.f) diag = PIProtocol::Failure;
|
||||
else if (good_percents <= 20.f) diag = PIProtocol::Bad;
|
||||
else if (good_percents > 20.f && good_percents <= 80.f) diag = PIProtocol::Average;
|
||||
else diag = PIProtocol::Good;
|
||||
if (diag != net_diag) {
|
||||
qualityChanged(diag, net_diag);
|
||||
net_diag = diag;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::calc_freq() {
|
||||
float tf;// = float(1000.f / diagTimer->elapsed_m());
|
||||
tf = immediate_freq = ifreq;
|
||||
ifreq = 0.f;
|
||||
if (last_freq.size_s() >= pckt_cnt_max && last_freq.size_s() > 0) last_freq.pop_front();
|
||||
last_freq.push_back(tf);
|
||||
tf = last_freq[0];
|
||||
for (uint i = 1; i < last_freq.size(); ++i)
|
||||
tf += last_freq[i];
|
||||
integral_freq = tf / last_freq.size();
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::check_state() {
|
||||
if (type_rec == PIProtocol::Serial) {
|
||||
if (ser != 0) {
|
||||
if (ser->isOpened()) devReceiverState = "Opened";
|
||||
else devReceiverState = "Not opened";
|
||||
}
|
||||
else devReceiverState = "Not exists";
|
||||
}
|
||||
if (type_rec == PIProtocol::Ethernet) {
|
||||
if (eth != 0) {
|
||||
if (eth->isOpened()) devReceiverState = "Opened";
|
||||
else devReceiverState = "Not opened";
|
||||
}
|
||||
else devReceiverState = "Not exists";
|
||||
}
|
||||
if (type_send == PIProtocol::Serial) {
|
||||
if (ser != 0) {
|
||||
if (ser->isOpened()) devSenderState = "Opened";
|
||||
else devSenderState = "Not opened";
|
||||
}
|
||||
else devSenderState = "Not exists";
|
||||
}
|
||||
if (type_send == PIProtocol::Ethernet) {
|
||||
if (eth != 0) {
|
||||
if (eth->isOpened()) devSenderState = "Opened";
|
||||
else devSenderState = "Not opened";
|
||||
}
|
||||
else devSenderState = "Not exists";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::send(const void * data, int size, bool direct) {
|
||||
if (!direct) {
|
||||
if (data == 0 || size == 0) return;
|
||||
if (!aboutSend()) return;
|
||||
}
|
||||
if (history_write_send) {
|
||||
history_file_send.writeToBinLog(history_id_send, data, size);
|
||||
history_rsize_send.setReadableSize(history_file_send.pos());
|
||||
}
|
||||
if (type_send == PIProtocol::Serial)
|
||||
if (ser->send(data, size)) {
|
||||
send_count++;
|
||||
packets_out_sec++;
|
||||
bytes_out_sec += size;
|
||||
}
|
||||
if (type_send == PIProtocol::Ethernet)
|
||||
if (eth->send(data, size)) {
|
||||
send_count++;
|
||||
packets_out_sec++;
|
||||
bytes_out_sec += size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIProtocol::send() {
|
||||
//lock();
|
||||
//memcpy(packet, sendDataPtr, sendDataSize);
|
||||
//unlock();
|
||||
//cout << "**send" << endl;
|
||||
if (!aboutSend()) return;
|
||||
if (sendDataPtr == 0 || sendDataSize == 0) return;
|
||||
if (history_write_send) {
|
||||
history_file_send.writeToBinLog(history_id_send, sendDataPtr, sendDataSize);
|
||||
history_rsize_send.setReadableSize(history_file_send.pos());
|
||||
}
|
||||
if (type_send == PIProtocol::Serial)
|
||||
if (ser->send(sendDataPtr, sendDataSize)) {
|
||||
send_count++;
|
||||
packets_out_sec++;
|
||||
bytes_out_sec += sendDataSize;
|
||||
}
|
||||
if (type_send == PIProtocol::Ethernet)
|
||||
if (eth->send(sendDataPtr, sendDataSize)) {
|
||||
send_count++;
|
||||
packets_out_sec++;
|
||||
bytes_out_sec += sendDataSize;
|
||||
}
|
||||
}
|
||||
248
piprotocol.h
248
piprotocol.h
@@ -1,248 +0,0 @@
|
||||
/*! \file piprotocol.h
|
||||
* \brief Highly configurable from file I/O channel
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Protocol, input/output channel (COM, UDP)
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com, Bychkov Andrey wapmobil@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIPROTOCOL_H
|
||||
#define PIPROTOCOL_H
|
||||
|
||||
#include "piserial.h"
|
||||
#include "piethernet.h"
|
||||
#include "pipacketextractor.h"
|
||||
#include "pitimer.h"
|
||||
#include "piconfig.h"
|
||||
#include "math.h"
|
||||
|
||||
class PIProtocol;
|
||||
|
||||
class PIP_EXPORT PIMultiProtocolBase: protected PIObject
|
||||
{
|
||||
PIOBJECT(PIMultiProtocolBase)
|
||||
friend class PIProtocol;
|
||||
public:
|
||||
PIMultiProtocolBase() {;}
|
||||
virtual ~PIMultiProtocolBase() {;}
|
||||
|
||||
protected:
|
||||
virtual void received(PIProtocol * prot, bool corrected, uchar * data, int size) {;}
|
||||
|
||||
private:
|
||||
static void receiveEvent(PIMultiProtocolBase * p, PIProtocol * prot, bool corrected, uchar * data, int size) {p->mutex_receive.lock(); p->received(prot, corrected, data, size); p->mutex_receive.unlock();}
|
||||
|
||||
PIMutex mutex_receive;
|
||||
|
||||
};
|
||||
|
||||
typedef void (*ReceiveFunc)(void * );
|
||||
|
||||
/// events:
|
||||
/// void receiverStarted()
|
||||
/// void receiverStopped()
|
||||
/// void senderStarted()
|
||||
/// void senderStopped()
|
||||
/// void received(bool validate_is_ok)
|
||||
/// void qualityChanged(PIProtocol::Quality old_quality, PIProtocol::Quality new_quality)
|
||||
///
|
||||
/// handlers:
|
||||
/// void startReceive(float exp_frequency = -1.f)
|
||||
/// void stopReceive()
|
||||
/// void startSend(float frequency = -1.f)
|
||||
/// void stopSend()
|
||||
/// void start()
|
||||
/// void stop()
|
||||
/// void send()
|
||||
/// void send(const void * data, int size, bool direct = false)
|
||||
class PIP_EXPORT PIProtocol: public PIObject
|
||||
{
|
||||
PIOBJECT(PIProtocol)
|
||||
friend class PIMultiProtocolBase;
|
||||
friend class PIMultiProtocol;
|
||||
enum Type {None, Serial, Ethernet};
|
||||
public:
|
||||
|
||||
//! Contructs an empty unconfigured protocol
|
||||
PIProtocol(): PIObject() {init();}
|
||||
|
||||
//! Contructs protocol configured from file "config", config file section "name"
|
||||
PIProtocol(const PIString & config, const PIString & name, void * recHeaderPtr = 0, int recHeaderSize = 0,
|
||||
void * recDataPtr = 0, int recDataSize = 0, void * sendDataPtr = 0, int sendDataSize = 0); // from config
|
||||
|
||||
virtual ~PIProtocol();
|
||||
|
||||
//! Connection quality
|
||||
enum Quality {
|
||||
Unknown /** Unknown, no one packet received yet */ = 1,
|
||||
Failure /** No connection, no one correct packet received for last period */ = 2,
|
||||
Bad /** Bad connection, correct packets received <= 20% */ = 3,
|
||||
Average /** Average connection, correct packets received > 20% and <= 80% */ = 4,
|
||||
Good /** Good connection, correct packets received > 80% */ = 5
|
||||
};
|
||||
|
||||
EVENT_HANDLER0(void, startReceive) {startReceive(-1.f);}
|
||||
EVENT_HANDLER1(void, startReceive, float, exp_frequency); // if "frequency = -1" used last passed value
|
||||
EVENT_HANDLER0(void, stopReceive);
|
||||
void setExpectedFrequency(float frequency); // for connection quality diagnostic
|
||||
void setReceiverDevice(const PIString & device, PISerial::Speed speed, bool force = false); // for Serial
|
||||
void setReceiverData(void * dataPtr, int dataSize) {this->dataPtr = (uchar * )dataPtr; this->dataSize = dataSize; packet_ext->setHeader(PIByteArray(headerPtr, headerSize)); packet_ext->setPayloadSize(dataSize); packet_ext->setPacketSize(dataSize);}
|
||||
void setReceiverDataHeader(void * headerPtr, int headerSize) {this->headerPtr = (uchar * )headerPtr; this->headerSize = headerSize; packet_ext->setHeader(PIByteArray(headerPtr, headerSize)); packet_ext->setPayloadSize(dataSize); packet_ext->setPacketSize(dataSize);}
|
||||
void setReceiverAddress(const PIString & ip, int port, bool force = false); // for Ethernet
|
||||
void setReceiverParameters(PIFlags<PISerial::Parameters> parameters) {if (type_rec == PIProtocol::Serial || type_send == PIProtocol::Serial) ser->setParameters(parameters);} // for Serial
|
||||
void setReceiveSlot(ReceiveFunc slot) {ret_func = slot;}
|
||||
float expectedFrequency() const {return exp_freq;}
|
||||
|
||||
EVENT_HANDLER0(void, startSend) {startSend(-1.f);} // if "frequency = -1" used last passed value
|
||||
EVENT_HANDLER1(void, startSend, float, frequency); // if "frequency = -1" used last passed value
|
||||
EVENT_HANDLER0(void, stopSend) {sendTimer->stop(); senderStopped();}
|
||||
void setSenderFrequency(float frequency) {send_freq = frequency;}
|
||||
void setSenderDevice(const PIString & device, PISerial::Speed speed, bool force = false); // for Serial
|
||||
void setSenderData(void * dataPtr, int dataSize) {sendDataPtr = (uchar * )dataPtr; sendDataSize = dataSize;}
|
||||
void setSenderAddress(const PIString & ip, int port, bool force = false); // for Ethernet
|
||||
void setSenderIP(const PIString & ip, bool force = false); // for Ethernet
|
||||
void setSenderPort(int port, bool force = false); // for Ethernet
|
||||
void setSenderParameters(PIFlags<PISerial::Parameters> parameters) {if (type_send == PIProtocol::Serial) ser->setParameters(parameters);} // for Serial
|
||||
float senderFrequency() const {return send_freq;}
|
||||
|
||||
EVENT_HANDLER0(void, start) {startReceive(); startSend();}
|
||||
EVENT_HANDLER0(void, stop) {stopReceive(); stopSend();}
|
||||
EVENT_HANDLER0(void, send);
|
||||
EVENT_HANDLER2(void, send, const void *, data, int, size) {send(data, size, false);}
|
||||
EVENT_HANDLER3(void, send, const void *, data, int, size, bool, direct);
|
||||
|
||||
void setName(const PIString & name) {protName = name; PIObject::setName(name);}
|
||||
PIString name() const {return protName;}
|
||||
void setDisconnectTimeout(float timeout) {timeout_ = timeout; changeDisconnectTimeout();}
|
||||
float disconnectTimeout() const {return timeout_;}
|
||||
const float * disconnectTimeout_ptr() const {return &timeout_;}
|
||||
float immediateFrequency() const {return immediate_freq;}
|
||||
float integralFrequency() const {return integral_freq;}
|
||||
const float * immediateFrequency_ptr() const {return &immediate_freq;}
|
||||
const float * integralFrequency_ptr() const {return &integral_freq;}
|
||||
ullong receiveCountPerSec() const {return packets_in_sec;}
|
||||
const ullong * receiveCountPerSec_ptr() const {return &packets_in_sec;}
|
||||
ullong sendCountPerSec() const {return packets_out_sec;}
|
||||
const ullong * sendCountPerSec_ptr() const {return &packets_out_sec;}
|
||||
ullong receiveBytesPerSec() const {return bytes_in_sec;}
|
||||
const ullong * receiveBytesPerSec_ptr() const {return &bytes_in_sec;}
|
||||
ullong sendBytesPerSec() const {return bytes_out_sec;}
|
||||
const ullong * sendBytesPerSec_ptr() const {return &bytes_out_sec;}
|
||||
ullong receiveCount() const {return receive_count;}
|
||||
const ullong * receiveCount_ptr() const {return &receive_count;}
|
||||
ullong wrongCount() const {return wrong_count;}
|
||||
const ullong * wrongCount_ptr() const {return &wrong_count;}
|
||||
ullong sendCount() const {return send_count;}
|
||||
const ullong * sendCount_ptr() const {return &send_count;}
|
||||
ullong missedCount() const {return missed_count;}
|
||||
const ullong * missedCount_ptr() const {return &missed_count;}
|
||||
PIProtocol::Quality quality() const {return net_diag;} // receive quality
|
||||
const int * quality_ptr() const {return (int * )&net_diag;} // receive quality pointer
|
||||
PIString receiverDeviceName() const {return devReceiverName;}
|
||||
PIString senderDeviceName() const {return devSenderName;}
|
||||
PIString receiverDeviceState() const {return devReceiverState;}
|
||||
const PIString * receiverDeviceState_ptr() const {return &devReceiverState;}
|
||||
PIString senderDeviceState() const {return devSenderState;}
|
||||
const PIString * senderDeviceState_ptr() const {return &devSenderState;}
|
||||
PIString receiveSpeed() const {return speedIn;}
|
||||
const PIString * receiveSpeed_ptr() const {return &speedIn;}
|
||||
PIString sendSpeed() const {return speedOut;}
|
||||
const PIString * sendSpeed_ptr() const {return &speedOut;}
|
||||
PIString receiverHistorySize() const {return history_rsize_rec;}
|
||||
const PIString * receiverHistorySize_ptr() const {return &history_rsize_rec;}
|
||||
PIString senderHistorySize() const {return history_rsize_send;}
|
||||
const PIString * senderHistorySize_ptr() const {return &history_rsize_send;}
|
||||
bool writeReceiverHistory() const {return history_write_rec;}
|
||||
const bool * writeReceiverHistory_ptr() const {return &history_write_rec;}
|
||||
bool writeSenderHistory() const {return history_write_send;}
|
||||
const bool * writeSenderHistory_ptr() const {return &history_write_send;}
|
||||
|
||||
void * receiveData() {return dataPtr;}
|
||||
void * sendData() {return sendDataPtr;}
|
||||
|
||||
PIPacketExtractor * packetExtractor() {return packet_ext;}
|
||||
PIByteArray lastHeader() {return packet_ext->lastHeader();}
|
||||
|
||||
EVENT0(receiverStarted)
|
||||
EVENT0(receiverStopped)
|
||||
EVENT0(senderStarted)
|
||||
EVENT0(senderStopped)
|
||||
EVENT1(received, bool, validate_is_ok)
|
||||
EVENT2(qualityChanged, PIProtocol::Quality, new_quality, PIProtocol::Quality, old_quality)
|
||||
|
||||
protected:
|
||||
virtual bool receive(uchar * data, int size) {if (dataPtr != 0) memcpy(dataPtr, data, size); return true;} // executed when raw data received, break if 'false' return
|
||||
virtual bool validate() {return true;} // function for validate algorithm and save data from dataPtr to external struct
|
||||
virtual bool headerValidate(uchar * src, uchar * rec, int size) {for (int i = 0; i < size; ++i) if (src[i] != rec[i]) return false; return true;} // function for validate header (COM-port and headerSize > 0)
|
||||
virtual uint checksum_i(void * data, int size) { // function for checksum (uint)
|
||||
uint c = 0;
|
||||
for (int i = 0; i < size; ++i)
|
||||
c += ((uchar*)data)[i];
|
||||
return ~(c + 1);
|
||||
}
|
||||
virtual uchar checksum_c(void * data, int size) { // function for checksum (uchar)
|
||||
uchar c = 0;
|
||||
for (int i = 0; i < size; ++i)
|
||||
c += ((uchar*)data)[i];
|
||||
return ~(c + 1);
|
||||
}
|
||||
virtual bool aboutSend() {return true;} // executed before send data, if return 'false' then data is not sending
|
||||
|
||||
void init();
|
||||
void init_sender(PIConfig::Entry & b, PIConfig::Entry & sb, const PIString & config);
|
||||
void init_receiver(PIConfig::Entry & b, PIConfig::Entry & rb, const PIString & config);
|
||||
void check_state();
|
||||
void calc_freq();
|
||||
void calc_diag();
|
||||
|
||||
PISerial * ser;
|
||||
PIEthernet * eth;
|
||||
uint dataSize, headerSize, sendDataSize;
|
||||
uchar * dataPtr, * headerPtr, * sendDataPtr;
|
||||
|
||||
private:
|
||||
static void sendEvent(void * e, int) {((PIProtocol * )e)->send();}
|
||||
static bool receiveEvent(void * t, uchar * data, int size);
|
||||
static bool headerValidateEvent(void * t, uchar * src, uchar * rec, int size) {return ((PIProtocol * )t)->headerValidate(src, rec, size);}
|
||||
static void diagEvent(void * t, int);
|
||||
static void secEvent(void * t, int);
|
||||
|
||||
void setMultiProtocolOwner(PIMultiProtocolBase * mp) {mp_owner = mp;}
|
||||
PIMultiProtocolBase * multiProtocolOwner() const {return mp_owner;}
|
||||
void changeDisconnectTimeout();
|
||||
|
||||
ReceiveFunc ret_func;
|
||||
PIPacketExtractor * packet_ext;
|
||||
PITimer * diagTimer, * sendTimer, * secTimer;
|
||||
PIMultiProtocolBase * mp_owner;
|
||||
PIProtocol::Type type_send, type_rec;
|
||||
PIProtocol::Quality net_diag;
|
||||
PIDeque<float> last_freq;
|
||||
PIDeque<char> last_packets;
|
||||
PIString protName, devReceiverName, devReceiverState, devSenderName, devSenderState, speedIn, speedOut;
|
||||
PIString history_path_rec, history_path_send, history_rsize_rec, history_rsize_send;
|
||||
PIFile history_file_rec, history_file_send;
|
||||
ushort history_id_rec, history_id_send;
|
||||
bool work, new_mp_prot, history_write_rec, history_write_send;
|
||||
float exp_freq, send_freq, ifreq, immediate_freq, integral_freq, timeout_;
|
||||
int packets[2], pckt_cnt, pckt_cnt_max;
|
||||
char cur_pckt;
|
||||
ullong wrong_count, receive_count, send_count, missed_count, packets_in_sec, packets_out_sec, bytes_in_sec, bytes_out_sec;
|
||||
|
||||
};
|
||||
|
||||
#endif // PIPROTOCOL_H
|
||||
41
piqueue.h
41
piqueue.h
@@ -1,41 +0,0 @@
|
||||
/*! \file picontainers.h
|
||||
* \brief Queue container
|
||||
*
|
||||
* This file declare PIQueue
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Queue container
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIQUEUE_H
|
||||
#define PIQUEUE_H
|
||||
|
||||
#include "pivector.h"
|
||||
|
||||
template<typename T>
|
||||
class PIP_EXPORT PIQueue: public PIVector<T> {
|
||||
public:
|
||||
PIQueue() {;}
|
||||
PIVector<T> & enqueue(const T & v) {PIVector<T>::push_front(v); return *this;}
|
||||
T dequeue() {return PIVector<T>::take_back();}
|
||||
T & head() {return PIVector<T>::back();}
|
||||
const T & head() const {return PIVector<T>::back();}
|
||||
PIVector<T> toVector() {PIVector<T> v(PIVector<T>::size()); for (uint i = 0; i < PIVector<T>::size(); ++i) v[i] = PIVector<T>::at(i); return v;}
|
||||
};
|
||||
|
||||
#endif // PIQUEUE_H
|
||||
664
piserial.cpp
664
piserial.cpp
@@ -1,664 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
COM
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com, Bychkov Andrey wapmobil@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piserial.h"
|
||||
#include "piconfig.h"
|
||||
#include "pidir.h"
|
||||
|
||||
|
||||
/*! \class PISerial
|
||||
* \brief Serial device
|
||||
*
|
||||
* \section PISerial_sec0 Synopsis
|
||||
* This class provide access to serial device, e.g. COM port. It can read,
|
||||
* write, wait for write. There are several read and write functions.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
REGISTER_DEVICE(PISerial);
|
||||
|
||||
|
||||
PISerial::PISerial(): PIIODevice("", ReadWrite) {
|
||||
_init();
|
||||
}
|
||||
|
||||
|
||||
PISerial::PISerial(const PIString & device_, PISerial::Speed speed_, PIFlags<PISerial::Parameters> params_): PIIODevice(device_, ReadWrite) {
|
||||
_init();
|
||||
setPath(device_);
|
||||
setSpeed(speed_);
|
||||
setParameters(params_);
|
||||
}
|
||||
|
||||
|
||||
PISerial::~PISerial() {
|
||||
piMonitor.serials--;
|
||||
}
|
||||
|
||||
|
||||
void PISerial::_init() {
|
||||
fd = -1;
|
||||
piMonitor.serials++;
|
||||
setPriority(piHigh);
|
||||
block_read = true;
|
||||
vtime = 1;
|
||||
#ifdef WINDOWS
|
||||
block_write = true;
|
||||
hCom = 0;
|
||||
#endif
|
||||
setParameters(0);
|
||||
setSpeed(S115200);
|
||||
setDataBitsCount(8);
|
||||
//init();
|
||||
}
|
||||
|
||||
|
||||
void PISerial::setParameter(PISerial::Parameters parameter, bool on) {
|
||||
PIFlags<Parameters> cp = (PIFlags<Parameters>)(property("parameters").toInt());
|
||||
cp.setFlag(parameter, on);
|
||||
setParameters(cp);
|
||||
}
|
||||
|
||||
|
||||
bool PISerial::isParameterSet(PISerial::Parameters parameter) const {
|
||||
PIFlags<Parameters> cp = (PIFlags<Parameters>)(property("parameters").toInt());
|
||||
return cp[parameter];
|
||||
}
|
||||
|
||||
|
||||
bool PISerial::setPin(int number, bool on) {
|
||||
switch (number) {
|
||||
case 1: return setCAR(on); break;
|
||||
case 2: return setSR(on); break;
|
||||
case 3: return setST(on); break;
|
||||
case 4: return setDTR(on); break;
|
||||
case 5:
|
||||
piCoutObj << "Pin number 5 is ground";
|
||||
return false;
|
||||
case 6: return setDSR(on); break;
|
||||
case 7: return setRTS(on); break;
|
||||
case 8: return setCTS(on); break;
|
||||
case 9: return setRNG(on); break;
|
||||
default:
|
||||
piCoutObj << "Pin number " << number << " doesn`t exists!";
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PISerial::isPin(int number) const {
|
||||
switch (number) {
|
||||
case 1: return isCAR(); break;
|
||||
case 2: return isSR(); break;
|
||||
case 3: return isST(); break;
|
||||
case 4: return isDTR(); break;
|
||||
case 5: return false;
|
||||
case 6: return isDSR(); break;
|
||||
case 7: return isRTS(); break;
|
||||
case 8: return isCTS(); break;
|
||||
case 9: return isRNG(); break;
|
||||
default:
|
||||
piCoutObj << "Pin number " << number << " doesn`t exists!";
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PISerial::setBit(int bit, bool on, const PIString & bname) {
|
||||
#ifndef WINDOWS
|
||||
if (fd < 0) {
|
||||
piCoutObj << "setBit" << bname << " error: \"" << path() << "\" is not opened!";
|
||||
return false;
|
||||
}
|
||||
if (ioctl(fd, on ? TIOCMBIS : TIOCMBIC, &bit) < 0) {
|
||||
piCoutObj << "setBit" << bname << " error: " << errorString();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
piCoutObj << "setBit" << bname << " doesn`t implemented on Windows, sorry :-(";
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PISerial::isBit(int bit, const PIString & bname) const {
|
||||
#ifndef WINDOWS
|
||||
if (fd < 0) {
|
||||
piCoutObj << "isBit" << bname << " error: \"" << path() << "\" is not opened!";
|
||||
return false;
|
||||
}
|
||||
int ret = 0;
|
||||
if (ioctl(fd, TIOCMGET, &ret) < 0)
|
||||
piCoutObj << "isBit" << bname << " error: " << errorString();
|
||||
return ret & bit;
|
||||
#else
|
||||
piCoutObj << "isBit" << bname << " doesn`t implemented on Windows, sorry :-(";
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PISerial::closeDevice() {
|
||||
if (!isInitialized()) return true;
|
||||
if (isRunning()) {
|
||||
stop();
|
||||
PIThread::terminate();
|
||||
}
|
||||
if (fd != -1) {
|
||||
#ifdef WINDOWS
|
||||
SetCommState(hCom, &sdesc);
|
||||
SetCommMask(hCom, mask);
|
||||
CloseHandle(hCom);
|
||||
hCom = 0;
|
||||
#else
|
||||
tcsetattr(fd, TCSANOW, &sdesc);
|
||||
::close(fd);
|
||||
#endif
|
||||
fd = -1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int PISerial::convertSpeed(PISerial::Speed speed) {
|
||||
switch (speed) {
|
||||
case S50: return B50;
|
||||
case S75: return B75;
|
||||
case S110: return B110;
|
||||
case S300: return B300;
|
||||
case S600: return B600;
|
||||
case S1200: return B1200;
|
||||
case S2400: return B2400;
|
||||
case S4800: return B4800;
|
||||
case S9600: return B9600;
|
||||
case S19200: return B19200;
|
||||
case S38400: return B38400;
|
||||
case S57600: return B57600;
|
||||
case S115200: return B115200;
|
||||
case S1500000: return B1500000;
|
||||
case S2000000: return B2000000;
|
||||
case S2500000: return B2500000;
|
||||
case S3000000: return B3000000;
|
||||
case S3500000: return B3500000;
|
||||
case S4000000: return B4000000;
|
||||
default: break;
|
||||
}
|
||||
return B115200;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Advanced read function
|
||||
* \details Read to pointer "read_to" no more than "max_size" and no longer
|
||||
* than "timeout_ms" milliseconds. If "timeout_ms" < 0 function will be
|
||||
* wait forever until "max_size" will be readed. If size <= 0 function
|
||||
* immediate returns \b false. For read data with unknown size use function
|
||||
* \a readData().
|
||||
* \returns \b True if readed bytes count = "max_size", else \b false
|
||||
* \sa \a readData() */
|
||||
bool PISerial::read(void * data, int size, double timeout_ms) {
|
||||
if (data == 0 || size <= 0) return false;
|
||||
int ret, all = 0;
|
||||
if (timeout_ms > 0.) {
|
||||
setReadIsBlocking(false);
|
||||
all = read(data, 1);
|
||||
timer.reset();
|
||||
while (all < size && timer.elapsed_m() < timeout_ms) {
|
||||
ret = read(&((uchar * )data)[all], size - all);
|
||||
if (ret > 0) all += ret;
|
||||
else msleep(1);
|
||||
}
|
||||
received(data, all);
|
||||
return (all == size);
|
||||
} else {
|
||||
setReadIsBlocking(true);
|
||||
all = read(data, 1);
|
||||
while (all < size) {
|
||||
ret = read(&((uchar * )data)[all], size - all);
|
||||
if (ret > 0) all += ret;
|
||||
}
|
||||
received(data, all);
|
||||
return (all == size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Advanced read function
|
||||
* \details Read all or no more than "size" and no longer than
|
||||
* "timeout_ms" milliseconds. If "timeout_ms" < 0 function will be
|
||||
* wait forever until "size" will be readed. If "size" <= 0
|
||||
* function will be read all until "timeout_ms" elaped. \n If size <= 0
|
||||
* and "timeout_ms" <= 0 function immediate returns empty string.
|
||||
* \n This function similar to \a readData() but returns data as string.
|
||||
* \sa \a readData() */
|
||||
PIString PISerial::read(int size, double timeout_ms) {
|
||||
PIString str;
|
||||
if (size <= 0 && timeout_ms <= 0.) return str;
|
||||
int ret, all = 0;
|
||||
uchar td[1024];
|
||||
if (timeout_ms > 0.) {
|
||||
setReadIsBlocking(false);
|
||||
timer.reset();
|
||||
if (size <= 0) {
|
||||
while (timer.elapsed_m() < timeout_ms) {
|
||||
ret = read(td, 1024);
|
||||
if (ret <= 0) msleep(1);
|
||||
else str << PIString((char*)td, ret);
|
||||
}
|
||||
} else {
|
||||
while (all < size && timer.elapsed_m() < timeout_ms) {
|
||||
ret = read(td, size - all);
|
||||
if (ret <= 0) msleep(1);
|
||||
else {
|
||||
str << PIString((char*)td, ret);
|
||||
all += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setReadIsBlocking(true);
|
||||
all = read(td, 1);
|
||||
str << PIString((char*)td, all);
|
||||
while (all < size) {
|
||||
ret = read(td, size - all);
|
||||
if (ret <= 0) msleep(1);
|
||||
else {
|
||||
str << PIString((char*)td, ret);
|
||||
all += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
received(str.data(), str.size_s());
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Advanced read function
|
||||
* \details Read all or no more than "size" and no longer than
|
||||
* "timeout_ms" milliseconds. If "timeout_ms" < 0 function will be
|
||||
* wait forever until "size" will be readed. If "size" <= 0
|
||||
* function will be read all until "timeout_ms" elaped. \n If size <= 0
|
||||
* and "timeout_ms" <= 0 function immediate returns empty byte array.
|
||||
* \n This function similar to \a read() but returns data as byte array.
|
||||
* \sa \a read() */
|
||||
PIByteArray PISerial::readData(int size, double timeout_ms) {
|
||||
PIByteArray str;
|
||||
if (size <= 0 && timeout_ms <= 0.) return str;
|
||||
int ret, all = 0;
|
||||
uchar td[1024];
|
||||
if (timeout_ms > 0.) {
|
||||
setReadIsBlocking(false);
|
||||
timer.reset();
|
||||
if (size <= 0) {
|
||||
while (timer.elapsed_m() < timeout_ms) {
|
||||
ret = read(td, 1024);
|
||||
if (ret <= 0) msleep(1);
|
||||
else str.append(td, ret);
|
||||
}
|
||||
} else {
|
||||
while (all < size && timer.elapsed_m() < timeout_ms) {
|
||||
ret = read(td, size - all);
|
||||
if (ret <= 0) msleep(1);
|
||||
else {
|
||||
str.append(td, ret);
|
||||
all += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setReadIsBlocking(true);
|
||||
all = read(td, 1);
|
||||
str.append(td, all);
|
||||
while (all < size) {
|
||||
ret = read(td, size - all);
|
||||
if (ret <= 0) msleep(1);
|
||||
else {
|
||||
str.append(td, ret);
|
||||
all += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
received(str.data(), str.size_s());
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
bool PISerial::openDevice() {
|
||||
//piCout << "ser open" << path();
|
||||
if (path().isEmpty()) return false;
|
||||
#ifdef WINDOWS
|
||||
DWORD ds = 0, sm = 0;
|
||||
if (isReadable()) {ds |= GENERIC_READ; sm |= FILE_SHARE_READ;}
|
||||
if (isWriteable()) {ds |= GENERIC_WRITE; sm |= FILE_SHARE_WRITE;}
|
||||
PIString wp = "//./" + path();
|
||||
hCom = CreateFileA(wp.data(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||
if (hCom == INVALID_HANDLE_VALUE) {
|
||||
piCoutObj << "Unable to open \"" << path() << "\"";
|
||||
fd = -1;
|
||||
return false;
|
||||
}
|
||||
fd = 0;
|
||||
#else
|
||||
int om = 0;
|
||||
switch (mode()) {
|
||||
case PIIODevice::ReadOnly: om = O_RDONLY; break;
|
||||
case PIIODevice::WriteOnly: om = O_WRONLY; break;
|
||||
case PIIODevice::ReadWrite: om = O_RDWR; break;
|
||||
}
|
||||
//cout << "init ser " << path_ << " mode " << om << " param " << params << endl;
|
||||
fd = ::open(path().data(), O_NOCTTY | om);
|
||||
if (fd == -1) {
|
||||
piCoutObj << "Unable to open \"" << path() << "\"";
|
||||
return false;
|
||||
}
|
||||
tcgetattr(fd, &desc);
|
||||
sdesc = desc;
|
||||
//piCoutObj << "Initialized " << path_;
|
||||
#endif
|
||||
applySettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PISerial::applySettings() {
|
||||
#ifdef WINDOWS
|
||||
if (fd == -1) return;
|
||||
COMMTIMEOUTS times;
|
||||
times.ReadIntervalTimeout = block_read ? vtime : MAXDWORD;
|
||||
times.ReadTotalTimeoutConstant = block_read ? 0 : 1;
|
||||
times.ReadTotalTimeoutMultiplier = block_read ? 0 : MAXDWORD;
|
||||
times.WriteTotalTimeoutConstant = 0;
|
||||
times.WriteTotalTimeoutMultiplier = block_write ? 0 : 1;
|
||||
if (SetCommTimeouts(hCom, ×) == -1)
|
||||
piCoutObj << "Unable to set timeouts for \"" << path() << "\"";
|
||||
GetCommMask(hCom, &mask);
|
||||
SetCommMask(hCom, EV_RXCHAR);
|
||||
GetCommState(hCom, &sdesc);
|
||||
desc = sdesc;
|
||||
desc.DCBlength = sizeof(desc);
|
||||
desc.BaudRate = convertSpeed(outSpeed());
|
||||
if (dataBitsCount() >= 5 && dataBitsCount() <= 8)
|
||||
desc.ByteSize = dataBitsCount();
|
||||
else
|
||||
desc.ByteSize = 8;
|
||||
PIFlags<Parameters> params = parameters();
|
||||
if (params[PISerial::ParityControl]) {
|
||||
desc.fParity = 1;
|
||||
desc.Parity = params[PISerial::ParityOdd] ? 1 : 2;
|
||||
}
|
||||
desc.StopBits = params[PISerial::TwoStopBits] ? TWOSTOPBITS : ONESTOPBIT;
|
||||
if (SetCommState(hCom, &desc) == -1) {
|
||||
piCoutObj << "Unable to set comm state for \"" << path() << "\"";
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (fd == -1) return;
|
||||
tcgetattr(fd, &desc);
|
||||
desc.c_oflag = desc.c_lflag = desc.c_cflag = 0;
|
||||
desc.c_iflag = IGNBRK;
|
||||
desc.c_cflag = CLOCAL | HUPCL;
|
||||
switch (dataBitsCount()) {
|
||||
case 5: desc.c_cflag |= (CSIZE & CS5); break;
|
||||
case 6: desc.c_cflag |= (CSIZE & CS6); break;
|
||||
case 7: desc.c_cflag |= (CSIZE & CS7); break;
|
||||
case 8: default: desc.c_cflag |= (CSIZE & CS8); break;
|
||||
};
|
||||
if (isReadable()) desc.c_cflag |= CREAD;
|
||||
PIFlags<Parameters> params = parameters();
|
||||
if (params[PISerial::TwoStopBits]) desc.c_cflag |= CSTOPB;
|
||||
if (params[PISerial::ParityControl]) {
|
||||
desc.c_iflag |= INPCK;
|
||||
desc.c_cflag |= PARENB;
|
||||
if (params[PISerial::ParityOdd]) desc.c_cflag |= PARODD;
|
||||
}
|
||||
desc.c_cc[VMIN] = 1;
|
||||
desc.c_cc[VTIME] = vtime;
|
||||
|
||||
cfsetispeed(&desc, convertSpeed(inSpeed()));
|
||||
cfsetospeed(&desc, convertSpeed(outSpeed()));
|
||||
|
||||
tcflush(fd, TCIOFLUSH);
|
||||
fcntl(fd, F_SETFL, block_read ? 0 : O_NONBLOCK);
|
||||
|
||||
if(tcsetattr(fd, TCSANOW, &desc) < 0) {
|
||||
piCoutObj << "Can`t set attributes for \"" << path() << "\"";
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PISerial::setReadIsBlocking(bool yes) {
|
||||
block_read = yes;
|
||||
#ifdef WINDOWS
|
||||
COMMTIMEOUTS times;
|
||||
times.ReadIntervalTimeout = block_read ? vtime : MAXDWORD;
|
||||
times.ReadTotalTimeoutConstant = block_read ? 0 : 1;
|
||||
times.ReadTotalTimeoutMultiplier = block_read ? 0 : MAXDWORD;
|
||||
times.WriteTotalTimeoutConstant = 0;
|
||||
times.WriteTotalTimeoutMultiplier = block_write ? 0 : 1;
|
||||
if (isOpened()) SetCommTimeouts(hCom, ×);
|
||||
#else
|
||||
if (isOpened()) fcntl(fd, F_SETFL, yes ? 0 : O_NONBLOCK);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/** \brief Basic read function
|
||||
* \details Read to pointer "read_to" no more than "max_size". If read is
|
||||
* set to blocking this function will be wait at least one byte.
|
||||
* \returns Readed bytes count
|
||||
* \sa \a readData() */
|
||||
int PISerial::read(void * read_to, int max_size) {
|
||||
#ifdef WINDOWS
|
||||
if (!canRead()) return -1;
|
||||
WaitCommEvent(hCom, 0, 0);
|
||||
ReadFile(hCom, read_to, max_size, &readed, 0);
|
||||
return readed;
|
||||
#else
|
||||
if (!canRead()) return -1;
|
||||
return ::read(fd, read_to, max_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int PISerial::write(const void * data, int max_size, bool wait) {
|
||||
//piCoutObj << "send " << max_size << ": " << PIString((char*)data, max_size);
|
||||
if (fd == -1 || !canWrite()) {
|
||||
//piCoutObj << "Can`t write to uninitialized COM";
|
||||
return -1;
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
if (block_write != wait) {
|
||||
block_write = wait;
|
||||
setReadIsBlocking(block_read);
|
||||
}
|
||||
DWORD wrote;
|
||||
WriteFile(hCom, data, max_size, &wrote, 0);
|
||||
#else
|
||||
int wrote;
|
||||
wrote = ::write(fd, data, max_size);
|
||||
if (wait) tcdrain(fd);
|
||||
#endif
|
||||
return (int)wrote;
|
||||
//piCoutObj << "Error while sending";
|
||||
//piCoutObj << "Wrote " << wrote << " bytes in " << path_;
|
||||
}
|
||||
|
||||
|
||||
bool PISerial::configureDevice(const void * e_main, const void * e_parent) {
|
||||
PIConfig::Entry * em = (PIConfig::Entry * )e_main;
|
||||
PIConfig::Entry * ep = (PIConfig::Entry * )e_parent;
|
||||
setDevice(readDeviceSetting<PIString>("device", device(), em, ep));
|
||||
setSpeed((PISerial::Speed)(readDeviceSetting<int>("speed", (int)outSpeed(), em, ep)));
|
||||
setDataBitsCount(readDeviceSetting<int>("dataBitsCount", dataBitsCount(), em, ep));
|
||||
setParameter(PISerial::ParityControl, readDeviceSetting<bool>("parityControl", isParameterSet(PISerial::ParityControl), em, ep));
|
||||
setParameter(PISerial::ParityOdd, readDeviceSetting<bool>("parityOdd", isParameterSet(PISerial::ParityOdd), em, ep));
|
||||
setParameter(PISerial::TwoStopBits, readDeviceSetting<bool>("twoStopBits", isParameterSet(PISerial::TwoStopBits), em, ep));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PIString PISerial::constructFullPath() const {
|
||||
PIString ret(fullPathPrefix() + "://");
|
||||
ret << path() << ":" << int(inSpeed()) << ":" << dataBitsCount();
|
||||
if (parameters()[ParityControl]) {
|
||||
if (parameters()[ParityOdd]) ret << ":O";
|
||||
else ret << ":E";
|
||||
} else ret << ":N";
|
||||
if (parameters()[TwoStopBits]) ret << ":2";
|
||||
else ret << ":1";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PISerial::configureFromFullPath(const PIString & full_path) {
|
||||
PIStringList pl = full_path.split(":");
|
||||
for (int i = 0; i < pl.size_s(); ++i) {
|
||||
PIString p(pl[i]);
|
||||
switch (i) {
|
||||
case 0: setPath(p); break;
|
||||
case 1: setSpeed((Speed)(p.toInt())); break;
|
||||
case 2: setDataBitsCount(p.toInt()); break;
|
||||
case 3:
|
||||
p = p.toLowerCase();
|
||||
if (p != "n") setParameter(ParityControl);
|
||||
if (p == "o") setParameter(ParityOdd);
|
||||
break;
|
||||
case 4: if (p.toInt() == 2) setParameter(TwoStopBits); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIVector<int> PISerial::availableSpeeds() {
|
||||
PIVector<int> spds;
|
||||
spds << 50 << 75 << 110 << 300 << 600 << 1200 << 2400 << 4800 <<
|
||||
9600 << 19200 << 38400 << 57600 << 115200 << 1500000 <<
|
||||
2000000 << 2500000 << 3000000 << 3500000 << 4000000;
|
||||
return spds;
|
||||
}
|
||||
|
||||
|
||||
PIStringList PISerial::availableDevices(bool test) {
|
||||
PIStringList dl;
|
||||
#ifdef WINDOWS
|
||||
HKEY key = 0;
|
||||
RegOpenKey(HKEY_LOCAL_MACHINE, (LPCTSTR)"HARDWARE\\DEVICEMAP\\SERIALCOMM", &key);
|
||||
if (key != 0) {
|
||||
char name[1024], data[1024];
|
||||
DWORD name_len = 1024, data_len = 1024, type = 0, index = 0;
|
||||
LONG ret;
|
||||
while ((ret = RegEnumValue(key, index, (LPTSTR)name, &name_len, NULL, &type, (uchar * )data, &data_len)) != ERROR_NO_MORE_ITEMS) {
|
||||
dl << PIString(data);
|
||||
index++;
|
||||
}
|
||||
RegCloseKey(key);
|
||||
}
|
||||
#else
|
||||
# ifndef ANDROID
|
||||
PIStringList prefixes;
|
||||
# ifdef QNX
|
||||
prefixes << "ser";
|
||||
# else
|
||||
prefixes << "ttyS" << "ttyO" << "ttyUSB" << "ttyACM" << "ttyGS"
|
||||
<< "ttyMI" << "ttymxc" << "ttyAMA" << "rfcomm" << "ircomm";
|
||||
# ifdef FREE_BSD
|
||||
prefixes << "cu";
|
||||
# endif
|
||||
PIFile file_prefixes("/proc/tty/drivers", PIIODevice::ReadOnly);
|
||||
if (file_prefixes.open()) {
|
||||
PIString fc = file_prefixes.readAll(true), line, cpref;
|
||||
PIStringList words;
|
||||
file_prefixes.close();
|
||||
while (!fc.isEmpty()) {
|
||||
words.clear();
|
||||
line = fc.takeLine();
|
||||
if (line.isEmpty()) break;
|
||||
while (!line.isEmpty())
|
||||
words << line.takeWord();
|
||||
if (words.size_s() < 2) break;
|
||||
if (words.back() != "serial") continue;
|
||||
cpref = words[1];
|
||||
int li = cpref.findLast("/");
|
||||
if (li > 0) cpref.cutLeft(li + 1);
|
||||
prefixes << cpref;
|
||||
}
|
||||
prefixes.removeDuplicates();
|
||||
}
|
||||
# endif
|
||||
PIDir dir("/dev");
|
||||
PIVector<PIDir::DirEntry> de = dir.entries();
|
||||
piForeachC (PIDir::DirEntry & e, de) {
|
||||
piForeachC (PIString & p, prefixes) {
|
||||
if (e.name.left(p.size_s()) != p) continue;
|
||||
dl << "/dev/" + e.name;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
if (test) {
|
||||
for (int i = 0; i < dl.size_s(); ++i) {
|
||||
#ifdef WINDOWS
|
||||
void * hCom = CreateFileA(dl[i].data(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||
if (hCom == INVALID_HANDLE_VALUE) {
|
||||
#else
|
||||
int fd = ::open(dl[i].data(), O_NOCTTY | O_RDONLY);
|
||||
if (fd == -1) {
|
||||
#endif
|
||||
dl.remove(i);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
int void_ = 0;
|
||||
bool rok = true;
|
||||
#ifdef WINDOWS
|
||||
/*COMMTIMEOUTS times;
|
||||
times.ReadIntervalTimeout = MAXDWORD;
|
||||
times.ReadTotalTimeoutConstant = 0;
|
||||
times.ReadTotalTimeoutMultiplier = 0;
|
||||
times.WriteTotalTimeoutConstant = 1;
|
||||
times.WriteTotalTimeoutMultiplier = 0;
|
||||
SetCommTimeouts(hCom, ×);
|
||||
if (ReadFile(hCom, &void_, 1, &readed_, 0) == 0)
|
||||
rok = GetLastError() == ;*/
|
||||
#else
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
if (::read(fd, &void_, 1) == -1)
|
||||
rok = errno != EIO;
|
||||
|
||||
#endif
|
||||
if (!rok) {
|
||||
dl.remove(i);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
CloseHandle(hCom);
|
||||
#else
|
||||
::close(fd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return dl;
|
||||
}
|
||||
310
piserial.h
310
piserial.h
@@ -1,310 +0,0 @@
|
||||
/*! \file piserial.h
|
||||
* \brief Serial device
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
COM
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com, Bychkov Andrey wapmobil@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PISERIAL_H
|
||||
#define PISERIAL_H
|
||||
|
||||
#include "pitimer.h"
|
||||
#include "piiodevice.h"
|
||||
#ifndef WINDOWS
|
||||
# include <termios.h>
|
||||
# include <fcntl.h>
|
||||
# include <sys/ioctl.h>
|
||||
# ifndef B50
|
||||
# define B50 0000001
|
||||
# endif
|
||||
# ifndef B75
|
||||
# define B75 0000002
|
||||
# endif
|
||||
# ifndef B1500000
|
||||
# define B1500000 0010012
|
||||
# endif
|
||||
# ifndef B2000000
|
||||
# define B2000000 0010013
|
||||
# endif
|
||||
# ifndef B2500000
|
||||
# define B2500000 0010014
|
||||
# endif
|
||||
# ifndef B3000000
|
||||
# define B3000000 0010015
|
||||
# endif
|
||||
# ifndef B3500000
|
||||
# define B3500000 0010016
|
||||
# endif
|
||||
# ifndef B4000000
|
||||
# define B4000000 0010017
|
||||
# endif
|
||||
#else
|
||||
# define TIOCM_LE 1
|
||||
# define TIOCM_DTR 4
|
||||
# define TIOCM_RTS 7
|
||||
# define TIOCM_CTS 8
|
||||
# define TIOCM_ST 3
|
||||
# define TIOCM_SR 2
|
||||
# define TIOCM_CAR 1
|
||||
# define TIOCM_RNG 9
|
||||
# define TIOCM_DSR 6
|
||||
# define B50 50
|
||||
# define B75 75
|
||||
# define B110 110
|
||||
# define B300 300
|
||||
# define B600 600
|
||||
# define B1200 1200
|
||||
# define B2400 2400
|
||||
# define B4800 4800
|
||||
# define B9600 9600
|
||||
# define B14400 14400
|
||||
# define B19200 19200
|
||||
# define B38400 38400
|
||||
# define B57600 57600
|
||||
# define B115200 115200
|
||||
# define B128000 128000
|
||||
# define B256000 256000
|
||||
# define B1500000 1500000
|
||||
# define B2000000 2000000
|
||||
# define B2500000 2500000
|
||||
# define B3000000 3000000
|
||||
# define B3500000 3500000
|
||||
# define B4000000 4000000
|
||||
#endif
|
||||
#ifndef CRTSCTS
|
||||
# define CRTSCTS 020000000000
|
||||
#endif
|
||||
|
||||
|
||||
class PIP_EXPORT PISerial: public PIIODevice
|
||||
{
|
||||
PIIODEVICE(PISerial)
|
||||
public:
|
||||
|
||||
//! Contructs an empty %PISerial
|
||||
PISerial();
|
||||
|
||||
//! \brief Parameters of PISerial
|
||||
enum Parameters {
|
||||
ParityControl /*! Enable parity check and generate */ = 0x1,
|
||||
ParityOdd /*! Parity is odd instead of even */ = 0x2,
|
||||
TwoStopBits /*! Two stop bits instead of one */ = 0x4
|
||||
};
|
||||
|
||||
//! \brief Speed of PISerial
|
||||
enum Speed {
|
||||
S50 /*! 50 baud */ = 50,
|
||||
S75 /*! 75 baud */ = 75,
|
||||
S110 /*! 110 baud */ = 110,
|
||||
S300 /*! 300 baud */ = 300,
|
||||
S600 /*! 600 baud */ = 600,
|
||||
S1200 /*! 1200 baud */ = 1200,
|
||||
S2400 /*! 2400 baud */ = 2400,
|
||||
S4800 /*! 4800 baud */ = 4800,
|
||||
S9600 /*! 9600 baud */ = 9600,
|
||||
S19200 /*! 19200 baud */ = 19200,
|
||||
S38400 /*! 38400 baud */ = 38400,
|
||||
S57600 /*! 57600 baud */ = 57600,
|
||||
S115200 /*! 115200 baud */ = 115200,
|
||||
S1500000 = 1500000, // Linux only
|
||||
S2000000 = 2000000, // Linux only
|
||||
S2500000 = 2500000, // Linux only
|
||||
S3000000 = 3000000, // Linux only
|
||||
S3500000 = 3500000, // Linux only
|
||||
S4000000 = 4000000 // Linux only
|
||||
};
|
||||
|
||||
//! Contructs %PISerial with device name "device", speed "speed" and parameters "params"
|
||||
PISerial(const PIString & device, PISerial::Speed speed = S115200, PIFlags<PISerial::Parameters> params = 0);
|
||||
|
||||
~PISerial();
|
||||
|
||||
|
||||
//! Set both input and output speed to "speed"
|
||||
void setSpeed(PISerial::Speed speed) {setProperty("outSpeed", (int)speed); setProperty("inSpeed", (int)speed); applySettings();}
|
||||
|
||||
//! Set output speed to "speed"
|
||||
void setOutSpeed(PISerial::Speed speed) {setProperty("outSpeed", (int)speed); applySettings();}
|
||||
|
||||
//! Set input speed to "speed"
|
||||
void setInSpeed(PISerial::Speed speed) {setProperty("inSpeed", (int)speed); applySettings();}
|
||||
|
||||
//! Set device name to "dev"
|
||||
void setDevice(const PIString & dev) {setPath(dev); if (isOpened()) {close(); open();};}
|
||||
|
||||
|
||||
//! Set parameters to "parameters_"
|
||||
void setParameters(PIFlags<PISerial::Parameters> parameters_) {setProperty("parameters", (int)parameters_); applySettings();}
|
||||
|
||||
//! Set parameter "parameter" to "on" state
|
||||
void setParameter(PISerial::Parameters parameter, bool on = true);
|
||||
|
||||
//! Returns if parameter "parameter" is set
|
||||
bool isParameterSet(PISerial::Parameters parameter) const;
|
||||
|
||||
//! Returns parameters
|
||||
PIFlags<PISerial::Parameters> parameters() const {return (PIFlags<Parameters>)(property("parameters").toInt());}
|
||||
|
||||
|
||||
//! Set data bits count. Valid range is from 5 to 8, befault is 8
|
||||
void setDataBitsCount(int bits) {setProperty("dataBitsCount", bits); applySettings();}
|
||||
|
||||
//! Returns data bits count
|
||||
int dataBitsCount() const {return property("dataBitsCount").toInt();}
|
||||
|
||||
|
||||
//! Set pin number "number" to logic level "on". Valid numbers are 4 (DTR) and 7 (RTS)
|
||||
bool setPin(int number, bool on);
|
||||
|
||||
//! Returns pin number "number" logic level. Valid numbers range is from 1 to 9
|
||||
bool isPin(int number) const;
|
||||
|
||||
bool setLE(bool on) {return setBit(TIOCM_LE, on, "LE");} // useless function, just formally
|
||||
bool setDTR(bool on) {return setBit(TIOCM_DTR, on, "DTR");}
|
||||
bool setRTS(bool on) {return setBit(TIOCM_RTS, on, "RTS");}
|
||||
bool setCTS(bool on) {return setBit(TIOCM_CTS, on, "CTS");} // useless function, just formally
|
||||
bool setST(bool on) {return setBit(TIOCM_ST, on, "ST");} // useless function, just formally
|
||||
bool setSR(bool on) {return setBit(TIOCM_SR, on, "SR");} // useless function, just formally
|
||||
bool setCAR(bool on) {return setBit(TIOCM_CAR, on, "CAR");} // useless function, just formally
|
||||
bool setRNG(bool on) {return setBit(TIOCM_RNG, on, "RNG");} // useless function, just formally
|
||||
bool setDSR(bool on) {return setBit(TIOCM_DSR, on, "DSR");} // useless function, just formally
|
||||
|
||||
bool isLE() const {return isBit(TIOCM_LE, "LE");}
|
||||
bool isDTR() const {return isBit(TIOCM_DTR, "DTR");}
|
||||
bool isRTS() const {return isBit(TIOCM_RTS, "RTS");}
|
||||
bool isCTS() const {return isBit(TIOCM_CTS, "CTS");}
|
||||
bool isST() const {return isBit(TIOCM_ST, "ST");}
|
||||
bool isSR() const {return isBit(TIOCM_SR, "SR");}
|
||||
bool isCAR() const {return isBit(TIOCM_CAR, "CAR");}
|
||||
bool isRNG() const {return isBit(TIOCM_RNG, "RNG");}
|
||||
bool isDSR() const {return isBit(TIOCM_DSR, "DSR");}
|
||||
|
||||
void setVTime(int t) {vtime = t; applySettings();}
|
||||
|
||||
|
||||
//! Set read is blocking for function read(void * read_to, int max_size)
|
||||
void setReadIsBlocking(bool yes);
|
||||
|
||||
|
||||
//! Returns device name
|
||||
PIString device() const {return path();}
|
||||
|
||||
//! Returns output speed
|
||||
PISerial::Speed outSpeed() const {return (PISerial::Speed)(property("outSpeed").toInt());}
|
||||
|
||||
//! Returns input speed
|
||||
PISerial::Speed inSpeed() const {return (PISerial::Speed)(property("inSpeed").toInt());}
|
||||
|
||||
int VTime() const {return vtime;}
|
||||
|
||||
|
||||
//! Discard all buffered input and output data
|
||||
void flush() {
|
||||
#ifndef WINDOWS
|
||||
if (fd != -1) tcflush(fd, TCIOFLUSH);
|
||||
#endif
|
||||
}
|
||||
|
||||
int read(void * read_to, int max_size);
|
||||
bool read(void * read_to, int max_size, double timeout_ms);
|
||||
PIString read(int size = -1, double timeout_ms = 1000.);
|
||||
PIByteArray readData(int size = -1, double timeout_ms = 1000.);
|
||||
|
||||
|
||||
//! \brief Write to device data "data" with maximum size "max_size" and wait for data written if "wait" is \b true.
|
||||
//! \returns sended bytes count
|
||||
int write(const void * data, int max_size, bool wait = false);
|
||||
|
||||
//! \brief Write to device data "data" with maximum size "size" and wait for data written if "wait" is \b true.
|
||||
//! \returns \b true if sended bytes count = "size"
|
||||
bool send(const void * data, int size, bool wait = false) {return (write(data, size, wait) == size);}
|
||||
|
||||
//! \brief Write to device string "data" and wait for data written if "wait" is \b true.
|
||||
//! \returns \b true if sended bytes count = size of string
|
||||
bool send(const PIString & data, bool wait = false) {return (write(data.data(), data.lengthAscii(), wait) == data.size_s());}
|
||||
|
||||
//! \brief Write to device byte array "data" and wait for data written if "wait" is \b true.
|
||||
//! \returns \b true if sended bytes count = size of string
|
||||
bool send(const PIByteArray & data, bool wait = false) {return (write(data.data(), data.size_s(), wait) == data.size_s());}
|
||||
|
||||
PIString constructFullPath() const;
|
||||
|
||||
|
||||
//! \brief Returns all available speeds for serial devices
|
||||
static PIVector<int> availableSpeeds();
|
||||
|
||||
//! \brief Returns all available system devices. If "test" each device will be tried to open
|
||||
static PIStringList availableDevices(bool test = false);
|
||||
|
||||
//! \ioparams
|
||||
//! \{
|
||||
#ifdef DOXYGEN
|
||||
//! \brief device, default ""
|
||||
string device;
|
||||
|
||||
//! \brief input/output speed, default 115200
|
||||
int speed;
|
||||
|
||||
//! \brief dataBitsCount, default 8
|
||||
int dataBitsCount;
|
||||
|
||||
//! \brief parityControl, default false
|
||||
bool parityControl;
|
||||
|
||||
//! \brief parityOdd, default false
|
||||
bool parityOdd;
|
||||
|
||||
//! \brief twoStopBits, default false
|
||||
bool twoStopBits;
|
||||
#endif
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
PIString fullPathPrefix() const {return "ser";}
|
||||
void configureFromFullPath(const PIString & full_path);
|
||||
bool configureDevice(const void * e_main, const void * e_parent = 0);
|
||||
int write(const void * data, int max_size) {return write(data, max_size, true);}
|
||||
|
||||
//! Executes when any read function was successful. Default implementation does nothing
|
||||
virtual void received(const void * data, int size) {;}
|
||||
|
||||
void _init();
|
||||
void applySettings();
|
||||
int convertSpeed(PISerial::Speed speed);
|
||||
bool setBit(int bit, bool on, const PIString & bname);
|
||||
bool isBit(int bit, const PIString & bname) const;
|
||||
|
||||
bool openDevice();
|
||||
bool closeDevice();
|
||||
|
||||
#ifdef WINDOWS
|
||||
DCB desc, sdesc;
|
||||
void * hCom;
|
||||
DWORD readed, mask;
|
||||
bool block_write;
|
||||
#else
|
||||
termios desc, sdesc;
|
||||
uint readed;
|
||||
#endif
|
||||
int fd, vtime;
|
||||
bool block_read;
|
||||
PITimer timer;
|
||||
|
||||
};
|
||||
|
||||
#endif // PISERIAL_H
|
||||
111
pisignals.cpp
111
pisignals.cpp
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Signals
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pisignals.h"
|
||||
|
||||
PISignals::SignalEvent PISignals::ret_func;
|
||||
|
||||
|
||||
void PISignals::grabSignals(PIFlags<PISignals::Signal> signals_) {
|
||||
if (signals_[PISignals::Interrupt]) signal(signalCode(PISignals::Interrupt), PISignals::signal_event);
|
||||
if (signals_[PISignals::Illegal]) signal(signalCode(PISignals::Illegal), PISignals::signal_event);
|
||||
if (signals_[PISignals::Abort]) signal(signalCode(PISignals::Abort), PISignals::signal_event);
|
||||
if (signals_[PISignals::FPE]) signal(signalCode(PISignals::FPE), PISignals::signal_event);
|
||||
if (signals_[PISignals::SegFault]) signal(signalCode(PISignals::SegFault), PISignals::signal_event);
|
||||
if (signals_[PISignals::Termination]) signal(signalCode(PISignals::Termination), PISignals::signal_event);
|
||||
#ifndef WINDOWS
|
||||
if (signals_[PISignals::Hangup]) signal(signalCode(PISignals::Hangup), PISignals::signal_event);
|
||||
if (signals_[PISignals::Quit]) signal(signalCode(PISignals::Quit), PISignals::signal_event);
|
||||
if (signals_[PISignals::Kill]) signal(signalCode(PISignals::Kill), PISignals::signal_event);
|
||||
if (signals_[PISignals::BrokenPipe]) signal(signalCode(PISignals::BrokenPipe), PISignals::signal_event);
|
||||
if (signals_[PISignals::Timer]) signal(signalCode(PISignals::Timer), PISignals::signal_event);
|
||||
if (signals_[PISignals::UserDefined1]) signal(signalCode(PISignals::UserDefined1), PISignals::signal_event);
|
||||
if (signals_[PISignals::UserDefined2]) signal(signalCode(PISignals::UserDefined2), PISignals::signal_event);
|
||||
if (signals_[PISignals::ChildStopped]) signal(signalCode(PISignals::ChildStopped), PISignals::signal_event);
|
||||
if (signals_[PISignals::Continue]) signal(signalCode(PISignals::Continue), PISignals::signal_event);
|
||||
if (signals_[PISignals::StopProcess]) signal(signalCode(PISignals::StopProcess), PISignals::signal_event);
|
||||
if (signals_[PISignals::StopTTY]) signal(signalCode(PISignals::StopTTY), PISignals::signal_event);
|
||||
if (signals_[PISignals::StopTTYInput]) signal(signalCode(PISignals::StopTTYInput), PISignals::signal_event);
|
||||
if (signals_[PISignals::StopTTYOutput]) signal(signalCode(PISignals::StopTTYOutput), PISignals::signal_event);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int PISignals::signalCode(PISignals::Signal signal) {
|
||||
switch (signal) {
|
||||
case PISignals::Interrupt: return SIGINT;
|
||||
case PISignals::Illegal: return SIGILL;
|
||||
case PISignals::Abort: return SIGABRT;
|
||||
case PISignals::FPE: return SIGFPE;
|
||||
case PISignals::SegFault: return SIGSEGV;
|
||||
case PISignals::Termination: return SIGTERM;
|
||||
#ifndef WINDOWS
|
||||
case PISignals::Hangup: return SIGHUP;
|
||||
case PISignals::Quit: return SIGQUIT;
|
||||
case PISignals::Kill: return SIGKILL;
|
||||
case PISignals::BrokenPipe: return SIGPIPE;
|
||||
case PISignals::Timer: return SIGALRM;
|
||||
case PISignals::UserDefined1: return SIGUSR1;
|
||||
case PISignals::UserDefined2: return SIGUSR2;
|
||||
case PISignals::ChildStopped: return SIGCHLD;
|
||||
case PISignals::Continue: return SIGCONT;
|
||||
case PISignals::StopProcess: return SIGSTOP;
|
||||
case PISignals::StopTTY: return SIGTSTP;
|
||||
case PISignals::StopTTYInput: return SIGTTIN;
|
||||
case PISignals::StopTTYOutput:return SIGTTOU;
|
||||
#endif
|
||||
default:;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PISignals::Signal PISignals::signalFromCode(int signal) {
|
||||
switch (signal) {
|
||||
case SIGINT: return PISignals::Interrupt;
|
||||
case SIGILL: return PISignals::Illegal;
|
||||
case SIGABRT: return PISignals::Abort;
|
||||
case SIGFPE: return PISignals::FPE;
|
||||
case SIGSEGV: return PISignals::SegFault;
|
||||
case SIGTERM: return PISignals::Termination;
|
||||
#ifndef WINDOWS
|
||||
case SIGHUP: return PISignals::Hangup;
|
||||
case SIGQUIT: return PISignals::Quit;
|
||||
case SIGKILL: return PISignals::Kill;
|
||||
case SIGPIPE: return PISignals::BrokenPipe;
|
||||
case SIGALRM: return PISignals::Timer;
|
||||
case SIGUSR1: return PISignals::UserDefined1;
|
||||
case SIGUSR2: return PISignals::UserDefined2;
|
||||
case SIGCHLD: return PISignals::ChildStopped;
|
||||
case SIGCONT: return PISignals::Continue;
|
||||
case SIGSTOP: return PISignals::StopProcess;
|
||||
case SIGTSTP: return PISignals::StopTTY;
|
||||
case SIGTTIN: return PISignals::StopTTYInput;
|
||||
case SIGTTOU: return PISignals::StopTTYOutput;
|
||||
#endif
|
||||
default:;
|
||||
}
|
||||
return PISignals::Termination;
|
||||
}
|
||||
|
||||
|
||||
void PISignals::signal_event(int signal) {
|
||||
if (PISignals::ret_func == 0) return;
|
||||
PISignals::ret_func(PISignals::signalFromCode(signal));
|
||||
}
|
||||
76
pisignals.h
76
pisignals.h
@@ -1,76 +0,0 @@
|
||||
/*! \file pisignals.h
|
||||
* \brief System signals
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Signals
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PISIGNALS_H
|
||||
#define PISIGNALS_H
|
||||
|
||||
#include "picontainers.h"
|
||||
#include <csignal>
|
||||
|
||||
class PIP_EXPORT PISignals
|
||||
{
|
||||
public:
|
||||
enum Signal {
|
||||
Interrupt /** Interrupt from keyboard */ = 0x01, // Term Interrupt from keyboard
|
||||
Illegal /** Illegal Instruction */ = 0x02, // Core Illegal Instruction
|
||||
Abort /** Abort signal */ = 0x04, // Core Abort signal from abort
|
||||
FPE /** Floating point exception */ = 0x08, // Core Floating point exception
|
||||
SegFault /** Invalid memory reference */ = 0x10, // Core Invalid memory reference
|
||||
Termination /** Termination signal */ = 0x20, // Term Termination signal
|
||||
#ifndef WINDOWS
|
||||
Hangup = 0x40, // Term Hangup detected on controlling terminal or death of controlling process
|
||||
Quit = 0x80, // Core Quit from keyboard
|
||||
Kill = 0x100, // Term Kill signal
|
||||
BrokenPipe = 0x200, // Term Broken pipe: write to pipe with no readers
|
||||
Timer = 0x400, // Term Timer signal from alarm
|
||||
UserDefined1 = 0x800, // Term User-defined signal 1
|
||||
UserDefined2 = 0x1000, // Term User-defined signal 2
|
||||
ChildStopped = 0x2000, // Ign Child stopped or terminated
|
||||
Continue = 0x4000, // Cont Continue if stopped
|
||||
StopProcess = 0x8000, // Stop Stop process
|
||||
StopTTY = 0x10000, // Stop Stop typed at tty
|
||||
StopTTYInput = 0x20000, // Stop tty input for background process
|
||||
StopTTYOutput = 0x40000, // Stop tty output for background process
|
||||
#endif
|
||||
All = 0xFFFFF
|
||||
};
|
||||
|
||||
typedef void (*SignalEvent)(PISignals::Signal);
|
||||
// slot is any function format "void <func>(PISignals::Signal)"
|
||||
static void setSlot(SignalEvent slot) {ret_func = slot;}
|
||||
static void grabSignals(PIFlags<PISignals::Signal> signals_);
|
||||
static void raiseSignal(PISignals::Signal signal) {raise(signalCode(signal));}
|
||||
|
||||
private:
|
||||
PISignals() {ret_func = 0;}
|
||||
~PISignals() {}
|
||||
|
||||
static int signalCode(PISignals::Signal signal);
|
||||
static PISignals::Signal signalFromCode(int signal);
|
||||
static void signal_event(int signal);
|
||||
|
||||
static SignalEvent ret_func;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // PISIGNALS_H
|
||||
41
pistack.h
41
pistack.h
@@ -1,41 +0,0 @@
|
||||
/*! \file picontainers.h
|
||||
* \brief Stack container
|
||||
*
|
||||
* This file declare PIStack
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Stack container
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PISTACK_H
|
||||
#define PISTACK_H
|
||||
|
||||
#include "pivector.h"
|
||||
|
||||
template<typename T>
|
||||
class PIP_EXPORT PIStack: public PIVector<T> {
|
||||
public:
|
||||
PIStack() {;}
|
||||
PIVector<T> & push(const T & v) {PIVector<T>::push_back(v); return *this;}
|
||||
T pop() {return PIVector<T>::take_back();}
|
||||
T & top() {return PIVector<T>::back();}
|
||||
const T & top() const {return PIVector<T>::back();}
|
||||
PIVector<T> toVector() {PIVector<T> v(PIVector<T>::size()); for (uint i = 0; i < PIVector<T>::size(); ++i) v[i] = PIVector<T>::at(i); return v;}
|
||||
};
|
||||
|
||||
#endif // PISTACK_H
|
||||
333
pistatemachine.h
333
pistatemachine.h
@@ -1,333 +0,0 @@
|
||||
/*! \file pistatemachine.h
|
||||
* \brief Base class for custom state machine
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
State machine
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PISTATEMACHINE_H
|
||||
#define PISTATEMACHINE_H
|
||||
|
||||
#include "piobject.h"
|
||||
|
||||
/*! \brief Base class for custom state machine
|
||||
*
|
||||
* \section PIStateMachine_synopsis Synopsis
|
||||
* This class provide functionality of state machine.
|
||||
* You should inherit from this class, implement \a execution()
|
||||
* and \a transition() functions, set rules and periodically
|
||||
* call \a tick() function to proper work of machine.
|
||||
*
|
||||
* \section PIStateMachine_prepare Prepare for work
|
||||
* %State machine operates with "state", "rule" and "condition".
|
||||
* * "State" is some class (by default \c int), associated name and
|
||||
* optional "handler" - pointer to function executed on every \a tick();
|
||||
* * "Rule" define rule of transition from one machine state to other.
|
||||
* It is also has optional "handler";
|
||||
* * "Condition" is a part of rule and define possibility of transition.
|
||||
*
|
||||
* First of all you should define states of your machine by function
|
||||
* \a addState(). Then you should define transition rules for machine
|
||||
* by function \a addRule(). Finally you can set initial state by function
|
||||
* \a setInitialState() and provide periodically execution of function
|
||||
* \a tick().
|
||||
*
|
||||
* \section PIStateMachine_principle Principle of work
|
||||
* At any time the state machine is in some state. You can ask machine
|
||||
* to enter in new state by function \a switchToState(). If all conditions
|
||||
* done machine switch it state immediately, else machine remember request
|
||||
* and will be try switch to the new state every tick. Successfull state
|
||||
* switching execute function \a transition(), every tick execute
|
||||
* function \a execution() with current state. On successfull transition
|
||||
* if rule "handler" is not null it execute. Every \a tick() if current
|
||||
* state "handler" is not null it execute.
|
||||
*
|
||||
* \section PIStateMachine_conditions Conditions
|
||||
* Each rule has transition condition. Condition is array of pairs
|
||||
* (string, number). It means that every condition by name "string"
|
||||
* should be performed as least "number" times. Empty condition always
|
||||
* permits transition.
|
||||
*
|
||||
* %State machine have current performed conditions. You can read this
|
||||
* conditions by function \a currentConditions() and perform new
|
||||
* conditions by functions \a performCondition() and \a performConditions().
|
||||
* Currend conditions can de erased by function \a resetConditions().
|
||||
*
|
||||
* \section PIStateMachine_example Example
|
||||
* This is simple example demonstrates all features:
|
||||
* \snippet pistatemachine.cpp main
|
||||
*/
|
||||
template <typename Type = int>
|
||||
class PIP_EXPORT PIStateMachine: public PIObject
|
||||
{
|
||||
PIOBJECT(PIStateMachine)
|
||||
public:
|
||||
//! Constructs an empty state machine
|
||||
PIStateMachine(void * _parent = 0) {if (_parent == 0) parent_ = this; else parent_ = _parent; resetConditions();}
|
||||
~PIStateMachine() {;}
|
||||
|
||||
//! %Condition is a pair (string, number)
|
||||
typedef PIPair<PIString, int> Condition;
|
||||
|
||||
//! %Rule of transition between states of machine
|
||||
struct Rule {
|
||||
//! Constuctor
|
||||
Rule() {handler = 0;}
|
||||
//! Constuctor
|
||||
Rule(Type f, Type t, const PIStringList & c = PIStringList(), Handler h = 0, bool at = false, bool rac = false) {
|
||||
from = f;
|
||||
to = t;
|
||||
for (int i = 0; i < c.size_s(); ++i)
|
||||
conditions << Condition(c[i], 1);
|
||||
autoTransition = at;
|
||||
resetAllConditions = rac;
|
||||
handler = h;
|
||||
}
|
||||
//! Source state
|
||||
Type from;
|
||||
//! Destination state
|
||||
Type to;
|
||||
//! %Conditions of transition
|
||||
PIVector<Condition> conditions;
|
||||
//! Automatic transition
|
||||
bool autoTransition;
|
||||
//! Reset or not all performed conditions of machine on transition
|
||||
bool resetAllConditions;
|
||||
//! Pointer to function executed on transition
|
||||
Handler handler;
|
||||
//! Add condition of transition
|
||||
void addCondition(const PIString & name, int times = 1) {if (times > 0) conditions << Condition(name, times);}
|
||||
bool operator ==(const Rule & other) const {return (from == other.from) && (to == other.to);}
|
||||
bool operator !=(const Rule & other) const {return (from != other.from) || (to != other.to);}
|
||||
};
|
||||
|
||||
//! %State of machine
|
||||
struct State {
|
||||
//! Constuctor
|
||||
State() {handler = 0;}
|
||||
//! Constuctor
|
||||
State(Type v, const PIString & n = "", Handler h = 0) {value = v; name = n; handler = h;}
|
||||
//! %State value
|
||||
Type value;
|
||||
//! %State name
|
||||
PIString name;
|
||||
//! Pointer to function executed on tick
|
||||
Handler handler;
|
||||
bool operator ==(const State & other) const {return value == other.value;}
|
||||
bool operator !=(const State & other) const {return value != other.value;}
|
||||
};
|
||||
|
||||
void * parent() const {return parent_;}
|
||||
void setParent(void * parent) {parent_ = parent;}
|
||||
|
||||
//! Add state of machine
|
||||
void addState(Type value, const PIString & name = "", Handler handler = 0) {if (states_.contains(State(value, name))) return; states_ << State(value, name, handler);}
|
||||
|
||||
//! States count
|
||||
int statesCount() const {return states_.size_s();}
|
||||
|
||||
//! Remove all states
|
||||
void clearStates() {states_.clear();}
|
||||
|
||||
|
||||
//! Add rule of transition
|
||||
void addRule(Type from, Type to, const PIString & condition, Handler handler = 0, bool autoTransition = false, bool resetAllConditions = false) {if (rules_.contains(Rule(from, to))) return; rules_ << Rule(from, to, PIStringList(condition), handler, autoTransition, resetAllConditions);}
|
||||
|
||||
//! Add rule of transition
|
||||
void addRule(Type from, Type to, Handler handler, bool autoTransition = false, bool resetAllConditions = false) {if (rules_.contains(Rule(from, to))) return; rules_ << Rule(from, to, PIStringList(), handler, autoTransition, resetAllConditions);}
|
||||
|
||||
//! Add rule of transition
|
||||
void addRule(Type from, Type to, const PIStringList & conditions = PIStringList(), Handler handler = 0, bool autoTransition = false, bool resetAllConditions = false) {if (rules_.contains(Rule(from, to))) return; rules_ << Rule(from, to, conditions, handler, autoTransition, resetAllConditions);}
|
||||
|
||||
//! Add rule of transition
|
||||
void addRule(const Rule & rule) {if (rules_.contains(rule)) return; rules_ << rule;}
|
||||
|
||||
//! Rules count
|
||||
int rulesCount() const {return rules_.size_s();}
|
||||
|
||||
//! Remove all rules
|
||||
void clearRules() {rules_.clear();}
|
||||
|
||||
|
||||
//! Setup initial state. \a reset() will set machine state to "value"
|
||||
void setInitialState(Type value) {
|
||||
for (int i = 0; i < states_.size_s(); ++i)
|
||||
if (states_[i].value == value) {
|
||||
init_ = state_ = states_[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief Try to switch machine state to state "to"
|
||||
* \details If there is rule of transition exists and this rule conditions
|
||||
* is performed then machine switched to new state immediately. Otherwise machine
|
||||
* will be try to enter to new state every \a tick().
|
||||
* \return \c true if state switched immediately, otherwise \c false */
|
||||
bool switchToState(Type to) {
|
||||
switch_to = to;
|
||||
for (int i = 0; i < rules_.size_s(); ++i) {
|
||||
Rule & r(rules_[i]);
|
||||
if ((r.from != state_.value) || (r.to != to)) continue;
|
||||
if (!checkConditions(r)) continue;
|
||||
State ts = findState(to);
|
||||
if (r.handler != 0 && parent_ != 0) r.handler(parent_);
|
||||
transition(state_, ts);
|
||||
state_ = ts;
|
||||
resetConditions(r);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Reset machine state to initial and clear all conditions
|
||||
void reset() {state_ = init_; resetConditions();}
|
||||
|
||||
//! Returns current state of machine
|
||||
const State & currentState() const {return state_;}
|
||||
|
||||
|
||||
//! Reset all performed conditions
|
||||
void resetConditions() {cond.clear();}
|
||||
|
||||
//! Reset performed condition with name "name"
|
||||
void resetCondition(const PIString & name) {
|
||||
for (int i = 0; i < cond.size_s(); ++i)
|
||||
if (cond[i].first == name) {
|
||||
cond.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
//! Perform condition with name "name" "times" times.
|
||||
void performCondition(const PIString & name, int times = 1) {
|
||||
if (times <= 0) return;
|
||||
for (int i = 0; i < cond.size_s(); ++i)
|
||||
if (cond[i].first == name) {
|
||||
cond[i].second += times;
|
||||
return;
|
||||
}
|
||||
cond << Condition(name, times);
|
||||
}
|
||||
|
||||
//! Perform every condition with name from "names" one time.
|
||||
void performConditions(const PIStringList & names) {
|
||||
bool ok;
|
||||
for (int n = 0; n < names.size_s(); ++n) {
|
||||
ok = false;
|
||||
for (int i = 0; i < cond.size_s(); ++i) {
|
||||
if (cond[i].first == names[n]) {
|
||||
cond[i].second++;
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok) continue;
|
||||
cond << Condition(names[n], 1);
|
||||
}
|
||||
}
|
||||
|
||||
//! Returns all current performed conditions
|
||||
const PIVector<Condition> & currentConditions() const {return cond;}
|
||||
|
||||
Type * currentState_ptr() {return &state_.value;}
|
||||
int * conditionsCount_ptr() {static int c = 0; c = cond.size_s(); return &c;}
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void tick()
|
||||
//! \brief Main function of machine. Execute \a execution() and check if need to switch state
|
||||
|
||||
//! \fn void tick(void * data, int delim)
|
||||
//! \brief Main function of machine. Execute \a execution() and check if need to switch state
|
||||
|
||||
//! \}
|
||||
|
||||
EVENT_HANDLER(void, tick) {tick(0, 0);}
|
||||
EVENT_HANDLER2(void, tick, void * , data, int, delim) {
|
||||
execution(state_);
|
||||
if (state_.handler != 0 && parent_ != 0) state_.handler(parent_);
|
||||
if (switch_to != state_.value) switchToState(switch_to);
|
||||
else {
|
||||
piForeachC (Rule & r, rules_) {
|
||||
if (!r.autoTransition || r.from != state_.value) continue;
|
||||
if (checkConditions(r)) {
|
||||
switchToState(r.to);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//! Reimplement this function to process current state of machine
|
||||
virtual void execution(const State & state) {;}
|
||||
|
||||
//! Reimplement this function to process switching current state of machine
|
||||
virtual void transition(const State & from, const State & to) {;}
|
||||
|
||||
private:
|
||||
State findState(Type value) {
|
||||
for (int i = 0; i < states_.size_s(); ++i)
|
||||
if (states_[i].value == value)
|
||||
return states_[i];
|
||||
return State();
|
||||
}
|
||||
bool checkConditions(const Rule & rule) {
|
||||
//if (cond.size_s() < rule.conditions.size_s()) return false;
|
||||
int oc = 0;
|
||||
for (int i = 0; i < cond.size_s(); ++i) {
|
||||
PIString & rn(cond[i].first);
|
||||
for (int j = 0; j < rule.conditions.size_s(); ++j) {
|
||||
if (rn != rule.conditions[j].first) continue;
|
||||
if (cond[i].second < rule.conditions[j].second) return false;
|
||||
oc++;
|
||||
}
|
||||
}
|
||||
return (rule.conditions.size_s() == oc);
|
||||
}
|
||||
void resetConditions(const Rule & rule) {
|
||||
if (rule.resetAllConditions) {
|
||||
cond.clear();
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < cond.size_s(); ++i) {
|
||||
PIString & rn(cond[i].first);
|
||||
for (int j = 0; j < rule.conditions.size_s(); ++j) {
|
||||
if (rn != rule.conditions[j].first) continue;
|
||||
cond[i].second -= rule.conditions[j].second;
|
||||
if (cond[i].second <= 0) {
|
||||
cond.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PIVector<State> states_;
|
||||
PIVector<Rule> rules_;
|
||||
State init_, state_;
|
||||
Type switch_to;
|
||||
void * parent_;
|
||||
PIVector<Condition> cond;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // PISTATEMACHINE_H
|
||||
764
pistring.cpp
764
pistring.cpp
@@ -1,764 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
String
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pistring.h"
|
||||
|
||||
|
||||
/*! \class PIString
|
||||
* \brief String class
|
||||
* \details PIP use this class for use string information.
|
||||
*
|
||||
* \section PIString_sec0 Synopsis
|
||||
* This class based on \a PIVector to store information.
|
||||
* String is a sequence of \a PIChar and can contain multibyte
|
||||
* symbols. Therefore real memory size of string is symbols count * 4.
|
||||
* String can be constucted from many types of data and can be converted
|
||||
* to many types. There are man operators and handly functions to use
|
||||
* string as you wish.
|
||||
*
|
||||
* \section PIString_sec1 To/from data convertions
|
||||
* Most common constructor is \a PIString(const char * str), where "str"
|
||||
* is null-terminated string, e.g. \c "string". This is 7 chars with last char = 0.
|
||||
* Also you can constructs \a PIString from single \a PIChar, \a PIByteArray,
|
||||
* other \a PIString or sequency of the same characters with custom length.\n \n
|
||||
* This class has implicit conversions to <tt>const char * </tt> and
|
||||
* \c std::string. Also there are functions to make same convertions:
|
||||
* * \a data() - to <tt>const char * </tt>,
|
||||
* * \a stdString() - to \c std::string,
|
||||
* * \a toByteArray() - to \a PIByteArray.
|
||||
*
|
||||
* \section PIString_sec2 Numeric operations
|
||||
* You can get symbolic representation of any numeric value with function
|
||||
* \a setNumber(any integer value, int base = 10, bool * ok = 0). Default
|
||||
* arguments are set for decimal base system, but you can choose any system
|
||||
* from 2 to 40. There are the same static functions \a fromNumber(), that
|
||||
* returns \a PIString. \n
|
||||
* Also there is function \a setReadableSize() which is set human-readable
|
||||
* size in bytes, Kb, Mb, Gb or Pb. Static analog is \a readableSize().
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
const char PIString::toBaseN[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^'};
|
||||
const int PIString::fromBaseN[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
|
||||
|
||||
|
||||
void PIString::appendFromChars(const char * c, int s) {
|
||||
int sz;
|
||||
wchar_t wc;
|
||||
for (int i = 0; i < s; ++i) {
|
||||
if (/*isascii(c[i])*/c[i] >= 0) {
|
||||
push_back(PIChar(c[i]));
|
||||
continue;
|
||||
}
|
||||
sz = mbtowc(&wc, &(c[i]), 4);
|
||||
//cout << sz << endl;
|
||||
switch (sz) {
|
||||
case 4:
|
||||
push_back(PIChar(*(int*)&(c[i])));
|
||||
i += 3;
|
||||
continue;
|
||||
case 3:
|
||||
push_back(PIChar(*(int*)&(c[i])));
|
||||
back().ch &= 0xFFFFFF;
|
||||
i += 2;
|
||||
continue;
|
||||
case 2:
|
||||
push_back(PIChar(*(short * )&(c[i])));
|
||||
++i;
|
||||
continue;
|
||||
default:
|
||||
push_back(PIChar(c[i]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::operator +=(const char * str) {
|
||||
int l = 0;
|
||||
while (str[l] != '\0') ++l;
|
||||
appendFromChars(str, l);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::operator +=(const wchar_t * str) {
|
||||
//cout << "wc" << endl;
|
||||
int l = 0, sz;
|
||||
char * c = new char[MB_CUR_MAX];
|
||||
while (str[l] != 0) ++l;
|
||||
for (int i = 0; i < l; ++i) {
|
||||
sz = wctomb(c, str[i]);
|
||||
switch (sz) {
|
||||
case 4:
|
||||
push_back(PIChar(*(int*)c));
|
||||
continue;
|
||||
case 3:
|
||||
push_back(PIChar(*(int*)c));
|
||||
back().ch &= 0xFFFFFF;
|
||||
continue;
|
||||
case 2:
|
||||
push_back(PIChar(*(short * )c));
|
||||
continue;
|
||||
default:
|
||||
push_back(PIChar(c[0]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete[] c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAS_LOCALE
|
||||
PIString & PIString::operator +=(const wstring & str) {
|
||||
uint l = str.size();
|
||||
for (uint i = 0; i < l; ++i) push_back(str[i]);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
PIString & PIString::operator +=(const PIString & str) {
|
||||
//uint l = str.size();
|
||||
*((PIDeque<PIChar>*)this) << *((PIDeque<PIChar>*)&str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool PIString::operator ==(const PIString & str) const {
|
||||
uint l = str.size();
|
||||
if (size() != l) return false;
|
||||
for (uint i = 0; i < l; ++i)
|
||||
if (str[i] != at(i))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIString::operator !=(const PIString & str) const {
|
||||
uint l = str.size();
|
||||
if (size() != l) return true;
|
||||
for (uint i = 0; i < l; ++i)
|
||||
if (str[i] != at(i))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PIString::operator <(const PIString & str) const {
|
||||
uint l = str.size();
|
||||
if (size() < l) return true;
|
||||
if (size() > l) return false;
|
||||
for (uint i = 0; i < l; ++i) {
|
||||
if (str[i] == at(i)) continue;
|
||||
if (str[i] < at(i)) return true;
|
||||
else return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PIString::operator >(const PIString & str) const {
|
||||
uint l = str.size();
|
||||
if (size() < l) return false;
|
||||
if (size() > l) return true;
|
||||
for (uint i = 0; i < l; ++i) {
|
||||
if (str[i] == at(i)) continue;
|
||||
if (str[i] < at(i)) return false;
|
||||
else return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::mid(const int start, const int len) const {
|
||||
//PIString str;
|
||||
int s = start, l = len;
|
||||
if (l == 0) return PIString();
|
||||
if (s < 0) {
|
||||
l += s;
|
||||
s = 0;
|
||||
}
|
||||
if (l < 0) {
|
||||
//for (uint i = s; i < size(); ++i)
|
||||
// str += at(i);
|
||||
return PIString(&(at(s)), size() - s);
|
||||
} else {
|
||||
if (l > length() - s)
|
||||
l = length() - s;
|
||||
//for (int i = s; i < s + l; ++i)
|
||||
// str += at(i);
|
||||
return PIString(&(at(s)), l);
|
||||
}
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::cutMid(const int start, const int len) {
|
||||
int s = start, l = len;
|
||||
if (l == 0) return *this;
|
||||
if (s < 0) {
|
||||
l += s;
|
||||
s = 0;
|
||||
}
|
||||
if (l < 0)
|
||||
remove(s, size() - s);
|
||||
else {
|
||||
if (l > length() - s)
|
||||
l = length() - s;
|
||||
remove(s, l);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::trim() {
|
||||
int st = 0, fn = 0;
|
||||
for (int i = 0; i < length(); ++i)
|
||||
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12))
|
||||
{st = i; break;}
|
||||
for (int i = length() - 1; i >= 0; --i)
|
||||
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12))
|
||||
{fn = i; break;}
|
||||
//*this = mid(st, fn - st + 1);
|
||||
if (fn < size_s() - 1) cutRight(size_s() - fn - 1);
|
||||
if (st > 0) cutLeft(st);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::trimmed() const {
|
||||
int st = 0, fn = 0;
|
||||
for (int i = 0; i < length(); ++i)
|
||||
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12))
|
||||
{st = i; break;}
|
||||
for (int i = length() - 1; i >= 0; --i)
|
||||
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12))
|
||||
{fn = i; break;}
|
||||
return mid(st, fn - st + 1);
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::replace(int from, int count, const PIString & with) {
|
||||
if (count < length() - from) remove(from, count);
|
||||
else remove(from, length() - from);
|
||||
uint c = with.length();
|
||||
for (uint i = 0; i < c; ++i) insert(from + i, with[i]);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::replace(const PIString & what, const PIString & with, bool * ok) {
|
||||
//piCout << "replace" << what << with;
|
||||
if (what.isEmpty()) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
int s = find(what);
|
||||
if (s >= 0) replace(s, what.length(), with);
|
||||
if (ok != 0) *ok = (s >= 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::replaceAll(const PIString & what, const PIString & with) {
|
||||
if (what.isEmpty() || what == with) return *this;
|
||||
bool ok = true;
|
||||
while (ok) replace(what, with, &ok);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::insert(int index, const PIString & str) {
|
||||
//uint c = str.length();
|
||||
//for (uint i = 0; i < c; ++i) insert(index + i, str[i]);
|
||||
PIDeque<PIChar>::insert(index, *((const PIDeque<PIChar>*)&str));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIStringList PIString::split(const PIString & delim) const {
|
||||
PIStringList sl;
|
||||
if (isEmpty() || delim.isEmpty()) return sl;
|
||||
PIString ts(*this);
|
||||
int ci = ts.find(delim);
|
||||
while (ci >= 0) {
|
||||
sl << ts.left(ci);
|
||||
ts.cutLeft(ci + delim.length());
|
||||
ci = ts.find(delim);
|
||||
}
|
||||
if (ts.length() > 0) sl << ts;
|
||||
return sl;
|
||||
}
|
||||
|
||||
|
||||
int PIString::find(const char str, const int start) const {
|
||||
for (int i = start; i < length(); ++i)
|
||||
if (at(i) == str)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int PIString::find(const PIString str, const int start) const {
|
||||
int l = str.length();
|
||||
for (int i = start; i < length() - l + 1; ++i)
|
||||
if (mid(i, l) == str)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int PIString::findLast(const char str, const int start) const {
|
||||
for (int i = length() - 1; i >= start; --i)
|
||||
if (at(i) == str)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int PIString::findLast(const PIString str, const int start) const {
|
||||
int l = str.length();
|
||||
for (int i = length() - l; i >= start; --i)
|
||||
if (mid(i, l) == str)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int PIString::findWord(const PIString & word, const int start) const {
|
||||
int f = start - 1, tl = length(), wl = word.length();
|
||||
while ((f = find(word, f + 1)) >= 0) {
|
||||
bool ok = true;
|
||||
PIChar c;
|
||||
if (f > 0) {c = (*this)[f - 1]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) {ok = false; continue;}}
|
||||
if (f + wl < tl) {c = (*this)[f + wl]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) {ok = false; continue;}}
|
||||
if (ok) return f;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int PIString::findCWord(const PIString & word, const int start) const {
|
||||
int f = start - 1, tl = length(), wl = word.length();
|
||||
while ((f = find(word, f + 1)) >= 0) {
|
||||
bool ok = true;
|
||||
PIChar c;
|
||||
if (f > 0) {c = (*this)[f - 1]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r' || (c != '_' && !c.isAlpha() && !c.isDigit()))) {ok = false; continue;}}
|
||||
if (f + wl < tl) {c = (*this)[f + wl]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r' || (c != '_' && !c.isAlpha() && !c.isDigit()))) {ok = false; continue;}}
|
||||
if (ok) return f;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
bool PIString::startsWith(const PIString & str) const {
|
||||
if (size() < str.size()) return false;
|
||||
return str == left(str.size());
|
||||
}
|
||||
|
||||
|
||||
bool PIString::endsWith(const PIString & str) const {
|
||||
if (size() < str.size()) return false;
|
||||
return str == right(str.size());
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::takeSymbol() {
|
||||
PIString ret;
|
||||
int sz = size_s(), ss = -1;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
PIChar c = at(i);
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
|
||||
continue;
|
||||
ss = i;
|
||||
break;
|
||||
}
|
||||
if (ss < 0) return ret;
|
||||
ret = mid(ss, 1);
|
||||
cutLeft(ss + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::takeWord() {
|
||||
int sz = size_s(), ws = -1, we = -1;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
PIChar c = at(i);
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
||||
if (we < 0 && ws >= 0) {
|
||||
we = i;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (ws < 0) ws = i;
|
||||
if (we >= 0) break;
|
||||
}
|
||||
}
|
||||
PIString ret = mid(ws, we - ws);
|
||||
cutLeft(we < 0 ? sz : we);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::takeCWord() {
|
||||
PIString ret;
|
||||
int sz = size_s(), ws = -1, we = -1;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
PIChar c = at(i);
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
||||
if (we < 0 && ws >= 0) {
|
||||
we = i;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (ws < 0) {
|
||||
if (c.isAlpha() || c == '_')
|
||||
ws = i;
|
||||
else
|
||||
return ret;
|
||||
} else {
|
||||
if (!c.isAlpha() && !c.isDigit() && c != '_') {
|
||||
we = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (we >= 0) break;
|
||||
}
|
||||
}
|
||||
ret = mid(ws, we - ws);
|
||||
cutLeft(we < 0 ? sz : we);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::takeLine() {
|
||||
int sz = size_s(), le = -1;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
PIChar c = at(i);
|
||||
if (c == '\n') {
|
||||
le = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
PIString ret = left(le);
|
||||
if (!ret.isEmpty())
|
||||
if (ret.back() == '\r')
|
||||
ret.cutRight(1);
|
||||
cutLeft(le < 0 ? sz : le + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::takeNumber() {
|
||||
PIString ret;
|
||||
int sz = size_s(), ls = -1, le = -1, phase = 0;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
if (phase > 7) break;
|
||||
PIChar c = at(i);
|
||||
//piCout << "char " << c << "phase" << phase;
|
||||
switch (phase) {
|
||||
case 0: // trim
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
|
||||
continue;
|
||||
phase = 7;
|
||||
case 7: // sign
|
||||
if (c == '-' || c == '+') {ls = i; phase = 1; break;}
|
||||
case 1: // search start
|
||||
if (c >= '0' && c <= '9') {le = i; if (ls < 0) ls = i; phase = 2; break;}
|
||||
if (c == '.') {le = i; if (ls < 0) ls = i; phase = 3; break;}
|
||||
phase = 9;
|
||||
break;
|
||||
case 2: // integer
|
||||
if (c == '.') {le = i; phase = 3; break;}
|
||||
if (c == 'e' || c == 'E') {le = i; phase = 4; break;}
|
||||
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || c == 'x') {le = i; break;}
|
||||
phase = 6;
|
||||
break;
|
||||
case 3: // point
|
||||
if (c == 'e' || c == 'E') {le = i; phase = 4; break;}
|
||||
if (c >= '0' && c <= '9') {le = i; break;}
|
||||
phase = 6;
|
||||
break;
|
||||
case 4: // exp
|
||||
if ((c >= '0' && c <= '9') || c == '-' || c == '+') {le = i; phase = 5; break;}
|
||||
phase = 6;
|
||||
break;
|
||||
case 5: // power
|
||||
if (c >= '0' && c <= '9') {le = i; break;}
|
||||
phase = 6;
|
||||
break;
|
||||
case 6: // suffix
|
||||
if (c == 'f' || c == 's' || c == 'u' || c == 'l' || c == 'L') {le = i; break;}
|
||||
phase = 9;
|
||||
break;
|
||||
}
|
||||
if (phase == 6) {
|
||||
if (c == 'f' || c == 's' || c == 'u' || c == 'l' || c == 'L') le = i;
|
||||
else phase = 9;
|
||||
}
|
||||
}
|
||||
//piCout << ls << le;
|
||||
if (le < ls) return ret;
|
||||
ret = mid(ls, le - ls + 1);
|
||||
cutLeft(le + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::takeRange(const PIChar & start, const PIChar & end, const PIChar & shield) {
|
||||
PIString ret;
|
||||
bool trim_ = (start != ' ' && start != '\t' && start != '\n' && start != '\r'), eq = (start == end);
|
||||
int sz = size_s(), ls = -1, le = -1, cnt = 0;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
PIChar c = at(i);
|
||||
if (c == shield) {++i; continue;}
|
||||
if (trim_) {
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
|
||||
continue;
|
||||
trim_ = false;
|
||||
}
|
||||
if (eq) {
|
||||
if (c == start) {
|
||||
if (cnt == 0) ls = i;
|
||||
else {le = i; cnt = 0; break;}
|
||||
cnt++;
|
||||
}
|
||||
} else {
|
||||
if (c == start) {
|
||||
if (cnt == 0) ls = i;
|
||||
cnt++;
|
||||
}
|
||||
if (c == end) {
|
||||
cnt--;
|
||||
if (cnt == 0) le = i;
|
||||
}
|
||||
}
|
||||
if (cnt <= 0) break;
|
||||
}
|
||||
//piCout << ls << le << cnt;
|
||||
if (le < ls || ls < 0 || le < 0 || cnt != 0) return ret;
|
||||
ret = mid(ls + 1, le - ls - 1);
|
||||
cutLeft(le + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::toUpperCase() const {
|
||||
PIString str(*this);
|
||||
int l = str.size();
|
||||
for (int i = 0; i < l; ++i) str[i] = str[i].toUpper();
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::toLowerCase() const {
|
||||
PIString str(*this);
|
||||
int l = str.size();
|
||||
for (int i = 0; i < l; ++i) str[i] = str[i].toLower();
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
int PIString::lengthAscii() const {
|
||||
int j = 0;
|
||||
for (int i = 0; i < size_s(); ++i, ++j)
|
||||
if (!at(i).isAscii()) ++j;
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
const char * PIString::data() const {
|
||||
data_.clear();
|
||||
uint wc;
|
||||
uchar tc;
|
||||
//printf("PIString::data %d\n", size_s());
|
||||
for (int i = 0, j = 0; i < size_s(); ++i) {
|
||||
wc = uint(at(i).toInt());
|
||||
//printf("__%d_%d\n", i, wc);
|
||||
while (tc = wc & 0xFF, tc) {
|
||||
data_.push_back(uchar(tc)); ++j;
|
||||
wc >>= 8;
|
||||
//printf("____%d\n", wc);
|
||||
}
|
||||
/*if (at(i).isAscii())
|
||||
data_.push_back(uchar(at(i).toAscii()));
|
||||
else {
|
||||
data_.push_back((at(i).toCharPtr()[0])); ++j;
|
||||
data_.push_back((at(i).toCharPtr()[1]));
|
||||
}*/
|
||||
}
|
||||
data_.push_back(uchar('\0'));
|
||||
return (const char * )data_.data();
|
||||
}
|
||||
|
||||
|
||||
string PIString::convertToStd() const {
|
||||
string s;
|
||||
uint wc;
|
||||
uchar tc;
|
||||
if (size() > 0) {
|
||||
for (int i = 0; i < length(); ++i) {
|
||||
wc = uint(at(i).toInt());
|
||||
while (tc = wc & 0xFF, tc) {
|
||||
s.push_back(char(tc));
|
||||
wc >>= 8;
|
||||
}
|
||||
/*if (at(i).isAscii())
|
||||
s.push_back(at(i).toAscii());
|
||||
else {
|
||||
s.push_back(at(i).toCharPtr()[0]);
|
||||
s.push_back(at(i).toCharPtr()[1]);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
char PIString::toChar() const {
|
||||
PIString s(toNativeDecimalPoints());
|
||||
char v;
|
||||
sscanf(s.data(), "%c", &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
short PIString::toShort() const {
|
||||
PIString s(trimmed().toLowerCase().toNativeDecimalPoints());
|
||||
short v;
|
||||
if (s.left(2) == "0x") {sscanf(s.data(), "%hx", &v); return v;}
|
||||
if (s.left(1) == "0") {sscanf(s.data(), "%ho", &v); return v;}
|
||||
sscanf(s.data(), "%hd", &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
int PIString::toInt() const {
|
||||
PIString s(trimmed().toLowerCase().toNativeDecimalPoints());
|
||||
int v;
|
||||
if (s.left(2) == "0x") {sscanf(s.data(), "%x", &v); return v;}
|
||||
if (s.left(1) == "0") {sscanf(s.data(), "%o", &v); return v;}
|
||||
sscanf(s.data(), "%d", &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
long PIString::toLong() const {
|
||||
PIString s(trimmed().toLowerCase().toNativeDecimalPoints());
|
||||
long v;
|
||||
if (s.left(2) == "0x") {sscanf(s.data(), "%lx", &v); return v;}
|
||||
if (s.left(1) == "0") {sscanf(s.data(), "%lo", &v); return v;}
|
||||
sscanf(s.data(), "%ld", &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
llong PIString::toLLong() const {
|
||||
PIString s(trimmed().toLowerCase().toNativeDecimalPoints());
|
||||
llong v;
|
||||
if (s.left(2) == "0x") {sscanf(s.data(), "%llx", &v); return v;}
|
||||
if (s.left(1) == "0") {sscanf(s.data(), "%llo", &v); return v;}
|
||||
sscanf(s.data(), "%lld", &v);
|
||||
return v;
|
||||
}
|
||||
*/
|
||||
|
||||
PIString & PIString::setReadableSize(llong bytes) {
|
||||
clear();
|
||||
if (bytes < 1024) {*this += (PIString::fromNumber(bytes) + " B"); return *this;}
|
||||
double fres = bytes / 1024.;
|
||||
llong res = bytes / 1024;
|
||||
fres -= res;
|
||||
if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " kB"); return *this;}
|
||||
fres = res / 1024.;
|
||||
res /= 1024;
|
||||
fres -= res;
|
||||
if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " MB"); return *this;}
|
||||
fres = res / 1024.;
|
||||
res /= 1024;
|
||||
fres -= res;
|
||||
if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " GB"); return *this;}
|
||||
fres = res / 1024.;
|
||||
res /= 1024;
|
||||
fres -= res;
|
||||
if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " TB"); return *this;}
|
||||
fres = res / 1024.;
|
||||
res /= 1024;
|
||||
fres -= res;
|
||||
*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " PB");
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline char chrUpr(char c) {
|
||||
if (c >= 'a' && c <= 'z') return c + 'A' - 'a';
|
||||
//if (c >= 'а' && c <= 'я') return c + 'А' - 'а';
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
inline char chrLwr(char c) {
|
||||
if (c >= 'A' && c <= 'Z') return c + 'a' - 'A';
|
||||
//if (c >= 'А' && c <= 'Я') return c + 'а' - 'А';
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PIStringList& PIStringList::removeDuplicates() {
|
||||
PIStringList l;
|
||||
PIString s;
|
||||
bool ae;
|
||||
for (int i = 0; i < size_s(); ++i) {
|
||||
ae = false;
|
||||
s = at(i);
|
||||
for (int j = 0; j < l.size_s(); ++j) {
|
||||
if (s != l[j]) continue;
|
||||
ae = true; break;
|
||||
}
|
||||
if (!ae) {
|
||||
l << s;
|
||||
continue;
|
||||
}
|
||||
remove(i);
|
||||
--i;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
901
pistring.h
901
pistring.h
@@ -1,901 +0,0 @@
|
||||
/*! \file pistring.h
|
||||
* \brief String
|
||||
*
|
||||
* This file declare string and string list classes
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
String
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PISTRING_H
|
||||
#define PISTRING_H
|
||||
|
||||
#include "pibytearray.h"
|
||||
#include "pichar.h"
|
||||
#include "math.h"
|
||||
|
||||
class PIStringList;
|
||||
|
||||
class PIP_EXPORT PIString: public PIDeque<PIChar>
|
||||
{
|
||||
public:
|
||||
//! Contructs an empty string
|
||||
PIString(): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--;}
|
||||
|
||||
//inline PIString & operator +=(const char c) {push_back(c); return *this;}
|
||||
PIString & operator +=(const PIChar & c) {push_back(c); return *this;}
|
||||
PIString & operator +=(const char * str);
|
||||
PIString & operator +=(const wchar_t * str);
|
||||
PIString & operator +=(const string & str) {appendFromChars(str.c_str(), str.length()); return *this;}
|
||||
PIString & operator +=(const PIByteArray & ba) {appendFromChars((const char * )ba.data(), ba.size_s()); return *this;}
|
||||
PIString & operator +=(const PIString & str);
|
||||
#ifdef HAS_LOCALE
|
||||
PIString & operator +=(const wstring & str);
|
||||
#endif
|
||||
|
||||
//PIString(const char c) {*this += c;}
|
||||
PIString(const PIString & o): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this += o;}
|
||||
|
||||
|
||||
//! Contructs string with single symbol "c"
|
||||
PIString(const PIChar & c): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this += c;}
|
||||
PIString(const char c): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this += PIChar(c);}
|
||||
|
||||
/*! \brief Contructs string from c-string "str"
|
||||
* \details "str" should be null-terminated\n
|
||||
* Example: \snippet pistring.cpp PIString(char * ) */
|
||||
PIString(const char * str): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this += str;}
|
||||
|
||||
/*! \brief Contructs string from \c wchar_t c-string "str"
|
||||
* \details "str" should be null-terminated\n
|
||||
* Example: \snippet pistring.cpp PIString(wchar_t * ) */
|
||||
PIString(const wchar_t * str): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this += str;}
|
||||
|
||||
//! Contructs string from std::string "str"
|
||||
PIString(const string & str): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this += str;}
|
||||
|
||||
#ifdef HAS_LOCALE
|
||||
PIString(const wstring & str): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this += str;}
|
||||
#endif
|
||||
|
||||
//! Contructs string from byte array "ba"
|
||||
PIString(const PIByteArray & ba): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this += ba;}
|
||||
|
||||
//! \brief Contructs string from "len" characters of buffer "str"
|
||||
PIString(const PIChar * str, const int len): PIDeque<PIChar>(str, size_t(len)) {/*reserve(256); */piMonitor.strings++; piMonitor.containers--;}
|
||||
|
||||
/*! \brief Contructs string from "len" characters of buffer "str"
|
||||
* \details Example: \snippet pistring.cpp PIString(char * , int) */
|
||||
PIString(const char * str, const int len): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this += string(str, len);}
|
||||
|
||||
/*! \brief Contructs string as sequence of characters "c" of buffer with length "len"
|
||||
* \details Example: \snippet pistring.cpp PIString(int, char) */
|
||||
PIString(const int len, const char c): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; for (int i = 0; i < len; ++i) push_back(c);}
|
||||
|
||||
/*! \brief Contructs string as sequence of symbols "c" of buffer with length "len"
|
||||
* \details Example: \snippet pistring.cpp PIString(int, PIChar) */
|
||||
PIString(const int len, const PIChar & c): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; for (int i = 0; i < len; ++i) push_back(c);}
|
||||
|
||||
|
||||
PIString(const short & value): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this = fromNumber(value);}
|
||||
PIString(const ushort & value): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this = fromNumber(value);}
|
||||
PIString(const int & value): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this = fromNumber(value);}
|
||||
PIString(const uint & value): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this = fromNumber(value);}
|
||||
PIString(const long & value): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this = fromNumber(value);}
|
||||
PIString(const ulong & value): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this = fromNumber(value);}
|
||||
PIString(const llong & value): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this = fromNumber(value);}
|
||||
PIString(const ullong & value): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this = fromNumber(value);}
|
||||
PIString(const float & value): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this = fromNumber(value);}
|
||||
PIString(const double & value): PIDeque<PIChar>() {/*reserve(256); */piMonitor.strings++; piMonitor.containers--; *this = fromNumber(value);}
|
||||
|
||||
|
||||
//~PIString() {piMonitor.strings--; piMonitor.containers++;}
|
||||
|
||||
|
||||
PIString & operator =(const PIString & o) {clear(); *this += o; return *this;}
|
||||
|
||||
/*! \brief Return c-string representation of string
|
||||
* \details Converts content of string to c-string and return
|
||||
* pointer to first char. This buffer is valid until new convertion
|
||||
* or execution \a data() or \a toByteArray().\n
|
||||
* Example: \snippet pistring.cpp PIString::char* */
|
||||
operator const char*() {return data();}
|
||||
|
||||
//! Return std::string representation of string
|
||||
operator const string() {if (size() == 0) return string(); string s; for (int i = 0; i < length(); ++i) s.push_back(at(i).toAscii()); return s;}
|
||||
|
||||
//! Return symbol at index "pos"
|
||||
PIChar operator [](const int pos) const {return at(pos);}
|
||||
|
||||
//! Return reference to symbol at index "pos"
|
||||
PIChar & operator [](const int pos) {return at(pos);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator ==(const PIString & str) const;
|
||||
|
||||
//! Compare operator
|
||||
bool operator ==(const PIChar c) const {return *this == PIString(c);}
|
||||
//inline bool operator ==(const char c) const {return *this == PIString(c);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator ==(const char * str) const {return *this == PIString(str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator ==(const string & str) const {return *this == PIString(str);}
|
||||
|
||||
|
||||
//! Compare operator
|
||||
bool operator !=(const PIString & str) const;
|
||||
|
||||
//! Compare operator
|
||||
bool operator !=(const PIChar c) const {return *this != PIString(c);}
|
||||
//inline bool operator !=(const char c) const {return *this != PIString(c);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator !=(const char * str) const {return *this != PIString(str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator !=(const string & str) const {return *this != PIString(str);}
|
||||
|
||||
|
||||
//! Compare operator
|
||||
bool operator <(const PIString & str) const;
|
||||
|
||||
//! Compare operator
|
||||
bool operator <(const PIChar c) const {return *this < PIString(c);}
|
||||
//inline bool operator <(const char c) const {return *this < PIString(c);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator <(const char * str) const {return *this < PIString(str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator <(const string & str) const {return *this < PIString(str);}
|
||||
|
||||
|
||||
//! Compare operator
|
||||
bool operator >(const PIString & str) const;
|
||||
|
||||
//! Compare operator
|
||||
bool operator >(const PIChar c) const {return *this > PIString(c);}
|
||||
//inline bool operator >(const char c) const {return *this > PIString(c);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator >(const char * str) const {return *this > PIString(str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator >(const string & str) const {return *this > PIString(str);}
|
||||
|
||||
|
||||
//! Compare operator
|
||||
bool operator <=(const PIString & str) const {return !(*this > str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator <=(const PIChar c) const {return *this <= PIString(c);}
|
||||
//inline bool operator <=(const char c) const {return *this <= PIString(c);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator <=(const char * str) const {return *this <= PIString(str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator <=(const string & str) const {return *this <= PIString(str);}
|
||||
|
||||
|
||||
//! Compare operator
|
||||
bool operator >=(const PIString & str) const {return !(*this < str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator >=(const PIChar c) const {return *this >= PIString(c);}
|
||||
//inline bool operator >=(const char c) const {return *this >= PIString(c);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator >=(const char * str) const {return *this >= PIString(str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator >=(const string & str) const {return *this >= PIString(str);}
|
||||
|
||||
|
||||
operator short() const {return toShort();}
|
||||
operator ushort() const {return toUShort();}
|
||||
operator int() const {return toInt();}
|
||||
operator uint() const {return toUInt();}
|
||||
operator long() const {return toLong();}
|
||||
operator ulong() const {return toULong();}
|
||||
operator llong() const {return toLLong();}
|
||||
operator ullong() const {return toULLong();}
|
||||
operator float() const {return toFloat();}
|
||||
operator double() const {return toDouble();}
|
||||
|
||||
|
||||
/*! \brief Append string "str" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(PIString) */
|
||||
PIString & operator <<(const PIString & str) {*this += str; return *this;}
|
||||
//inline PIString & operator <<(const char c) {*this += c; return *this;}
|
||||
|
||||
/*! \brief Append symbol "c" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(PIChar) */
|
||||
PIString & operator <<(const PIChar & c) {*this += c; return *this;}
|
||||
|
||||
/*! \brief Append c-string "str" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(char * ) */
|
||||
PIString & operator <<(const char * str) {*this += str; return *this;}
|
||||
|
||||
/*! \brief Append \c wchar_t c-string "str" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(wchar_t * ) */
|
||||
PIString & operator <<(const wchar_t * str) {*this += str; return *this;}
|
||||
|
||||
//! Append std::string "str" at the end of string
|
||||
PIString & operator <<(const string & str) {*this += str; return *this;}
|
||||
|
||||
/*! \brief Append string representation of "num" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(int) */
|
||||
PIString & operator <<(const int & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
PIString & operator <<(const uint & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
/*! \brief Append string representation of "num" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(int) */
|
||||
PIString & operator <<(const short & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
PIString & operator <<(const ushort & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
/*! \brief Append string representation of "num" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(int) */
|
||||
PIString & operator <<(const long & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
PIString & operator <<(const ulong & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
PIString & operator <<(const llong & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
PIString & operator <<(const ullong & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
/*! \brief Append string representation of "num" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(int) */
|
||||
PIString & operator <<(const float & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
/*! \brief Append string representation of "num" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(int) */
|
||||
PIString & operator <<(const double & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
|
||||
//! \brief Insert string "str" at the begin of string
|
||||
PIString & prepend(const PIString & str) {insert(0, str); return *this;}
|
||||
|
||||
//! \brief Insert string "str" at the end of string
|
||||
PIString & append(const PIString & str) {*this += str; return *this;}
|
||||
|
||||
|
||||
/*! \brief Return part of string from symbol at index "start" and maximum length "len"
|
||||
* \details All variants demonstrated in example: \snippet pistring.cpp PIString::mid
|
||||
* \sa \a left(), \a right() */
|
||||
PIString mid(const int start, const int len = -1) const;
|
||||
|
||||
/*! \brief Return part of string from left and maximum length "len"
|
||||
* \details Example: \snippet pistring.cpp PIString::left
|
||||
* \sa \a mid(), \a right() */
|
||||
PIString left(const int len) const {return len <= 0 ? PIString() : mid(0, len);}
|
||||
|
||||
/*! \brief Return part of string from right and maximum length "len"
|
||||
* \details Example: \snippet pistring.cpp PIString::right
|
||||
* \sa \a mid(), \a left() */
|
||||
PIString right(const int len) const {return len <= 0 ? PIString() : mid(size() - len, len);}
|
||||
|
||||
/*! \brief Remove part of string from symbol as index "start" and maximum length "len"
|
||||
* and return this string
|
||||
* \details All variants demonstrated in example: \snippet pistring.cpp PIString::cutMid
|
||||
* \sa \a cutLeft(), \a cutRight() */
|
||||
PIString & cutMid(const int start, const int len);
|
||||
|
||||
/*! \brief Remove part of string from left and maximum length "len" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::cutLeft
|
||||
* \sa \a cutMid(), \a cutRight() */
|
||||
PIString & cutLeft(const int len) {return len <= 0 ? *this : cutMid(0, len);}
|
||||
|
||||
/*! \brief Remove part of string from right and maximum length "len" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::cutRight
|
||||
* \sa \a cutMid(), \a cutLeft() */
|
||||
PIString & cutRight(const int len) {return len <= 0 ? *this : cutMid(size() - len, len);}
|
||||
|
||||
/*! \brief Remove spaces at the start and at the end of string and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::trim
|
||||
* \sa \a trimmed() */
|
||||
PIString & trim();
|
||||
|
||||
/*! \brief Return copy of this string without spaces at the start and at the end
|
||||
* \details Example: \snippet pistring.cpp PIString::trimmed
|
||||
* \sa \a trim() */
|
||||
PIString trimmed() const;
|
||||
|
||||
/*! \brief Replace part of string from index "from" and maximum length "len"
|
||||
* with string "with" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::replace_0
|
||||
* \sa \a replaced(), \a replaceAll() */
|
||||
PIString & replace(const int from, const int count, const PIString & with);
|
||||
|
||||
/*! \brief Replace part copy of this string from index "from" and maximum length "len"
|
||||
* with string "with" and return copied string
|
||||
* \details Example: \snippet pistring.cpp PIString::replaced_0
|
||||
* \sa \a replace(), \a replaceAll() */
|
||||
PIString replaced(const int from, const int count, const PIString & with) const {PIString str(*this); str.replace(from, count, with); return str;}
|
||||
|
||||
/*! \brief Replace first founded substring "what" with string "with" and return this string
|
||||
* \details If "ok" is not null, it set to "true" if something was replaced\n
|
||||
* Example: \snippet pistring.cpp PIString::replace_1
|
||||
* \sa \a replaced(), \a replaceAll() */
|
||||
PIString & replace(const PIString & what, const PIString & with, bool * ok = 0);
|
||||
|
||||
/*! \brief Replace first founded substring "what" with string "with" and return copied string
|
||||
* \details If "ok" is not null, it set to "true" if something was replaced\n
|
||||
* Example: \snippet pistring.cpp PIString::replaced_1
|
||||
* \sa \a replaced(), \a replaceAll() */
|
||||
PIString replaced(const PIString & what, const PIString & with, bool * ok = 0) const {PIString str(*this); str.replace(what, with, ok); return str;}
|
||||
|
||||
/*! \brief Replace all founded substrings "what" with strings "with" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::replaceAll
|
||||
* \sa \a replace(), \a replaced() */
|
||||
PIString & replaceAll(const PIString & what, const PIString & with);
|
||||
PIString replaceAll(const PIString & what, const PIString & with) const {PIString str(*this); str.replaceAll(what, with); return str;}
|
||||
|
||||
/*! \brief Repeat content of string "times" times and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::repeat */
|
||||
PIString & repeat(int times) {PIString ss(*this); times--; piForTimes (times) *this += ss; return *this;}
|
||||
|
||||
/*! \brief Returns repeated "times" times string
|
||||
* \details Example: \snippet pistring.cpp PIString::repeated */
|
||||
PIString repeated(int times) const {PIString ss(*this); return ss.repeat(times);}
|
||||
|
||||
/*! \brief Insert symbol "c" after index "index" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::insert_0 */
|
||||
PIString & insert(const int index, const PIChar & c) {PIDeque<PIChar>::insert(index, c); return *this;}
|
||||
|
||||
/*! \brief Insert symbol "c" after index "index" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::insert_1 */
|
||||
PIString & insert(const int index, const char & c) {return insert(index, PIChar(c));}
|
||||
|
||||
/*! \brief Insert string "str" after index "index" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::insert_2 */
|
||||
PIString & insert(const int index, const PIString & str);
|
||||
|
||||
/*! \brief Insert string "str" after index "index" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::insert_2 */
|
||||
PIString & insert(const int index, const char * c) {return insert(index, PIString(c));}
|
||||
|
||||
/*! \brief Enlarge string to length "len" by addition sequence of symbols
|
||||
* "c" at the end of string, and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::expandRightTo
|
||||
* \sa \a expandLeftTo() */
|
||||
PIString & expandRightTo(const int len, const PIChar & c) {if (len > length()) resize(len, c); return *this;}
|
||||
|
||||
/*! \brief Enlarge string to length "len" by addition sequence of symbols
|
||||
* "c" at the beginning of string, and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::expandLeftTo
|
||||
* \sa \a expandRightTo() */
|
||||
PIString & expandLeftTo(const int len, const PIChar & c) {if (len > length()) insert(0, PIString(len - length(), c)); return *this;}
|
||||
|
||||
/*! \brief Reverse string and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::reverse
|
||||
* \sa \a reversed() */
|
||||
PIString & reverse() {PIString str(*this); clear(); piForeachR (const PIChar & c, str) push_back(c); return *this;}
|
||||
|
||||
/*! \brief Reverse copy of this string and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::reversed
|
||||
* \sa \a reverse() */
|
||||
PIString reversed() const {PIString str(*this); str.reverse(); return str;}
|
||||
|
||||
|
||||
/*! \brief Take a part of string from symbol at index "start" and maximum length "len" and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeMid
|
||||
* \sa \a takeLeft, \a takeRight() */
|
||||
PIString takeMid(const int start, const int len = -1) {PIString ret(mid(start, len)); cutMid(start, len); return ret;}
|
||||
|
||||
/*! \brief Take a part from the begin of string with maximum length "len" and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeLeft
|
||||
* \sa \a takeMid(), \a takeRight() */
|
||||
PIString takeLeft(const int len) {PIString ret(left(len)); cutLeft(len); return ret;}
|
||||
|
||||
/*! \brief Take a part from the end of string with maximum length "len" and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeRight
|
||||
* \sa \a takeMid(), \a takeLeft() */
|
||||
PIString takeRight(const int len) {PIString ret(right(len)); cutRight(len); return ret;}
|
||||
|
||||
/*! \brief Take a symbol from the begin of this string and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeSymbol
|
||||
* \sa \a takeWord(), \a takeCWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
|
||||
PIString takeSymbol();
|
||||
|
||||
/*! \brief Take a word from the begin of this string and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeWord
|
||||
* \sa \a takeSymbol(), \a takeCWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
|
||||
PIString takeWord();
|
||||
|
||||
/*! \brief Take a word with letters, numbers and '_' symbols from the
|
||||
* begin of this string and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeCWord
|
||||
* \sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
|
||||
PIString takeCWord();
|
||||
|
||||
/*! \brief Take a line from the begin of this string and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeLine
|
||||
* \sa \a takeSymbol(), \a takeWord(), \a takeCWord(), \a takeNumber(), \a takeRange() */
|
||||
PIString takeLine();
|
||||
|
||||
/*! \brief Take a number with C-format from the begin of this string and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeNumber
|
||||
* \sa \a takeSymbol(), \a takeWord(), \a takeCWord(), \a takeLine(), \a takeRange() */
|
||||
PIString takeNumber();
|
||||
|
||||
/*! \brief Take a range between "start" and "end" symbols from the begin of this
|
||||
* string and return it.
|
||||
* \details "Shield" symbol prevent analysis of the next symbol.
|
||||
* Example: \snippet pistring.cpp PIString::takeRange
|
||||
* \sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeNumber() */
|
||||
PIString takeRange(const PIChar & start, const PIChar & end, const PIChar & shield = '\\');
|
||||
|
||||
//const char * data() {return convertToStd().c_str();}
|
||||
|
||||
|
||||
/*! \brief Return real bytes count of this string
|
||||
* \details It`s equivalent length of char sequence
|
||||
* returned by function \a data() \n
|
||||
* Example: \snippet pistring.cpp PIString::lengthAscii
|
||||
* \sa \a data() */
|
||||
int lengthAscii() const;
|
||||
|
||||
/*! \brief Return \c char * representation of this string
|
||||
* \details This function fill buffer by sequence
|
||||
* of chars. Minimum length of this buffer is count
|
||||
* of symbols. Returned \c char * is valid until next
|
||||
* execution of this function.\n
|
||||
* Example: \snippet pistring.cpp PIString::data
|
||||
* \sa \a lengthAscii() */
|
||||
const char * data() const;
|
||||
|
||||
//! \brief Return \c std::string representation of this string
|
||||
std::string stdString() const {return convertToStd();}
|
||||
#ifdef HAS_LOCALE
|
||||
wstring stdWString() const {return convertToWString();}
|
||||
#endif
|
||||
|
||||
//! \brief Return \a PIByteArray contains \a data() of this string
|
||||
PIByteArray toByteArray() const {const char * d = data(); return PIByteArray(d, lengthAscii());}
|
||||
|
||||
/*! \brief Split string with delimiter "delim" to \a PIStringList and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::split */
|
||||
PIStringList split(const PIString & delim) const;
|
||||
|
||||
|
||||
//! \brief Convert each symbol in copyed string to upper case and return it
|
||||
PIString toUpperCase() const;
|
||||
|
||||
//! \brief Convert each symbol in copyed string to lower case and return it
|
||||
PIString toLowerCase() const;
|
||||
#ifdef HAS_LOCALE
|
||||
PIString toNativeDecimalPoints() const {PIString s(*this); if (currentLocale == 0) return s; return s.replaceAll(".", currentLocale->decimal_point).replaceAll(",", currentLocale->decimal_point);}
|
||||
#else
|
||||
PIString toNativeDecimalPoints() const {return PIString(*this).replaceAll(",", ".");}
|
||||
#endif
|
||||
|
||||
|
||||
//! \brief Search substring "str" from symbol at index "start" and return first occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::find
|
||||
int find(const char str, const int start = 0) const;
|
||||
|
||||
//! \brief Search substring "str" from symbol at index "start" and return first occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::find
|
||||
int find(const PIString str, const int start = 0) const;
|
||||
|
||||
//! \brief Search substring "str" from symbol at index "start" and return first occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::find
|
||||
int find(const char * str, const int start = 0) const {return find(PIString(str), start);}
|
||||
|
||||
//! \brief Search substring "str" from symbol at index "start" and return first occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::find
|
||||
int find(const string str, const int start = 0) const {return find(PIString(str), start);}
|
||||
|
||||
//! \brief Search substring "str" from symbol at index "start" and return last occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::findLast
|
||||
int findLast(const char str, const int start = 0) const;
|
||||
|
||||
//! \brief Search substring "str" from symbol at index "start" and return last occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::findLast
|
||||
int findLast(const PIString str, const int start = 0) const;
|
||||
|
||||
//! \brief Search substring "str" from symbol at index "start" and return last occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::findLast
|
||||
int findLast(const char * str, const int start = 0) const {return findLast(PIString(str), start);}
|
||||
|
||||
//! \brief Search substring "str" from symbol at index "start" and return last occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::findLast
|
||||
int findLast(const string str, const int start = 0) const {return findLast(PIString(str), start);}
|
||||
|
||||
//! \brief Search word "word" from symbol at index "start" and return first occur position.
|
||||
//! \details Example: \snippet pistring.cpp PIString::findWord
|
||||
int findWord(const PIString & word, const int start = 0) const;
|
||||
|
||||
//! \brief Search C-style word "word" from symbol at index "start" and return first occur position.
|
||||
//! \details Example: \snippet pistring.cpp PIString::findCWord
|
||||
int findCWord(const PIString & word, const int start = 0) const;
|
||||
|
||||
//! \brief Return if string starts with "str"
|
||||
bool startsWith(const PIString & str) const;
|
||||
|
||||
//! \brief Return if string ends with "str"
|
||||
bool endsWith(const PIString & str) const;
|
||||
|
||||
//! \brief Return symbols length of string
|
||||
int length() const {return size();}
|
||||
|
||||
//! \brief Return \c true if string is empty, i.e. length = 0
|
||||
bool isEmpty() const {return (size() == 0 || *this == "");}
|
||||
|
||||
|
||||
//! \brief Return \c true if string equal "true", "yes", "on" or positive not null numeric value
|
||||
bool toBool() const {PIString s(*this); if (atof(s.toNativeDecimalPoints().data()) > 0. || s.trimmed().toLowerCase() == "true" || s.trimmed().toLowerCase() == "yes" || s.trimmed().toLowerCase() == "on") return true; return false;}
|
||||
|
||||
//! \brief Return \c char numeric value of string
|
||||
char toChar() const;
|
||||
|
||||
//! \brief Return \c short numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
short toShort(int base = -1, bool * ok = 0) const {return short(toNumberBase(*this, base, ok));}
|
||||
|
||||
//! \brief Return \c ushort numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
ushort toUShort(int base = -1, bool * ok = 0) const {return ushort(toNumberBase(*this, base, ok));}
|
||||
|
||||
//! \brief Return \c int numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
int toInt(int base = -1, bool * ok = 0) const {return int(toNumberBase(*this, base, ok));}
|
||||
|
||||
//! \brief Return \c uint numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
uint toUInt(int base = -1, bool * ok = 0) const {return uint(toNumberBase(*this, base, ok));}
|
||||
|
||||
//! \brief Return \c long numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
long toLong(int base = -1, bool * ok = 0) const {return long(toNumberBase(*this, base, ok));}
|
||||
|
||||
//! \brief Return \c ulong numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
ulong toULong(int base = -1, bool * ok = 0) const {return ulong(toNumberBase(*this, base, ok));}
|
||||
|
||||
//! \brief Return \c llong numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
llong toLLong(int base = -1, bool * ok = 0) const {return toNumberBase(*this, base, ok);}
|
||||
|
||||
//! \brief Return \c ullong numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
ullong toULLong(int base = -1, bool * ok = 0) const {return ullong(toNumberBase(*this, base, ok));}
|
||||
|
||||
//! \brief Return \c float numeric value of string
|
||||
//! \details Example: \snippet pistring.cpp PIString::toFloat
|
||||
float toFloat() const {return (float)atof(toNativeDecimalPoints().data());}
|
||||
|
||||
//! \brief Return \c double numeric value of string
|
||||
//! \details Example: \snippet pistring.cpp PIString::toFloat
|
||||
double toDouble() const {return atof(toNativeDecimalPoints().data());}
|
||||
|
||||
//! \brief Return \c ldouble numeric value of string
|
||||
//! \details Example: \snippet pistring.cpp PIString::toFloat
|
||||
ldouble toLDouble() const {return atof(toNativeDecimalPoints().data());}
|
||||
|
||||
//inline PIString & setNumber(const char value) {clear(); *this += itos(value); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const short value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const ushort value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const int value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const uint value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const long value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const ulong value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const llong & value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const ullong & value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setFloat
|
||||
PIString & setNumber(const float value) {clear(); *this += ftos(value); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setFloat
|
||||
PIString & setNumber(const double & value) {clear(); *this += dtos(value); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setFloat
|
||||
PIString & setNumber(const ldouble & value) {clear(); *this += dtos(value); return *this;}
|
||||
|
||||
//! \brief Set string content to human readable size in B/kB/MB/GB/TB
|
||||
//! \details Example: \snippet pistring.cpp PIString::setReadableSize
|
||||
PIString & setReadableSize(llong bytes);
|
||||
|
||||
//inline static PIString fromNumber(const char value) {return PIString(itos(value));}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const short value, int base = 10, bool * ok = 0) {return fromNumberBaseS(llong(value), base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const ushort value, int base = 10, bool * ok = 0) {return fromNumberBaseU(ullong(value), base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const int value, int base = 10, bool * ok = 0) {return fromNumberBaseS(llong(value), base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const uint value, int base = 10, bool * ok = 0) {return fromNumberBaseU(ullong(value), base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const long value, int base = 10, bool * ok = 0) {return fromNumberBaseS(llong(value), base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const ulong value, int base = 10, bool * ok = 0) {return fromNumberBaseU(ullong(value), base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const llong & value, int base = 10, bool * ok = 0) {return fromNumberBaseS(value, base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const ullong & value, int base = 10, bool * ok = 0) {return fromNumberBaseU(value, base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromFloat
|
||||
static PIString fromNumber(const float value) {return PIString(ftos(value));}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromFloat
|
||||
static PIString fromNumber(const double & value) {return PIString(dtos(value));}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromFloat
|
||||
static PIString fromNumber(const ldouble & value) {return PIString(dtos(value));}
|
||||
|
||||
//! \brief Return "true" or "false"
|
||||
static PIString fromBool(const bool value) {return PIString(value ? "true" : "false");}
|
||||
|
||||
//! \brief Return string contains human readable size in B/kB/MB/GB/TB
|
||||
//! \details Example: \snippet pistring.cpp PIString::readableSize
|
||||
static PIString readableSize(llong bytes) {PIString s; s.setReadableSize(bytes); return s;}
|
||||
|
||||
PIString & removeAll(char v) {replaceAll(v, ""); return *this;}
|
||||
PIString & removeAll(const PIString & v) {replaceAll(v, ""); return *this;}
|
||||
|
||||
private:
|
||||
static const char toBaseN[];
|
||||
static const int fromBaseN[];
|
||||
|
||||
static PIString fromNumberBaseS(const llong value, int base = 10, bool * ok = 0) {
|
||||
if (value == 0) return PIString("0");
|
||||
if (base < 2 || base > 40) {if (ok != 0) *ok = false; return PIString();}
|
||||
if (ok != 0) *ok = true;
|
||||
if (base == 10) return itos(value);
|
||||
PIString ret;
|
||||
llong v = value < 0 ? -value : value, cn;
|
||||
int b = base;
|
||||
while (v >= llong(base)) {
|
||||
cn = v % b;
|
||||
v /= b;
|
||||
//cout << int(cn) << ", " << int(v) << endl;
|
||||
ret.push_front(PIChar(toBaseN[cn]));
|
||||
}
|
||||
if (v > 0) ret.push_front(PIChar(toBaseN[v]));
|
||||
if (value < 0) ret.push_front('-');
|
||||
return ret;
|
||||
}
|
||||
static PIString fromNumberBaseU(const ullong value, int base = 10, bool * ok = 0) {
|
||||
if (value == 0) return PIString("0");
|
||||
if (base < 2 || base > 40) {if (ok != 0) *ok = false; return PIString();}
|
||||
if (ok != 0) *ok = true;
|
||||
if (base == 10) return itos(value);
|
||||
PIString ret;
|
||||
ullong v = value, cn;
|
||||
int b = base;
|
||||
while (v >= ullong(base)) {
|
||||
cn = v % b;
|
||||
v /= b;
|
||||
//cout << int(cn) << ", " << int(v) << endl;
|
||||
ret.push_front(PIChar(toBaseN[cn]));
|
||||
}
|
||||
if (v > 0) ret.push_front(PIChar(toBaseN[v]));
|
||||
return ret;
|
||||
}
|
||||
static llong toNumberBase(const PIString & value, int base = -1, bool * ok = 0) {
|
||||
PIString v = value.trimmed();
|
||||
if (base < 0) {
|
||||
int ind = v.find("0x");
|
||||
if (ind == 0 || ind == 1) {v.remove(ind, 2); base = 16;}
|
||||
else base = 10;
|
||||
} else
|
||||
if (base < 2 || base > 40) {if (ok != 0) *ok = false; return 0;}
|
||||
//v.reverse();
|
||||
if (ok != 0) *ok = true;
|
||||
PIVector<int> digits;
|
||||
llong ret = 0, m = 1;
|
||||
bool neg = false;
|
||||
int cs;
|
||||
for (int i = 0; i < v.size_s(); ++i) {
|
||||
if (v[i] == PIChar('-')) {neg = !neg; continue;}
|
||||
cs = fromBaseN[int(v[i].toAscii())];
|
||||
if (cs < 0 || cs >= base) break;
|
||||
digits << cs;
|
||||
}
|
||||
for (int i = digits.size_s() - 1; i >= 0; --i) {
|
||||
ret += digits[i] * m;
|
||||
m *= base;
|
||||
}
|
||||
if (neg) ret = -ret;
|
||||
/*piForeachC (PIChar & i, v) {
|
||||
if (i == PIChar('-')) {ret = -ret; continue;}
|
||||
cs = fromBaseN[int(i.toAscii())];
|
||||
cout << i << " = " << cs << endl;
|
||||
if (cs < 0 || cs >= base) return ret;
|
||||
ret += cs * m;
|
||||
m *= base;
|
||||
}*/
|
||||
return ret;
|
||||
}
|
||||
void appendFromChars(const char * c, int s);
|
||||
string convertToStd() const;
|
||||
#ifdef HAS_LOCALE
|
||||
wstring convertToWString() const {wstring s; for (int i = 0; i < length(); ++i) s.push_back(at(i).toWChar()); return s;}
|
||||
#endif
|
||||
|
||||
mutable PIByteArray data_;
|
||||
//string std_string;
|
||||
//wstring std_wstring;
|
||||
|
||||
};
|
||||
|
||||
|
||||
//! \relatesalso PIString \brief Output operator to std::ostream (cout)
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIString & v) {for (int i = 0; i < v.length(); ++i) s << v[i]; return s;}
|
||||
|
||||
//! \relatesalso PIString \brief Input operator from std::istream (cin)
|
||||
inline std::istream & operator >>(std::istream & s, PIString & v) {string ss; s >> ss; v << PIString(ss); return s;}
|
||||
|
||||
//! \relatesalso PIString \relatesalso PICout \brief Output operator to PICout
|
||||
inline PICout operator <<(PICout s, const PIString & v) {s.space(); s.quote(); s.setControl(0, true); for (int i = 0; i < v.length(); ++i) s << v[i]; s.restoreControl(); s.quote(); return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIString \relatesalso PIByteArray \brief Output operator to PIByteArray
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIString & v) {int l = v.lengthAscii(); s << l; if (l <= 0) return s; int os = s.size_s(); s.enlarge(l); memcpy(s.data(os), v.data(), l); return s;}
|
||||
|
||||
//! \relatesalso PIString \relatesalso PIByteArray \brief Input operator from PIByteArray
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIString & v) {if (s.size() < 4) {v.clear(); return s;} int l; s >> l; if (l <= 0) return s; v = PIString((const char * )s.data(), l); s.remove(0, l); return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIString \brief Return concatenated string
|
||||
inline PIString operator +(const PIString & str, const PIString & f) {PIString s(str); s += f; return s;}
|
||||
|
||||
//inline PIString operator +(const PIString & f, const char c) {PIString s(f); s.push_back(c); return s;}
|
||||
|
||||
//! \relatesalso PIString \brief Return concatenated string
|
||||
inline PIString operator +(const PIString & f, const char * str) {PIString s(f); s += str; return s;}
|
||||
|
||||
//! \relatesalso PIString \brief Return concatenated string
|
||||
inline PIString operator +(const PIString & f, const string & str) {PIString s(f); s += str; return s;}
|
||||
|
||||
//inline PIString operator +(const char c, const PIString & f) {return PIString(c) + f;}
|
||||
|
||||
//! \relatesalso PIString \brief Return concatenated string
|
||||
inline PIString operator +(const char * str, const PIString & f) {return PIString(str) + f;}
|
||||
|
||||
//! \relatesalso PIString \brief Return concatenated string
|
||||
inline PIString operator +(const string & str, const PIString & f) {return PIString(str) + f;}
|
||||
|
||||
inline char chrUpr(char c);
|
||||
inline char chrLwr(char c);
|
||||
|
||||
|
||||
/*!\brief Strings array class
|
||||
* \details This class is based on \a PIVector<PIString> and
|
||||
* expand it functionality. */
|
||||
class PIP_EXPORT PIStringList: public PIDeque<PIString>
|
||||
{
|
||||
public:
|
||||
|
||||
//! Contructs empty strings list
|
||||
PIStringList() {;}
|
||||
|
||||
//! Contructs strings list with one string "str"
|
||||
PIStringList(const PIString & str) {push_back(str);}
|
||||
|
||||
//! Contructs empty strings list with strings "s0" and "s1"
|
||||
PIStringList(const PIString & s0, const PIString & s1) {push_back(s0); push_back(s1);}
|
||||
|
||||
//! Contructs empty strings list with strings "s0", "s1" and "s2"
|
||||
PIStringList(const PIString & s0, const PIString & s1, const PIString & s2) {push_back(s0); push_back(s1); push_back(s2);}
|
||||
|
||||
//! Contructs empty strings list with strings "s0", "s1", "s2" and "s3"
|
||||
PIStringList(const PIString & s0, const PIString & s1, const PIString & s2, const PIString & s3) {push_back(s0); push_back(s1); push_back(s2); push_back(s3);}
|
||||
|
||||
PIStringList(const PIStringList & o): PIDeque<PIString>() {resize(o.size()); for (uint i = 0; i < size(); ++i) (*this)[i] = o[i];}
|
||||
|
||||
|
||||
//! \brief Join all strings in one with delimiter "delim" and return it
|
||||
//! \details Example: \snippet pistring.cpp PIStringList::join
|
||||
PIString join(const PIString & delim) const {PIString s; for (uint i = 0; i < size(); ++i) {s += at(i); if (i < size() - 1) s += delim;} return s;}
|
||||
|
||||
//! \brief Remove all strings equal "value" and return this
|
||||
//! \details Example: \snippet pistring.cpp PIStringList::removeStrings
|
||||
PIStringList & removeStrings(const PIString & value) {for (uint i = 0; i < size(); ++i) {if (at(i) == value) {remove(i); --i;}} return *this;}
|
||||
|
||||
PIStringList & remove(uint num) {PIDeque<PIString>::remove(num); return *this;}
|
||||
PIStringList & remove(uint num, uint count) {PIDeque<PIString>::remove(num, count); return *this;}
|
||||
|
||||
//! \brief Remove duplicated strings and return this
|
||||
//! \details Example: \snippet pistring.cpp PIStringList::removeDuplicates
|
||||
PIStringList & removeDuplicates();
|
||||
|
||||
//! \brief Trim all strings
|
||||
//! \details Example: \snippet pistring.cpp PIStringList::trim
|
||||
PIStringList & trim() {for (uint i = 0; i < size(); ++i) at(i).trim(); return *this;}
|
||||
|
||||
//! Return sum of lengths of all strings
|
||||
uint contentSize() {uint s = 0; for (uint i = 0; i < size(); ++i) s += at(i).size(); return s;}
|
||||
|
||||
PIStringList & operator =(const PIStringList & o) {clear(); for (uint i = 0; i < o.size(); ++i) *this << o[i]; return *this;}
|
||||
|
||||
PIStringList & operator <<(const PIString & str) {push_back(str); return *this;}
|
||||
PIStringList & operator <<(const PIStringList & sl) {piForeachC (PIString & i, sl) push_back(i); return *this;}
|
||||
//inline PIStringList & operator <<(const char c) {push_back(PIString(c)); return *this;}
|
||||
PIStringList & operator <<(const char * str) {push_back(PIString(str)); return *this;}
|
||||
PIStringList & operator <<(const string & str) {push_back(str); return *this;}
|
||||
PIStringList & operator <<(const int & num) {push_back(PIString::fromNumber(num)); return *this;}
|
||||
PIStringList & operator <<(const short & num) {push_back(PIString::fromNumber(num)); return *this;}
|
||||
PIStringList & operator <<(const long & num) {push_back(PIString::fromNumber(num)); return *this;}
|
||||
PIStringList & operator <<(const float & num) {push_back(PIString::fromNumber(num)); return *this;}
|
||||
PIStringList & operator <<(const double & num) {push_back(PIString::fromNumber(num)); return *this;}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//! \relatesalso PIStringList \relatesalso PIByteArray \brief Output operator to PIByteArray
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIStringList & v) {s << v.size_s(); for (int i = 0; i < v.size_s(); ++i) s << v[i]; return s;}
|
||||
|
||||
//! \relatesalso PIStringList \relatesalso PIByteArray \brief Input operator from PIByteArray
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIStringList & v) {int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIStringList \brief Output operator to std::ostream (cout)
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIStringList & v) {s << "{"; for (uint i = 0; i < v.size(); ++i) {s << '\"' << v[i] << '\"'; if (i < v.size() - 1) s << ", ";} s << "}"; return s;}
|
||||
|
||||
//! \relatesalso PIStringList \relatesalso PICout \brief Output operator to PICout
|
||||
inline PICout operator <<(PICout s, const PIStringList & v) {s.space(); s.setControl(0, true); s << "{"; for (uint i = 0; i < v.size(); ++i) {s << '\"' << v[i] << '\"'; if (i < v.size() - 1) s << ", ";} s << "}"; s.restoreControl(); return s;}
|
||||
|
||||
#endif // PISTRING_H
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Process resource monitor
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pisystemmonitor.h"
|
||||
|
||||
|
||||
PISystemMonitor::PISystemMonitor(): PIThread() {
|
||||
pID_ = cycle = 0;
|
||||
cpu_count = 1;
|
||||
#ifndef WINDOWS
|
||||
# ifdef QNX
|
||||
page_size = 4096;
|
||||
# else
|
||||
page_size = getpagesize();
|
||||
# endif
|
||||
cpu_count = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (cpu_count < 1) cpu_count = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PISystemMonitor::startOnProcess(int pID) {
|
||||
stop();
|
||||
pID_ = pID;
|
||||
#ifndef WINDOWS
|
||||
file.open("/proc/" + PIString::fromNumber(pID_) + "/stat", PIIODevice::ReadOnly);
|
||||
filem.open("/proc/" + PIString::fromNumber(pID_) + "/statm", PIIODevice::ReadOnly);
|
||||
if (!file.isOpened()) {
|
||||
piCoutObj << "Can`t find process with ID = " << pID_ << "!";
|
||||
return false;
|
||||
}
|
||||
cycle = -1;
|
||||
#endif
|
||||
return start(25);
|
||||
}
|
||||
|
||||
|
||||
void PISystemMonitor::run() {
|
||||
#ifndef WINDOWS
|
||||
file.seekToBegin();
|
||||
PIString str(file.readAll(true));
|
||||
int si = str.find('(') + 1, fi = 0, cc = 1;
|
||||
for (int i = si; i < str.size_s(); ++i) {
|
||||
if (str[i] == '(') cc++;
|
||||
if (str[i] == ')') cc--;
|
||||
if (cc <= 0) {
|
||||
fi = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
stat.exec_name = str.mid(si, fi - si);
|
||||
str.cutMid(si - 1, fi - si + 3);
|
||||
PIStringList sl = str.split(" ");
|
||||
if (sl.size_s() < 18) return;
|
||||
stat.ID = sl[0].toInt();
|
||||
stat.state = sl[1];
|
||||
stat.parent_ID = sl[2].toInt();
|
||||
stat.group_ID = sl[3].toInt();
|
||||
stat.session_ID = sl[4].toInt();
|
||||
if (cycle < 0) {
|
||||
cpu_u_prev = cpu_u_cur = sl[12].toLLong();
|
||||
cpu_s_prev = cpu_s_cur = sl[13].toLLong();
|
||||
}
|
||||
cycle++;
|
||||
if (cycle >= 40) {
|
||||
cpu_u_prev = cpu_u_cur;
|
||||
cpu_s_prev = cpu_s_cur;
|
||||
cpu_u_cur = sl[12].toLLong();
|
||||
cpu_s_cur = sl[13].toLLong();
|
||||
stat.cpu_load_system = cpu_s_cur - cpu_s_prev;
|
||||
stat.cpu_load_user = cpu_u_cur - cpu_u_prev;
|
||||
if (stat.cpu_load_system > 100) stat.cpu_load_system = 100;
|
||||
if (stat.cpu_load_user > 100) stat.cpu_load_user = 100;
|
||||
stat.cpu_load_system /= cpu_count;
|
||||
stat.cpu_load_user /= cpu_count;
|
||||
cycle = 0;
|
||||
}
|
||||
stat.priority = sl[16].toInt();
|
||||
stat.threads = sl[18].toInt();
|
||||
|
||||
filem.seekToBegin();
|
||||
str = filem.readAll(true);
|
||||
sl = str.split(" ");
|
||||
if (sl.size_s() < 5) return;
|
||||
stat.virtual_memsize = sl[0].toLong() * page_size;
|
||||
stat.resident_memsize = sl[1].toLong() * page_size;
|
||||
stat.share_memsize = sl[2].toLong() * page_size;
|
||||
stat.data_memsize = sl[5].toLong() * page_size;
|
||||
stat.physical_memsize = stat.resident_memsize - stat.share_memsize;
|
||||
|
||||
stat.physical_memsize_readable = PIString::readableSize(stat.physical_memsize);
|
||||
stat.resident_memsize_readable = PIString::readableSize(stat.resident_memsize);
|
||||
stat.share_memsize_readable = PIString::readableSize(stat.share_memsize);
|
||||
stat.virtual_memsize_readable = PIString::readableSize(stat.virtual_memsize);
|
||||
stat.data_memsize_readable = PIString::readableSize(stat.data_memsize);
|
||||
#endif
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Process resource monitor
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PISYSTEMMONITOR_H
|
||||
#define PISYSTEMMONITOR_H
|
||||
|
||||
#include "pithread.h"
|
||||
#include "piprocess.h"
|
||||
|
||||
class PIP_EXPORT PISystemMonitor: public PIThread
|
||||
{
|
||||
public:
|
||||
PISystemMonitor();
|
||||
|
||||
struct ProcessStats {
|
||||
PIString exec_name;
|
||||
PIString state;
|
||||
int ID;
|
||||
int parent_ID;
|
||||
int group_ID;
|
||||
int session_ID;
|
||||
int priority;
|
||||
int threads;
|
||||
ulong physical_memsize;
|
||||
ulong resident_memsize;
|
||||
ulong share_memsize;
|
||||
ulong virtual_memsize;
|
||||
ulong data_memsize;
|
||||
PIString physical_memsize_readable;
|
||||
PIString resident_memsize_readable;
|
||||
PIString share_memsize_readable;
|
||||
PIString virtual_memsize_readable;
|
||||
PIString data_memsize_readable;
|
||||
float cpu_load_system;
|
||||
float cpu_load_user;
|
||||
};
|
||||
|
||||
bool startOnProcess(int pID);
|
||||
bool startOnSelf() {return startOnProcess(PIProcess::currentPID());}
|
||||
const ProcessStats & statistic() const {return stat;}
|
||||
|
||||
private:
|
||||
void run();
|
||||
|
||||
PIFile file, filem;
|
||||
ProcessStats stat;
|
||||
int pID_, page_size, cpu_count, cycle;
|
||||
#ifndef WINDOWS
|
||||
llong cpu_u_cur, cpu_u_prev, cpu_s_cur, cpu_s_prev;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // PISYSTEMMONITOR_H
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
System tests results (see system_test folder)
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pisystemtests.h"
|
||||
|
||||
|
||||
namespace PISystemTests {
|
||||
long time_resolution_ns = 1;
|
||||
long time_elapsed_ns = 0;
|
||||
long usleep_offset_us = 60;
|
||||
|
||||
PISystemTestReader pisystestreader;
|
||||
|
||||
};
|
||||
|
||||
|
||||
PISystemTests::PISystemTestReader::PISystemTestReader() {
|
||||
#ifndef WINDOWS
|
||||
PIConfig conf("/etc/pip.conf", PIIODevice::ReadOnly);
|
||||
conf.setReopenEnabled(false);
|
||||
time_resolution_ns = conf.getValue("time_resolution_ns", 1);
|
||||
time_elapsed_ns = conf.getValue("time_elapsed_ns", 0);
|
||||
usleep_offset_us = conf.getValue("usleep_offset_us", 60);
|
||||
#endif
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
System tests results (see system_test folder)
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PISYSTEMTESTS_H
|
||||
#define PISYSTEMTESTS_H
|
||||
|
||||
#include "piconfig.h"
|
||||
|
||||
namespace PISystemTests {
|
||||
PIP_EXPORT extern long time_resolution_ns;
|
||||
PIP_EXPORT extern long time_elapsed_ns;
|
||||
PIP_EXPORT extern long usleep_offset_us;
|
||||
|
||||
class PISystemTestReader {
|
||||
public:
|
||||
PISystemTestReader();
|
||||
};
|
||||
|
||||
extern PISystemTestReader pisystestreader;
|
||||
|
||||
};
|
||||
|
||||
#endif // PISYSTEMTESTS_H
|
||||
288
pithread.cpp
288
pithread.cpp
@@ -1,288 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Thread
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pithread.h"
|
||||
#include "pisystemtests.h"
|
||||
|
||||
|
||||
/*! \class PIThread
|
||||
* \brief Thread class
|
||||
* \details This class allow you exec your code in separate thread.
|
||||
*
|
||||
* \section PIThread_sec0 Synopsis
|
||||
* Multithreading allow you to write program which will be executed
|
||||
* in several threads simultaneously. This trend allow you to use all
|
||||
* cores of modern processors, but there are many dangers.
|
||||
*
|
||||
* This class provide virtual functions \a begin(), \a run() and \a end(),
|
||||
* which describes start, execution and finish work of some process.
|
||||
* These functions executes in \b separate thread. When you execute
|
||||
* \a start(), %PIThread create separate system thread and sequentially
|
||||
* executes function \a begin(), \a run() and \a end(). You can
|
||||
* reimplement each function and write your own code to execute.
|
||||
* Scheme of functions executing:
|
||||
\code{.cpp}
|
||||
begin();
|
||||
event started();
|
||||
while (isRunning()) {
|
||||
run();
|
||||
ThreadFunc();
|
||||
msleep(timer_delay);
|
||||
}
|
||||
event stopped();
|
||||
end();
|
||||
\endcode
|
||||
* Unlike from directly using "pthread" or some similar you doesn`t need
|
||||
* to write your own main thread cycle and sleep at every cycle end.
|
||||
* %PIThread make it for you, and your job is to set sleep value from
|
||||
* contructor or when starting thread, and reimplement \a begin(), \a run()
|
||||
* and \a end() functions.
|
||||
*
|
||||
* \section PIThread_sec1 Using without subclassing
|
||||
* You can use %PIThread without subclassing by using "ThreadFunc" pointer
|
||||
* that can be set from constructor or by overloaded function \a start(ThreadFunc func, int timer_delay).
|
||||
* If "func" if not null this function will be executed as \a run(). ThreadFunc is any static
|
||||
* function with format void func(void * data). "Data" is custom data set from constructor or
|
||||
* with function \a setData(). \n Also you can connect to event \a started(), but
|
||||
* in this case you should to white your thread main cycle, because this event raised only one time.
|
||||
*
|
||||
* \section PIThread_sec2 Locking
|
||||
* %PIThread has inrternal mutex that can be locked and unlocked every \a run() if you set this flag
|
||||
* with function \a needLockRun(bool). Also you can access to this mutex by functions \a lock(), \a unlock()
|
||||
* and \a mutex(). Using this functions together with needLockRun(true) can guarantee one-thread access to
|
||||
* some data.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
PIThread::PIThread(void * data, ThreadFunc func, bool startNow, int timer_delay): PIObject() {
|
||||
piMonitor.threads++;
|
||||
thread = 0;
|
||||
data_ = data;
|
||||
ret_func = func;
|
||||
running = lockRun = false;
|
||||
priority_ = piNormal;
|
||||
timer = timer_delay;
|
||||
if (startNow) start(timer_delay);
|
||||
}
|
||||
|
||||
|
||||
PIThread::PIThread(bool startNow, int timer_delay): PIObject() {
|
||||
piMonitor.threads++;
|
||||
thread = 0;
|
||||
ret_func = 0;
|
||||
running = lockRun = false;
|
||||
priority_ = piNormal;
|
||||
timer = timer_delay;
|
||||
if (startNow) start(timer_delay);
|
||||
}
|
||||
|
||||
|
||||
PIThread::~PIThread() {
|
||||
piMonitor.threads--;
|
||||
if (!running || thread == 0) return;
|
||||
#ifndef WINDOWS
|
||||
# ifdef ANDROID
|
||||
pthread_kill(thread, SIGSTOP);
|
||||
# else
|
||||
pthread_cancel(thread);
|
||||
# endif
|
||||
#else
|
||||
TerminateThread(thread, 0);
|
||||
CloseHandle(thread);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::start(int timer_delay) {
|
||||
if (running) return false;
|
||||
terminating = running = false;
|
||||
timer = timer_delay;
|
||||
#ifndef WINDOWS
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setschedparam(&attr, &sparam);
|
||||
if (pthread_create(&thread, &attr, thread_function, this) == 0) {
|
||||
setPriority(priority_);
|
||||
running = true;
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)thread_function, this, 0, 0);
|
||||
if (thread != 0) {
|
||||
setPriority(priority_);
|
||||
running = true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::startOnce() {
|
||||
if (running) return false;
|
||||
terminating = running = false;
|
||||
#ifndef WINDOWS
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setschedparam(&attr, &sparam);
|
||||
if (pthread_create(&thread, &attr, thread_function_once, this) == 0) {
|
||||
setPriority(priority_);
|
||||
running = true;
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)thread_function_once, this, 0, 0);
|
||||
if (thread != 0) {
|
||||
setPriority(priority_);
|
||||
running = true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void PIThread::terminate() {
|
||||
if (thread == 0) return;
|
||||
running = false;
|
||||
#ifndef WINDOWS
|
||||
# ifdef ANDROID
|
||||
pthread_kill(thread, SIGSTOP);
|
||||
# else
|
||||
pthread_cancel(thread);
|
||||
# endif
|
||||
#else
|
||||
TerminateThread(thread, 0);
|
||||
CloseHandle(thread);
|
||||
#endif
|
||||
thread = 0;
|
||||
end();
|
||||
}
|
||||
|
||||
|
||||
void * PIThread::thread_function(void * t) {
|
||||
#ifndef WINDOWS
|
||||
# ifndef ANDROID
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
|
||||
# endif
|
||||
#else
|
||||
__PISetTimerResolution();
|
||||
#endif
|
||||
PIThread & ct = *((PIThread * )t);
|
||||
ct.running = true;
|
||||
ct.begin();
|
||||
ct.started();
|
||||
while (!ct.terminating) {
|
||||
if (ct.lockRun) ct.mutex_.lock();
|
||||
ct.run();
|
||||
if (ct.ret_func != 0) ct.ret_func(ct.data_);
|
||||
if (ct.lockRun) ct.mutex_.unlock();
|
||||
if (ct.timer > 0) msleep(ct.timer);
|
||||
}
|
||||
ct.stopped();
|
||||
ct.end();
|
||||
ct.running = false;
|
||||
//cout << "thread " << t << " exiting ... " << endl;
|
||||
#ifndef WINDOWS
|
||||
pthread_exit(0);
|
||||
#else
|
||||
ExitThread(0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void * PIThread::thread_function_once(void * t) {
|
||||
#ifndef WINDOWS
|
||||
# ifndef ANDROID
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
|
||||
# endif
|
||||
#else
|
||||
__PISetTimerResolution();
|
||||
#endif
|
||||
PIThread & ct = *((PIThread * )t);
|
||||
ct.running = true;
|
||||
ct.begin();
|
||||
ct.started();
|
||||
if (ct.lockRun) ct.mutex_.lock();
|
||||
ct.run();
|
||||
if (ct.ret_func != 0) ct.ret_func(ct.data_);
|
||||
if (ct.lockRun) ct.mutex_.unlock();
|
||||
ct.stopped();
|
||||
ct.end();
|
||||
ct.running = false;
|
||||
//cout << "thread " << t << " exiting ... " << endl;
|
||||
#ifndef WINDOWS
|
||||
pthread_exit(0);
|
||||
#else
|
||||
ExitThread(0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void PIThread::setPriority(PIThread::Priority prior) {
|
||||
priority_ = prior;
|
||||
#ifndef WINDOWS
|
||||
# ifndef LINUX
|
||||
sparam.sched_priority = (int)priority_;
|
||||
# else
|
||||
sparam.__sched_priority = (int)priority_;
|
||||
# endif
|
||||
if (!running) return;
|
||||
pthread_getschedparam(thread, &policy, &sparam);
|
||||
pthread_setschedparam(thread, policy, &sparam);
|
||||
#else
|
||||
if (!running) return;
|
||||
SetThreadPriority(thread, -(int)priority_);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::waitForFinish(int timeout_msecs) {
|
||||
if (timeout_msecs < 0) {
|
||||
while (running)
|
||||
msleep(1);
|
||||
return true;
|
||||
}
|
||||
int cnt = 0;
|
||||
while (running && cnt < timeout_msecs) {
|
||||
msleep(1);
|
||||
++cnt;
|
||||
}
|
||||
return cnt < timeout_msecs;
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::waitForStart(int timeout_msecs) {
|
||||
if (timeout_msecs < 0) {
|
||||
while (!running)
|
||||
msleep(1);
|
||||
return true;
|
||||
}
|
||||
int cnt = 0;
|
||||
while (!running && cnt < timeout_msecs) {
|
||||
msleep(1);
|
||||
++cnt;
|
||||
}
|
||||
return cnt < timeout_msecs;
|
||||
}
|
||||
219
pithread.h
219
pithread.h
@@ -1,219 +0,0 @@
|
||||
/*! \file pithread.h
|
||||
* \brief Thread
|
||||
*
|
||||
* This file declare thread class and some wait functions
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Thread
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PITHREAD_H
|
||||
#define PITHREAD_H
|
||||
|
||||
#include <signal.h>
|
||||
#include "pimutex.h"
|
||||
#include "piobject.h"
|
||||
|
||||
typedef void (*ThreadFunc)(void * );
|
||||
|
||||
class PIP_EXPORT PIThread: public PIObject
|
||||
{
|
||||
PIOBJECT(PIThread)
|
||||
public:
|
||||
|
||||
//! Contructs thread with custom data "data", external function "func" and main cycle delay "timer_delay".
|
||||
PIThread(void * data, ThreadFunc func, bool startNow = false, int timer_delay = -1);
|
||||
|
||||
//! Contructs thread with main cycle delay "timer_delay".
|
||||
PIThread(bool startNow = false, int timer_delay = -1);
|
||||
virtual ~PIThread();
|
||||
|
||||
#ifdef DOXYGEN
|
||||
//! Priority of thread
|
||||
enum Priority {piHighest /** Highest */,
|
||||
piHigh /** High */,
|
||||
piNormal /** Normal, default */,
|
||||
piLow /** Low */,
|
||||
piLowerst /** Lowest */
|
||||
};
|
||||
#else
|
||||
# ifdef QNX
|
||||
enum Priority {piHighest = 12,
|
||||
piHigh = 11,
|
||||
piNormal = 10,
|
||||
piLow = 9,
|
||||
piLowerst = 8 };
|
||||
# else
|
||||
enum Priority {piHighest = -2,
|
||||
piHigh = -1,
|
||||
piNormal = 0,
|
||||
piLow = 1,
|
||||
piLowerst = 2 };
|
||||
# endif
|
||||
#endif
|
||||
|
||||
EVENT_HANDLER0(bool, start) {return start(-1);}
|
||||
EVENT_HANDLER1(bool, start, int, timer_delay);
|
||||
EVENT_HANDLER1(bool, start, ThreadFunc, func) {ret_func = func; return start(-1);}
|
||||
EVENT_HANDLER2(bool, start, ThreadFunc, func, int, timer_delay) {ret_func = func; return start(timer_delay);}
|
||||
EVENT_HANDLER0(bool, startOnce);
|
||||
EVENT_HANDLER1(bool, startOnce, ThreadFunc, func) {ret_func = func; return startOnce();}
|
||||
EVENT_HANDLER0(void, stop) {stop(false);}
|
||||
EVENT_HANDLER1(void, stop, bool, wait) {terminating = true; if (wait) waitForFinish();}
|
||||
EVENT_HANDLER0(void, terminate);
|
||||
|
||||
//! \brief Set common data passed to external function
|
||||
void setData(void * d) {data_ = d;}
|
||||
|
||||
//! \brief Set external function that will be executed after every \a run()
|
||||
void setSlot(ThreadFunc func) {ret_func = func;}
|
||||
|
||||
//! \brief Set priority of thread
|
||||
void setPriority(PIThread::Priority prior);
|
||||
|
||||
//! \brief Returns common data passed to external function
|
||||
void * data() const {return data_;}
|
||||
|
||||
//! \brief Return priority of thread
|
||||
PIThread::Priority priority() const {return priority_;}
|
||||
|
||||
//! \brief Return \c true if thread is running
|
||||
bool isRunning() const {return running;}
|
||||
|
||||
bool isStopping() const {return running && terminating;}
|
||||
|
||||
EVENT_HANDLER0(bool, waitForStart) {return waitForStart(-1);}
|
||||
EVENT_HANDLER1(bool, waitForStart, int, timeout_msecs);
|
||||
EVENT_HANDLER0(bool, waitForFinish) {return waitForFinish(-1);}
|
||||
EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs);
|
||||
|
||||
//! \brief Set necessity of lock every \a run with internal mutex
|
||||
void needLockRun(bool need) {lockRun = need;}
|
||||
EVENT_HANDLER0(void, lock) {mutex_.lock();}
|
||||
EVENT_HANDLER0(void, unlock) {mutex_.unlock();}
|
||||
|
||||
//! \brief Return internal mutex
|
||||
PIMutex & mutex() {return mutex_;}
|
||||
|
||||
EVENT(started)
|
||||
EVENT(stopped)
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
/** \fn bool start(int timer_delay = -1)
|
||||
* \brief Start thread
|
||||
* \details Start execution of \a run() in internal loop with
|
||||
* "timer_delay" delay in milliseconds. If "timer_delay" <= 0
|
||||
* there is no delay in loop. Thread also exec external function
|
||||
* set by \a setSlot() if it`s not null
|
||||
*
|
||||
* \return \c false if thread already started or can`t start thread */
|
||||
|
||||
/** \fn bool start(ThreadFunc func, int timer_delay = -1)
|
||||
* \brief Start thread
|
||||
* \details Overloaded function. Set external function "func" before start
|
||||
*
|
||||
* \return \c false if thread already started or can`t start thread */
|
||||
|
||||
/** \fn bool startOnce()
|
||||
* \brief Start thread without internal loop
|
||||
* \details Start execution of \a run() once. Thread also exec
|
||||
* external function set by \a setSlot() if it`s not null
|
||||
*
|
||||
* \return \c false if thread already started or can`t start thread */
|
||||
|
||||
/** \fn bool startOnce(ThreadFunc func)
|
||||
* \brief Start thread without internal loop
|
||||
* \details Overloaded function. Set external function "func" before start
|
||||
*
|
||||
* \return \c false if thread already started or can`t start thread */
|
||||
|
||||
/** \fn void stop(bool wait = false)
|
||||
* \brief Stop thread
|
||||
* \details Stop execution of thread and wait for it finish
|
||||
* if "wait" is \c true. This function can block for infinite
|
||||
* time if "wait" is \c true and any of thread function is
|
||||
* busy forever */
|
||||
|
||||
/** \fn void terminate()
|
||||
* \brief Strongly stop thread
|
||||
* \details Stop execution of thread immediately */
|
||||
|
||||
/** \fn bool waitForStart(int timeout_msecs = -1)
|
||||
* \brief Wait for thread start
|
||||
* \details This function block until thread finish for "timeout_msecs"
|
||||
* or forever if "timeout_msecs" < 0
|
||||
*
|
||||
* \return \c false if timeout is exceeded */
|
||||
|
||||
/** \fn bool waitForFinish(int timeout_msecs = -1)
|
||||
* \brief Wait for thread finish
|
||||
* \details This function block until thread start for "timeout_msecs"
|
||||
* or forever if "timeout_msecs" < 0
|
||||
*
|
||||
* \return \c false if timeout is exceeded */
|
||||
|
||||
//! \fn void lock()
|
||||
//! \brief Lock internal mutex
|
||||
|
||||
//! \fn void unlock()
|
||||
//! \brief Unlock internal mutex
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void started()
|
||||
//! \brief Raise on thread start
|
||||
|
||||
//! \fn void stopped()
|
||||
//! \brief Raise on thread stop
|
||||
|
||||
//! \}
|
||||
|
||||
protected:
|
||||
static void * thread_function(void * t);
|
||||
static void * thread_function_once(void * t);
|
||||
|
||||
|
||||
//! Function executed once at the start of thread.
|
||||
virtual void begin() {;}
|
||||
|
||||
//! Function executed at every "timer_delay" msecs until thread was stopped.
|
||||
virtual void run() {;}
|
||||
|
||||
//! Function executed once at the end of thread.
|
||||
virtual void end() {;}
|
||||
|
||||
volatile bool terminating, running, lockRun;
|
||||
int timer, policy;
|
||||
void * data_;
|
||||
PIMutex mutex_;
|
||||
PIThread::Priority priority_;
|
||||
ThreadFunc ret_func;
|
||||
#ifndef WINDOWS
|
||||
pthread_t thread;
|
||||
sched_param sparam;
|
||||
#else
|
||||
void * thread;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // PITHREAD_H
|
||||
363
pitime.cpp
363
pitime.cpp
@@ -1,363 +0,0 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Timer
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pitime.h"
|
||||
#include "pisystemtests.h"
|
||||
|
||||
|
||||
/*! \class PISystemTime
|
||||
* \brief System time
|
||||
*
|
||||
* \section PISystemTime_sec0 Synopsis
|
||||
* This class provide arithmetic functions for POSIX system time.
|
||||
* This time represents as seconds and nanosecons in integer formats.
|
||||
* You can take current system time with function \a PISystemTime::current(),
|
||||
* compare times, sum or subtract two times, convert time to/from
|
||||
* seconds, milliseconds, microseconds or nanoseconds.
|
||||
* \section PISystemTime_sec1 Example
|
||||
* \snippet pitimer.cpp system_time
|
||||
*/
|
||||
|
||||
|
||||
void piUSleep(int usecs) {
|
||||
if (usecs <= 0) return;
|
||||
#ifdef WINDOWS
|
||||
if (usecs > 0) Sleep(usecs / 1000);
|
||||
#else
|
||||
usecs -= PISystemTests::usleep_offset_us;
|
||||
if (usecs > 0) usleep(usecs);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool operator ==(const PITime & t0, const PITime & t1) {
|
||||
return (t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds);
|
||||
}
|
||||
|
||||
|
||||
bool operator <(const PITime & t0, const PITime & t1) {
|
||||
if (t0.hours == t1.hours) {
|
||||
if (t0.minutes == t1.minutes) {
|
||||
return t0.seconds < t1.seconds;
|
||||
} else return t0.minutes < t1.minutes;
|
||||
} else return t0.hours < t1.hours;
|
||||
}
|
||||
|
||||
|
||||
bool operator >(const PITime & t0, const PITime & t1) {
|
||||
if (t0.hours == t1.hours) {
|
||||
if (t0.minutes == t1.minutes) {
|
||||
return t0.seconds > t1.seconds;
|
||||
} else return t0.minutes > t1.minutes;
|
||||
} else return t0.hours > t1.hours;
|
||||
}
|
||||
|
||||
bool operator ==(const PIDate & t0, const PIDate & t1) {
|
||||
return (t0.year == t1.year && t0.month == t1.month && t0.day == t1.day);
|
||||
}
|
||||
|
||||
|
||||
bool operator <(const PIDate & t0, const PIDate & t1) {
|
||||
if (t0.year == t1.year) {
|
||||
if (t0.month == t1.month) {
|
||||
return t0.day < t1.day;
|
||||
} else return t0.month < t1.month;
|
||||
} else return t0.year < t1.year;
|
||||
}
|
||||
|
||||
|
||||
bool operator >(const PIDate & t0, const PIDate & t1) {
|
||||
if (t0.year == t1.year) {
|
||||
if (t0.month == t1.month) {
|
||||
return t0.day > t1.day;
|
||||
} else return t0.month > t1.month;
|
||||
} else return t0.year > t1.year;
|
||||
}
|
||||
|
||||
bool operator ==(const PIDateTime & t0, const PIDateTime & t1) {
|
||||
return (t0.year == t1.year && t0.month == t1.month && t0.day == t1.day &&
|
||||
t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds);
|
||||
}
|
||||
|
||||
|
||||
bool operator <(const PIDateTime & t0, const PIDateTime & t1) {
|
||||
if (t0.year == t1.year) {
|
||||
if (t0.month == t1.month) {
|
||||
if (t0.day == t1.day) {
|
||||
if (t0.hours == t1.hours) {
|
||||
if (t0.minutes == t1.minutes) {
|
||||
return t0.seconds < t1.seconds;
|
||||
} else return t0.minutes < t1.minutes;
|
||||
} else return t0.hours < t1.hours;
|
||||
} else return t0.day < t1.day;
|
||||
} else return t0.month < t1.month;
|
||||
} else return t0.year < t1.year;
|
||||
}
|
||||
|
||||
|
||||
bool operator >(const PIDateTime & t0, const PIDateTime & t1) {
|
||||
if (t0.year == t1.year) {
|
||||
if (t0.month == t1.month) {
|
||||
if (t0.day == t1.day) {
|
||||
if (t0.hours == t1.hours) {
|
||||
if (t0.minutes == t1.minutes) {
|
||||
return t0.seconds > t1.seconds;
|
||||
} else return t0.minutes > t1.minutes;
|
||||
} else return t0.hours > t1.hours;
|
||||
} else return t0.day > t1.day;
|
||||
} else return t0.month > t1.month;
|
||||
} else return t0.year > t1.year;
|
||||
}
|
||||
|
||||
|
||||
PITime PITime::current() {
|
||||
time_t rt = ::time(0);
|
||||
tm * pt = localtime(&rt);
|
||||
PITime t;
|
||||
t.seconds = pt->tm_sec;
|
||||
t.minutes = pt->tm_min;
|
||||
t.hours = pt->tm_hour;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
PIDate PIDate::current() {
|
||||
time_t rt = ::time(0);
|
||||
tm * pt = localtime(&rt);
|
||||
PIDate d;
|
||||
d.day = pt->tm_mday;
|
||||
d.month = pt->tm_mon + 1;
|
||||
d.year = pt->tm_year + 1900;
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
PIDateTime PIDateTime::current() {
|
||||
time_t rt = ::time(0);
|
||||
tm * pt = localtime(&rt);
|
||||
PIDateTime dt;
|
||||
dt.milliseconds = 0;
|
||||
dt.seconds = pt->tm_sec;
|
||||
dt.minutes = pt->tm_min;
|
||||
dt.hours = pt->tm_hour;
|
||||
dt.day = pt->tm_mday;
|
||||
dt.month = pt->tm_mon + 1;
|
||||
dt.year = pt->tm_year + 1900;
|
||||
return dt;
|
||||
}
|
||||
|
||||
|
||||
PISystemTime PISystemTime::abs() const {
|
||||
if (seconds < 0)
|
||||
return PISystemTime(piAbsl(seconds) - 1, 1e+9 - piAbsl(nanoseconds));
|
||||
else
|
||||
return PISystemTime(piAbsl(seconds), piAbsl(nanoseconds));
|
||||
}
|
||||
|
||||
|
||||
PISystemTime PISystemTime::current(bool precise_but_not_system) {
|
||||
#ifdef WINDOWS
|
||||
if (precise_but_not_system) {
|
||||
llong qpc(0);
|
||||
if (__pi_perf_freq > 0) {
|
||||
qpc = __PIQueryPerformanceCounter();
|
||||
return PISystemTime::fromSeconds(qpc / double(__pi_perf_freq));
|
||||
}
|
||||
return PISystemTime();
|
||||
} else {
|
||||
FILETIME ft, sft;
|
||||
# if (_WIN32_WINNT >= 0x0602)
|
||||
GetSystemTimePreciseAsFileTime(&ft);
|
||||
# else
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
# endif
|
||||
sft.dwHighDateTime = ft.dwHighDateTime - __pi_ftjan1970.dwHighDateTime;
|
||||
if (ft.dwLowDateTime < __pi_ftjan1970.dwLowDateTime) {
|
||||
sft.dwLowDateTime = ft.dwLowDateTime + (0xFFFFFFFF - __pi_ftjan1970.dwLowDateTime);
|
||||
sft.dwHighDateTime++;
|
||||
} else
|
||||
sft.dwLowDateTime = ft.dwLowDateTime - __pi_ftjan1970.dwLowDateTime;
|
||||
ullong lt = ullong(sft.dwHighDateTime) * 0x100000000U + ullong(sft.dwLowDateTime);
|
||||
return PISystemTime(lt / 10000000U, (lt % 10000000U) * 100U);
|
||||
}
|
||||
//long t_cur = GetCurrentTime();
|
||||
//return PISystemTime(t_cur / 1000, (t_cur % 1000) * 1000000);
|
||||
#else
|
||||
# ifdef MAC_OS
|
||||
mach_timespec_t t_cur;
|
||||
clock_get_time(__pi_mac_clock, &t_cur);
|
||||
# else
|
||||
timespec t_cur;
|
||||
clock_gettime(0, &t_cur);
|
||||
# endif
|
||||
return PISystemTime(t_cur.tv_sec, t_cur.tv_nsec);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PIString PITime::toString(const PIString & format) const {
|
||||
PIString ts = format;
|
||||
ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0'));
|
||||
ts.replace("h", PIString::fromNumber(hours));
|
||||
ts.replace("mm", PIString::fromNumber(minutes).expandLeftTo(2, '0'));
|
||||
ts.replace("m", PIString::fromNumber(minutes));
|
||||
ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0'));
|
||||
ts.replace("s", PIString::fromNumber(seconds));
|
||||
ts.replace("zzz", PIString::fromNumber(milliseconds).expandLeftTo(3, '0'));
|
||||
ts.replace("zz", PIString::fromNumber(milliseconds).expandLeftTo(2, '0'));
|
||||
ts.replace("z", PIString::fromNumber(milliseconds));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
PIString PIDate::toString(const PIString & format) const {
|
||||
PIString ts = format;
|
||||
ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0'));
|
||||
ts.replace("yy", PIString::fromNumber(year).right(2));
|
||||
ts.replace("y", PIString::fromNumber(year).right(1));
|
||||
ts.replace("MM", PIString::fromNumber(month).expandLeftTo(2, '0'));
|
||||
ts.replace("M", PIString::fromNumber(month));
|
||||
ts.replace("dd", PIString::fromNumber(day).expandLeftTo(2, '0'));
|
||||
ts.replace("d", PIString::fromNumber(day));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
PIString PIDateTime::toString(const PIString & format) const {
|
||||
PIString ts = format;
|
||||
ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0'));
|
||||
ts.replace("yy", PIString::fromNumber(year).right(2));
|
||||
ts.replace("y", PIString::fromNumber(year).right(1));
|
||||
ts.replace("MM", PIString::fromNumber(month).expandLeftTo(2, '0'));
|
||||
ts.replace("M", PIString::fromNumber(month));
|
||||
ts.replace("dd", PIString::fromNumber(day).expandLeftTo(2, '0'));
|
||||
ts.replace("d", PIString::fromNumber(day));
|
||||
ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0'));
|
||||
ts.replace("h", PIString::fromNumber(hours));
|
||||
ts.replace("mm", PIString::fromNumber(minutes).expandLeftTo(2, '0'));
|
||||
ts.replace("m", PIString::fromNumber(minutes));
|
||||
ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0'));
|
||||
ts.replace("s", PIString::fromNumber(seconds));
|
||||
ts.replace("zzz", PIString::fromNumber(milliseconds).expandLeftTo(3, '0'));
|
||||
ts.replace("zz", PIString::fromNumber(milliseconds).expandLeftTo(2, '0'));
|
||||
ts.replace("z", PIString::fromNumber(milliseconds));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
time_t PIDateTime::toSecondSinceEpoch() const {
|
||||
tm pt;
|
||||
memset(&pt, 0, sizeof(pt));
|
||||
pt.tm_sec = seconds;
|
||||
pt.tm_min = minutes;
|
||||
pt.tm_hour = hours;
|
||||
pt.tm_mday = day;
|
||||
pt.tm_mon = month - 1;
|
||||
pt.tm_year = piMaxi(year - 1900, 71);
|
||||
return mktime(&pt);
|
||||
}
|
||||
|
||||
|
||||
PIDateTime PIDateTime::fromSecondSinceEpoch(const time_t sec) {
|
||||
tm * pt = localtime(&sec);
|
||||
PIDateTime dt;
|
||||
dt.seconds = pt->tm_sec;
|
||||
dt.minutes = pt->tm_min;
|
||||
dt.hours = pt->tm_hour;
|
||||
dt.day = pt->tm_mday;
|
||||
dt.month = pt->tm_mon + 1;
|
||||
dt.year = pt->tm_year + 1900;
|
||||
return dt;
|
||||
|
||||
}
|
||||
|
||||
|
||||
PIString time2string(const PITime & time, const PIString & format) {
|
||||
PIString ts = format;
|
||||
ts.replace("hh", PIString::fromNumber(time.hours).expandLeftTo(2, '0'));
|
||||
ts.replace("h", PIString::fromNumber(time.hours));
|
||||
ts.replace("mm", PIString::fromNumber(time.minutes).expandLeftTo(2, '0'));
|
||||
ts.replace("m", PIString::fromNumber(time.minutes));
|
||||
ts.replace("ss", PIString::fromNumber(time.seconds).expandLeftTo(2, '0'));
|
||||
ts.replace("s", PIString::fromNumber(time.seconds));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
PIString date2string(const PIDate & date, const PIString & format) {
|
||||
PIString ts = format;
|
||||
ts.replace("yyyy", PIString::fromNumber(date.year).expandLeftTo(4, '0'));
|
||||
ts.replace("yy", PIString::fromNumber(date.year).right(2));
|
||||
ts.replace("y", PIString::fromNumber(date.year).right(1));
|
||||
ts.replace("MM", PIString::fromNumber(date.month).expandLeftTo(2, '0'));
|
||||
ts.replace("M", PIString::fromNumber(date.month));
|
||||
ts.replace("dd", PIString::fromNumber(date.day).expandLeftTo(2, '0'));
|
||||
ts.replace("d", PIString::fromNumber(date.day));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
PIString datetime2string(const PIDateTime & date, const PIString & format) {
|
||||
PIString ts = format;
|
||||
ts.replace("hh", PIString::fromNumber(date.hours).expandLeftTo(2, '0'));
|
||||
ts.replace("h", PIString::fromNumber(date.hours));
|
||||
ts.replace("mm", PIString::fromNumber(date.minutes).expandLeftTo(2, '0'));
|
||||
ts.replace("m", PIString::fromNumber(date.minutes));
|
||||
ts.replace("ss", PIString::fromNumber(date.seconds).expandLeftTo(2, '0'));
|
||||
ts.replace("s", PIString::fromNumber(date.seconds));
|
||||
ts.replace("yyyy", PIString::fromNumber(date.year).expandLeftTo(4, '0'));
|
||||
ts.replace("yy", PIString::fromNumber(date.year).right(2));
|
||||
ts.replace("y", PIString::fromNumber(date.year).right(1));
|
||||
ts.replace("MM", PIString::fromNumber(date.month).expandLeftTo(2, '0'));
|
||||
ts.replace("M", PIString::fromNumber(date.month));
|
||||
ts.replace("dd", PIString::fromNumber(date.day).expandLeftTo(2, '0'));
|
||||
ts.replace("d", PIString::fromNumber(date.day));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PITimeMeasurer::PITimeMeasurer() {
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
double PITimeMeasurer::elapsed_n() {
|
||||
return (PISystemTime::current(true) - t_st).toNanoseconds() - PISystemTests::time_elapsed_ns;
|
||||
}
|
||||
|
||||
|
||||
double PITimeMeasurer::elapsed_u() {
|
||||
return (PISystemTime::current(true) - t_st).toMicroseconds() - PISystemTests::time_elapsed_ns / 1.E+3;
|
||||
}
|
||||
|
||||
|
||||
double PITimeMeasurer::elapsed_m() {
|
||||
return (PISystemTime::current(true) - t_st).toMilliseconds() - PISystemTests::time_elapsed_ns / 1.E+6;
|
||||
}
|
||||
|
||||
|
||||
double PITimeMeasurer::elapsed_s() {
|
||||
return (PISystemTime::current(true) - t_st).toSeconds() - PISystemTests::time_elapsed_ns / 1.E+9;
|
||||
}
|
||||
|
||||
|
||||
PISystemTime PITimeMeasurer::elapsed() {
|
||||
return (PISystemTime::current(true) - t_st);
|
||||
}
|
||||
315
pitime.h
315
pitime.h
@@ -1,315 +0,0 @@
|
||||
/*! \file pitime.h
|
||||
* \brief Time structs
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Time structs
|
||||
Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PITIME_H
|
||||
#define PITIME_H
|
||||
|
||||
#include <ctime>
|
||||
#include <csignal>
|
||||
#include "pistring.h"
|
||||
|
||||
#ifdef DOXYGEN
|
||||
//! \brief Sleep for "msecs" milliseconds
|
||||
void msleep(int msecs);
|
||||
#else
|
||||
# ifdef WINDOWS
|
||||
inline void msleep(int msecs) {Sleep(msecs);}
|
||||
# else
|
||||
inline void msleep(int msecs) {usleep(msecs * 1000);}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*! \brief Precise sleep for "usecs" microseconds
|
||||
* \details This function consider \c "usleep" offset
|
||||
* on QNX/Linux/Mac, which is calculated with
|
||||
* \a pip_sys_test program. If there is correct
|
||||
* offset value in system config, this function
|
||||
* wait \b exactly "usecs" microseconds. */
|
||||
void piUSleep(int usecs); // on !Windows consider constant "usleep" offset
|
||||
|
||||
/*! \brief Precise sleep for "msecs" milliseconds
|
||||
* \details This function exec \a piUSleep (msecs * 1000). */
|
||||
inline void piMSleep(double msecs) {piUSleep(msecs * 1000);} // on !Windows consider constant "usleep" offset
|
||||
|
||||
/*! \brief Precise sleep for "secs" seconds
|
||||
* \details This function exec \a piUSleep (msecs * 1000000). */
|
||||
inline void piSleep(double secs) {piUSleep(secs * 1000000);} // on !Windows consider constant "usleep" offset
|
||||
|
||||
class PIP_EXPORT PISystemTime {
|
||||
public:
|
||||
|
||||
//! Contructs system time with s = ns = 0
|
||||
PISystemTime() {seconds = nanoseconds = 0;}
|
||||
|
||||
//! Contructs system time with s = "s" and ns = "ns"
|
||||
PISystemTime(long s, long ns) {seconds = s; nanoseconds = ns; checkOverflows();}
|
||||
|
||||
//! Contructs system time from another
|
||||
PISystemTime(const PISystemTime & t) {seconds = t.seconds; nanoseconds = t.nanoseconds;}
|
||||
|
||||
//! Returns stored system time value in seconds
|
||||
double toSeconds() const {return double(seconds) + nanoseconds / 1.e+9;}
|
||||
|
||||
//! Returns stored system time value in milliseconds
|
||||
double toMilliseconds() const {return seconds * 1.e+3 + nanoseconds / 1.e+6;}
|
||||
|
||||
//! Returns stored system time value in microseconds
|
||||
double toMicroseconds() const {return seconds * 1.e+6 + nanoseconds / 1.e+3;}
|
||||
|
||||
//! Returns stored system time value in nanoseconds
|
||||
double toNanoseconds() const {return seconds * 1.e+9 + double(nanoseconds);}
|
||||
|
||||
|
||||
//! Add to stored system time "v" seconds
|
||||
PISystemTime & addSeconds(double v) {*this += fromSeconds(v); return *this;}
|
||||
|
||||
//! Add to stored system time "v" milliseconds
|
||||
PISystemTime & addMilliseconds(double v) {*this += fromMilliseconds(v); return *this;}
|
||||
|
||||
//! Add to stored system time "v" microseconds
|
||||
PISystemTime & addMicroseconds(double v) {*this += fromMicroseconds(v); return *this;}
|
||||
|
||||
//! Add to stored system time "v" nanoseconds
|
||||
PISystemTime & addNanoseconds(double v) {*this += fromNanoseconds(v); return *this;}
|
||||
|
||||
|
||||
//! Sleep for stored value. \warning Use this function to sleep for difference of system times or constructs system time.
|
||||
//! If you call this function on system time returned with \a PISystemTime::current() thread will be sleep almost forever.
|
||||
void sleep() {piUSleep(piFloord(toMicroseconds()));} // wait self value, useful to wait some dT = (t1 - t0)
|
||||
|
||||
|
||||
//! Returns copy of this system time with absolutely values of s and ns
|
||||
PISystemTime abs() const;
|
||||
|
||||
//! Returns sum of this system time with "t"
|
||||
PISystemTime operator +(const PISystemTime & t) const {PISystemTime tt(*this); tt.seconds += t.seconds; tt.nanoseconds += t.nanoseconds; tt.checkOverflows(); return tt;}
|
||||
|
||||
//! Returns difference between this system time and "t"
|
||||
PISystemTime operator -(const PISystemTime & t) const {PISystemTime tt(*this); tt.seconds -= t.seconds; tt.nanoseconds -= t.nanoseconds; tt.checkOverflows(); return tt;}
|
||||
|
||||
//! Returns multiplication between this system time and "t"
|
||||
PISystemTime operator *(const double & v) const {return fromMilliseconds(toMilliseconds() * v);}
|
||||
|
||||
//! Returns division between this system time and "t"
|
||||
PISystemTime operator /(const double & v) const {return fromMilliseconds(toMilliseconds() / v);}
|
||||
|
||||
//! Add to stored value system time "t"
|
||||
PISystemTime & operator +=(const PISystemTime & t) {seconds += t.seconds; nanoseconds += t.nanoseconds; checkOverflows(); return *this;}
|
||||
|
||||
//! Subtract from stored value system time "t"
|
||||
PISystemTime & operator -=(const PISystemTime & t) {seconds -= t.seconds; nanoseconds -= t.nanoseconds; checkOverflows(); return *this;}
|
||||
|
||||
//! Multiply stored value system time by "v"
|
||||
PISystemTime & operator *=(const double & v) {*this = fromMilliseconds(toMilliseconds() * v); return *this;}
|
||||
|
||||
//! Divide stored value system time by "v"
|
||||
PISystemTime & operator /=(const double & v) {*this = fromMilliseconds(toMilliseconds() / v); return *this;}
|
||||
|
||||
|
||||
//! Compare system times
|
||||
bool operator ==(const PISystemTime & t) const {return ((seconds == t.seconds) && (nanoseconds == t.nanoseconds));}
|
||||
|
||||
//! Compare system times
|
||||
bool operator !=(const PISystemTime & t) const {return ((seconds != t.seconds) || (nanoseconds != t.nanoseconds));}
|
||||
|
||||
//! Compare system times
|
||||
bool operator >(const PISystemTime & t) const {if (seconds == t.seconds) return nanoseconds > t.nanoseconds; return seconds > t.seconds;}
|
||||
|
||||
//! Compare system times
|
||||
bool operator <(const PISystemTime & t) const {if (seconds == t.seconds) return nanoseconds < t.nanoseconds; return seconds < t.seconds;}
|
||||
|
||||
//! Compare system times
|
||||
bool operator >=(const PISystemTime & t) const {if (seconds == t.seconds) return nanoseconds >= t.nanoseconds; return seconds >= t.seconds;}
|
||||
|
||||
//! Compare system times
|
||||
bool operator <=(const PISystemTime & t) const {if (seconds == t.seconds) return nanoseconds <= t.nanoseconds; return seconds <= t.seconds;}
|
||||
|
||||
|
||||
//! Contructs system time from seconds "v"
|
||||
static PISystemTime fromSeconds(double v) {long s = piFloord(v); return PISystemTime(s, (v - s) * 1000000000);}
|
||||
|
||||
//! Contructs system time from milliseconds "v"
|
||||
static PISystemTime fromMilliseconds(double v) {long s = piFloord(v / 1000.); return PISystemTime(s, (v / 1000. - s) * 1000000000);}
|
||||
|
||||
//! Contructs system time from microseconds "v"
|
||||
static PISystemTime fromMicroseconds(double v) {long s = piFloord(v / 1000000.); return PISystemTime(s, (v / 1000000. - s) * 1000000000);}
|
||||
|
||||
//! Contructs system time from nanoseconds "v"
|
||||
static PISystemTime fromNanoseconds(double v) {long s = piFloord(v / 1000000000.); return PISystemTime(s, (v / 1000000000. - s) * 1000000000);}
|
||||
|
||||
//! Returns current system time
|
||||
static PISystemTime current(bool precise_but_not_system = false);
|
||||
|
||||
//! Seconds of stored system time
|
||||
long seconds;
|
||||
|
||||
//! Nanoseconds of stored system time
|
||||
long nanoseconds;
|
||||
|
||||
private:
|
||||
void checkOverflows() {while (nanoseconds >= 1000000000) {nanoseconds -= 1000000000; seconds++;} while (nanoseconds < 0) {nanoseconds += 1000000000; seconds--;}}
|
||||
|
||||
};
|
||||
|
||||
//! \relatesalso PICout \relatesalso PIByteArray \brief Output operator to PICout
|
||||
inline PICout operator <<(PICout s, const PISystemTime & v) {s.space(); s.setControl(0, true); s << "(" << v.seconds << " s, " << v.nanoseconds << " ns)"; s.restoreControl(); return s;}
|
||||
|
||||
//! \relatesalso PISystemTime \relatesalso PIByteArray \brief Output operator to PIByteArray
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PISystemTime & v) {s << v.seconds << v.nanoseconds; return s;}
|
||||
|
||||
//! \relatesalso PISystemTime \relatesalso PIByteArray \brief Input operator from PIByteArray
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PISystemTime & v) {s >> v.seconds >> v.nanoseconds; return s;}
|
||||
|
||||
struct PIP_EXPORT PITime {
|
||||
PITime(int hours_ = 0, int minutes_ = 0, int seconds_ = 0, int milliseconds_ = 0): hours(hours_), minutes(minutes_), seconds(seconds_), milliseconds(milliseconds_) {;}
|
||||
int hours;
|
||||
int minutes;
|
||||
int seconds;
|
||||
int milliseconds;
|
||||
PIString toString(const PIString & format = "h:mm:ss") const;
|
||||
static PITime current();
|
||||
};
|
||||
PIP_EXPORT bool operator ==(const PITime & t0, const PITime & t1);
|
||||
PIP_EXPORT bool operator <(const PITime & t0, const PITime & t1);
|
||||
PIP_EXPORT bool operator >(const PITime & t0, const PITime & t1);
|
||||
inline bool operator !=(const PITime & t0, const PITime & t1) {return !(t0 == t1);}
|
||||
inline bool operator <=(const PITime & t0, const PITime & t1) {return !(t0 > t1);}
|
||||
inline bool operator >=(const PITime & t0, const PITime & t1) {return !(t0 < t1);}
|
||||
|
||||
struct PIP_EXPORT PIDate {
|
||||
PIDate(int year_ = 0, int month_ = 0, int day_ = 0): year(year_), month(month_), day(day_) {;}
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
PIString toString(const PIString & format = "d.MM.yyyy") const;
|
||||
static PIDate current();
|
||||
};
|
||||
PIP_EXPORT bool operator ==(const PIDate & t0, const PIDate & t1);
|
||||
PIP_EXPORT bool operator <(const PIDate & t0, const PIDate & t1);
|
||||
PIP_EXPORT bool operator >(const PIDate & t0, const PIDate & t1);
|
||||
inline bool operator !=(const PIDate & t0, const PIDate & t1) {return !(t0 == t1);}
|
||||
inline bool operator <=(const PIDate & t0, const PIDate & t1) {return !(t0 > t1);}
|
||||
inline bool operator >=(const PIDate & t0, const PIDate & t1) {return !(t0 < t1);}
|
||||
|
||||
struct PIP_EXPORT PIDateTime {
|
||||
PIDateTime() {year = month = day = hours = minutes = seconds = milliseconds = 0;}
|
||||
PIDateTime(const PITime & time) {year = month = day = 0; hours = time.hours; minutes = time.minutes; seconds = time.seconds; milliseconds = time.milliseconds;}
|
||||
PIDateTime(const PIDate & date) {year = date.year; month = date.month; day = date.day; hours = minutes = seconds = milliseconds = 0;}
|
||||
PIDateTime(const PIDate & date, const PITime & time) {year = date.year; month = date.month; day = date.day; hours = time.hours; minutes = time.minutes; seconds = time.seconds; milliseconds = time.milliseconds;}
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
int hours;
|
||||
int minutes;
|
||||
int seconds;
|
||||
int milliseconds;
|
||||
PIDateTime normalized() const {return PIDateTime::fromSecondSinceEpoch(toSecondSinceEpoch());}
|
||||
void normalize() {*this = normalized();}
|
||||
PIString toString(const PIString & format = "h:mm:ss d.MM.yyyy") const;
|
||||
time_t toSecondSinceEpoch() const;
|
||||
PISystemTime toSystemTime() const {return PISystemTime(int(toSecondSinceEpoch()), milliseconds * 1000000);}
|
||||
PIDate date() const {return PIDate(year, month, day);}
|
||||
PITime time() const {return PITime(hours, minutes, seconds, milliseconds);}
|
||||
void setDate(const PIDate & d) {year = d.year; month = d.month; day = d.day;}
|
||||
void setTime(const PITime & t) {hours = t.hours; minutes = t.minutes; seconds = t.seconds; milliseconds = t.milliseconds;}
|
||||
void operator +=(const PIDateTime & d1) {year += d1.year; month += d1.month; day += d1.day; hours += d1.hours; minutes += d1.minutes; seconds += d1.seconds; normalize();}
|
||||
void operator -=(const PIDateTime & d1) {year -= d1.year; month -= d1.month; day -= d1.day; hours -= d1.hours; minutes -= d1.minutes; seconds -= d1.seconds; normalize();}
|
||||
static PIDateTime fromSecondSinceEpoch(const time_t sec);
|
||||
static PIDateTime fromSystemTime(const PISystemTime & st) {PIDateTime dt = fromSecondSinceEpoch(st.seconds); dt.milliseconds = piClampi(st.nanoseconds / 1000000, 0, 999); return dt;}
|
||||
static PIDateTime current();
|
||||
};
|
||||
inline PIDateTime operator +(const PIDateTime & d0, const PIDateTime & d1) {PIDateTime td = d0; td += d1; return td.normalized();}
|
||||
inline PIDateTime operator -(const PIDateTime & d0, const PIDateTime & d1) {PIDateTime td = d0; td -= d1; return td.normalized();}
|
||||
PIP_EXPORT bool operator ==(const PIDateTime & t0, const PIDateTime & t1);
|
||||
PIP_EXPORT bool operator <(const PIDateTime & t0, const PIDateTime & t1);
|
||||
PIP_EXPORT bool operator >(const PIDateTime & t0, const PIDateTime & t1);
|
||||
inline bool operator !=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 == t1);}
|
||||
inline bool operator <=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 > t1);}
|
||||
inline bool operator >=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 < t1);}
|
||||
|
||||
DEPRECATED inline PITime currentTime() {return PITime::current();} // obsolete, use PITime::current() instead
|
||||
DEPRECATED inline PIDate currentDate() {return PIDate::current();} // obsolete, use PIDate::current() instead
|
||||
DEPRECATED inline PIDateTime currentDateTime() {return PIDateTime::current();} // obsolete, use PIDateTime::current() instead
|
||||
|
||||
//! \brief Returns current system time \deprecated Use \a PISystemTime::current() instead
|
||||
DEPRECATED inline PISystemTime currentSystemTime() {return PISystemTime::current();} // obsolete, use PISystemTime::current() instead
|
||||
DEPRECATED PIP_EXPORT PIString time2string(const PITime & time, const PIString & format = "h:mm:ss"); // obsolete, use PITime.toString() instead
|
||||
DEPRECATED PIP_EXPORT PIString date2string(const PIDate & date, const PIString & format = "d.MM.yyyy"); // obsolete, use PITime.toString() instead
|
||||
DEPRECATED PIP_EXPORT PIString datetime2string(const PIDateTime & datetime, const PIString & format = "h:mm:ss d.MM.yyyy"); // obsolete, use PIDateTime.toString() instead
|
||||
|
||||
|
||||
class PITimeMeasurer {
|
||||
public:
|
||||
PITimeMeasurer();
|
||||
|
||||
/** \brief Set internal time mark to current system time
|
||||
* \details This function used for set start time mark. Later
|
||||
* you can find out elapsed time from this time mark to any
|
||||
* moment of time with \a elapsed_s(), \a elapsed_m(),
|
||||
* \a elapsed_u() or \a elapsed_n() functions.
|
||||
* \sa \a elapsed_s(), \a elapsed_m(), \a elapsed_u(), \a elapsed_n() */
|
||||
void reset() {t_st = PISystemTime::current(true);}
|
||||
|
||||
//! \brief Returns nanoseconds elapsed from last \a reset() execution or from timer measurer creation.
|
||||
double elapsed_n();
|
||||
|
||||
//! \brief Returns microseconds elapsed from last \a reset() execution or from timer measurer creation.
|
||||
double elapsed_u();
|
||||
|
||||
//! \brief Returns milliseconds elapsed from last \a reset() execution or from timer measurer creation.
|
||||
double elapsed_m();
|
||||
|
||||
//! \brief Returns seconds elapsed from last \a reset() execution or from timer measurer creation.
|
||||
double elapsed_s();
|
||||
|
||||
//! \brief Returns PISystemTime elapsed from last \a reset() execution or from timer measurer creation.
|
||||
PISystemTime elapsed();
|
||||
|
||||
double reset_time_n() {return t_st.toNanoseconds();}
|
||||
double reset_time_u() {return t_st.toMicroseconds();}
|
||||
double reset_time_m() {return t_st.toMilliseconds();}
|
||||
double reset_time_s() {return t_st.toSeconds();}
|
||||
|
||||
//! \brief Returns time mark of last \a reset() execution or timer measurer creation.
|
||||
PISystemTime reset_time() {return t_st;}
|
||||
|
||||
//! \brief Returns nanoseconds representation of current system time.
|
||||
static double elapsed_system_n() {return PISystemTime::current(true).toNanoseconds();}
|
||||
|
||||
//! \brief Returns microseconds representation of current system time.
|
||||
static double elapsed_system_u() {return PISystemTime::current(true).toMicroseconds();}
|
||||
|
||||
//! \brief Returns milliseconds representation of current system time.
|
||||
static double elapsed_system_m() {return PISystemTime::current(true).toMilliseconds();}
|
||||
|
||||
//! \brief Returns seconds representation of current system time.
|
||||
static double elapsed_system_s() {return PISystemTime::current(true).toSeconds();}
|
||||
|
||||
//! \brief Returns time mark of current system time.
|
||||
static PISystemTime elapsed_system() {return PISystemTime::current(true);}
|
||||
|
||||
private:
|
||||
PISystemTime t_st, t_cur;
|
||||
|
||||
};
|
||||
|
||||
#endif // PITIME_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user