3 Commits

Author SHA1 Message Date
Бычков Анлрей
e85b11a233 PIMap via pipair, fix tests 2022-05-26 18:07:44 +03:00
Бычков Анлрей
831adf3fc9 some new tests 2022-05-25 18:52:19 +03:00
Бычков Анлрей
a18f461ce3 pimap tests 2022-05-24 18:40:06 +03:00
442 changed files with 33259 additions and 58257 deletions

View File

@@ -1,224 +0,0 @@
---
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignArrayOfStructures: Left
AlignConsecutiveAssignments:
Enabled: true
AcrossEmptyLines: true
AcrossComments: true
AlignCompound: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: true
AcrossEmptyLines: false
AcrossComments: true
AlignCompound: false
PadOperators: true
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: true
AcrossComments: true
AlignCompound: false
PadOperators: true
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: false
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- __capability
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakInheritanceList: BeforeComma
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 140
CommentPragmas: '^ IWYU pragma:'
QualifierAlignment: Leave
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: false
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: Always
ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: CurrentLine
BasedOnStyle: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: true
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
- piForeach
- piForeachC
- piForeachR
- piForeachRC
- piForeachCR
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: false
IndentPPDirectives: AfterHash
IndentExternBlock: NoIndent
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: false
InsertTrailingCommas: Wrapped
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
LambdaBodyIndentation: Signature
MacroBlockBegin: "PRIVATE_DEFINITION_START|STATIC_INITIALIZER_BEGIN"
MacroBlockEnd: "PRIVATE_DEFINITION_END|STATIC_INITIALIZER_END"
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
PointerAlignment: Middle
PPIndentWidth: 2
ReferenceAlignment: Middle
ReflowComments: true
RemoveBracesLLVM: false
RequiresClausePosition: OwnLine
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: false
SpaceBeforeInheritanceColon: false
SpaceBeforeParens: ControlStatementsExceptControlMacros
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: false
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: false
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Both
SpaceBeforeRangeBasedForLoopColon: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: After
Standard: c++11
StatementAttributeLikeMacros:
- Q_EMIT
- PIMETA
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
- PRIVATE_DECLARATION
- NO_COPY_CLASS
- FOREVER_WAIT
- WAIT_FOREVER
TabWidth: 4
UseCRLF: false
UseTab: AlignWithSpaces
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
- PIMETA
...

View File

@@ -1,6 +0,0 @@
root = true
[*.{h,c,cpp}]
charset = utf-8
indent_style = tab
tab_width = 4

3
.gitignore vendored
View File

@@ -3,5 +3,4 @@
/doc/rtf /doc/rtf
_unsused _unsused
CMakeLists.txt.user* CMakeLists.txt.user*
/include /include
/release

View File

@@ -5,7 +5,7 @@
*/ */
#define lapi_c #define lapi_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lcode_c #define lcode_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lctype_c #define lctype_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define ldebug_c #define ldebug_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define ldo_c #define ldo_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define ldump_c #define ldump_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lfunc_c #define lfunc_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lgc_c #define lgc_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define llex_c #define llex_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lmem_c #define lmem_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lobject_c #define lobject_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lopcodes_c #define lopcodes_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lparser_c #define lparser_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lstate_c #define lstate_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lstring_c #define lstring_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define ltable_c #define ltable_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define ltm_c #define ltm_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lundump_c #define lundump_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lvm_c #define lvm_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lzio_c #define lzio_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -1,12 +1,12 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0017 NEW) # need include() with .cmake cmake_policy(SET CMP0017 NEW) # need include() with .cmake
project(PIP) project(pip)
set(PIP_MAJOR 4) set(pip_MAJOR 2)
set(PIP_MINOR 5) set(pip_MINOR 39)
set(PIP_REVISION 0) set(pip_REVISION 0)
set(PIP_SUFFIX ) set(pip_SUFFIX )
set(PIP_COMPANY SHS) set(pip_COMPANY SHS)
set(PIP_DOMAIN org.SHS) set(pip_DOMAIN org.SHS)
set(GIT_CMAKE_DIR) set(GIT_CMAKE_DIR)
if (NOT DEFINED SHSTKPROJECT) if (NOT DEFINED SHSTKPROJECT)
@@ -17,7 +17,7 @@ cmake_minimum_required(VERSION 2.8.2)
project(cmake-download NONE) project(cmake-download NONE)
include(ExternalProject) include(ExternalProject)
ExternalProject_Add(cmake ExternalProject_Add(cmake
GIT_REPOSITORY https://git.shstk.ru/SHS/cmake.git GIT_REPOSITORY https://git.shs.tools/SHS/cmake.git
GIT_TAG \"origin/master\" GIT_TAG \"origin/master\"
GIT_CONFIG \"advice.detachedHead=false\" GIT_CONFIG \"advice.detachedHead=false\"
SOURCE_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cmake-src\" SOURCE_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cmake-src\"
@@ -53,8 +53,7 @@ include(CheckFunctionExists)
include(PIPMacros) include(PIPMacros)
include(SHSTKMacros) include(SHSTKMacros)
shstk_begin_project(PIP) shstk_begin_project(pip PIP)
set(PIP_VERSION "${PIP_VERSION}" CACHE STRING "")
set(_ICU_DEFAULT OFF) set(_ICU_DEFAULT OFF)
if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE)) if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE))
@@ -62,6 +61,7 @@ if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE
endif() endif()
set(PIP_DLL_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "") set(PIP_DLL_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "")
# Options # Options
option(ICU "ICU support for convert codepages" ${_ICU_DEFAULT}) option(ICU "ICU support for convert codepages" ${_ICU_DEFAULT})
option(STD_IOSTREAM "Building with std iostream operators support" OFF) option(STD_IOSTREAM "Building with std iostream operators support" OFF)
@@ -72,13 +72,6 @@ set(PIP_UTILS 1)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE) set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
shstk_is_parent_exists(_pe)
if (_pe)
set(BUILDING_pip 1 PARENT_SCOPE)
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}")
endif()
# Basic # Basic
set(PIP_MODULES) set(PIP_MODULES)
@@ -91,7 +84,7 @@ set(PIP_UTILS_LIST)
set(PIP_TESTS_LIST) set(PIP_TESTS_LIST)
set(PIP_EXPORTS) set(PIP_EXPORTS)
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;client_server;cloud;lua;http_client;http_server") set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;cloud;lua")
foreach(_m ${PIP_SRC_MODULES}) foreach(_m ${PIP_SRC_MODULES})
set(PIP_MSG_${_m} "no") set(PIP_MSG_${_m} "no")
endforeach() endforeach()
@@ -103,7 +96,7 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
set(CRES) set(CRES)
file(GLOB_RECURSE CPPS "libs/${NAME}/*.cpp" "libs/${NAME}/*.c") file(GLOB_RECURSE CPPS "libs/${NAME}/*.cpp" "libs/${NAME}/*.c")
file(GLOB_RECURSE HS "libs/${NAME}/*.h") file(GLOB_RECURSE HS "libs/${NAME}/*.h")
file(GLOB_RECURSE PHS "libs/${NAME}/*_p.h" "libs/${NAME}/3rd/*.h") file(GLOB_RECURSE PHS "libs/${NAME}/*_p.h")
file(GLOB_RECURSE RES "libs/${NAME}/*.conf") file(GLOB_RECURSE RES "libs/${NAME}/*.conf")
if (NOT "x${PHS}" STREQUAL "x") if (NOT "x${PHS}" STREQUAL "x")
list(REMOVE_ITEM HS ${PHS}) list(REMOVE_ITEM HS ${PHS})
@@ -112,14 +105,9 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
file(GLOB_RECURSE ASRC "${SOURCES}/*.cpp" "${SOURCES}/*.c") file(GLOB_RECURSE ASRC "${SOURCES}/*.cpp" "${SOURCES}/*.c")
list(APPEND CPPS ${ASRC}) list(APPEND CPPS ${ASRC})
endif() endif()
#message("${NAME} HS = ${HS}")
list(APPEND HDRS ${HS}) list(APPEND HDRS ${HS})
list(APPEND PHDRS ${PHS}) list(APPEND PHDRS ${PHS})
if(${CMAKE_VERSION} VERSION_LESS "3.8.0")
else()
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${CPPS} ${HS} ${PHS})
endif()
set(_target "pip_${NAME}") set(_target "pip_${NAME}")
set(_libs "${LIBS}") set(_libs "${LIBS}")
if ("${NAME}" STREQUAL "main") if ("${NAME}" STREQUAL "main")
@@ -130,11 +118,11 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
string(TOUPPER "${_target}" DEF_NAME) string(TOUPPER "${_target}" DEF_NAME)
set(PIP_MSG_${NAME} "yes${MSG}") set(PIP_MSG_${NAME} "yes${MSG}")
import_version(${_target} PIP) import_version(${_target} pip)
set_deploy_property(${_target} ${PIP_LIB_TYPE} set_deploy_property(${_target} ${pip_LIB_TYPE}
LABEL "${LABEL}" LABEL "${LABEL}"
FULLNAME "${PIP_DOMAIN}.${_target}" FULLNAME "${pip_DOMAIN}.${_target}"
COMPANY "${PIP_COMPANY}" COMPANY "${pip_COMPANY}"
INFO "Platform-Independent Primitives") INFO "Platform-Independent Primitives")
make_rc(${_target} _RC) make_rc(${_target} _RC)
@@ -151,7 +139,7 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
pip_resources(CRES "${RES}") pip_resources(CRES "${RES}")
endif() endif()
add_definitions(-D${DEF_NAME}) add_definitions(-D${DEF_NAME})
add_library(${_target} ${PIP_LIB_TYPE} ${CPPS} ${CRES} ${_RC} ${HS} ${PHS}) add_library(${_target} ${pip_LIB_TYPE} ${CPPS} ${CRES} ${_RC})
target_include_directories(${_target} PUBLIC ${PIP_INCLUDES}) target_include_directories(${_target} PUBLIC ${PIP_INCLUDES})
if (NOT "x${RES}" STREQUAL "x") if (NOT "x${RES}" STREQUAL "x")
add_dependencies(${_target} pip_rc) add_dependencies(${_target} pip_rc)
@@ -183,12 +171,10 @@ if (NOT DEFINED PIP_CMG)
if (CMAKE_CROSSCOMPILING OR (DEFINED ANDROID_PLATFORM)) if (CMAKE_CROSSCOMPILING OR (DEFINED ANDROID_PLATFORM))
set(PIP_CMG "pip_cmg") set(PIP_CMG "pip_cmg")
set(PIP_RC "pip_rc") set(PIP_RC "pip_rc")
set(PIP_TR "pip_tr")
set(PIP_DEPLOY_TOOL "deploy_tool") set(PIP_DEPLOY_TOOL "deploy_tool")
else() else()
set(PIP_CMG "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator/pip_cmg") set(PIP_CMG "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator/pip_cmg")
set(PIP_RC "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler/pip_rc") set(PIP_RC "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler/pip_rc")
set(PIP_TR "${CMAKE_CURRENT_BINARY_DIR}/utils/translator/pip_tr")
set(PIP_DEPLOY_TOOL "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool/deploy_tool") set(PIP_DEPLOY_TOOL "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool/deploy_tool")
endif() endif()
endif() endif()
@@ -248,11 +234,26 @@ if(PIP_MATH_YN)
add_definitions(-DPIP_MATH_YN) add_definitions(-DPIP_MATH_YN)
endif() endif()
# Check if RT timers exists
set(CMAKE_REQUIRED_INCLUDES time.h)
set(CMAKE_REQUIRED_LIBRARIES )
if((NOT DEFINED ENV{QNX_HOST}) AND (NOT APPLE) AND (NOT WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT PIP_FREERTOS))
list(APPEND LIBS_MAIN rt)
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)
# Check if build debug version # Check if build debug version
if (PIP_BUILD_DEBUG) if (CMAKE_BUILD_TYPE MATCHES Debug)
set(PIP_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall")
add_definitions(-DPIP_DEBUG) add_definitions(-DPIP_DEBUG)
else() else()
set(PIP_BUILD_TYPE "Release")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall")
endif() endif()
@@ -280,14 +281,9 @@ endif()
# Check if ICU used for PIString and PIChar # Check if ICU used for PIString and PIChar
set(PIP_ICU "no") set(PIP_ICU "no")
if(ICU) if(ICU)
pip_find_lib(icuuc) set(PIP_ICU "yes")
if (icuuc_FOUND) add_definitions(-DPIP_ICU)
set(PIP_ICU "yes") list(APPEND LIBS_MAIN icuuc)
add_definitions(-DPIP_ICU)
list(APPEND LIBS_MAIN icuuc)
else()
message(STATUS "Warning: ICU requested, but not found. Build without ICU")
endif()
endif() endif()
@@ -311,6 +307,15 @@ list(APPEND HDRS ${_PIP_DEFS_FILE})
#message("${_PIP_DEFS_CHANGED}") #message("${_PIP_DEFS_CHANGED}")
# Check if RT timers exists
if(PIP_TIMER_RT_0 AND PIP_TIMER_RT_1 AND PIP_TIMER_RT_2)
set(PIP_TIMERS "Thread, ThreadRT, Pool")
add_definitions(-DPIP_TIMER_RT)
else()
set(PIP_TIMERS "Thread, Pool")
endif()
# Add main library # Add main library
if(APPLE) if(APPLE)
@@ -321,27 +326,23 @@ if ((NOT DEFINED SHSTKPROJECT) AND (DEFINED ANDROID_PLATFORM))
#message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include") #message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include")
#message("${ANDROID_NDK}/sysroot/usr/include") #message("${ANDROID_NDK}/sysroot/usr/include")
endif() endif()
if(NOT PIP_FREERTOS) if(NOT PIP_FREERTOS)
if(WIN32) if(WIN32)
if(${C_COMPILER} STREQUAL "cl.exe") if(${C_COMPILER} STREQUAL "cl.exe")
else()
list(APPEND LIBS_MAIN ws2_32 iphlpapi psapi cfgmgr32 setupapi)
endif()
else() else()
list(APPEND LIBS_MAIN dl) list(APPEND LIBS_MAIN ws2_32 iphlpapi psapi cfgmgr32 setupapi)
if(DEFINED ENV{QNX_HOST}) endif()
list(APPEND LIBS_MAIN socket) else()
else() list(APPEND LIBS_MAIN dl)
if (NOT DEFINED ANDROID_PLATFORM) if(DEFINED ENV{QNX_HOST})
list(APPEND LIBS_MAIN pthread util) list(APPEND LIBS_MAIN socket)
if (NOT APPLE) else()
list(APPEND LIBS_MAIN rt) if (NOT DEFINED ANDROID_PLATFORM)
endif() list(APPEND LIBS_MAIN pthread util)
endif()
endif() endif()
endif() endif()
endif() endif()
endif()
set(PIP_LIBS) set(PIP_LIBS)
if(PIP_FREERTOS) if(PIP_FREERTOS)
set(PIP_LIBS ${LIBS_MAIN}) set(PIP_LIBS ${LIBS_MAIN})
@@ -368,8 +369,6 @@ pip_module(main "${LIBS_MAIN}" "PIP main library" "" "" "")
generate_export_header(pip) generate_export_header(pip)
list(APPEND HDRS "${CMAKE_CURRENT_BINARY_DIR}/pip_export.h") list(APPEND HDRS "${CMAKE_CURRENT_BINARY_DIR}/pip_export.h")
file(GLOB_RECURSE _RM_HDRS "libs/main/digest/3rd/*.h")
list(REMOVE_ITEM HDRS ${_RM_HDRS})
foreach(_m ${PIP_SRC_MODULES}) foreach(_m ${PIP_SRC_MODULES})
set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_${_m}_EXPORTS) set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_${_m}_EXPORTS)
generate_export_header(pip BASE_NAME "pip_${_m}") generate_export_header(pip BASE_NAME "pip_${_m}")
@@ -377,17 +376,6 @@ foreach(_m ${PIP_SRC_MODULES})
endforeach() endforeach()
set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_EXPORTS) set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_EXPORTS)
# Override containers minimum bytes allocation
if(NOT "x${PIP_CONTAINERS_MIN_ALLOC}" STREQUAL "x")
target_compile_definitions(pip PRIVATE "-DPIP_CONTAINERS_MIN_ALLOC=${PIP_CONTAINERS_MIN_ALLOC}")
message(STATUS "Attention: Override PIP_CONTAINERS_MIN_ALLOC = ${PIP_CONTAINERS_MIN_ALLOC}")
endif()
# Override containers maximum bytes for power of two expansion, may be bytes or X_KiB, or X_MiB
if(NOT "x${PIP_CONTAINERS_MAX_POT_ALLOC}" STREQUAL "x")
target_compile_definitions(pip PRIVATE "-DPIP_CONTAINERS_MAX_POT_ALLOC=${PIP_CONTAINERS_MAX_POT_ALLOC}")
message(STATUS "Attention: Override PIP_CONTAINERS_MAX_POT_ALLOC = ${PIP_CONTAINERS_MAX_POT_ALLOC}")
endif()
if (NOT CROSSTOOLS) if (NOT CROSSTOOLS)
if (NOT PIP_FREERTOS) if (NOT PIP_FREERTOS)
@@ -411,7 +399,6 @@ if (NOT CROSSTOOLS)
pip_find_lib(sodium) pip_find_lib(sodium)
if(sodium_FOUND) if(sodium_FOUND)
pip_module(crypt "sodium" "PIP crypt support" "" "" "") pip_module(crypt "sodium" "PIP crypt support" "" "" "")
pip_module(client_server "pip_io_utils" "PIP client-server helper" "" "" "")
pip_module(cloud "pip_io_utils" "PIP cloud support" "" "" "") pip_module(cloud "pip_io_utils" "PIP cloud support" "" "" "")
endif() endif()
@@ -461,16 +448,17 @@ if (NOT CROSSTOOLS)
endif() endif()
if (NOT "x${MINGW_INCLUDE}" STREQUAL "x")
list(APPEND CMAKE_INCLUDE_PATH "${MINGW_INCLUDE}")
endif()
find_package(OpenCL QUIET) #OpenCL_VERSION_STRING find_package(OpenCL QUIET) #OpenCL_VERSION_STRING
if(OpenCL_FOUND) if(OpenCL_FOUND)
set(_opencl_lib OpenCL::OpenCL)
if(${CMAKE_VERSION} VERSION_LESS "3.7.0")
target_link_libraries(_opencl_lib OpenCL)
endif()
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}") set(_opencl_inc "${OpenCL_INCLUDE_DIRS}")
if(APPLE) if(APPLE)
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers") set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers")
endif() endif()
pip_module(opencl "OpenCL" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})") pip_module(opencl "${_opencl_lib}" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})")
endif() endif()
@@ -492,58 +480,15 @@ if (NOT CROSSTOOLS)
endif() endif()
list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge") list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge")
list(APPEND HDRS ${_lua_src_hdr}) list(APPEND HDRS ${_lua_src_hdr})
# libmicrohttpd
pip_find_lib(microhttpd HINTS "${MINGW_LIB}")
if (microhttpd_FOUND)
set(_microhttpd_add_libs microhttpd)
if(WIN32)
if("${C_COMPILER}" STREQUAL "cl.exe")
else()
list(APPEND _microhttpd_add_libs ws2_32)
endif()
else()
list(APPEND _microhttpd_add_libs dl)
find_library(tls_lib gnutls)
if (tls_lib)
set(gnutls_FOUND TRUE)
set(gnutls_LIBRARIES "${tls_lib}")
list(APPEND _microhttpd_add_libs gnutls)
endif()
if(DEFINED ENV{QNX_HOST})
list(APPEND _microhttpd_add_libs socket)
else()
if (NOT DEFINED ANDROID_PLATFORM)
list(APPEND _microhttpd_add_libs pthread util)
endif()
endif()
endif()
#list(APPEND microhttpd_LIBRARIES "${_microhttpd_add_libs}")
pip_module(http_server "${_microhttpd_add_libs}" "PIP HTTP server" "" "" "")
endif()
# libcurl
pip_find_lib(curl HINTS "${MINGW_LIB}")
if (curl_FOUND)
pip_module(http_client curl "PIP HTTP client" "" "" "")
endif()
# Test program # Test program
if(PIP_UTILS) if(PIP_UTILS)
#add_library(pip_plugin SHARED "test_plugin.h" "test_plugin.cpp")
#add_library(pip_plugin SHARED "test_plugin.h" "test_plugin.cpp" "ccm.h" "ccm.cpp")
#target_link_libraries(pip_plugin pip) #target_link_libraries(pip_plugin pip)
if (NOT DEFINED ANDROID_PLATFORM) add_executable(pip_test "main.cpp")
if(microhttpd_FOUND AND curl_FOUND) target_link_libraries(pip_test pip)
add_executable(pip_test "main.cpp")
target_link_libraries(pip_test pip pip_io_utils pip_client_server pip_http_server pip_http_client)
if(sodium_FOUND)
add_executable(pip_cloud_test "main_picloud_test.cpp")
target_link_libraries(pip_cloud_test pip_cloud)
endif()
endif()
endif()
endif() endif()
else() else()
@@ -556,43 +501,6 @@ endif()
string(REPLACE ";" "," PIP_EXPORTS_STR "${PIP_EXPORTS}") string(REPLACE ";" "," PIP_EXPORTS_STR "${PIP_EXPORTS}")
target_compile_definitions(pip PRIVATE "PICODE_DEFINES=\"${PIP_EXPORTS_STR}\"") target_compile_definitions(pip PRIVATE "PICODE_DEFINES=\"${PIP_EXPORTS_STR}\"")
if(NOT PIP_FREERTOS)
# Auxiliary
if (NOT CROSSTOOLS)
add_subdirectory("utils/piterminal")
endif()
# Utils
add_subdirectory("utils/code_model_generator")
add_subdirectory("utils/resources_compiler")
add_subdirectory("utils/deploy_tool")
add_subdirectory("utils/qt_support")
add_subdirectory("utils/translator")
add_subdirectory("utils/value_tree_translator")
if(PIP_UTILS AND (NOT CROSSTOOLS))
add_subdirectory("utils/system_test")
add_subdirectory("utils/udp_file_transfer")
if(sodium_FOUND)
add_subdirectory("utils/system_daemon")
add_subdirectory("utils/crypt_tool")
add_subdirectory("utils/cloud_dispatcher")
endif()
endif()
endif()
# Translations
set(PIP_LANG)
if (NOT CROSSTOOLS)
# pip_translation(PIP_LANG lang/pip_ru.ts)
# add_custom_target(pip_lang SOURCES "${PIP_LANG}")
file(GLOB PIP_LANG "lang/*.btf")
endif()
# Install # Install
# Check if system or local install will be used (to system install use "-DLIB=" argument of cmake) # Check if system or local install will be used (to system install use "-DLIB=" argument of cmake)
if(NOT LOCAL) if(NOT LOCAL)
@@ -600,9 +508,6 @@ if(NOT LOCAL)
if(MINGW) if(MINGW)
if (NOT CROSSTOOLS) if (NOT CROSSTOOLS)
install(FILES ${HDRS} DESTINATION ${MINGW_INCLUDE}/pip) install(FILES ${HDRS} DESTINATION ${MINGW_INCLUDE}/pip)
if(PIP_LANG)
install(FILES ${PIP_LANG} DESTINATION ${MINGW_INCLUDE}/../share/pip/lang)
endif()
if(HDR_DIRS) if(HDR_DIRS)
install(DIRECTORY ${HDR_DIRS} DESTINATION ${MINGW_INCLUDE}/pip) install(DIRECTORY ${HDR_DIRS} DESTINATION ${MINGW_INCLUDE}/pip)
endif() endif()
@@ -616,7 +521,6 @@ if(NOT LOCAL)
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator") file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator")
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler") file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler")
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool") file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool")
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/translator")
endif() endif()
else() else()
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pip_export.h DESTINATION include) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pip_export.h DESTINATION include)
@@ -624,9 +528,6 @@ if(NOT LOCAL)
else() else()
if (NOT CROSSTOOLS) if (NOT CROSSTOOLS)
install(FILES ${HDRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip) install(FILES ${HDRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip)
if(PIP_LANG)
install(FILES ${PIP_LANG} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pip/lang)
endif()
if(HDR_DIRS) if(HDR_DIRS)
install(DIRECTORY ${HDR_DIRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip) install(DIRECTORY ${HDR_DIRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip)
endif() endif()
@@ -642,9 +543,6 @@ else()
install(TARGETS ${PIP_MODULES} DESTINATION lib) install(TARGETS ${PIP_MODULES} DESTINATION lib)
endif() endif()
install(FILES ${HDRS} DESTINATION include/pip) install(FILES ${HDRS} DESTINATION include/pip)
if(PIP_LANG)
install(FILES ${PIP_LANG} DESTINATION share/pip/lang)
endif()
if(HDR_DIRS) if(HDR_DIRS)
install(DIRECTORY ${HDR_DIRS} DESTINATION include/pip) install(DIRECTORY ${HDR_DIRS} DESTINATION include/pip)
endif() endif()
@@ -653,6 +551,29 @@ endif()
file(GLOB CMAKES "cmake/*.cmake" "cmake/*.in") file(GLOB CMAKES "cmake/*.cmake" "cmake/*.in")
install(FILES ${CMAKES} DESTINATION ${CMAKE_ROOT}/Modules) install(FILES ${CMAKES} DESTINATION ${CMAKE_ROOT}/Modules)
if(NOT PIP_FREERTOS)
# Auxiliary
if (NOT CROSSTOOLS)
add_subdirectory("utils/piterminal")
endif()
# Utils
add_subdirectory("utils/code_model_generator")
add_subdirectory("utils/resources_compiler")
add_subdirectory("utils/deploy_tool")
if(PIP_UTILS AND (NOT CROSSTOOLS))
add_subdirectory("utils/system_test")
add_subdirectory("utils/udp_file_transfer")
if(sodium_FOUND)
add_subdirectory("utils/system_daemon")
add_subdirectory("utils/crypt_tool")
add_subdirectory("utils/cloud_dispatcher")
endif()
endif()
endif()
shstk_is_parent_exists(_pe) shstk_is_parent_exists(_pe)
if (_pe) if (_pe)
@@ -667,18 +588,18 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
find_package(Doxygen) find_package(Doxygen)
if(DOXYGEN_FOUND) if(DOXYGEN_FOUND)
set(DOXY_DEFINES "${PIP_EXPORTS}") set(DOXY_DEFINES "${PIP_EXPORTS}")
foreach (_m "console" "usb" "compress" "crypt" "client_server" "cloud" "fftw" "opencl" "io_utils" "lua" "http_server" "http_client") foreach (_m "console" "usb" "compress" "crypt" "cloud" "fftw" "opencl" "io_utils" "lua")
string(TOUPPER "${_m}" _mdef) string(TOUPPER "${_m}" _mdef)
list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT") list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT")
endforeach() endforeach()
set(DOXY_PROJECT_NUMBER "${PIP_VERSION}") set(DOXY_PROJECT_NUMBER "${pip_VERSION}")
set(DOXY_QHP_CUST_FILTER_ATTRS "\"PIP ${PIP_VERSION}\"") set(DOXY_QHP_CUST_FILTER_ATTRS "\"PIP ${pip_VERSION}\"")
set(DOXY_QHP_SECT_FILTER_ATTRS "\"PIP ${PIP_VERSION}\"") set(DOXY_QHP_SECT_FILTER_ATTRS "\"PIP ${pip_VERSION}\"")
set(DOXY_EXAMPLE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/examples\"") set(DOXY_EXAMPLE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/examples\"")
set(DOXY_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"") set(DOXY_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"")
set(DOXY_LOGO_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pip.png\"") set(DOXY_LOGO_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pip.png\"")
set(DOXY_EXCLUDE "\"${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd\"") set(DOXY_EXCLUDE "\"${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd\"")
set(DOXY_DOMAIN "${PIP_DOMAIN}.${PROJECT_NAME}.doc") set(DOXY_DOMAIN "${pip_DOMAIN}.${PROJECT_NAME}.doc")
if ("x${DOC_LANG}" STREQUAL "x") if ("x${DOC_LANG}" STREQUAL "x")
set(DOXY_OUTPUT_LANGUAGE English) set(DOXY_OUTPUT_LANGUAGE English)
set(DOXY_OUTPUT_DIR en) set(DOXY_OUTPUT_DIR en)
@@ -723,11 +644,10 @@ macro(expand_to_length _out _str _len)
endmacro() endmacro()
list(REMOVE_ITEM LIBS_STATUS ${PIP_MODULES}) list(REMOVE_ITEM LIBS_STATUS ${PIP_MODULES})
list(REMOVE_DUPLICATES LIBS_STATUS)
message("----------PIP----------") message("----------PIP----------")
message(" Version: ${PIP_VERSION} ") message(" Version: ${pip_VERSION} ")
message(" Linkage: ${PIP_LIB_TYPE_MSG}") message(" Linkage: ${pip_LIB_TYPE_MSG}")
message(" Type : ${CMAKE_BUILD_TYPE}") message(" Type : ${pip_BUILD_TYPE}")
if (NOT LOCAL) if (NOT LOCAL)
message(" Install: \"${CMAKE_INSTALL_PREFIX}\"") message(" Install: \"${CMAKE_INSTALL_PREFIX}\"")
else() else()
@@ -739,6 +659,7 @@ message("")
message(" Options:") message(" Options:")
message(" std::iostream: ${PIP_STD_IOSTREAM}") message(" std::iostream: ${PIP_STD_IOSTREAM}")
message(" ICU strings : ${PIP_ICU}") message(" ICU strings : ${PIP_ICU}")
message(" Timer types : ${PIP_TIMERS}")
message(" Introspection: ${PIP_INTROSPECTION}") message(" Introspection: ${PIP_INTROSPECTION}")
message(" Coverage : ${PIP_COVERAGE}") message(" Coverage : ${PIP_COVERAGE}")
if(INTROSPECTION) if(INTROSPECTION)

View File

@@ -33,10 +33,10 @@ You should add ${<out_var>} to your target.
## Documentation ## Documentation
[🇺🇸 Online documentation](https://shstk.ru/pip/html/en/index.html) [🇺🇸 Online documentation](https://shs.tools/pip/html/en/index.html)
[🇺🇸 Qt-help](https://shstk.ru/pip/pip_en.qch) [🇺🇸 Qt-help](https://shs.tools/pip/pip_en.qch)
[🇷🇺 Онлайн документация](https://shstk.ru/pip/html/ru/index.html) [🇷🇺 Онлайн документация](https://shs.tools/pip/html/ru/index.html)
[🇷🇺 Qt-help](https://shstk.ru/pip/pip_ru.qch) [🇷🇺 Qt-help](https://shs.tools/pip/pip_ru.qch)

View File

@@ -9,11 +9,8 @@ Create imported targets:
* PIP::FFTW * PIP::FFTW
* PIP::OpenCL * PIP::OpenCL
* PIP::IOUtils * PIP::IOUtils
* PIP::ClientServer
* PIP::Cloud * PIP::Cloud
* PIP::Lua * PIP::Lua
* PIP::HTTPClient
* PIP::HTTPServer
These targets include directories and depends on These targets include directories and depends on
main library main library
@@ -23,37 +20,40 @@ main library
cmake_policy(SET CMP0011 NEW) # don`t affect includer policies cmake_policy(SET CMP0011 NEW) # don`t affect includer policies
include(SHSTKMacros) include(SHSTKMacros)
shstk_set_find_dirs(PIP) shstk_set_find_dirs(pip)
if(PIP_DIR)
list(APPEND pip_LIBDIR "${PIP_DIR}/lib")
list(APPEND pip_INCDIR "${PIP_DIR}/include/pip")
list(APPEND pip_BINDIR "${PIP_DIR}/bin")
endif()
set(__libs "usb;crypt;console;fftw;compress;opencl;io_utils;client_server;cloud;lua;http_client;http_server") set(__libs "usb;crypt;console;fftw;compress;io_utils;opencl;cloud;lua")
if (BUILDING_PIP) if (BUILDING_pip)
#set(_libs "pip;pip_usb;pip_console;pip_crypt;pip_fftw;pip_compress;pip_opencl;pip_io_utils;pip_cloud;pip_lua;pip_http_client;pip_http_server") #set(_libs "pip;pip_usb;pip_console;pip_crypt;pip_fftw;pip_compress;pip_opencl;pip_io_utils;pip_cloud;pip_lua")
#set(_bins "pip_cmg;pip_rc;deploy_tool") #set(_bins "pip_cmg;pip_rc;deploy_tool")
#get_target_property(_path pip BINARY_DIR) #get_target_property(_path pip BINARY_DIR)
#get_target_property(_path pip LIBRARY_OUTPUT_NAME) #get_target_property(_path pip LIBRARY_OUTPUT_NAME)
#message("${_path}") #message("${_path}")
#set(PIP_LIBRARY "$<TARGET_FILE_DIR:pip>/$<TARGET_FILE_NAME:pip>" CACHE STRING "") #set(PIP_LIBRARY "$<TARGET_FILE_DIR:pip>/$<TARGET_FILE_NAME:pip>" CACHE STRING "")
set(PIP_LIBRARY pip CACHE STRING "") set(PIP_LIBRARY pip CACHE STRING "")
set(PIP_FOUND ON CACHE BOOL "") set(PIP_FOUND ON CACHE BOOL "")
else() else()
find_library(PIP_LIBRARY pip HINTS ${PIP_LIBDIR}) find_library(PIP_LIBRARY pip HINTS ${pip_LIBDIR})
foreach (_l ${__libs}) foreach (_l ${__libs})
find_library(PIP_LIBRARY_${_l} pip_${_l} HINTS ${PIP_LIBDIR}) find_library(PIP_LIBRARY_${_l} pip_${_l} HINTS ${pip_LIBDIR})
endforeach() endforeach()
endif() endif()
if (BUILDING_PIP AND (NOT CMAKE_CROSSCOMPILING)) if (BUILDING_pip AND (NOT CMAKE_CROSSCOMPILING))
set(PIP_CMG "$<TARGET_FILE_DIR:pip_cmg>/$<TARGET_FILE_NAME:pip_cmg>" CACHE STRING "") set(PIP_CMG "$<TARGET_FILE_DIR:pip_cmg>/$<TARGET_FILE_NAME:pip_cmg>" CACHE STRING "")
set(PIP_RC "$<TARGET_FILE_DIR:pip_rc>/$<TARGET_FILE_NAME:pip_rc>" CACHE STRING "") set(PIP_RC "$<TARGET_FILE_DIR:pip_rc>/$<TARGET_FILE_NAME:pip_rc>" CACHE STRING "")
set(PIP_TR "$<TARGET_FILE_DIR:pip_tr>/$<TARGET_FILE_NAME:pip_tr>" CACHE STRING "")
set(PIP_DEPLOY_TOOL "$<TARGET_FILE_DIR:deploy_tool>/$<TARGET_FILE_NAME:deploy_tool>" CACHE STRING "") set(PIP_DEPLOY_TOOL "$<TARGET_FILE_DIR:deploy_tool>/$<TARGET_FILE_NAME:deploy_tool>" CACHE STRING "")
else() else()
find_program(PIP_CMG pip_cmg${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG}) find_program(PIP_CMG pip_cmg${pip_BINEXT} HINTS ${pip_BINDIR} ${pip_FIND_PROGRAM_ARG})
find_program(PIP_RC pip_rc${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG}) find_program(PIP_RC pip_rc${pip_BINEXT} HINTS ${pip_BINDIR} ${pip_FIND_PROGRAM_ARG})
find_program(PIP_TR pip_tr${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG}) find_program(PIP_DEPLOY_TOOL deploy_tool${pip_BINEXT} HINTS ${pip_BINDIR} ${pip_FIND_PROGRAM_ARG})
find_program(PIP_DEPLOY_TOOL deploy_tool${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG})
endif() endif()
if (NOT PIP_LIBRARY) if (NOT PIP_LIBRARY)
if(PIP_FIND_REQUIRED) if(PIP_FIND_REQUIRED)
@@ -63,7 +63,7 @@ if (NOT PIP_LIBRARY)
endif() endif()
set(_PIP_LIBRARY_PATH_ "${PIP_LIBRARY}") set(_PIP_LIBRARY_PATH_ "${PIP_LIBRARY}")
set(_PIP_ADD_LIBS_ "") set(_PIP_ADD_LIBS_ "")
if (NOT BUILDING_PIP) if (NOT BUILDING_pip)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
find_library(DL_LIBRARY dl) find_library(DL_LIBRARY dl)
list(APPEND PIP_LIBRARY ${DL_LIBRARY}) list(APPEND PIP_LIBRARY ${DL_LIBRARY})
@@ -80,26 +80,23 @@ if (NOT BUILDING_PIP)
endif() endif()
endif() endif()
if (NOT BUILDING_PIP) if (NOT BUILDING_pip)
shstk_find_header(PIP "pip_version.h" "${_PIP_LIBRARY_PATH_}") shstk_find_header(pip PIP "pip_version.h" "${_PIP_LIBRARY_PATH_}")
set(PIP_INCLUDES "${PIP_INCLUDES}" CACHE STRING "") set(PIP_INCLUDES "${pip_INCLUDES}" CACHE STRING "")
endif() endif()
if(PIP_FIND_VERSION VERSION_GREATER PIP_VERSION) if(PIP_FIND_VERSION VERSION_GREATER PIP_VERSION)
message(FATAL_ERROR "PIP version ${PIP_VERSION} is available, but ${PIP_FIND_VERSION} requested!") message(FATAL_ERROR "PIP version ${PIP_VERSION} is available, but ${PIP_FIND_VERSION} requested!")
endif() endif()
set(__module_usb USB ) set(__module_usb USB )
set(__module_console Console ) set(__module_console Console )
set(__module_crypt Crypt ) set(__module_crypt Crypt )
set(__module_fftw FFTW ) set(__module_fftw FFTW )
set(__module_compress Compress ) set(__module_compress Compress )
set(__module_opencl OpenCL ) set(__module_opencl OpenCL )
set(__module_io_utils IOUtils ) set(__module_io_utils IOUtils )
set(__module_client_server ClientServer) set(__module_cloud Cloud )
set(__module_cloud Cloud ) set(__module_lua Lua )
set(__module_lua Lua )
set(__module_http_client HTTPClient )
set(__module_http_server HTTPServer )
foreach (_l ${__libs}) foreach (_l ${__libs})
set( __inc_${_l} "") set( __inc_${_l} "")
@@ -107,15 +104,14 @@ foreach (_l ${__libs})
set(__libs_${_l} "") set(__libs_${_l} "")
endforeach() endforeach()
set(__deps_io_utils "PIP::Crypt" ) set(__deps_io_utils "PIP::Crypt")
set(__deps_client_server "PIP::IOUtils") set(__deps_cloud "PIP::IOUtils")
set(__deps_cloud "PIP::IOUtils")
if (BUILDING_PIP) if (BUILDING_pip)
if (NOT SET_TARGETS_PIP) if (NOT SET_TARGETS_pip)
set(SET_TARGETS_PIP ON CACHE BOOL "") set(SET_TARGETS_pip ON CACHE BOOL "")
#message("create aliases") #message("create aliases")
if((NOT TARGET PIP) AND PIP_LIBRARY) if((NOT TARGET PIP) AND PIP_LIBRARY)
#message("alias PIP = pip") #message("alias PIP = pip")
@@ -137,7 +133,7 @@ else()
add_library(PIP UNKNOWN IMPORTED) add_library(PIP UNKNOWN IMPORTED)
set_target_properties(PIP PROPERTIES set_target_properties(PIP PROPERTIES
IMPORTED_LOCATION "${_PIP_LIBRARY_PATH_}" IMPORTED_LOCATION "${_PIP_LIBRARY_PATH_}"
INTERFACE_INCLUDE_DIRECTORIES "${PIP_INCLUDES}" INTERFACE_INCLUDE_DIRECTORIES "${pip_INCLUDES}"
INTERFACE_LINK_LIBRARIES "${_PIP_ADD_LIBS_}") INTERFACE_LINK_LIBRARIES "${_PIP_ADD_LIBS_}")
#message("imported PIP = ${PIP_LIBRARY}") #message("imported PIP = ${PIP_LIBRARY}")
endif() endif()

View File

@@ -18,14 +18,6 @@
Generate C++ files for resource file Generate C++ files for resource file
You should add ${<out_var>} to your target You should add ${<out_var>} to your target
pip_translation(<out_var> ts_file)
Generate *.btf (binary translation file) from *.ts file
You should add ${<out_var>} to your target and then install it to somewhere
for later loading in runtime by PITranslator
]] ]]
@@ -127,34 +119,3 @@ macro(pip_resources RESULT INPUT)
VERBATIM) VERBATIM)
endmacro() endmacro()
macro(pip_translation RESULT INPUT)
#message(STATUS "src = ${CCM_SRC}")
#message(STATUS "result = ${RESULT}")
#message(STATUS "options = \"${CCM_OPTS}\"")
get_filename_component(BTF_FILENAME "${INPUT}" NAME_WE)
set(BTF_FILENAME "${BTF_FILENAME}.btf")
set(BTF_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BTF_FILENAME})
list(APPEND ${RESULT} "${BTF_OUTPUT}")
if(IS_ABSOLUTE "${INPUT}")
set(IN_FILES "${INPUT}")
else()
set(IN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}")
endif()
#message(STATUS "CCM = ${RESULT}")
if(NOT DEFINED PIP_DLL_DIR)
set(PIP_DLL_DIR ${CMAKE_CURRENT_BINARY_DIR})
endif()
#message("PIP_TR: ${PIP_TR}")
#message("BTF_OUTPUT: ${BTF_OUTPUT}")
#message("IN_FILES: ${IN_FILES}")
#message("PIP_DLL_DIR: ${PIP_DLL_DIR}")
add_custom_command(OUTPUT ${BTF_OUTPUT}
COMMAND ${PIP_TR}
ARGS -C -o "${BTF_OUTPUT}" "${IN_FILES}"
DEPENDS ${IN_FILES}
WORKING_DIRECTORY ${PIP_DLL_DIR}
COMMENT "Generating ${BTF_FILENAME}"
VERBATIM)
endmacro()

View File

@@ -2282,7 +2282,7 @@ EXTERNAL_GROUPS = YES
# be listed. # be listed.
# The default value is: YES. # The default value is: YES.
EXTERNAL_PAGES = NO EXTERNAL_PAGES = YES
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the dot tool # Configuration options related to the dot tool

View File

@@ -9,14 +9,8 @@ struct S {
}; };
// Operators // Operators
PIByteArray & operator<<(PIByteArray & b, const S & s) { PIByteArray & operator <<(PIByteArray & b, const S & s) {b << s.i << s.f << s.s; return b;}
b << s.i << s.f << s.s; PIByteArray & operator >>(PIByteArray & b, S & s) {b >> s.i >> s.f >> s.s; return b;}
return b;
}
PIByteArray & operator>>(PIByteArray & b, S & s) {
b >> s.i >> s.f >> s.s;
return b;
}
//! [struct] //! [struct]
//! [write] //! [write]
// Write chunk stream // Write chunk stream
@@ -28,7 +22,10 @@ PIVector<float> f;
f << -1. << 2.5 << 11.; f << -1. << 2.5 << 11.;
// write some data to empty stream // write some data to empty stream
PIChunkStream cs; PIChunkStream cs;
cs << cs.chunk(1, int(10)) << cs.chunk(2, PIString("text")) << cs.chunk(4, f) << cs.chunk(3, s); cs << cs.chunk(1, int(10))
<< cs.chunk(2, PIString("text"))
<< cs.chunk(4, f)
<< cs.chunk(3, s);
// now you can take cs.data() and send or place it somewhere ... // now you can take cs.data() and send or place it somewhere ...
//! [write] //! [write]
//! [read] //! [read]
@@ -45,14 +42,14 @@ while (!cs2.atEnd()) {
case 1: i = cs2.getData<int>(); break; case 1: i = cs2.getData<int>(); break;
case 2: str = cs2.getData<PIString>(); break; case 2: str = cs2.getData<PIString>(); break;
case 3: s = cs2.getData<S>(); break; case 3: s = cs2.getData<S>(); break;
case 4: f = cs2.getData<PIVector<float>>(); break; case 4: f = cs2.getData<PIVector<float> >(); break;
} }
} }
piCout << i << str << f << s.i << s.f << s.s; piCout << i << str << f << s.i << s.f << s.s;
//! [read] //! [read]
//! [write_new] //! [write_new]
PIByteArray & operator<<(PIByteArray & s, const S & value) { PIByteArray & operator <<(PIByteArray & s, const S & value) {
PIChunkStream cs; PIChunkStream cs;
cs.add(1, value.i).add(2, value.f).add(3, value.s); cs.add(1, value.i).add(2, value.f).add(3, value.s);
s << cs.data(); s << cs.data();
@@ -60,11 +57,11 @@ PIByteArray & operator<<(PIByteArray & s, const S & value) {
} }
//! [write_new] //! [write_new]
//! [read_new] //! [read_new]
PIByteArray & operator>>(PIByteArray & s, S & value) { PIByteArray & operator >>(PIByteArray & s, S & value) {
PIChunkStream cs; PIChunkStream cs;
if (!cs.extract(s)) return s; if (!cs.extract(s)) return s;
cs.readAll(); cs.readAll();
cs.get(1, value.i).get(2, value.f).get(3, value.s); cs.get(1, value.i).get(2, value.f).get(3, value.s);
return s; return b;
} }
//! [read_new] //! [read_new]

View File

@@ -1,57 +1,54 @@
#include "pip.h" #include "pip.h"
//! [own] //! [own]
inline PICout operator<<(PICout s, const PIByteArray & ba) { inline PICout operator <<(PICout s, const PIByteArray & ba) {
s.space(); // insert space after previous output s.space(); // insert space after previous output
s.quote(); // ONLY if you want to quoted your type s.quote(); // ONLY if you want to quoted your type
s.saveAndSetControls(0); // clear all features and s.setControl(0, true); // clear all features and
// save them to stack, // save them to stack,
// now it`s behavior similar to std::cout // now it`s behavior similar to std::cout
// your output // your output
for (uint i = 0; i < ba.size(); ++i) for (uint i = 0; i < ba.size(); ++i)
s << ba[i]; s << ba[i];
s.restoreControls(); // restore features from stack s.restoreControl(); // restore features from stack
s.quote(); // ONLY if you want to quoted your type s.quote(); // ONLY if you want to quoted your type
return s; return s;
} }
//! [own] //! [own]
// clang-format off
void _() { void _() {
//! [0] //! [0]
using namespace PICoutManipulators;
int a = 10, b = 32, c = 11; int a = 10, b = 32, c = 11;
piCout << a << Hex << b << Bin << c; piCout << a << Hex << b << Bin << c;
// 10 20 1011 // 10 20 1011
piCout << "this" piCout << "this" << "is" << Green << "green" << Default << "word";
<< "is" << Green << "green" << Default << "word";
// this is green word // this is green word
PICout(AddSpaces | AddNewLine | AddQuotes) << Tab << "tab and" PICout(AddSpaces | AddNewLine | AddQuotes) << Tab << "tab and" << "quotes";
<< "quotes";
// "tab and" "quotes" // "tab and" "quotes"
//! [0] //! [0]
} }
// clang-format on
//! [notifier] //! [notifier]
class A: public PIObject { class A: public PIObject {
PIOBJECT(A) PIOBJECT(A)
public: public:
A() {} A() {}
EVENT_HANDLER2(void, pcf, int, id, PIString *, buff) { piCout << "PICout(" << id << ") finished:" << (*buff); } EVENT_HANDLER2(void, pcf, int, id, PIString*, buff) {
piCout << "PICout(" << id << ") finished:" << (*buff);
}
}; };
int main() { int main() {
A a; A a;
CONNECTU(PICout::Notifier::object(), finished, &a, pcf); CONNECTU(PICout::Notifier::object(), finished, &a, pcf);
PIString buffer = "my buff:"; PIString buffer = "my buff:";
int my_id = PICout::registerExternalBufferID(); PICout(&buffer, 1) << "int 10 ->" << 10 << ", time ->" << PITime::current();
PICout::withExternalBufferAndID(&buffer, my_id) << "int 10 ->" << 10 << ", time ->" << PITime::current();
return 0; return 0;
} }
// PICout( 1 ) finished: my buff:int 10 -> 10 , time -> PITime(14:07:09:000) // PICout( 1 ) finished: my buff:int 10 -> 10 , time -> PITime(14:07:09:000)

View File

@@ -7,19 +7,19 @@ class SomeIO: public PIIODevice {
public: public:
SomeIO(): PIIODevice() {} SomeIO(): PIIODevice() {}
protected: protected:
bool openDevice() override { bool openDevice() {
// open your device here // open your device here
return if_success; return if_success;
} }
ssize_t readDevice(void * read_to, ssize_t max_size) override { int read(void * read_to, int max_size) {
// read from your device here // read from your device here
return readed_bytes; return readed_bytes;
} }
ssize_t writeDevice(const void * data, ssize_t max_size) override { int write(const void * data, int max_size) {
// write to your device here // write to your device here
return written_bytes; return written_bytes;
} }
void configureFromFullPathDevice(const PIString & full_path) override { void configureFromFullPath(const PIString & full_path) {
// parse full_path and configure device here // parse full_path and configure device here
} }
}; };
@@ -38,7 +38,7 @@ ser.configure("example.conf", "dev");
//! [configureDevice] //! [configureDevice]
class SomeIO: public PIIODevice { class SomeIO: public PIIODevice {
... ...
bool configureDevice(const void * e_main, const void * e_parent) override { bool configureDevice(const void * e_main, const void * e_parent) {
PIConfig::Entry * em = (PIConfig::Entry * )e_main; PIConfig::Entry * em = (PIConfig::Entry * )e_main;
PIConfig::Entry * ep = (PIConfig::Entry * )e_parent; PIConfig::Entry * ep = (PIConfig::Entry * )e_parent;
setStringParam(readDeviceSetting<PIString>("stringParam", stringParam(), em, ep)); setStringParam(readDeviceSetting<PIString>("stringParam", stringParam(), em, ep));

View File

@@ -1,10 +1,10 @@
#include "pip.h" #include "pip.h"
//! [delimiter] //! [delimiter]
void tfunc(int delim) { void tfunc(void * , int delim) {
piCout << "tick with delimiter" << delim; piCout << "tick with delimiter" << delim;
}; };
void tfunc4(int delim) { void tfunc4(void * , int delim) {
piCout << "tick4 with delimiter" << delim; piCout << "tick4 with delimiter" << delim;
}; };
int main() { int main() {
@@ -13,7 +13,8 @@ int main() {
timer.addDelimiter(4, tfunc4); timer.addDelimiter(4, tfunc4);
timer.start(50); timer.start(50);
piMSleep(200); piMSleep(200);
timer.stopAndWait(); timer.stop();
timer.waitForFinish();
return 0; return 0;
}; };
/* Result: /* Result:
@@ -28,14 +29,14 @@ tick4 with delimiter 4
//! [delimiter] //! [delimiter]
//! [elapsed] //! [elapsed]
int main() { int main() {
PITimeMeasurer tm; PITimer timer;
piMSleep(100); piMSleep(100);
piCout << "elapsed" << tm.elapsed_m() << "ms"; piCout << "elapsed" << timer.elapsed_m() << "ms";
piMSleep(100); piMSleep(100);
piCout << "elapsed" << tm.elapsed_m() << "ms"; piCout << "elapsed" << timer.elapsed_m() << "ms";
tm.reset(); timer.reset();
piMSleep(150); piMSleep(150);
piCout << "elapsed" << tm.elapsed_s() << "s"; piCout << "elapsed" << timer.elapsed_s() << "s";
return 0; return 0;
}; };
/* Result: /* Result:
@@ -46,21 +47,22 @@ elapsed 0.15 s
//! [elapsed] //! [elapsed]
//! [system_time] //! [system_time]
int main() { int main() {
PISystemTime t0; // s = ns = 0 PISystemTime t0; // s = ns = 0
t0.addMilliseconds(200); // s = 0, ns = 200000000 t0.addMilliseconds(200); // s = 0, ns = 200000000
t0.addMilliseconds(900); // s = 1, ns = 100000000 t0.addMilliseconds(900); // s = 1, ns = 100000000
t0 -= PISystemTime::fromSeconds(0.1); // s = 1, ns = 0 t0 -= PISystemTime::fromSeconds(0.1); // s = 1, ns = 0
t0.sleep(); // sleep for 1 second t0.sleep(); // sleep for 1 second
PISystemTime t1; PISystemTime t1;
t0 = PISystemTime::current(); t0 = currentSystemTime();
piMSleep(500); piMSleep(500);
t1 = PISystemTime::current(); t1 = currentSystemTime();
(t1 - t0).sleep(); // sleep for 500 milliseconds (t1 - t0).sleep(); // sleep for 500 milliseconds
return 0; return 0;
}; };
//! [system_time] //! [system_time]
void _(){ void _() {
}; };

View File

@@ -1,297 +0,0 @@
\~english \page code_model Code generation
\~russian \page code_model Генерация кода
\~english
\~russian
# Введение
Кодогенерация помогает в случаях, когда нужен доступ к строковому представлению
сущностей (классов, перечислений, ...), либо автоматизированная де/сериализация
структур и классов.
Например, необходимо для создания интерфейса получить в готовом виде список
пар "имя" = "значение" от какого-либо перечисления, либо обойти список
вложенных в класс структур с дополнительными метками. Или просто описать
структуру любой сложности, пометить поля номерами и получить готовые операторы
де/сериализации для PIBinaryStream с возможностью будущих изменений и сохранением
обратной совместимости.
# pip_cmg
PIP предоставляет утилиту, которая берет на вход файлы исходного кода, пути
включения, параметры и макросы, и на выходе создает h/cpp пару файлов с
необходимым функционалом. В зависимости от параметров, в этих файлах будут
присутствовать секции:
* метаинформации о сущностях;
* операторы де/сериализации;
* возможность получить PIVariant любого члена структуры по имени.
Параметры обработки:
* -s - не следовать "#include" внутри файлов;
* -I<include_dir> - добавить папку включения (например, -I.. -I../some_dir -I/usr/include);
* -D<define> - добавить макрос, PICODE всегда объявлен (например, -DMY_DEFINE добавит макрос MY_DEFINE).
Параметры создания:
* -A - создать всё;
* -M - создать метаинформацию (имена и типы всех членов, иерархия включения);
* -E - создать перечисления (списки перечислений);
* -S - создать операторы де/сериализации;
* -G - создать методы получения значений переменных по именам;
* -o <output_file> - имя файлов модели без расширения (например, "ccm" - создадутся файлы "ccm.h" и "ccm.cpp")
# CMake
Для автоматизации кодогенерации существует CMake макрос pip_code_model, который сам вызывает pip_cmg и
следит за актуальностью модели.
Формат вызова макроса:
\code{.cmake}
pip_code_model(<out_var> file0 [file1 ...] [OPTIONS opt0 [opt1 ...] ] [NAME name])
\endcode
Параметры:
* out_var - имя переменной, куда будут записаны абсолютные пути сгенерённых файлов;
* file... - файлы для генерации, допускаются относительные или абсолютные пути;
* OPTIONS - передаваемые в pip_cmg параметры, например, "-Es";
* NAME - базовое имя файлов модели, если не указано, то используется "ccm_${PROJECT_NAME}".
Этот макрос сам включает все пути для PIP.
Для получения актуальных параметров pip_cmg можно вызывать "pip_cmg -v".
# Подробности
## Метаинформация
Метаинформация - это текстовое представление всех членов и методов структуры или класса C++.
Для доступа к ним используется PICODEINFO::classes().value("name"), который возвращает
указатель на структуру PICodeInfo::ClassInfo, содержащую всю информацию о сущности.
В любой структуре PICodeInfo есть поле "MetaMap meta", содержащее произвольные
данные, видимые для кодогенератора, но невидимые для компилятора.
Для этого используется макрос PIMETA(), который необходимо вписать после объявления
переменной, метода либо сущности, например:
\code{.cpp}
struct MyStruct: Header PIMETA(type=in,port=5005) {
ushort calcChecksum() const PIMETA(show=true);
bool checkChecksum() const;
void setChecksum();
uchar block_id PIMETA(type=int) = 0;
};
enum FOV { // Поле зрения
fovWide PIMETA(label="Широкое",angle=90),
fovNormal PIMETA(label="Нормальное",angle=60),
fovNarrow PIMETA(label="Узкое",angle=30)
};
\endcode
В этом примере в каждом месте, где указана PIMETA, её можно будет получить через "MetaMap meta".
## Перечисления
Перечисления записываются отдельно, для доступа к ним используется PICODEINFO::enums().value("name"),
который возвращает указатель на структуру PICodeInfo::EnumInfo, содержащую всю информацию о перечеслении.
## Операторы де/сериализации
Эти операторы создаются в h файле для всех сутрктур и классов, в которых есть хотя бы один член,
доступный для работы. Операторы работают с PIBinaryStream в двух вариантах - простом или через PIChunkStream.
Для каждой структуры можно указать режим де/сериализации с помощью фиксированного поля в PIMETA:
* нет указаний - работа через PIChunkStream;
* simple-stream - работа просто через PIBinaryStream;
* no-stream - не создавать операторы.
Например, для структуры
\code{.cpp}
struct DateTime {
uchar seconds;
uchar minutes;
uchar hours;
uchar days;
uchar months;
uchar years;
};
\endcode
создадутся операторы
\code{.cpp}
BINARY_STREAM_WRITE(DateTime) {
PIChunkStream cs;
cs << cs.chunk(1, v.seconds);
cs << cs.chunk(2, v.minutes);
cs << cs.chunk(3, v.hours);
cs << cs.chunk(4, v.days);
cs << cs.chunk(5, v.months);
cs << cs.chunk(6, v.years);
s << cs.data();
return s;
}
BINARY_STREAM_READ (DateTime) {
PIByteArray csba; s >> csba;
PIChunkStream cs(csba);
while (!cs.atEnd()) {
switch (cs.read()) {
case 1: cs.get(v.seconds); break;
case 2: cs.get(v.minutes); break;
case 3: cs.get(v.hours); break;
case 4: cs.get(v.days); break;
case 5: cs.get(v.months); break;
case 6: cs.get(v.years); break;
}
}
return s;
}
\endcode
, где порядок id последовательнен.
Для структуры
\code{.cpp}
struct DateTime PIMETA(simple-stream) {
uchar seconds;
uchar minutes;
uchar hours;
uchar days;
uchar months;
uchar years;
};
\endcode
создадутся операторы
\code{.cpp}
BINARY_STREAM_WRITE(DateTime) {
s << v.seconds;
s << v.minutes;
s << v.hours;
s << v.days;
s << v.months;
s << v.years;
return s;
}
BINARY_STREAM_READ (DateTime) {
s >> v.seconds;
s >> v.minutes;
s >> v.hours;
s >> v.days;
s >> v.months;
s >> v.years;
return s;
}
\endcode
Для структуры
\code{.cpp}
struct DateTime PIMETA(no-stream) {
uchar seconds;
uchar minutes;
uchar hours;
uchar days;
uchar months;
uchar years;
};
\endcode
не создадутся операторы
В режиме работы через PIChunkStream также можно указать индивидуальные id,
что очень полезно для сохранения обратной совместимости структур разных версий:
Для структуры
\code{.cpp}
struct DateTime {
PIMETA(id=10) uchar seconds;
PIMETA(id=11) uchar minutes;
PIMETA(id=12) uchar hours;
PIMETA(id=20) uchar days;
PIMETA(id=21) uchar months;
PIMETA(id=22) uchar years;
};
\endcode
\code{.cpp}
BINARY_STREAM_WRITE(DateTime) {
PIChunkStream cs;
cs << cs.chunk(10, v.seconds);
cs << cs.chunk(11, v.minutes);
cs << cs.chunk(12, v.hours);
cs << cs.chunk(20, v.days);
cs << cs.chunk(21, v.months);
cs << cs.chunk(22, v.years);
s << cs.data();
return s;
}
BINARY_STREAM_READ (DateTime) {
PIByteArray csba; s >> csba;
PIChunkStream cs(csba);
while (!cs.atEnd()) {
switch (cs.read()) {
case 10: cs.get(v.seconds); break;
case 11: cs.get(v.minutes); break;
case 12: cs.get(v.hours); break;
case 20: cs.get(v.days); break;
case 21: cs.get(v.months); break;
case 22: cs.get(v.years); break;
}
}
return s;
}
\endcode
Если в этом режиме какую-либо переменную надо проигнорировать, то вместо
числа id можно указать "-":
\code{.cpp}
struct DateTime {
PIMETA(id=10) uchar seconds;
PIMETA(id=11) uchar minutes;
PIMETA(id=-) uchar hours;
PIMETA(id=20) uchar days;
PIMETA(id=21) uchar months;
PIMETA(id=-) uchar years;
};
\endcode
\code{.cpp}
BINARY_STREAM_WRITE(DateTime) {
PIChunkStream cs;
cs << cs.chunk(10, v.seconds);
cs << cs.chunk(11, v.minutes);
cs << cs.chunk(20, v.days);
cs << cs.chunk(21, v.months);
s << cs.data();
return s;
}
BINARY_STREAM_READ (DateTime) {
PIByteArray csba; s >> csba;
PIChunkStream cs(csba);
while (!cs.atEnd()) {
switch (cs.read()) {
case 10: cs.get(v.seconds); break;
case 11: cs.get(v.minutes); break;
case 20: cs.get(v.days); break;
case 21: cs.get(v.months); break;
}
}
return s;
}
\endcode
# Интеграция в проект
При использовании CMake достаточно включить содержимое переменной out_var в приложение
или библиотеку, и включить через "#include" сгенерированный заголовочный файл в нужном месте.
После этого перечисления и метаинформация будут загружены в момент запуска, до int main(),
а операторы станут доступны через заголовочный файл.
CMakeLists.txt:
\code{.cmake}
project(myapp)
pip_code_model(CCM "structures.h" OPTIONS "-EMs")
add_executable(${PROJECT_NAME} ${CPPS} ${CCM})
\endcode
C++:
\code{.cpp}
#include "ccm_myapp.h"
...
PICodeInfo::EnumInfo * ei = PICODEINFO::enums().value("MyEnum", 0);
if (ei) {
ei->members.forEach([](const PICodeInfo::EnumeratorInfo & e){piCout << e.name << "=" << e.value;});
}
\endcode

View File

@@ -1,125 +0,0 @@
\~english \page iostream Input/Output stream
\~russian \page iostream Поток ввода/вывода
\~english
\~russian
%PIBinaryStream представляет собой интерфейс бинарной сериализации.
Не может быть использован в чистом виде, только в виде миксина или
готовых классов: PIByteArray и PIIOBinaryStream.
Используется для сохранения или чтения любых данных. Простые типы читаются/пишутся
как блоки памяти, если не созданы конкретные операторы. Сложные типы
([нетривиальные](https://ru.cppreference.com/w/cpp/types/is_trivially_copyable))
обязаны иметь операторы ввода/вывода, иначе возникнет ошибка компиляции.
Также поддерживаются контейнеры с типами по таким же правилам.
Перечисления интерпретируются как int, логические типы как один байт.
Операторы сохранения добавляют данные в конец потока, а операторы извлечения
берут данные из его начала.
Для облегчения написания операторов есть макросы:
* BINARY_STREAM_FRIEND(T) - объявить операторы с доступом к приватному
содержимому типа T, необязателен;
* BINARY_STREAM_WRITE(T) - запись в поток, "s" - объект потока, "v" - объект типа T;
* BINARY_STREAM_READ(T) - чтение из потока, "s" - объект потока, "v" - объект типа T.
Пример:
\~\code{.cpp}
#include <pibytearray.h>
class MyType {
BINARY_STREAM_FRIEND(MyType);
public:
void setInt(int v) {m_i = v;}
int getInt() const {return m_i;}
void setString(PIString v) {m_s = v;}
PIString getString() const {return m_s;}
private:
int m_i = 0;
PIString m_s;
};
BINARY_STREAM_WRITE(MyType) {s << v.m_i << v.m_s; return s;}
BINARY_STREAM_READ (MyType) {s >> v.m_i >> v.m_s; return s;}
int main(int argc, char * argv[]) {
MyType t_read, t_write;
t_write.setInt(10);
t_write.setString("text");
PIByteArray data;
data << t_write;
piCout << data.toHex();
data >> t_read;
piCout << t_read.getInt() << t_read.getString();
piCout << data.toHex();
}
\endcode
\~english Result:
\~russian Результат:
\~\code{.cpp}
0a000000040000007400650078007400
10 text
\endcode
\~english
For store/restore custom data blocks this is PIMemoryBlock class. Stream
operators of this class simply store/restore data block to/from stream:
\~russian
Для сохранения/извлечения блоков произвольных данных используется класс PIMemoryBlock.
Потоковые операторы для него просто сохраняют/извлекают блоки байтов в/из потока:
\~\code{.cpp}
float a_read[10], a_write[10];
for (int i = 0; i < 10; ++i) {
a_read [i] = 0.f;
a_write[i] = i / 10.f;
}
PIByteArray data;
data << PIMemoryBlock(a_write, 10 * sizeof(float));
piCout << data.toHex();
data >> PIMemoryBlock(a_read, 10 * sizeof(float));
for (int i = 0; i < 10; ++i)
piCout << a_read[i];
\endcode
\~english Result:
\~russian Результат:
\~\code{.cpp}
00000000cdcccc3dcdcc4c3e9a99993ecdcccc3e0000003f9a99193f3333333fcdcc4c3f6666663f
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
\endcode
\~english
\~russian
Если при чтении из потока не хватило данных (например, закончился массив или файл), то проверка
объекта потока на wasReadError() вернёт true. Рекомендуется делать эту проверку после чтения
данных для корректной обработки ошибки.

View File

@@ -3,19 +3,19 @@
\~english \~english
* Direct output to console (\a PICout) * direct output to console (\a PICout)
* Containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet) * containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
* Byte array (\a PIByteArray) * byte array (\a PIByteArray)
* Serialization (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON) * serialization (\a PIChunkStream)
* String (\a PIConstChars, \a PIString, \a PIStringList) * string (\a PIConstChars, \a PIString, \a PIStringList)
* Base object (events and handlers) (\a PIObject) * base object (events and handlers) (\a PIObject)
* Multithreading * multithreading
* thread (\a PIThread) * thread (\a PIThread)
* blocking (\a PIMutex, \a PISpinlock, \a PIConditionVariable, \a PISemaphore, \a PIReadWriteLock) * blocking (\a PIMutex, \a PISpinlock)
* executor (\a PIThreadPoolExecutor, \a PIThreadPoolLoop) * executor (\a PIThreadPoolExecutor)
* blocking dequeue (\a PIBlockingDequeue) * blocking dequeue (\a PIBlockingDequeue)
* timer (\a PITimer) * timer (\a PITimer)
* Tiling console (with widgets) (\a PIScreen) * tiling console (with widgets) (\a PIScreen)
* simple text rows * simple text rows
* scroll bar * scroll bar
* list * list
@@ -37,8 +37,7 @@
* peering net node (\a PIPeer) * peering net node (\a PIPeer)
* connection quality diagnotic (\a PIDiagnostics) * connection quality diagnotic (\a PIDiagnostics)
* Run-time libraries * Run-time libraries
* external process (\a PIProcess) * abstract (\a PILibrary)
* external library (\a PILibrary)
* plugin (\a PIPluginLoader) * plugin (\a PIPluginLoader)
* Mathematics * Mathematics
* complex numbers * complex numbers
@@ -50,33 +49,24 @@
* CRC checksum (\a PICRC) * CRC checksum (\a PICRC)
* Fourier transform (\a PIFFTW, \a PIFFT) * Fourier transform (\a PIFFTW, \a PIFFT)
* expression evaluator (\a PIEvaluator) * expression evaluator (\a PIEvaluator)
* Application-level * command-line arguments parser (\a PICLI)
* command-line arguments parser (\a PICLI) * process (\a PIProcess)
* system resources monitoring (\a PISystemMonitor)
* single-instance application control (\a PISingleApplication)
* high-level log (\a PILog)
* translation support (\a PITranslator)
* State machine ([By stantard](https://www.w3.org/TR/scxml/)) (\a PIStateMachine)
* High-level TCP client-server
* server (\a PIClientServer::Server, \a PIClientServer::ServerClient)
* client (\a PIClientServer::Client)
* Crypt support (\a PICrypt, \a PIAuth)
\~russian \~russian
* Общение с консолью (\a PICout) * общение с консолью (\a PICout)
* Контейнеры (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet) * контейнеры (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
* Байтовый массив (\a PIByteArray) * байтовый массив (\a PIByteArray)
* Сериализация (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON) * сериализация (\a PIChunkStream)
* Строка (\a PIConstChars, \a PIString, \a PIStringList) * строка (\a PIConstChars, \a PIString, \a PIStringList)
* Базовый объект (события и обработчики) (\a PIObject) * базовый объект (события и обработчики) (\a PIObject)
* Многопоточность * многопоточность
* поток (\a PIThread) * поток (\a PIThread)
* блокировки (\a PIMutex, \a PISpinlock, \a PIConditionVariable, \a PISemaphore, \a PIReadWriteLock) * блокировки (\a PIMutex, \a PISpinlock)
* исполнитель (\a PIThreadPoolExecutor, \a PIThreadPoolLoop) * исполнитель (\a PIThreadPoolExecutor)
* блокирующая очередь (\a PIBlockingDequeue) * блокирующая очередь (\a PIBlockingDequeue)
* таймер (\a PITimer) * таймер (\a PITimer)
* Тайлинговая консоль (с виджетами) (\a PIScreen) * тайлинговая консоль (с виджетами) (\a PIScreen)
* простой вывод строк * простой вывод строк
* скроллбар * скроллбар
* лист * лист
@@ -86,7 +76,7 @@
* прогрессбар * прогрессбар
* вывод PICout * вывод PICout
* текстовый ввод * текстовый ввод
* Устройства ввода/вывода * устройства ввода/вывода
* базовый класс (\a PIIODevice) * базовый класс (\a PIIODevice)
* файл (\a PIFile) * файл (\a PIFile)
* последовательный порт (\a PISerial) * последовательный порт (\a PISerial)
@@ -97,9 +87,8 @@
* сложное составное устройство (\a PIConnection) * сложное составное устройство (\a PIConnection)
* пиринговая сеть (\a PIPeer) * пиринговая сеть (\a PIPeer)
* диагностика качества связи (\a PIDiagnostics) * диагностика качества связи (\a PIDiagnostics)
* Поддержка библиотек времени выполнения * поддержка библиотек времени выполнения
* внешний процесс (\a PIProcess) * базовая функциональность (\a PILibrary)
* внешняя библиотека (\a PILibrary)
* плагин (\a PIPluginLoader) * плагин (\a PIPluginLoader)
* Математика * Математика
* комплексные числа * комплексные числа
@@ -111,14 +100,5 @@
* CRC контрольная сумма (\a PICRC) * CRC контрольная сумма (\a PICRC)
* преобразования Фурье (\a PIFFTW, \a PIFFT) * преобразования Фурье (\a PIFFTW, \a PIFFT)
* вычислитель выражений (\a PIEvaluator) * вычислитель выражений (\a PIEvaluator)
* Уровень приложения * парсер аргументов командной строки (\a PICLI)
* парсер аргументов командной строки (\a PICLI) * процесс (\a PIProcess)
* мониторинг ресурсов системы (\a PISystemMonitor)
* контроль одного экземпляра приложения (\a PISingleApplication)
* высокоуровневый лог (\a PILog)
* поддержка перевода (\a PITranslator)
* Машина состояний ([По стандарту](https://www.w3.org/TR/scxml/)) (\a PIStateMachine)
* Высокоуровневый TCP клиент-сервер
* сервер (\a PIClientServer::Server, \a PIClientServer::ServerClient)
* клиент (\a PIClientServer::Client)
* Поддержка шифрования (\a PICrypt, \a PIAuth)

View File

@@ -56,7 +56,7 @@ class MainClass: public PITimer {
public: public:
MainClass() {} MainClass() {}
protected: protected:
void tick(int delimiter) { void tick(void * data, int delimiter) {
piCout << "timer tick"; piCout << "timer tick";
// timer tick // timer tick
} }

View File

@@ -1 +1,2 @@
#include "pip.h" #include "pip.h"

View File

@@ -1 +0,0 @@
pip_tr --Compile -o pip_ru.btf pip_ru.ts

Binary file not shown.

View File

@@ -1,531 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru">
<context>
<name>PICLI</name>
<message>
<location filename="../libs/main/application/picli.cpp" line="120"/>
<source>Arguments overflow, &quot;%1&quot; ignored</source>
<translation>Переизбыток аргументов, &quot;%1&quot; проигнорирован</translation>
</message>
</context>
<context>
<name>PIDiag</name>
<message>
<location filename="../libs/main/io_utils/pidiagnostics.cpp" line="155"/>
<source>/s</source>
<translation>/сек</translation>
</message>
</context>
<context>
<name>PIFile</name>
<message>
<location filename="../libs/main/io_devices/pifile.cpp" line="299"/>
<source>Downsize is not supported yet :-(</source>
<translation>Уменьшение размера не поддерживается</translation>
</message>
</context>
<context>
<name>PICloud</name>
<message>
<location filename="../libs/cloud/picloudtcp.cpp" line="139"/>
<source>Invalid PICloud::TCP version!</source>
<translation>Неверная версия PICloud::TCP!</translation>
</message>
<message>
<location filename="../libs/cloud/picloudserver.cpp" line="230"/>
<source>Error: buffer overflow, drop %1 bytes</source>
<translation>Ошибка: переполнение буфера, отброшено %1 байт</translation>
</message>
<message>
<location filename="../libs/cloud/picloudserver.cpp" line="251"/>
<source>Warning: reject client with duplicated ID</source>
<translation>Предупреждение: отклонен клиент с дублирующимся ID</translation>
</message>
</context>
<context>
<name>PICrypt</name>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="205"/>
<source>internal error: bad hash size</source>
<translation>внутренняя ошибка: плохой размер хэша</translation>
</message>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="39"/>
<source>Error while initialize sodium!</source>
<translation>Ошибка инициализации sodium!</translation>
</message>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="209"/>
<source>invalid key size %1, should be %2, filled with zeros</source>
<translation>неверный размер ключа %1, должен быть %2, заполненный нулями</translation>
</message>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="29"/>
<source>Warning: PICrypt is disabled, to enable install sodium library and rebuild pip</source>
<translation>Предупреждение: PICrypt неактивен, для активации установите библиотеку sodium и пересоберите PIP</translation>
</message>
</context>
<context>
<name>PIBinLog</name>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="436"/>
<source>Read record error</source>
<translation>Ошибка чтения записи</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="432"/>
<source>End of BinLog file</source>
<translation>Конец BinLog файла</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="776"/>
<source>Error, can&apos;t open &quot;%1&quot;</source>
<translation>Ошибка, невозможно открыть &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="262"/>
<source>Creating directory &quot;%1&quot;</source>
<translation>Создание директории &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="785"/>
<source>Error, can&apos;t create &quot;%1&quot;</source>
<translation>Ошибка, невозможно создать &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="140"/>
<source>Error: File is null &quot;%1&quot;</source>
<translation>Ошибка, Файл пуст &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="789"/>
<source>Start join binlogs to &quot;%1&quot;</source>
<translation>Начало слияния логов в &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="514"/>
<source>BinLogFile has too old verion</source>
<translation>BinLogFile очень старой версии</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="513"/>
<source>BinLogFile has invalid version</source>
<translation>BinLogFile неверной версии</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="515"/>
<source>BinLogFile has too new version</source>
<translation>BinLogFile очень новой версии</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="386"/>
<source>Can&apos;t find record with id = %1</source>
<translation>Невозможно найти запись с ID = %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="803"/>
<source>Error, can&apos;t write to file &quot;%1&quot;</source>
<translation>Ошибка, невозможно записать в &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="126"/>
<source>Error: Can&apos;t open file &quot;%1&quot;: %2</source>
<translation>Ошибка: Невозможно открыть файл &quot;%1&quot;: %2</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="149"/>
<source>Warning: Empty BinLog file &quot;%1&quot;</source>
<translation>Предупреждение: Пустой BinLog файл &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="825"/>
<source>Finish join binlogs, total time %1</source>
<translation>Завершение слияния логов, общее время %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="440"/>
<source>too small read buffer: %1, data size: %2</source>
<translation>слишком маленький буфер: %1, размер данных: %2</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="133"/>
<source>Error: Can&apos;t write binlog file header &quot;%1&quot;</source>
<translation>Ошибка: Невозможно записать заголовок в &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="319"/>
<source>Error: can`t write with id = 0! ID must be &gt; 0</source>
<translation>Ошибка: Невозможно записать с ID = 0! ID должен быть &gt; 0</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="495"/>
<source>BinLogFile signature is corrupted or invalid file</source>
<translation>Неверный заголовок BinLogFile, либо файл поврежден</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="295"/>
<source>Can&apos;t create new file, maybe path &quot;%1&quot; is invalid</source>
<translation>Невозможно создать новый файл, возможно путь &quot;%1&quot; неверен</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="286"/>
<source>Can&apos;t create new file, maybe LogDir &quot;%1&quot; is invalid</source>
<translation>Невозможно создать новый файл, возможно LogDir &quot;%1&quot; неверен</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="104"/>
<source>Error: ReadWrite mode not supported, use WriteOnly or ReadOnly</source>
<translation>Ошибка: Режим ReadWrite не поддерживается, используйте WriteOnly или ReadOnly</translation>
</message>
</context>
<context>
<name>PIOpenCL</name>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="509"/>
<source>Error: empty range</source>
<translation>Ошибка: пустой диапазон</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="586"/>
<source>setArgValue invalid index %1</source>
<translation>setArgValue неверный индекс %1</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="616"/>
<source>bindArgValue invalid index %1</source>
<translation>bindArgValue неверный индекс %1</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="592"/>
<source>setArgValue set scalar to &quot;%1 %2&quot;</source>
<translation>setArgValue устанавливается скаляр в &quot;%1 %2&quot;</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="93"/>
<source>Error: OpenCL platforms not found!</source>
<translation>Ошибка: Платформы OpenCL не найдены!</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="622"/>
<source>bindArgValue set buffer to &quot;%1 %2&quot;</source>
<translation>bindArgValue устанавливается буфер в &quot;%1 %2&quot;</translation>
</message>
</context>
<context>
<name>PISerial</name>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="887"/>
<source>Read error: %1</source>
<translation>Ошибка чтения: %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="726"/>
<source>Unable to open &quot;%1&quot;: %2</source>
<translation>Невозможно открыть &quot;%1&quot;: %2</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="467"/>
<source>Warning: Custom speed %1</source>
<translation>Предупреждение: Нестандартная скорость %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="695"/>
<source>Unable to find device &quot;%1&quot;</source>
<translation>Невозможно найти устройство &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="826"/>
<source>Can`t set attributes for &quot;%1&quot;</source>
<translation>Невозможно установить атрибуты для &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="792"/>
<source>Unable to set comm state for &quot;%1&quot;</source>
<translation>Невозможно установить comm state для &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="470"/>
<source>Warning: Unknown speed %1, using 115200</source>
<translation>Предупреждение: Неизвестная скорость %1, используется 115200</translation>
</message>
</context>
<context>
<name>PIString</name>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1774"/>
<source>B</source>
<translation>Б</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1794"/>
<source>EiB</source>
<translation>ЭиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1791"/>
<source>GiB</source>
<translation>ГиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1789"/>
<source>KiB</source>
<translation>КиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1790"/>
<source>MiB</source>
<translation>МиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1793"/>
<source>PiB</source>
<translation>ПиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1792"/>
<source>TiB</source>
<translation>ТиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1796"/>
<source>YiB</source>
<translation>ЙиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1795"/>
<source>ZiB</source>
<translation>ЗиБ</translation>
</message>
</context>
<context>
<name>PIThread</name>
<message>
<location filename="../libs/main/thread/pithread.cpp" line="667"/>
<source>Warning, terminate!</source>
<translation>Предупреждение, прекращение потока!</translation>
</message>
<message>
<location filename="../libs/main/thread/pithread.cpp" line="785"/>
<source>Error: Can`t start new thread: %1</source>
<translation>Ошибка: Невозможно начать новый поток: %1</translation>
</message>
<message>
<location filename="../libs/main/thread/pithread.cpp" line="572"/>
<source>[PIThread &quot;%1&quot;] Warning, terminate on destructor!</source>
<translation>[PIThread &quot;%1&quot;] Предупреждение, прекращение в деструкторе!</translation>
</message>
</context>
<context>
<name>PIProcess</name>
<message>
<location filename="../libs/main/system/piprocess.cpp" line="200"/>
<source>&quot;CreateProcess&quot; error: %1</source>
<translation>Ошибка &quot;CreateProcess&quot;: %1</translation>
</message>
</context>
<context>
<name>PIVariant</name>
<message>
<location filename="../libs/main/types/pivariant.cpp" line="415"/>
<source>Can`t initialize PIVariant from unregistered type &quot;%1&quot;!</source>
<translation>Невозможно инициализировать PIVariant из незарегистрированного типа &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/types/pivariant.cpp" line="393"/>
<source>Can`t initialize PIVariant from unregistered typeID &quot;%1&quot;!</source>
<translation>Невозможно инициализировать PIVariant из незарегистрированного ID типа &quot;%1&quot;!</translation>
</message>
</context>
<context>
<name>PICompress</name>
<message>
<location filename="../libs/compress/picompress.cpp" line="63"/>
<source>Error: invalid input</source>
<translation>Ошибка: неверный вход</translation>
</message>
<message>
<location filename="../libs/compress/picompress.cpp" line="74"/>
<source>Error: invalid input or not enought memory</source>
<translation>Ошибка: неверный вход или недостаточно памяти</translation>
</message>
<message>
<location filename="../libs/compress/picompress.cpp" line="80"/>
<source>Warning: PICompress is disabled, to enable install zlib library and build pip_compress library</source>
<translation>Предупреждение: PICompress неактивен, для активации установите библиотеку zlib и пересоберите PIP</translation>
</message>
</context>
<context>
<name>PIEthernet</name>
<message>
<location filename="../libs/main/io_devices/piethernet.cpp" line="1233"/>
<source>Can`t get interfaces: %1</source>
<translation>Невозможно получить интерфейсы: %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piethernet.cpp" line="903"/>
<source>Can`t accept new connection, %1</source>
<translation>Невозможно принять новое соединение, %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piethernet.cpp" line="1096"/>
<source>Error allocating memory needed to call GetAdaptersInfo</source>
<translation>Ошибка выделения памяти для вызова GetAdaptersInfo</translation>
</message>
</context>
<context>
<name>PIIODevice</name>
<message>
<location filename="../libs/main/io_devices/piiodevice.cpp" line="226"/>
<source>Error: Device is running after destructor!</source>
<translation>Ошибка: Устройство в поточном выполнении после деструктора!</translation>
</message>
</context>
<context>
<name>PIIOString</name>
<message>
<location filename="../libs/main/io_devices/piiostring.cpp" line="54"/>
<source>Error: ReadWrite mode not supported, use WriteOnly or ReadOnly</source>
<translation>Ошибка: Режим ReadWrite не поддерживается, используйте WriteOnly или ReadOnly</translation>
</message>
</context>
<context>
<name>PIConnection</name>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="146"/>
<source>Error,</source>
<translation>Ошибка,</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="922"/>
<source>Null Device!</source>
<translation>Нет Устройства!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="913"/>
<source>No such device &quot;%1&quot;!</source>
<translation>Нет устройства &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="903"/>
<source>No such full path &quot;%1&quot;!</source>
<translation>Нет полного пути &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="927"/>
<source>Device &quot;%1&quot; can`t write!</source>
<translation>Устройство &quot;%1&quot; не может писать!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="986"/>
<source>Error: can`t create device &quot;%1&quot;!</source>
<translation>Ошибка: Невозможно создать устройство &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="242"/>
<source>&quot;addFilter&quot; error: no such device &quot;%1&quot;!</source>
<translation>ошибка &quot;addFilter&quot;: нет устройства &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="743"/>
<source>&quot;addSender&quot; error: no such device &quot;%1&quot;!</source>
<translation>ошибка &quot;addSender&quot;: нет устройства &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="146"/>
<source>names assigned to both devices and filters!</source>
<translation>имена назначены одновременно устройствам и фильтрам!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="512"/>
<source>&quot;addFilter&quot; error: no such device or filter &quot;%1&quot;!</source>
<translation>ошибка &quot;addFilter&quot;: нет устройства или фильтра &quot;%1&quot;!</translation>
</message>
</context>
<context>
<name>PISystemTime</name>
<message>
<location filename="../libs/main/types/pisystemtime.cpp" line="335"/>
<source>fromSystemTime() Warning: null frequency</source>
<translation>fromSystemTime() Предупреждение: нулевая частота</translation>
</message>
<message>
<location filename="../libs/main/types/pisystemtime.cpp" line="325"/>
<source>toSystemTime() Warning: invalid hertz: %1</source>
<translation>toSystemTime() Предупреждение: неверная частота: %1</translation>
</message>
</context>
<context>
<name>PIEthUtilBase</name>
<message>
<location filename="../libs/io_utils/piethutilbase.cpp" line="91"/>
<source>PICrypt wasn`t built!</source>
<translation>PICrypt не был собран!</translation>
</message>
</context>
<context>
<name>PIBaseTransfer</name>
<message>
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="125"/>
<source>invalid CRC</source>
<translation>неверная CRC</translation>
</message>
<message>
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="219"/>
<source>restart receive</source>
<translation>перезапуск приема</translation>
</message>
<message>
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="176"/>
<source>invalid reply id</source>
<translation>неверный ID ответа</translation>
</message>
<message>
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="102"/>
<source>invalid packet signature</source>
<translation>неверная подпись пакета</translation>
</message>
</context>
<context>
<name>PIClientServer</name>
<message>
<location filename="../libs/client_server/piclientserver_server.cpp" line="39"/>
<source>ClientFactory returns nullptr!</source>
<translation>ClientFactory вернул nullptr!</translation>
</message>
<message>
<location filename="../libs/client_server/piclientserver_server.cpp" line="33"/>
<source>Server::newConnection overflow clients count</source>
<translation>Server::newConnection переполнение количества клиентов</translation>
</message>
</context>
<context>
<name>PIStateMachine</name>
<message>
<location filename="../libs/main/state_machine/pistatemachine_state.cpp" line="111"/>
<source>Error: &quot;%1&quot; no initial state!</source>
<translation>Ошибка: &quot;%1&quot; без стартового состояния!</translation>
</message>
</context>
<context>
<name>PIStreamPacker</name>
<message>
<location filename="../libs/io_utils/pistreampacker.cpp" line="218"/>
<source>Warning! Not recommended to use with non-reliable device</source>
<translation>Предупреждение! Не рекомендуется использовать с ненадежными устройствами</translation>
</message>
</context>
<context>
<name>PISystemMonitor</name>
<message>
<location filename="../libs/main/application/pisystemmonitor.cpp" line="111"/>
<source>Can`t find process with ID = %1!</source>
<translation>Невозможно найти процесс с ID = %1!</translation>
</message>
<message>
<location filename="../libs/main/application/pisystemmonitor.cpp" line="118"/>
<source>Can`t open process with ID = %1, %2!</source>
<translation>Невозможно открыть процесс с ID = %1, %2!</translation>
</message>
</context>
</TS>

View File

@@ -1 +0,0 @@
pip_tr --Parse -r -l ru -o pip_ru.ts ../libs

View File

@@ -1,53 +0,0 @@
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piclientserver_client.h"
#include "piclientserver_server.h"
#include "piethernet.h"
void PIClientServer::ServerClient::createForServer(Server * parent, PIEthernet * tcp_) {
tcp = tcp_;
tcp->setParameter(PIEthernet::KeepConnection, false);
init();
CONNECTL(tcp, disconnected, ([this, parent](bool) { parent->clientDisconnected(this); }));
}
PIClientServer::Client::Client() {
tcp = new PIEthernet(PIEthernet::TCP_Client);
tcp->setParameter(PIEthernet::KeepConnection, true);
own_tcp = true;
init();
}
PIClientServer::Client::~Client() {
if (tcp) tcp->setDebug(false);
close();
stopAndWait();
}
void PIClientServer::Client::connect(PINetworkAddress addr) {
if (!tcp || !own_tcp) return;
close();
tcp->connect(addr, true);
tcp->startThreadedRead();
}

View File

@@ -1,117 +0,0 @@
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piclientserver_client_base.h"
#include "piethernet.h"
#include "piliterals_time.h"
PIClientServer::ClientBase::ClientBase() {}
PIClientServer::ClientBase::~ClientBase() {
close();
stopAndWait();
if (own_tcp) piDeleteSafety(tcp);
piDeleteSafety(diag);
}
void PIClientServer::ClientBase::close() {
if (!tcp) return;
can_write = false;
tcp->stop();
stream.clear();
}
void PIClientServer::ClientBase::stopAndWait() {
if (!tcp) return;
tcp->stopAndWait(10_s);
if (tcp->isThreadedRead()) tcp->terminateThreadedRead();
tcp->close();
stream.clear();
}
int PIClientServer::ClientBase::write(const void * d, const size_t s) {
if (!tcp) return -1;
if (!can_write) return 0;
PIMutexLocker guard(write_mutex);
// piCout << "... send ...";
stream.send(PIByteArray(d, s));
// piCout << "... send ok";
return s;
}
void PIClientServer::ClientBase::enableDiagnostics() {
if (diag) return;
diag = new PIDiagnostics();
}
PIDiagnostics::State PIClientServer::ClientBase::diagnostics() const {
if (!diag) return {};
return diag->state();
}
int PIClientServer::ClientBase::receivePacketProgress() const {
return stream.receivePacketProgress();
}
void PIClientServer::ClientBase::init() {
if (!tcp) return;
CONNECTL(&stream, sendRequest, [this](const PIByteArray & ba) {
if (!can_write) return;
tcp->send(ba);
if (diag) diag->sended(ba.size_s());
// piMSleep(1);
});
CONNECTL(&stream, packetReceiveEvent, [this](PIByteArray & ba) { readed(ba); });
CONNECTL(&stream, startPacketReceive, [this](int size) { receivePacketStart(size); });
CONNECTL(&stream, endPacketReceive, [this]() { receivePacketEnd(); });
CONNECTL(tcp, threadedReadEvent, [this](const uchar * readed, ssize_t size) {
if (!can_write) return;
stream.received(readed, size);
if (diag) diag->received(size);
});
CONNECTL(tcp, connected, [this]() {
can_write = true;
// piCout << "Connected";
connected();
});
CONNECTL(tcp, disconnected, [this](bool) {
can_write = false;
stream.clear();
// piCout << "Disconnected";
disconnected();
});
}
void PIClientServer::ClientBase::destroy() {
write_mutex.lock();
close();
piDeleteSafety(tcp);
write_mutex.unlock();
// piCout << "Destroyed";
}

View File

@@ -1,143 +0,0 @@
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piclientserver_server.h"
#include "piclientserver_client.h"
#include "piethernet.h"
#include "pitranslator.h"
PIClientServer::Server::Server() {
tcp_server = new PIEthernet(PIEthernet::TCP_Server);
clean_thread = new PIThread();
client_factory = [] { return new ServerClient(); };
CONNECTL(tcp_server, newConnection, [this](PIEthernet * c) {
PIMutexLocker guard(clients_mutex);
if (clients.size_s() >= max_clients) {
piCout << "Server::newConnection overflow clients count"_tr("PIClientServer");
delete c;
return;
}
auto sc = client_factory();
if (!sc) {
piCout << "ClientFactory returns nullptr!"_tr("PIClientServer");
return;
}
sc->createForServer(this, c);
newClient(sc);
});
clean_thread->start([this]() {
clean_notifier.wait();
PIVector<ServerClient *> to_delete;
clients_mutex.lock();
for (auto c: clients) {
const PIEthernet * eth = c->getTCP();
if (!eth) continue;
if (eth->isConnected()) continue;
c->can_write = false;
to_delete << c;
}
for (auto c: to_delete)
clients.removeOne(c);
clients_mutex.unlock();
for (auto c: to_delete) {
c->aboutDelete();
c->destroy();
delete c;
}
});
}
PIClientServer::Server::~Server() {
clean_thread->stop();
clean_notifier.notify();
clean_thread->waitForFinish();
piDeleteSafety(clean_thread);
stopServer();
for (auto c: clients) {
c->aboutDelete();
c->destroy();
delete c;
}
piDeleteSafety(tcp_server);
}
void PIClientServer::Server::listen(PINetworkAddress addr) {
if (!tcp_server) return;
stopServer();
is_closing = false;
tcp_server->listen(addr, true);
// piCout << "Listen on" << addr.toString();
}
void PIClientServer::Server::closeAll() {
clients_mutex.lock();
for (auto c: clients) {
c->aboutDelete();
c->destroy();
delete c;
}
clients.clear();
clients_mutex.unlock();
}
void PIClientServer::Server::setMaxClients(int new_max_clients) {
max_clients = new_max_clients;
}
int PIClientServer::Server::clientsCount() const {
PIMutexLocker guard(clients_mutex);
return clients.size_s();
}
void PIClientServer::Server::forEachClient(std::function<void(ServerClient *)> func) {
PIMutexLocker guard(clients_mutex);
for (auto * c: clients) {
func(c);
if (is_closing) break;
}
}
void PIClientServer::Server::stopServer() {
if (!tcp_server) return;
is_closing = true;
tcp_server->stopThreadedListen();
tcp_server->stopAndWait();
}
void PIClientServer::Server::newClient(ServerClient * c) {
clients << c;
c->setConfiguration(configuration());
c->tcp->startThreadedRead();
c->connected();
}
void PIClientServer::Server::clientDisconnected(ServerClient * c) {
clean_notifier.notify();
}

View File

@@ -1,7 +1,7 @@
#include "picloudbase.h" #include "picloudbase.h"
PICloudBase::PICloudBase(): eth(PIEthernet::TCP_Client), streampacker(&eth), tcp(&streampacker) { PICloudBase::PICloudBase() : eth(PIEthernet::TCP_Client), streampacker(&eth), tcp(&streampacker) {
eth.setDebug(false); eth.setDebug(false);
} }

View File

@@ -1,192 +1,178 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud Client PICloud Client
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "picloudclient.h" #include "picloudclient.h"
#include "picloudtcp.h"
#include "picloudtcp.h"
#include "pitranslator.h"
PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode) : PIIODevice(path, mode), PICloudBase() {
tcp.setRole(PICloud::TCP::Client);
PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() { setName("cloud_client");
tcp.setRole(PICloud::TCP::Client); is_connected = false;
setThreadedReadBufferSize(eth.threadedReadBufferSize()); is_deleted = false;
setName("cloud_client"); // setReopenEnabled(false);
is_connected = false; CONNECTL(&eth, connected, [this](){opened_ = true; tcp.sendStart();});
is_deleted = false; CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
// setReopenEnabled(false); CONNECTL(&eth, disconnected, [this](bool){
CONNECTL(&eth, connected, [this]() { if (is_deleted) return;
opened_ = true; bool need_disconn = is_connected;
tcp.sendStart(); //piCoutObj << "eth disconnected";
}); static_cast<PIThread*>(&eth)->stop();
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed); opened_ = false;
CONNECTL(&eth, disconnected, [this](bool) { internalDisconnect();
if (is_deleted) return; if (need_disconn)
bool need_disconn = is_connected; disconnected();
// piCoutObj << "eth disconnected"; //piCoutObj << "eth disconnected done";
eth.stop(); });
opened_ = false; }
internalDisconnect();
if (need_disconn) disconnected();
// piCoutObj << "eth disconnected done"; PICloudClient::~PICloudClient() {
}); //piCoutObj << "~PICloudClient()";
} PIThread::stop();
//eth.close();
//if (is_connected) disconnected();
PICloudClient::~PICloudClient() { close();
// piCoutObj << "~PICloudClient() ..." << this; //piCoutObj << "~PICloudClient() closed";
is_deleted = true; internalDisconnect();
stopAndWait(); // stop(false);
close(); is_deleted = true;
internalDisconnect(); internalDisconnect();
// piCoutObj << "~PICloudClient() done" << this; //piCoutObj << "~PICloudClient() done";
} }
void PICloudClient::setServerName(const PIString & server_name) { void PICloudClient::setServerName(const PIString & server_name) {
setName("cloud_client__" + server_name); setName("cloud_client__" + server_name);
tcp.setServerName(server_name); tcp.setServerName(server_name);
} }
void PICloudClient::setKeepConnection(bool on) { void PICloudClient::setKeepConnection(bool on) {
eth.setParameter(PIEthernet::KeepConnection, on); eth.setParameter(PIEthernet::KeepConnection, on);
} }
void PICloudClient::interrupt() { bool PICloudClient::openDevice() {
cond_buff.notifyOne(); //piCoutObj << "open";// << path();
cond_connect.notifyOne(); bool op = eth.connect(PIEthernet::Address::resolve(path()), false);
eth.interrupt(); if (op) {
} mutex_connect.lock();
eth.startThreadedRead();
//piCoutObj << "connecting...";
bool PICloudClient::openDevice() { bool conn_ok = cond_connect.waitFor(mutex_connect, (int)eth.readTimeout());
// piCoutObj << "open";// << path(); //piCoutObj << "conn_ok" << conn_ok << is_connected;
bool op = eth.connect(PINetworkAddress::resolve(path()), false); mutex_connect.unlock();
if (op) { if (!conn_ok) {
mutex_connect.lock(); mutex_connect.lock();
eth.startThreadedRead(); eth.stop();
// piCoutObj << "connecting..."; eth.close();
bool conn_ok = cond_connect.waitFor(mutex_connect, eth.readTimeout()); mutex_connect.unlock();
// piCoutObj << "conn_ok" << conn_ok << is_connected; }
mutex_connect.unlock(); return is_connected;
if (!conn_ok) { } else {
mutex_connect.lock(); //eth.close();
eth.stopAndWait(); return false;
eth.close(); }
mutex_connect.unlock(); }
}
return is_connected;
} else { bool PICloudClient::closeDevice() {
// eth.close(); //PIThread::stop();
return false; if (is_connected) {
} internalDisconnect();
} }
eth.stop();
eth.close();
bool PICloudClient::closeDevice() { return true;
// PIThread::stop(); }
if (is_connected) {
internalDisconnect();
} int PICloudClient::readDevice(void * read_to, int max_size) {
eth.stopAndWait(); if (is_deleted) return -1;
eth.close(); //piCoutObj << "readDevice";
return true; if (!is_connected && eth.isClosed()) openDevice();
} int sz = -1;
mutex_buff.lock();
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;});
ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) { if (is_connected) {
if (is_deleted || max_size <= 0) return -1; sz = piMini(max_size, buff.size());
// piCoutObj << "readDevice ..."; memcpy(read_to, buff.data(), sz);
if (!is_connected && eth.isClosed()) openDevice(); buff.remove(0, sz);
ssize_t sz = -1; }
mutex_buff.lock(); mutex_buff.unlock();
if (is_connected) { if (!is_connected) opened_ = false;
if (buff.isEmpty()) { //piCoutObj << "readDevice done" << sz;
sz = 0; return sz;
} else { }
sz = piMin<ssize_t>(max_size, buff.size_s());
memcpy(read_to, buff.data(), sz);
buff.remove(0, sz); int PICloudClient::writeDevice(const void * data, int size) {
} if (is_deleted) return -1;
if (sz == 0) cond_buff.wait(mutex_buff); // piCoutObj << "writeDevice";
} return tcp.sendData(PIByteArray(data, size));
mutex_buff.unlock(); }
if (!is_connected) opened_ = false;
// piCoutObj << "readDevice done" << sz;
return sz; void PICloudClient::internalDisconnect() {
} is_connected = false;
cond_buff.notifyOne();
cond_connect.notifyOne();
ssize_t PICloudClient::writeDevice(const void * data, ssize_t size) { streampacker.clear();
if (is_deleted || !is_connected) return -1; buff.clear();
// piCoutObj << "writeDevice" << size; }
return tcp.sendData(PIByteArray(data, size));
}
void PICloudClient::_readed(PIByteArray & ba) {
if (is_deleted) return;
void PICloudClient::internalDisconnect() { PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
// piCoutObj << "internalDisconnect"; //piCoutObj << "_readed" << ba.size() << hdr.first << hdr.second;
is_connected = false; if (hdr.second == tcp.role()) {
cond_buff.notifyOne(); switch (hdr.first) {
cond_connect.notifyOne(); case PICloud::TCP::Connect:
streampacker.clear(); if (tcp.parseConnect(ba) == 1) {
buff.clear(); mutex_connect.lock();
} is_connected = true;
mutex_connect.unlock();
cond_connect.notifyOne();
void PICloudClient::_readed(PIByteArray & ba) { connected();
if (is_deleted) return; }
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba); break;
// piCoutObj << "_readed" << ba.size() << hdr.first << hdr.second; case PICloud::TCP::Disconnect:
if (hdr.second == tcp.role()) { static_cast<PIThread*>(&eth)->stop();
switch (hdr.first) { opened_ = false;
case PICloud::TCP::Connect: eth.close();
if (tcp.parseConnect(ba) == 1) { break;
mutex_connect.lock(); case PICloud::TCP::Data:
is_connected = true; if (is_connected) {
mutex_connect.unlock(); mutex_buff.lock();
cond_connect.notifyOne(); buff.append(ba);
connected(); mutex_buff.unlock();
} cond_buff.notifyOne();
break; }
case PICloud::TCP::Disconnect: break;
eth.stop(); default:
opened_ = false; break;
eth.close(); }
break; //piCoutObj << "readed" << ba.toHex();
case PICloud::TCP::Data: }
if (is_connected) { while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad
mutex_buff.lock(); //piCoutObj << "_readed done";
if (buff.size_s() > threadedReadBufferSize()) { }
piCoutObj << "Error: buffer overflow, drop %1 bytes"_tr("PICloud").arg(ba.size());
mutex_buff.unlock();
return;
}
buff.append(ba);
mutex_buff.unlock();
cond_buff.notifyOne();
}
break;
default: break;
}
// piCoutObj << "readed" << ba.toHex();
}
// piCoutObj << "_readed done";
}

View File

@@ -1,301 +1,238 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud Server PICloud Server
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "picloudserver.h" #include "picloudserver.h"
#include "piliterals_time.h"
#include "pitranslator.h" PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) : PIIODevice(path, mode), PICloudBase() {
PIString server_name = "PCS_" + PIString::fromNumber(randomi()%1000);
tcp.setRole(PICloud::TCP::Server);
PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() { tcp.setServerName(server_name);
PIString server_name = "PCS_" + PIString::fromNumber(randomi() % 1000); setName("cloud_server__" + server_name);
tcp.setRole(PICloud::TCP::Server); CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
tcp.setServerName(server_name); CONNECTL(&eth, connected, [this](){opened_ = true; piCoutObj << "connected"; tcp.sendStart();});
setName("cloud_server__" + server_name); CONNECTL(&eth, disconnected, [this](bool){
is_deleted = false; piCoutObj << "disconnected";
eth.setReopenEnabled(false); static_cast<PIThread*>(&eth)->stop();
setThreadedReadBufferSize(eth.threadedReadBufferSize()); opened_ = false;
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed); ping_timer.stop(false);
CONNECTL(&eth, connected, [this]() { piMSleep(100);
open_mutex.lock(); });
opened_ = true; CONNECTL(&ping_timer, tickEvent, [this] (void *, int){
cvar.notifyOne(); if (eth.isConnected()) tcp.sendPing();
open_mutex.unlock(); });
piCoutObj << "connected"; }
tcp.sendStart();
});
CONNECTL(&eth, disconnected, [this](bool) { PICloudServer::~PICloudServer() {
if (is_deleted) return; stop();
piCoutObj << "disconnected"; close();
clients_mutex.lock(); }
for (auto c: clients_) {
c->is_connected = false;
c->close(); void PICloudServer::setServerName(const PIString & server_name) {
} setName("cloud_server__" + server_name);
removed_clients_.append(clients_); tcp.setServerName(server_name);
clients_.clear(); }
index_clients.clear();
clients_mutex.unlock();
open_mutex.lock(); PIVector<PICloudServer::Client *> PICloudServer::clients() const {
opened_ = false; PIMutexLocker _ml(clients_mutex);
cvar.notifyOne(); return clients_;
open_mutex.unlock(); }
ping_timer.stop();
});
ping_timer.setSlot([this]() { bool PICloudServer::openDevice() {
if (eth.isConnected()) tcp.sendPing(); //piCout << "PICloudServer open device" << path();
}); bool op = eth.connect(PIEthernet::Address::resolve(path()), false);
} if (op) {
eth.startThreadedRead();
ping_timer.start(5000);
PICloudServer::~PICloudServer() { return true;
// piCoutObj << "~PICloudServer ..." << this; }
is_deleted = true; ping_timer.stop(false);
stop(); eth.close();
close(); return false;
waitThreadedReadFinished(); }
// piCout << "wait";
while (removed_clients_.isNotEmpty()) {
Client * c = removed_clients_.take_back(); bool PICloudServer::closeDevice() {
delete c; eth.stop();
} ping_timer.stop(false);
// piCoutObj << "~PICloudServer done" << this; clients_mutex.lock();
} for (auto c : clients_) {
c->close();
c->stop();
void PICloudServer::setServerName(const PIString & server_name) { }
setName("cloud_server__" + server_name); clients_mutex.unlock();
tcp.setServerName(server_name); eth.close();
} for (auto c : clients_)
delete c;
return true;
PIVector<PICloudServer::Client *> PICloudServer::clients() const { }
PIMutexLocker _ml(clients_mutex);
return clients_;
} int PICloudServer::readDevice(void * read_to, int max_size) {
//piCoutObj << "readDevice";
if (!opened_) openDevice();
bool PICloudServer::openDevice() { else piMSleep(eth.readTimeout());
piCoutObj << "open device" << path(); return -1;
if (is_deleted) return false; }
bool op = eth.connect(PINetworkAddress::resolve(path()), false);
if (op) {
eth.startThreadedRead(); int PICloudServer::writeDevice(const void * data, int max_size) {
ping_timer.start(5_s); //piCoutObj << "writeDevice";
return true; return -1;
} else { }
ping_timer.stop();
eth.close();
return false; void PICloudServer::clientDisconnect(uint client_id) {
} tcp.sendDisconnected(client_id);
} }
bool PICloudServer::closeDevice() { int PICloudServer::sendData(const PIByteArray & data, uint client_id) {
// piCoutObj << "closeDevice" << this; return tcp.sendData(data, client_id);
eth.stopAndWait(); }
ping_timer.stop();
eth.close();
cvar.notifyOne(); PICloudServer::Client::Client(PICloudServer * srv, uint id) : server(srv), client_id(id) {
clients_mutex.lock(); setMode(PIIODevice::ReadWrite);
for (auto c: clients_) { setReopenEnabled(false);
c->is_connected = false; is_connected = true;
c->close(); }
}
removed_clients_.append(clients_);
clients_.clear(); PICloudServer::Client::~Client() {
index_clients.clear(); if (is_connected) {
clients_mutex.unlock(); is_connected = false;
return true; cond_buff.notifyOne();
} }
close();
stop();
ssize_t PICloudServer::readDevice(void * read_to, ssize_t max_size) { }
if (is_deleted) return -1;
// piCoutObj << "readDevice";
open_mutex.lock(); bool PICloudServer::Client::openDevice() {
if (isOpened()) cvar.wait(open_mutex); return is_connected;
open_mutex.unlock(); }
// piCoutObj << "opened_ = " << opened_;
// else piMSleep(eth.readTimeout());
return -1; bool PICloudServer::Client::closeDevice() {
} PIThread::stop(false);
if (is_connected) {
server->clientDisconnect(client_id);
ssize_t PICloudServer::writeDevice(const void * data, ssize_t max_size) { is_connected = false;
// piCoutObj << "writeDevice"; }
return -1; cond_buff.notifyOne();
} return true;
}
void PICloudServer::interrupt() {
eth.interrupt(); int PICloudServer::Client::readDevice(void * read_to, int max_size) {
cvar.notifyOne(); if (!is_connected) return -1;
} int sz = -1;
mutex_buff.lock();
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;});
void PICloudServer::clientDisconnect(uint client_id) { if (is_connected) {
tcp.sendDisconnected(client_id); sz = piMini(max_size, buff.size());
} memcpy(read_to, buff.data(), sz);
buff.remove(0, sz);
}
int PICloudServer::sendData(const PIByteArray & data, uint client_id) { mutex_buff.unlock();
if (!opened_) return -1; return sz;
return tcp.sendData(data, client_id); }
}
int PICloudServer::Client::writeDevice(const void * data, int size) {
PICloudServer::Client::Client(PICloudServer * srv, uint id): server(srv), client_id(id) { return server->sendData(PIByteArray(data, size), client_id);
setMode(PIIODevice::ReadWrite); }
setReopenEnabled(false);
setThreadedReadBufferSize(server->threadedReadBufferSize());
is_connected = true; void PICloudServer::Client::pushBuffer(const PIByteArray & ba) {
} if (!is_connected) return;
mutex_buff.lock();
buff.append(ba);
PICloudServer::Client::~Client() { cond_buff.notifyOne();
// piCoutObj << "~PICloudServer::Client..." << this; mutex_buff.unlock();
close(); while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad
stopAndWait(10_s); }
// piCoutObj << "~PICloudServer::Client done" << this;
}
void PICloudServer::_readed(PIByteArray & ba) {
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
bool PICloudServer::Client::openDevice() { if (hdr.second == tcp.role()) {
return is_connected; switch (hdr.first) {
} case PICloud::TCP::Connect: {
uint id = tcp.parseConnect(ba);
clients_mutex.lock();
bool PICloudServer::Client::closeDevice() { Client * oc = index_clients.value(id, nullptr);
// piCoutObj << "closeDevice" << this; clients_mutex.unlock();
if (is_connected) { if (oc) {
server->clientDisconnect(client_id); tcp.sendDisconnected(id);
is_connected = false; } else {
} //piCoutObj << "new Client" << id;
cond_buff.notifyOne(); Client * c = new Client(this, id);
return true; CONNECTU(c, deleted, this, clientDeleted);
} clients_mutex.lock();
clients_ << c;
index_clients.insert(id, c);
ssize_t PICloudServer::Client::readDevice(void * read_to, ssize_t max_size) { clients_mutex.unlock();
if (!is_connected) return -1; newConnection(c);
ssize_t sz = -1; }
mutex_buff.lock(); } break;
if (is_connected) { case PICloud::TCP::Disconnect: {
if (buff.isEmpty()) { uint id = tcp.parseDisconnect(ba);
sz = 0; //piCoutObj << "remove Client" << id;
} else { clients_mutex.lock();
sz = piMini(max_size, buff.size()); Client * oc = index_clients.value(id, nullptr);
memcpy(read_to, buff.data(), sz); clients_mutex.unlock();
buff.remove(0, sz); if (oc) {
} oc->is_connected = false;
if (sz == 0) cond_buff.wait(mutex_buff); oc->close();
} }
mutex_buff.unlock(); } break;
return sz; case PICloud::TCP::Data: {
} PIPair<uint, PIByteArray> d = tcp.parseDataServer(ba);
clients_mutex.lock();
Client * oc = index_clients.value(d.first, nullptr);
ssize_t PICloudServer::Client::writeDevice(const void * data, ssize_t size) { clients_mutex.unlock();
if (!is_connected) return -1; //piCoutObj << "data for" << d.first << d.second.toHex();
return server->sendData(PIByteArray(data, size), client_id); if (oc && !d.second.isEmpty()) oc->pushBuffer(d.second);
} } break;
default: break;
}
void PICloudServer::Client::interrupt() { }
cond_buff.notifyOne(); }
}
void PICloudServer::clientDeleted(PIObject * o) {
void PICloudServer::Client::pushBuffer(const PIByteArray & ba) { PICloudServer::Client * c = (PICloudServer::Client*)o;
if (!is_connected) return; clients_mutex.lock();
mutex_buff.lock(); clients_.removeOne(c);
if (buff.size_s() > threadedReadBufferSize()) { auto it = index_clients.makeIterator();
piCoutObj << "Error: buffer overflow, drop %1 bytes"_tr("PICloud").arg(ba.size()); while (it.hasNext()) {
mutex_buff.unlock(); it.next();
return; if (it.value() == c) {
} index_clients.remove(it.key());
buff.append(ba); break;
cond_buff.notifyOne(); }
mutex_buff.unlock(); }
} clients_mutex.unlock();
}
void PICloudServer::_readed(PIByteArray & ba) {
if (is_deleted) return;
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
if (hdr.second == tcp.role()) {
switch (hdr.first) {
case PICloud::TCP::Connect: {
uint id = tcp.parseConnect(ba);
clients_mutex.lock();
Client * oc = index_clients.value(id, nullptr);
clients_mutex.unlock();
if (oc) {
piCoutObj << "Warning: reject client with duplicated ID"_tr("PICloud");
tcp.sendDisconnected(id);
} else {
Client * c = new Client(this, id);
// piCoutObj << "new Client" << id << c;
CONNECT1(void, PIObject *, c, deleted, this, clientDeleted);
clients_mutex.lock();
clients_ << c;
index_clients.insert(id, c);
clients_mutex.unlock();
newConnection(c);
}
} break;
case PICloud::TCP::Disconnect: {
uint id = tcp.parseDisconnect(ba);
// piCoutObj << "Close on logic";
clients_mutex.lock();
Client * oc = index_clients.take(id, nullptr);
clients_.removeOne(oc);
clients_mutex.unlock();
if (oc) {
oc->stopAndWait();
oc->is_connected = false;
oc->close();
removed_clients_ << oc;
// delete oc;
}
} break;
case PICloud::TCP::Data: {
PIPair<uint, PIByteArray> d = tcp.parseDataServer(ba);
clients_mutex.lock();
Client * oc = index_clients.value(d.first, nullptr);
clients_mutex.unlock();
// piCoutObj << "data for" << d.first << d.second.size();
if (oc && !d.second.isEmpty()) oc->pushBuffer(d.second);
} break;
default: break;
}
}
}
void PICloudServer::clientDeleted(PIObject * o) {
PICloudServer::Client * c = (PICloudServer::Client *)o;
// piCoutObj << "clientDeleted" << c;
clients_mutex.lock();
clients_.removeOne(c);
removed_clients_.removeAll(c);
index_clients.removeWhere([c](uint, Client * v) { return v == c; });
clients_mutex.unlock();
}

View File

@@ -1,185 +1,181 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud TCP transport PICloud TCP transport
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "picloudtcp.h" #include "picloudtcp.h"
#include "picrypt.h"
#include "pichunkstream.h" #include "pichunkstream.h"
#include "picrypt.h" #include "piethernet.h"
#include "piethernet.h" #include "pistreampacker.h"
#include "pistreampacker.h"
#include "pitranslator.h"
const char hash_cloud_key[] = "_picloud_";
const char hash_cloud_key[] = "_picloud_";
PICloud::TCP::Header::Header() {
version = Version_2;
PICloud::TCP::Header::Header() { }
version = Version_2;
}
PICloud::TCP::TCP(PIStreamPacker * s) : streampacker(s) {
streampacker->setMaxPacketSize(63*1024);
PICloud::TCP::TCP(PIStreamPacker * s): streampacker(s) { }
streampacker->setMaxPacketSize(63 * 1024);
} void PICloud::TCP::setRole(PICloud::TCP::Role r) {
header.role = r;
void PICloud::TCP::setRole(PICloud::TCP::Role r) { }
header.role = r;
}
void PICloud::TCP::setServerName(const PIString & server_name_) {
server_name = server_name_;
void PICloud::TCP::setServerName(const PIString & server_name_) { suuid = PICrypt::hash(PIByteArray(server_name_.data(), server_name_.size()), (const unsigned char *)hash_cloud_key, sizeof(hash_cloud_key));
server_name = server_name_; }
suuid =
PICrypt::hash(PIByteArray(server_name_.data(), server_name_.size()), (const unsigned char *)hash_cloud_key, sizeof(hash_cloud_key));
} PIString PICloud::TCP::serverName() const {
return server_name;
}
PIString PICloud::TCP::serverName() const {
return server_name;
} void PICloud::TCP::sendStart() {
//piCout << "sendStart";
if (suuid.size() != PICrypt::sizeHash()) {
void PICloud::TCP::sendStart() { piCout << "PICloud ERROR, server not set, invoke setServerName first";
// piCout << "sendStart"; return;
if (suuid.size() != PICrypt::sizeHash()) { }
piCout << "PICloud ERROR, server not set, invoke setServerName first"; header.type = PICloud::TCP::Connect;
return; PIByteArray ba;
} ba << header;
header.type = PICloud::TCP::Connect; ba.append(suuid);
PIByteArray ba; //mutex_send.lock();
ba << header; streampacker->send(ba);
ba.append(suuid); //mutex_send.unlock();
// mutex_send.lock(); }
streampacker->send(ba);
// mutex_send.unlock();
} void PICloud::TCP::sendConnected(uint client_id) {
header.type = PICloud::TCP::Connect;
PIByteArray ba;
void PICloud::TCP::sendConnected(uint client_id) { ba << header << client_id;
header.type = PICloud::TCP::Connect; // mutex_send.lock();
PIByteArray ba; streampacker->send(ba);
ba << header << client_id; // mutex_send.unlock();
// mutex_send.lock(); }
streampacker->send(ba);
// mutex_send.unlock();
} void PICloud::TCP::sendDisconnected(uint client_id) {
header.type = PICloud::TCP::Disconnect;
PIByteArray ba;
void PICloud::TCP::sendDisconnected(uint client_id) { ba << header << client_id;
header.type = PICloud::TCP::Disconnect; // mutex_send.lock();
PIByteArray ba; streampacker->send(ba);
ba << header << client_id; // mutex_send.unlock();
// mutex_send.lock(); }
streampacker->send(ba);
// mutex_send.unlock();
} int PICloud::TCP::sendData(const PIByteArray & data) {
header.type = PICloud::TCP::Data;
PIByteArray ba;
int PICloud::TCP::sendData(const PIByteArray & data) { ba << header;
header.type = PICloud::TCP::Data; ba.append(data);
PIByteArray ba; // piCout << "[PICloud::TCP] sendData" << ba.toHex();
ba << header; mutex_send.lock();
ba.append(data); streampacker->send(ba);
// piCout << "[PICloud::TCP] sendData" << ba.toHex(); mutex_send.unlock();
mutex_send.lock(); return data.size_s();
streampacker->send(ba); }
mutex_send.unlock();
return data.size_s();
} int PICloud::TCP::sendData(const PIByteArray & data, uint client_id) {
header.type = PICloud::TCP::Data;
PIByteArray ba;
int PICloud::TCP::sendData(const PIByteArray & data, uint client_id) { ba << header << client_id;
header.type = PICloud::TCP::Data; ba.append(data);
PIByteArray ba; mutex_send.lock();
ba << header << client_id; streampacker->send(ba);
ba.append(data); mutex_send.unlock();
mutex_send.lock(); return data.size_s();
streampacker->send(ba); }
mutex_send.unlock();
return data.size_s();
} void PICloud::TCP::sendPing() {
header.type = PICloud::TCP::Ping;
PIByteArray ba;
void PICloud::TCP::sendPing() { ba << header;
header.type = PICloud::TCP::Ping; ba.append(suuid);
PIByteArray ba; mutex_send.lock();
ba << header; streampacker->send(ba);
ba.append(suuid); mutex_send.unlock();
mutex_send.lock(); }
streampacker->send(ba);
mutex_send.unlock();
} PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteArray & ba) {
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> ret;
ret.first = InvalidType;
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteArray & ba) { ret.second = InvalidRole;
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> ret; if (ba.size() < sizeof(Header)) return ret;
ret.first = InvalidType; PICloud::TCP::Header hdr;
ret.second = InvalidRole; ba >> hdr;
if (ba.size() < sizeof(Header)) return ret; if (hdr.version != header.version) {
PICloud::TCP::Header hdr; piCout << "[PICloud]" << "invalid PICloud::TCP version!";
ba >> hdr; return ret;
if (hdr.version != header.version) { }
piCout << "[PICloud]" ret.first = (Type)hdr.type;
<< "Invalid PICloud::TCP version!"_tr("PICloud"); ret.second = (Role)hdr.role;
return ret; return ret;
} }
ret.first = (Type)hdr.type;
ret.second = (Role)hdr.role;
return ret; bool PICloud::TCP::canParseData(PIByteArray & ba) {
} return header.role == Client;
}
bool PICloud::TCP::canParseData(PIByteArray & ba) {
return header.role == Client; PIPair<uint, PIByteArray> PICloud::TCP::parseDataServer(PIByteArray & ba) {
} PIPair<uint, PIByteArray> ret;
ret.first = 0;
if (header.role == Server) {
PIPair<uint, PIByteArray> PICloud::TCP::parseDataServer(PIByteArray & ba) { ba >> ret.first;
PIPair<uint, PIByteArray> ret; ret.second.swap(ba);
ret.first = 0; }
if (header.role == Server) { return ret;
ba >> ret.first; }
ret.second.swap(ba);
}
return ret; PIByteArray PICloud::TCP::parseConnect_d(PIByteArray & ba) {
} if (ba.size() != PICrypt::sizeHash()) {
piCout << "PICloud ERROR, invalid server uuid";
return PIByteArray();
PIByteArray PICloud::TCP::parseConnect_d(PIByteArray & ba) { } else {
if (ba.size() != PICrypt::sizeHash()) { return ba;
piCout << "PICloud ERROR, invalid server uuid"; }
return PIByteArray(); }
} else {
return ba;
} uint PICloud::TCP::parseConnect(PIByteArray & ba) {
} uint ret;
ba >> ret;
return ret;
uint PICloud::TCP::parseConnect(PIByteArray & ba) { }
uint ret = 0;
ba >> ret;
return ret; uint PICloud::TCP::parseDisconnect(PIByteArray & ba) {
} uint ret;
ba >> ret;
return ret;
uint PICloud::TCP::parseDisconnect(PIByteArray & ba) { }
uint ret = 0;
ba >> ret;
return ret;
}

View File

@@ -1,83 +1,76 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Compress class using zlib Compress class using zlib
Andrey Bychkov work.a.b@yandex.ru Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "picompress.h" #include "picompress.h"
#ifdef PIP_COMPRESS
#include "pitranslator.h" # ifdef ESP_PLATFORM
#ifdef PIP_COMPRESS # include "esp32/rom/miniz.h"
# ifdef ESP_PLATFORM # define compress2 mz_compress2
# include "esp32/rom/miniz.h" # define Z_OK MZ_OK
# define compress2 mz_compress2 # define uncompress mz_uncompress
# define Z_OK MZ_OK # else
# define uncompress mz_uncompress # include <zlib.h>
# else # endif
# include <zlib.h> #endif
# endif
#endif
PIByteArray piCompress(const PIByteArray & ba, int level) {
#ifdef PIP_COMPRESS
PIByteArray piCompress(const PIByteArray & ba, int level) { PIByteArray zba;
#ifdef PIP_COMPRESS zba.resize(ba.size() + 128);
PIByteArray zba; int ret = 0;
zba.resize(ba.size() + 128); ulong sz = zba.size();
int ret = 0; ret = compress2(zba.data(), &sz, ba.data(), ba.size(), level);
ulong sz = zba.size(); if (ret != Z_OK) {
ret = compress2(zba.data(), &sz, ba.data(), ba.size(), level); piCout << "[PICompress]" << "Error: invalid input or not enought memory";
if (ret != Z_OK) { return ba;
piCout << "[PICompress]" }
<< "Error: invalid input or not enought memory"_tr("PICompress"); zba.resize(sz);
return ba; zba << ullong(ba.size());
} return zba;
zba.resize(sz); #else
zba << ullong(ba.size()); piCout << "[PICompress]" << "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
return zba; #endif
#else return ba;
piCout << "[PICompress]" }
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library"_tr("PICompress");
#endif
return ba; PIByteArray piDecompress(const PIByteArray & zba) {
} #ifdef PIP_COMPRESS
ullong sz;
if (zba.size() < sizeof(ullong)) {
PIByteArray piDecompress(const PIByteArray & zba) { piCout << "[PICompress]" << "Error: invalid input";
#ifdef PIP_COMPRESS return zba;
ullong sz = 0; }
if (zba.size() < sizeof(ullong)) { PIByteArray ba(zba.data(zba.size() - sizeof(ullong)), sizeof(ullong));
piCout << "[PICompress]" ba >> sz;
<< "Error: invalid input"_tr("PICompress"); ba.resize(sz);
return zba; int ret = 0;
} ulong s = sz;
PIByteArray ba(zba.data(zba.size() - sizeof(ullong)), sizeof(ullong)); ret = uncompress(ba.data(), &s, zba.data(), zba.size());
ba >> sz; if (ret != Z_OK) {
ba.resize(sz); piCout << "[PICompress]" << "Error: invalid input or not enought memory";
int ret = 0; return zba;
ulong s = sz; }
ret = uncompress(ba.data(), &s, zba.data(), zba.size()); return ba;
if (ret != Z_OK) { #else
piCout << "[PICompress]" piCout << "[PICompress]" << "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
<< "Error: invalid input or not enought memory"_tr("PICompress"); #endif
return zba; return zba;
} }
return ba;
#else
piCout << "[PICompress]"
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library"_tr("PICompress");
#endif
return zba;
}

View File

@@ -1,38 +1,34 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Console output/input Console output/input
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piscreen.h" #include "piscreen.h"
#include "piincludes_p.h" #include "piincludes_p.h"
#include "piliterals_time.h"
// clang-format off
#ifndef WINDOWS #ifndef WINDOWS
# include <fcntl.h>
# include <sys/ioctl.h> # include <sys/ioctl.h>
# include <fcntl.h>
# include <termios.h> # include <termios.h>
#else #else
# include <wingdi.h> # include <wingdi.h>
# include <wincon.h> # include <wincon.h>
# ifndef COMMON_LVB_UNDERSCORE # ifndef COMMON_LVB_UNDERSCORE
# define COMMON_LVB_UNDERSCORE 0x8000 # define COMMON_LVB_UNDERSCORE 0x8000
# endif # endif
#endif #endif
// clang-format on
using namespace PIScreenTypes; using namespace PIScreenTypes;
@@ -55,26 +51,14 @@ PRIVATE_DEFINITION_END(PIScreen::SystemConsole)
PIScreen::SystemConsole::SystemConsole() { PIScreen::SystemConsole::SystemConsole() {
width = height = pwidth = pheight = 0; width = height = pwidth = pheight = 0;
mouse_x = mouse_y = -1; mouse_x = mouse_y = -1;
}
PIScreen::SystemConsole::~SystemConsole() {
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
#endif
}
void PIScreen::SystemConsole::begin() {
int w, h; int w, h;
#ifdef WINDOWS #ifdef WINDOWS
PRIVATE->ulcoord.X = 0; PRIVATE->ulcoord.X = 0;
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE); PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
PRIVATE->dattr = PRIVATE->sbi.wAttributes; PRIVATE->dattr = PRIVATE->sbi.wAttributes;
w = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left; w = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
h = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top; h = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top; PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top;
GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode); GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode);
GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
@@ -90,6 +74,18 @@ void PIScreen::SystemConsole::begin() {
# endif # endif
#endif #endif
resize(w, h); resize(w, h);
}
PIScreen::SystemConsole::~SystemConsole() {
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
#endif
}
void PIScreen::SystemConsole::begin() {
#ifdef WINDOWS #ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT); SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT);
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
@@ -97,7 +93,6 @@ void PIScreen::SystemConsole::begin() {
PRIVATE->bc.Y = 0; PRIVATE->bc.Y = 0;
#endif #endif
clear(); clear();
clearScreen();
hideCursor(); hideCursor();
} }
@@ -139,9 +134,9 @@ void PIScreen::SystemConsole::clear() {
void PIScreen::SystemConsole::resize(int w, int h) { void PIScreen::SystemConsole::resize(int w, int h) {
if (w == pwidth && h == pheight) return; if (w == pwidth && h == pheight) return;
width = piMaxi(w, 0); width = piMaxi(w, 0);
height = piMaxi(h, 0); height = piMaxi(h, 0);
pwidth = width; pwidth = width;
pheight = height; pheight = height;
cells.resize(height); cells.resize(height);
pcells.resize(height); pcells.resize(height);
@@ -162,7 +157,7 @@ void PIScreen::SystemConsole::resize(int w, int h) {
void PIScreen::SystemConsole::print() { void PIScreen::SystemConsole::print() {
if (mouse_x >= 0 && mouse_x < width && mouse_y >= 0 && mouse_y < height) { if (mouse_x >= 0 && mouse_x < width && mouse_y >= 0 && mouse_y < height) {
/// cells[mouse_y][mouse_x].format.flags ^= Inverse; ///cells[mouse_y][mouse_x].format.flags ^= Inverse;
} }
#ifdef WINDOWS #ifdef WINDOWS
PRIVATE->srect = PRIVATE->sbi.srWindow; PRIVATE->srect = PRIVATE->sbi.srWindow;
@@ -190,10 +185,10 @@ void PIScreen::SystemConsole::print() {
int k = j * dw + i; int k = j * dw + i;
Cell & c(cells[j + dy0][i + dx0]); Cell & c(cells[j + dy0][i + dx0]);
PRIVATE->chars[k].Char.UnicodeChar = 0; PRIVATE->chars[k].Char.UnicodeChar = 0;
PRIVATE->chars[k].Char.AsciiChar = c.symbol.toConsole1Byte(); PRIVATE->chars[k].Char.AsciiChar = c.symbol.toConsole1Byte();
PRIVATE->chars[k].Attributes = attributes(c); PRIVATE->chars[k].Attributes = attributes(c);
} }
// piCout << "draw" << dw << dh; //piCout << "draw" << dw << dh;
PRIVATE->bs.X = dw; PRIVATE->bs.X = dw;
PRIVATE->bs.Y = dh; PRIVATE->bs.Y = dh;
PRIVATE->srect.Left += dx0; PRIVATE->srect.Left += dx0;
@@ -232,7 +227,7 @@ void PIScreen::SystemConsole::print() {
if (!s.isEmpty()) { if (!s.isEmpty()) {
moveTo(si, sj); moveTo(si, sj);
PICout::stdoutPIString(s); PICout::stdoutPIString(s);
// printf("%s", s.data()); //printf("%s", s.data());
s.clear(); s.clear();
} }
} }
@@ -244,37 +239,33 @@ void PIScreen::SystemConsole::print() {
#ifdef WINDOWS #ifdef WINDOWS
# define FOREGROUND_MASK (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define FOREGROUND_MASK (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
# define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) #define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) { ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) {
WORD attr = PRIVATE->dattr; WORD attr = PRIVATE->dattr;
if (c.format.flags & Bold) if (c.format.flags & Bold) attr |= FOREGROUND_INTENSITY;
attr |= FOREGROUND_INTENSITY; else attr &= ~FOREGROUND_INTENSITY;
else if (c.format.flags & Underline) attr |= COMMON_LVB_UNDERSCORE;
attr &= ~FOREGROUND_INTENSITY; else attr &= ~COMMON_LVB_UNDERSCORE;
if (c.format.flags & Underline)
attr |= COMMON_LVB_UNDERSCORE;
else
attr &= ~COMMON_LVB_UNDERSCORE;
switch (c.format.color_char) { switch (c.format.color_char) {
case Black: attr = (attr & ~FOREGROUND_MASK); break; case Black: attr = (attr & ~FOREGROUND_MASK); break;
case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break; case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break;
case Green: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN; break; case Green: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN; break;
case Blue: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_BLUE; break; case Blue: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_BLUE; break;
case Cyan: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE; break; case Cyan: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
case Magenta: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_BLUE; break; case Magenta: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_BLUE; break;
case Yellow: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_GREEN; break; case Yellow: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_GREEN; break;
case White: attr = attr | FOREGROUND_MASK; break; case White: attr = attr | FOREGROUND_MASK; break;
} }
switch (c.format.color_back) { switch (c.format.color_back) {
case Black: attr = (attr & ~BACKGROUND_MASK); break; case Black: attr = (attr & ~BACKGROUND_MASK); break;
case Red: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED; break; case Red: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED; break;
case Green: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN; break; case Green: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN; break;
case Blue: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_BLUE; break; case Blue: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_BLUE; break;
case Cyan: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE; break; case Cyan: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
case Magenta: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_BLUE; break; case Magenta: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_BLUE; break;
case Yellow: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_GREEN; break; case Yellow: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_GREEN; break;
case White: attr = attr | BACKGROUND_MASK; break; case White: attr = attr | BACKGROUND_MASK; break;
} }
if ((c.format.flags & Inverse) == Inverse) { if ((c.format.flags & Inverse) == Inverse) {
uchar f = attr & 0xFF; uchar f = attr & 0xFF;
@@ -284,8 +275,8 @@ ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) {
} }
return attr; return attr;
} }
# undef FOREGROUND_MASK #undef FOREGROUND_MASK
# undef BACKGROUND_MASK #undef BACKGROUND_MASK
void PIScreen::SystemConsole::getWinCurCoord() { void PIScreen::SystemConsole::getWinCurCoord() {
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi); GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi);
@@ -300,37 +291,36 @@ void PIScreen::SystemConsole::clearLine() {
void PIScreen::SystemConsole::newLine() { void PIScreen::SystemConsole::newLine() {
getWinCurCoord(); getWinCurCoord();
PRIVATE->ccoord.X = 0; PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++;
PRIVATE->ccoord.Y++;
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord); SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
} }
#else // WINDOWS #else // WINDOWS
PIString PIScreen::SystemConsole::formatString(const PIScreenTypes::Cell & c) { PIString PIScreen::SystemConsole::formatString(const PIScreenTypes::Cell & c) {
PIString ts = PIStringAscii("\e[0"); PIString ts = PIStringAscii("\e[0");
switch (c.format.color_char) { switch (c.format.color_char) {
case Black: ts += PIStringAscii(";30"); break; case Black: ts += PIStringAscii(";30"); break;
case Red: ts += PIStringAscii(";31"); break; case Red: ts += PIStringAscii(";31"); break;
case Green: ts += PIStringAscii(";32"); break; case Green: ts += PIStringAscii(";32"); break;
case Blue: ts += PIStringAscii(";34"); break; case Blue: ts += PIStringAscii(";34"); break;
case Cyan: ts += PIStringAscii(";36"); break; case Cyan: ts += PIStringAscii(";36"); break;
case Magenta: ts += PIStringAscii(";35"); break; case Magenta: ts += PIStringAscii(";35"); break;
case Yellow: ts += PIStringAscii(";33"); break; case Yellow: ts += PIStringAscii(";33"); break;
case White: ts += PIStringAscii(";37"); break; case White: ts += PIStringAscii(";37"); break;
} }
switch (c.format.color_back) { switch (c.format.color_back) {
case Black: ts += PIStringAscii(";40"); break; case Black: ts += PIStringAscii(";40"); break;
case Red: ts += PIStringAscii(";41"); break; case Red: ts += PIStringAscii(";41"); break;
case Green: ts += PIStringAscii(";42"); break; case Green: ts += PIStringAscii(";42"); break;
case Blue: ts += PIStringAscii(";44"); break; case Blue: ts += PIStringAscii(";44"); break;
case Cyan: ts += PIStringAscii(";46"); break; case Cyan: ts += PIStringAscii(";46"); break;
case Magenta: ts += PIStringAscii(";45"); break; case Magenta: ts += PIStringAscii(";45"); break;
case Yellow: ts += PIStringAscii(";43"); break; case Yellow: ts += PIStringAscii(";43"); break;
case White: ts += PIStringAscii(";47"); break; case White: ts += PIStringAscii(";47"); break;
} }
if ((c.format.flags & Bold) == Bold) ts += PIStringAscii(";1"); if ((c.format.flags & Bold ) == Bold ) ts += PIStringAscii(";1");
if ((c.format.flags & Underline) == Underline) ts += PIStringAscii(";4"); if ((c.format.flags & Underline) == Underline) ts += PIStringAscii(";4");
if ((c.format.flags & Blink) == Blink) ts += PIStringAscii(";5"); if ((c.format.flags & Blink ) == Blink ) ts += PIStringAscii(";5");
if ((c.format.flags & Inverse) == Inverse) ts += PIStringAscii(";7"); if ((c.format.flags & Inverse ) == Inverse ) ts += PIStringAscii(";7");
return ts + 'm'; return ts + 'm';
} }
#endif // WINDOWS #endif // WINDOWS
@@ -367,16 +357,8 @@ void PIScreen::SystemConsole::clearScreen() {
void PIScreen::SystemConsole::clearScreenLower() { void PIScreen::SystemConsole::clearScreenLower() {
#ifdef WINDOWS #ifdef WINDOWS
getWinCurCoord(); getWinCurCoord();
FillConsoleOutputAttribute(PRIVATE->hOut, FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
PRIVATE->dattr, FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X,
PRIVATE->ccoord,
&PRIVATE->written);
FillConsoleOutputCharacter(PRIVATE->hOut,
' ',
width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X,
PRIVATE->ccoord,
&PRIVATE->written);
#else #else
printf("\e[0m\e[J"); printf("\e[0m\e[J");
#endif #endif
@@ -401,33 +383,34 @@ void PIScreen::SystemConsole::showCursor() {
} }
// PIScreen
PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawer_(console.cells), root("rootTile") { PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawer_(console.cells), root("rootTile") {
setName("screen"); setName("screen");
setPriority(piLow); setPriority(piLow);
needLockRun(true); needLockRun(true);
mouse_ = false; mouse_ = false;
ret_func = slot; ret_func = slot;
tile_focus = tile_dialog = nullptr; tile_focus = tile_dialog = 0;
root.screen = this; root.screen = this;
listener = new PIKbdListener(key_eventS, this, startNow); listener = new PIKbdListener(key_eventS, this, startNow);
CONNECT1(void, PIKbdListener::MouseEvent, listener, mouseEvent, this, mouse_event); CONNECTU(listener, mouseEvent, this, mouse_event);
CONNECT1(void, PIKbdListener::WheelEvent, listener, wheelEvent, this, wheel_event); CONNECTU(listener, wheelEvent, this, wheel_event);
if (startNow) start(); if (startNow) start();
} }
PIScreen::~PIScreen() { PIScreen::~PIScreen() {
if (isRunning()) stop(); if (isRunning())
PIThread::waitForFinish(100_ms); stop();
listener->waitForFinish(100_ms); PIThread::waitForFinish(10);
listener->waitForFinish(10);
delete listener; delete listener;
} }
void PIScreen::setMouseEnabled(bool on) { void PIScreen::setMouseEnabled(bool on) {
mouse_ = on; mouse_ = on;
console.mouse_x = console.mouse_y = -1; console.mouse_x = console.mouse_y = -1;
} }
@@ -439,12 +422,14 @@ void PIScreen::key_event(PIKbdListener::KeyEvent key) {
return; return;
*/ */
PIScreenTile * rtile = rootTile(); PIScreenTile * rtile = rootTile();
if (tile_dialog) rtile = tile_dialog; if (tile_dialog)
rtile = tile_dialog;
bool used = nextFocus(rtile, key); bool used = nextFocus(rtile, key);
if (used) return; if (used) return;
if (!used && tile_focus) { if (!used && tile_focus) {
if (tile_focus->visible) { if (tile_focus->visible) {
if (tile_focus->keyEvent(key)) return; if (tile_focus->keyEvent(key))
return;
} }
} }
if (ret_func != 0) ret_func(key, data_); if (ret_func != 0) ret_func(key, data_);
@@ -452,14 +437,14 @@ void PIScreen::key_event(PIKbdListener::KeyEvent key) {
} }
PIVector<PIScreenTile *> PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) { PIVector<PIScreenTile * > PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) {
PIVector<PIScreenTile *> ret; PIVector<PIScreenTile * > ret;
if (!mouse_ || !e) return ret; if (!mouse_ || !e) return ret;
console.mouse_x = e->x; console.mouse_x = e->x;
console.mouse_y = e->y; console.mouse_y = e->y;
PIVector<PIScreenTile *> tl = tilesUnderMouse(e->x, e->y); PIVector<PIScreenTile * > tl = tilesUnderMouse(e->x, e->y);
bool ff = false; bool ff = false;
piForeachR(PIScreenTile * t, tl) { piForeachR (PIScreenTile * t, tl) {
if (!ff) { if (!ff) {
if (t->focus_flags[FocusOnMouse] && (e->action == PIKbdListener::MouseButtonPress)) { if (t->focus_flags[FocusOnMouse] && (e->action == PIKbdListener::MouseButtonPress)) {
t->setFocus(); t->setFocus();
@@ -470,19 +455,20 @@ PIVector<PIScreenTile *> PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) {
ff = true; ff = true;
} }
} }
} }
return tl; return tl;
} }
PIVector<PIScreenTile *> PIScreen::tilesUnderMouse(int x, int y) { PIVector<PIScreenTile * > PIScreen::tilesUnderMouse(int x, int y) {
PIVector<PIScreenTile *> ret; PIVector<PIScreenTile * > ret;
if (x < 0 || x >= console.width || y < 0 || y >= console.height) return ret; if (x < 0 || x >= console.width || y < 0 || y >= console.height) return ret;
PIScreenTile * ct = tile_dialog ? tile_dialog : rootTile(); PIScreenTile * ct = tile_dialog ? tile_dialog : rootTile();
bool f = true; bool f = true;
while (ct) { while (ct) {
if (!f) ret << ct; if (!f) ret << ct;
f = false; f = false;
ct = ct->childUnderMouse(x, y); ct = ct->childUnderMouse(x, y);
} }
return ret; return ret;
@@ -490,25 +476,27 @@ PIVector<PIScreenTile *> PIScreen::tilesUnderMouse(int x, int y) {
void PIScreen::mouse_event(PIKbdListener::MouseEvent me) { void PIScreen::mouse_event(PIKbdListener::MouseEvent me) {
PIVector<PIScreenTile *> tl = prepareMouse(&me); PIVector<PIScreenTile * > tl = prepareMouse(&me);
if (tl.isEmpty()) return; if (tl.isEmpty()) return;
piForeachR(PIScreenTile * t, tl) piForeachR (PIScreenTile * t, tl)
if (t->mouseEvent(me)) break; if (t->mouseEvent(me)) break;
} }
void PIScreen::wheel_event(PIKbdListener::WheelEvent we) { void PIScreen::wheel_event(PIKbdListener::WheelEvent we) {
PIVector<PIScreenTile *> tl = prepareMouse(&we); PIVector<PIScreenTile * > tl = prepareMouse(&we);
if (tl.isEmpty()) return; if (tl.isEmpty()) return;
piForeachR(PIScreenTile * t, tl) piForeachR (PIScreenTile * t, tl)
if (t->wheelEvent(we)) break; if (t->wheelEvent(we)) break;
} }
bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) { bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
PIVector<PIScreenTile *> vtl = rt->children(true), ftl; PIVector<PIScreenTile*> vtl = rt->children(true), ftl;
for (PIScreenTile * t: vtl) { piForeach (PIScreenTile * t, vtl) {
if (t->focus_flags[CanHasFocus]) ftl << t; if (t->focus_flags[CanHasFocus])
ftl << t;
} }
int ind = -1; int ind = -1;
for (int i = 0; i < ftl.size_s(); ++i) for (int i = 0; i < ftl.size_s(); ++i)
@@ -516,15 +504,18 @@ bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
ind = i; ind = i;
break; break;
} }
if (ind < 0) tile_focus = 0; if (ind < 0)
tile_focus = 0;
if (ftl.isEmpty()) if (ftl.isEmpty())
tile_focus = 0; tile_focus = 0;
else { else {
if (tile_focus) if (tile_focus)
if (!tile_focus->visible) tile_focus = 0; if (!tile_focus->visible)
tile_focus = 0;
int next = tile_focus ? 0 : 1; int next = tile_focus ? 0 : 1;
if (tile_focus) { if (tile_focus) {
if (tile_focus->focus_flags[NextByTab] && key.key == PIKbdListener::Tab) next = 1; if (tile_focus->focus_flags[NextByTab] && key.key == PIKbdListener::Tab)
next = 1;
if (tile_focus->focus_flags[NextByArrowsHorizontal]) { if (tile_focus->focus_flags[NextByArrowsHorizontal]) {
if (key.key == PIKbdListener::LeftArrow) next = -1; if (key.key == PIKbdListener::LeftArrow) next = -1;
if (key.key == PIKbdListener::RightArrow) next = 1; if (key.key == PIKbdListener::RightArrow) next = 1;
@@ -534,16 +525,16 @@ bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
if (key.key == PIKbdListener::DownArrow) next = 1; if (key.key == PIKbdListener::DownArrow) next = 1;
} }
} }
// piCout << ftl.size() << ind << next; //piCout << ftl.size() << ind << next;
if (next != 0) { if (next != 0) {
PIVector<PIScreenTile *> tl = rt->children(); PIVector<PIScreenTile*> tl = rt->children();
for (PIScreenTile * t: tl) piForeach (PIScreenTile * t, tl)
t->has_focus = false; t->has_focus = false;
if (!ftl.isEmpty()) { if (!ftl.isEmpty()) {
ind += next; ind += next;
if (ind >= ftl.size_s()) ind = 0; if (ind >= ftl.size_s()) ind = 0;
if (ind < 0) ind = ftl.size_s() - 1; if (ind < 0) ind = ftl.size_s() - 1;
tile_focus = ftl[ind]; tile_focus = ftl[ind];
tile_focus->has_focus = true; tile_focus->has_focus = true;
} }
return true; return true;
@@ -559,19 +550,22 @@ void PIScreen::tileEventInternal(PIScreenTile * t, TileEvent e) {
void PIScreen::tileRemovedInternal(PIScreenTile * t) { void PIScreen::tileRemovedInternal(PIScreenTile * t) {
if (tile_dialog == t) tile_dialog = 0; if (tile_dialog == t)
tile_dialog = 0;
} }
void PIScreen::tileSetFocusInternal(PIScreenTile * t) { void PIScreen::tileSetFocusInternal(PIScreenTile * t) {
PIScreenTile * rt = rootTile(); PIScreenTile * rt = rootTile();
if (tile_dialog) rt = tile_dialog; if (tile_dialog)
PIVector<PIScreenTile *> tl = rt->children(), ftl; rt = tile_dialog;
for (PIScreenTile * i: tl) PIVector<PIScreenTile*> tl = rt->children(), ftl;
piForeach (PIScreenTile * i, tl)
i->has_focus = false; i->has_focus = false;
tile_focus = t; tile_focus = t;
if (!tile_focus) return; if (!tile_focus) return;
if (tile_focus->focus_flags[CanHasFocus]) tile_focus->has_focus = true; if (tile_focus->focus_flags[CanHasFocus])
tile_focus->has_focus = true;
} }
@@ -593,14 +587,8 @@ void PIScreen::waitForFinish() {
} }
void PIScreen::start(bool wait) {
PIThread::start(25_Hz);
if (wait) waitForFinish();
}
void PIScreen::stop(bool clear) { void PIScreen::stop(bool clear) {
PIThread::stopAndWait(); PIThread::stop(true);
if (clear) console.clearScreen(); if (clear) console.clearScreen();
#ifndef WINDOWS #ifndef WINDOWS
fflush(0); fflush(0);
@@ -624,21 +612,16 @@ void PIScreen::run() {
if (tile_dialog) { if (tile_dialog) {
int sw(0), sh(0); int sw(0), sh(0);
tile_dialog->sizeHint(sw, sh); tile_dialog->sizeHint(sw, sh);
sw = piClampi(sw, tile_dialog->minimumWidth, tile_dialog->maximumWidth); sw = piClampi(sw, tile_dialog->minimumWidth, tile_dialog->maximumWidth);
sh = piClampi(sh, tile_dialog->minimumHeight, tile_dialog->maximumHeight); sh = piClampi(sh, tile_dialog->minimumHeight, tile_dialog->maximumHeight);
tile_dialog->x_ = (console.width - sw) / 2; tile_dialog->x_ = (console.width - sw) / 2;
tile_dialog->y_ = (console.height - sh) / 2; tile_dialog->y_ = (console.height - sh) / 2;
tile_dialog->width_ = sw; tile_dialog->width_ = sw;
tile_dialog->height_ = sh; tile_dialog->height_ = sh;
tile_dialog->layout(); tile_dialog->layout();
int dx = tile_dialog->x_ - 1, dy = tile_dialog->y_ - 1, dw = tile_dialog->width_, dh = tile_dialog->height_; int dx = tile_dialog->x_ - 1, dy = tile_dialog->y_ - 1, dw = tile_dialog->width_, dh = tile_dialog->height_;
drawer_.drawFrame(dx, drawer_.drawFrame(dx, dy, dx + dw + 1, dy + dh + 1, (Color)tile_dialog->back_format.color_char,
dy, (Color)tile_dialog->back_format.color_back, (CharFlags)tile_dialog->back_format.flags);
dx + dw + 1,
dy + dh + 1,
(Color)tile_dialog->back_format.color_char,
(Color)tile_dialog->back_format.color_back,
(CharFlags)tile_dialog->back_format.flags);
tile_dialog->drawEventInternal(&drawer_); tile_dialog->drawEventInternal(&drawer_);
} }
console.print(); console.print();
@@ -652,8 +635,10 @@ void PIScreen::end() {
PIScreenTile * PIScreen::tileByName(const PIString & name) { PIScreenTile * PIScreen::tileByName(const PIString & name) {
PIVector<PIScreenTile *> tl(tiles()); PIVector<PIScreenTile*> tl(tiles());
for (PIScreenTile * t: tl) piForeach (PIScreenTile * t, tl)
if (t->name() == name) return t; if (t->name() == name)
return t;
return 0; return 0;
} }

View File

@@ -1,20 +1,20 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Tile for PIScreen with PIConsole API Tile for PIScreen with PIConsole API
Andrey Bychkov work.a.b@yandex.ru Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piscreenconsole.h" #include "piscreenconsole.h"
@@ -22,14 +22,21 @@
using namespace PIScreenTypes; using namespace PIScreenTypes;
TileVars::TileVars(const PIString & n): PIScreenTile(n) { TileVars::TileVars(const PIString &n) : PIScreenTile(n) {
alignment = Left; alignment = Left;
} }
void TileVars::sizeHint(int & w, int & h) const {} void TileVars::sizeHint(int &w, int &h) const {
void TileVars::drawEvent(PIScreenDrawer * d) {} }
void TileVars::drawEvent(PIScreenDrawer *d) {
}
PIScreenConsoleTile::PIScreenConsoleTile() {} PIScreenConsoleTile::PIScreenConsoleTile() {
}

View File

@@ -1,20 +1,20 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Console output/input Console output/input
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piscreendrawer.h" #include "piscreendrawer.h"
@@ -25,68 +25,68 @@
using namespace PIScreenTypes; using namespace PIScreenTypes;
PIScreenDrawer::PIScreenDrawer(PIVector<PIVector<Cell>> & c): cells(c) { PIScreenDrawer::PIScreenDrawer(PIVector<PIVector<Cell> > & c): cells(c) {
arts_[LineVertical] = arts_[LineVertical] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('|'); PIChar('|');
#endif #endif
arts_[LineHorizontal] = arts_[LineHorizontal] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('-'); PIChar('-');
#endif #endif
arts_[Cross] = arts_[Cross] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('+'); PIChar('+');
#endif #endif
arts_[CornerTopLeft] = arts_[CornerTopLeft] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('+'); PIChar('+');
#endif #endif
arts_[CornerTopRight] = arts_[CornerTopRight] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('+'); PIChar('+');
#endif #endif
arts_[CornerBottomLeft] = arts_[CornerBottomLeft] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('+'); PIChar('+');
#endif #endif
arts_[CornerBottomRight] = arts_[CornerBottomRight] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('+'); PIChar('+');
#endif #endif
arts_[Unchecked] = arts_[Unchecked] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('O'); PIChar('O');
#endif #endif
arts_[Checked] = arts_[Checked] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('0'); PIChar('0');
#endif #endif
} }
@@ -98,43 +98,45 @@ void PIScreenDrawer::clear() {
void PIScreenDrawer::drawPixel(int x, int y, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { void PIScreenDrawer::drawPixel(int x, int y, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) {
if (x < 0 || x >= width || y < 0 || y >= height) return; if (x < 0 || x >= width || y < 0 || y >= height) return;
cells[y][x].symbol = c; cells[y][x].symbol = c;
cells[y][x].format.color_char = col_char; cells[y][x].format.color_char = col_char;
cells[y][x].format.color_back = col_back; cells[y][x].format.color_back = col_back;
cells[y][x].format.flags = flags_char; cells[y][x].format.flags = flags_char;
} }
void PIScreenDrawer::drawLine(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { void PIScreenDrawer::drawLine(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) {
if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char); if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char);
Cell cc; Cell cc;
cc.symbol = c; cc.symbol = c;
cc.format.color_char = col_char; cc.format.color_char = col_char;
cc.format.color_back = col_back; cc.format.color_back = col_back;
cc.format.flags = flags_char; cc.format.flags = flags_char;
int x = 0, y = 0; int x = 0, y = 0;
if (piAbsi(x1 - x0) >= piAbsi(y1 - y0)) { if (piAbsi(x1 - x0) >= piAbsi(y1 - y0)) {
float dy = (y1 - y0) / float(piAbsi(x1 - x0)), cy = y0; float dy = (y1 - y0) / float(piAbsi(x1 - x0)), cy = y0;
int dx = x0 < x1 ? 1 : -1; int dx = x0 < x1 ? 1 : -1;
for (int i = x0; i != x1; i += dx) { for (int i = x0; i != x1; i += dx) {
x = i; x = i; y = piRound(cy);
y = piRound(cy); if (x >= 0 && x < width && y >= 0 && y < height)
if (x >= 0 && x < width && y >= 0 && y < height) cells[y][x] = cc; cells[y][x] = cc;
cy += dy; cy += dy;
} }
y = piRound(cy); y = piRound(cy);
if (x1 >= 0 && x1 < width && y >= 0 && y < height) cells[y][x1] = cc; if (x1 >= 0 && x1 < width && y >= 0 && y < height)
cells[y][x1] = cc;
} else { } else {
float dx = (x1 - x0) / float(piAbsi(y1 - y0)), cx = x0; float dx = (x1 - x0) / float(piAbsi(y1 - y0)), cx = x0;
int dy = y0 < y1 ? 1 : -1; int dy = y0 < y1 ? 1 : -1;
for (int i = y0; i != y1; i += dy) { for (int i = y0; i != y1; i += dy) {
x = piRound(cx); x = piRound(cx); y = i;
y = i; if (x >= 0 && x < width && y >= 0 && y < height)
if (x >= 0 && x < width && y >= 0 && y < height) cells[y][x] = cc; cells[y][x] = cc;
cx += dx; cx += dx;
} }
x = piRound(cx); x = piRound(cx);
if (x >= 0 && x < width && y1 >= 0 && y1 < height) cells[y1][x] = cc; if (x >= 0 && x < width && y1 >= 0 && y1 < height)
cells[y1][x] = cc;
} }
} }
@@ -142,29 +144,32 @@ void PIScreenDrawer::drawLine(int x0, int y0, int x1, int y1, const PIChar & c,
void PIScreenDrawer::drawRect(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { void PIScreenDrawer::drawRect(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) {
if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char); if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char);
Cell cc; Cell cc;
cc.symbol = c; cc.symbol = c;
cc.format.color_char = col_char; cc.format.color_char = col_char;
cc.format.color_back = col_back; cc.format.color_back = col_back;
cc.format.flags = flags_char; cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1; int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1; int dy = y0 < y1 ? 1 : -1;
int xs[2] = {x0, x1}; int xs[2] = {x0, x1};
int ys[2] = {y0, y1}; int ys[2] = {y0, y1};
for (int k = 0; k < 2; ++k) { for (int k = 0; k < 2; ++k) {
int j = ys[k]; int j = ys[k];
if (j >= 0 && j < height) { if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]); PIVector<Cell> & cv(cells[j]);
for (int i = x0; i != x1; i += dx) for (int i = x0; i != x1; i += dx)
if (i >= 0 && i < width) cv[i] = cc; if (i >= 0 && i < width)
cv[i] = cc;
} }
j = xs[k]; j = xs[k];
if (j >= 0 && j < width) { if (j >= 0 && j < width) {
for (int i = y0; i != y1; i += dy) for (int i = y0; i != y1; i += dy)
if (i >= 0 && i < height) cells[i][j] = cc; if (i >= 0 && i < height)
cells[i][j] = cc;
} }
} }
int i = x1, j = y1; int i = x1, j = y1;
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; if (i >= 0 && i < width && j >= 0 && j < height)
cells[j][i] = cc;
} }
@@ -173,37 +178,35 @@ void PIScreenDrawer::drawFrame(int x0, int y0, int x1, int y1, Color col_char, C
Cell cc; Cell cc;
cc.format.color_char = col_char; cc.format.color_char = col_char;
cc.format.color_back = col_back; cc.format.color_back = col_back;
cc.format.flags = flags_char; cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1; int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1; int dy = y0 < y1 ? 1 : -1;
int xs[2] = {x0, x1}; int xs[2] = {x0, x1};
int ys[2] = {y0, y1}; int ys[2] = {y0, y1};
for (int k = 0; k < 2; ++k) { for (int k = 0; k < 2; ++k) {
int j = ys[k]; int j = ys[k];
if (j >= 0 && j < height) { if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]); PIVector<Cell> & cv(cells[j]);
cc.symbol = artChar(LineHorizontal); cc.symbol = artChar(LineHorizontal);
for (int i = x0 + 1; i != x1; i += dx) for (int i = x0 + 1; i != x1; i += dx)
if (i >= 0 && i < width) cv[i] = cc; if (i >= 0 && i < width)
cv[i] = cc;
} }
j = xs[k]; j = xs[k];
if (j >= 0 && j < width) { if (j >= 0 && j < width) {
cc.symbol = artChar(LineVertical); cc.symbol = artChar(LineVertical);
for (int i = y0 + 1; i != y1; i += dy) for (int i = y0 + 1; i != y1; i += dy)
if (i >= 0 && i < height) cells[i][j] = cc; if (i >= 0 && i < height)
cells[i][j] = cc;
} }
} }
int i = x0, j = y0; int i = x0, j = y0; cc.symbol = artChar(CornerTopLeft);
cc.symbol = artChar(CornerTopLeft);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
i = x1, j = y0; i = x1, j = y0; cc.symbol = artChar(CornerTopRight);
cc.symbol = artChar(CornerTopRight);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
i = x0, j = y1; i = x0, j = y1; cc.symbol = artChar(CornerBottomLeft);
cc.symbol = artChar(CornerBottomLeft);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
i = x1, j = y1; i = x1, j = y1; cc.symbol = artChar(CornerBottomRight);
cc.symbol = artChar(CornerBottomRight);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
} }
@@ -211,22 +214,23 @@ void PIScreenDrawer::drawFrame(int x0, int y0, int x1, int y1, Color col_char, C
void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) {
if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char); if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char);
Cell cc; Cell cc;
cc.symbol = c; cc.symbol = c;
cc.format.color_char = col_char; cc.format.color_char = col_char;
cc.format.color_back = col_back; cc.format.color_back = col_back;
cc.format.flags = flags_char; cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1; int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1; int dy = y0 < y1 ? 1 : -1;
for (int j = y0; j != y1; j += dy) for (int j = y0; j != y1; j += dy)
if (j >= 0 && j < height) { if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]); PIVector<Cell> & cv(cells[j]);
for (int i = x0; i != x1; i += dx) for (int i = x0; i != x1; i += dx)
if (i >= 0 && i < width) cv[i] = cc; if (i >= 0 && i < width)
cv[i] = cc;
} }
} }
void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<Cell>> & content) { void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<Cell> > & content) {
if (x0 > x1) piSwap(x0, x1); if (x0 > x1) piSwap(x0, x1);
if (y0 > y1) piSwap(y0, y1); if (y0 > y1) piSwap(y0, y1);
int w = x1 - x0; int w = x1 - x0;
@@ -237,13 +241,14 @@ void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<
PIVector<Cell> & cv(cells[y0 + j]); PIVector<Cell> & cv(cells[y0 + j]);
PIVector<Cell> & contv(content[j]); PIVector<Cell> & contv(content[j]);
for (int i = 0; i < piMini(w, contv.size_s()); ++i) for (int i = 0; i < piMini(w, contv.size_s()); ++i)
if ((i + x0) >= 0 && (i + x0) < width) cv[x0 + i] = contv[i]; if ((i + x0) >= 0 && (i + x0) < width)
cv[x0 + i] = contv[i];
} }
} }
} }
void PIScreenDrawer::clear(PIVector<PIVector<Cell>> & cells) { void PIScreenDrawer::clear(PIVector<PIVector<Cell> > & cells) {
for (int i = 0; i < cells.size_s(); ++i) for (int i = 0; i < cells.size_s(); ++i)
cells[i].fill(Cell()); cells[i].fill(Cell());
} }
@@ -255,12 +260,12 @@ void PIScreenDrawer::drawText(int x, int y, const PIString & s, Color col_char,
Cell cc; Cell cc;
cc.format.color_char = col_char; cc.format.color_char = col_char;
cc.format.color_back = col_back; cc.format.color_back = col_back;
cc.format.flags = flags_char; cc.format.flags = flags_char;
for (int i = 0; i < s.size_s(); ++i) { for (int i = 0; i < s.size_s(); ++i) {
int j = i + x; int j = i + x;
if (j >= 0 && j < width) { if (j >= 0 && j < width) {
cc.symbol = s[i]; cc.symbol = s[i];
cv[j] = cc; cv[j] = cc;
} }
} }
} }

View File

@@ -1,24 +1,23 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Basic PIScreen tile Basic PIScreen tile
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piscreentile.h" #include "piscreentile.h"
#include "piscreendrawer.h" #include "piscreendrawer.h"
@@ -26,23 +25,24 @@ using namespace PIScreenTypes;
PIScreenTile::PIScreenTile(const PIString & n, Direction d, SizePolicy p): PIObject(n) { PIScreenTile::PIScreenTile(const PIString & n, Direction d, SizePolicy p): PIObject(n) {
direction = d; direction = d;
size_policy = p; size_policy = p;
focus_flags = 0; focus_flags = 0;
screen = 0; screen = 0;
minimumWidth = minimumHeight = x_ = y_ = width_ = height_ = pw = ph = 0; minimumWidth = minimumHeight = x_ = y_ = width_ = height_ = pw = ph = 0;
maximumWidth = maximumHeight = 65535; maximumWidth = maximumHeight = 65535;
marginLeft = marginRight = marginTop = marginBottom = spacing = 0; marginLeft = marginRight = marginTop = marginBottom = spacing = 0;
parent = 0; parent = 0;
back_symbol = ' '; back_symbol = ' ';
visible = true; visible = true;
has_focus = false; has_focus = false;
} }
PIScreenTile::~PIScreenTile() { PIScreenTile::~PIScreenTile() {
// piCout << this << "~"; //piCout << this << "~";
if (screen) screen->tileRemovedInternal(this); if (screen)
screen->tileRemovedInternal(this);
setScreen(0); setScreen(0);
deleteChildren(); deleteChildren();
if (!parent) return; if (!parent) return;
@@ -76,18 +76,20 @@ void PIScreenTile::removeTile(PIScreenTile * t) {
} }
PIVector<PIScreenTile *> PIScreenTile::children(bool only_visible) { PIVector<PIScreenTile * > PIScreenTile::children(bool only_visible) {
PIVector<PIScreenTile *> ret; PIVector<PIScreenTile * > ret;
for (auto * t: tiles) piForeach (PIScreenTile * t, tiles)
if (t->visible || !only_visible) ret << t << t->children(only_visible); if (t->visible || !only_visible)
ret << t << t->children(only_visible);
return ret; return ret;
} }
PIScreenTile * PIScreenTile::childUnderMouse(int x, int y) { PIScreenTile * PIScreenTile::childUnderMouse(int x, int y) {
for (auto * t: tiles) { piForeach (PIScreenTile * t, tiles) {
if (!t->visible) continue; if (!t->visible) continue;
if (x >= t->x_ && (x - t->x_) < t->width_ && y >= t->y_ && (y - t->y_) < t->height_) { if (x >= t->x_ && (x - t->x_) < t->width_ &&
y >= t->y_ && (y - t->y_) < t->height_) {
return t; return t;
} }
} }
@@ -103,13 +105,13 @@ void PIScreenTile::raiseEvent(TileEvent e) {
void PIScreenTile::setScreen(PIScreenBase * s) { void PIScreenTile::setScreen(PIScreenBase * s) {
screen = s; screen = s;
for (auto * t: tiles) piForeach (PIScreenTile * t, tiles)
t->setScreen(s); t->setScreen(s);
} }
void PIScreenTile::deleteChildren() { void PIScreenTile::deleteChildren() {
for (auto * t: tiles) { piForeach (PIScreenTile * t, tiles) {
t->parent = 0; t->parent = 0;
delete t; delete t;
} }
@@ -127,16 +129,9 @@ void PIScreenTile::drawEventInternal(PIScreenDrawer * d) {
if (!visible) { if (!visible) {
return; return;
} }
d->fillRect(x_, d->fillRect(x_, y_, x_ + width_, y_ + height_, back_symbol, (Color)back_format.color_char, (Color)back_format.color_back, back_format.flags);
y_,
x_ + width_,
y_ + height_,
back_symbol,
(Color)back_format.color_char,
(Color)back_format.color_back,
back_format.flags);
drawEvent(d); drawEvent(d);
for (auto * t: tiles) piForeach (PIScreenTile * t, tiles)
t->drawEventInternal(d); t->drawEventInternal(d);
} }
@@ -146,22 +141,18 @@ void PIScreenTile::sizeHint(int & w, int & h) const {
h = 0; h = 0;
if (tiles.isEmpty()) return; if (tiles.isEmpty()) return;
int sl = spacing * (tiles.size_s() - 1); int sl = spacing * (tiles.size_s() - 1);
if (direction == Horizontal) if (direction == Horizontal) w += sl;
w += sl; else h += sl;
else piForeachC (PIScreenTile * t, tiles) {
h += sl;
for (const auto * t: tiles) {
if (!t->visible) continue; if (!t->visible) continue;
int cw(0), ch(0); int cw(0), ch(0);
t->sizeHint(cw, ch); t->sizeHint(cw, ch);
cw = piClampi(cw, t->minimumWidth, t->maximumWidth); cw = piClampi(cw, t->minimumWidth, t->maximumWidth);
ch = piClampi(ch, t->minimumHeight, t->maximumHeight); ch = piClampi(ch, t->minimumHeight, t->maximumHeight);
if (direction == Horizontal) { if (direction == Horizontal) {
w += cw; w += cw; h = piMaxi(h, ch);
h = piMaxi(h, ch);
} else { } else {
h += ch; h += ch; w = piMaxi(w, cw);
w = piMaxi(w, cw);
} }
} }
w += marginLeft + marginRight; w += marginLeft + marginRight;
@@ -172,7 +163,7 @@ void PIScreenTile::sizeHint(int & w, int & h) const {
void PIScreenTile::layout() { void PIScreenTile::layout() {
if (tiles.isEmpty() || !visible) return; if (tiles.isEmpty() || !visible) return;
int as(0), ts(0), ts2(0), ecnt(0), pcnt(0); int as(0), ts(0), ts2(0), ecnt(0), pcnt(0);
ts = (direction == Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom); ts = (direction == Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom);
ts2 = (direction != Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom); ts2 = (direction != Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom);
ts -= spacing * (tiles.size_s() - 1); ts -= spacing * (tiles.size_s() - 1);
PIVector<int> hints(tiles.size_s()); PIVector<int> hints(tiles.size_s());
@@ -189,7 +180,7 @@ void PIScreenTile::layout() {
cs = (direction == Horizontal) ? cw : ch; cs = (direction == Horizontal) ? cw : ch;
as += cs; as += cs;
} }
hints[i] = cs; hints[i] = cs;
asizes[i] = 0.f; asizes[i] = 0.f;
} }
if (as <= ts) { if (as <= ts) {
@@ -197,10 +188,10 @@ void PIScreenTile::layout() {
SizePolicy pol = Fixed; SizePolicy pol = Fixed;
if (ecnt > 0) { if (ecnt > 0) {
acnt = ecnt; acnt = ecnt;
pol = Expanding; pol = Expanding;
} else if (pcnt > 0) { } else if (pcnt > 0) {
acnt = pcnt; acnt = pcnt;
pol = Preferred; pol = Preferred;
} }
if (acnt > 0) { if (acnt > 0) {
float add_a = float(ts - as), add_s = add_a / acnt, add_da(0.); float add_a = float(ts - as), add_s = add_a / acnt, add_da(0.);
@@ -219,7 +210,8 @@ void PIScreenTile::layout() {
for (int j = 0; j < tiles.size_s(); ++j) { for (int j = 0; j < tiles.size_s(); ++j) {
if (i == j) continue; if (i == j) continue;
if (max_tl[j]) continue; if (max_tl[j]) continue;
if (tiles[j]->size_policy == pol && tiles[j]->visible && tiles[j]->needLayout()) asizes[j] += pas; if (tiles[j]->size_policy == pol && tiles[j]->visible && tiles[j]->needLayout())
asizes[j] += pas;
} }
} }
} }
@@ -241,15 +233,16 @@ void PIScreenTile::layout() {
t->x_ = cx; t->x_ = cx;
t->y_ = cy; t->y_ = cy;
if (direction == Horizontal) { if (direction == Horizontal) {
t->width_ = hints[i]; t->width_ = hints[i];
t->height_ = ts2; t->height_ = ts2;
cx += hints[i] + spacing; cx += hints[i] + spacing;
} else { } else {
t->width_ = ts2; t->width_ = ts2;
t->height_ = hints[i]; t->height_ = hints[i];
cy += hints[i] + spacing; cy += hints[i] + spacing;
} }
if (t->pw != t->width_ || t->ph != t->height_) t->resizeEvent(t->width_, t->height_); if (t->pw != t->width_ || t->ph != t->height_)
t->resizeEvent(t->width_, t->height_);
t->pw = t->width_; t->pw = t->width_;
t->ph = t->height_; t->ph = t->height_;
t->layout(); t->layout();

View File

@@ -1,24 +1,23 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Various tiles for PIScreen Various tiles for PIScreen
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piscreentiles.h" #include "piscreentiles.h"
#include "piscreendrawer.h" #include "piscreendrawer.h"
@@ -38,7 +37,7 @@ TileSimple::TileSimple(const TileSimple::Row & r): PIScreenTile() {
void TileSimple::sizeHint(int & w, int & h) const { void TileSimple::sizeHint(int & w, int & h) const {
w = h = 0; w = h = 0;
for (const auto & r: content) piForeachC (Row & r, content)
w = piMaxi(w, r.first.size_s()); w = piMaxi(w, r.first.size_s());
h = content.size_s(); h = content.size_s();
} }
@@ -58,13 +57,13 @@ void TileSimple::drawEvent(PIScreenDrawer * d) {
} }
// TileScrollBar
TileScrollBar::TileScrollBar(const PIString & n) { TileScrollBar::TileScrollBar(const PIString & n) {
direction = Vertical; direction = Vertical;
thickness = 1; thickness = 1;
minimum_ = value_ = 0; minimum_ = value_ = 0;
maximum_ = 100; maximum_ = 100;
} }
@@ -123,15 +122,15 @@ bool TileScrollBar::mouseEvent(PIKbdListener::MouseEvent me) {
} }
// TileList
TileList::TileList(const PIString & n, SelectionMode sm): PIScreenTile(n) { TileList::TileList(const PIString & n, SelectionMode sm): PIScreenTile(n) {
alignment = Left; alignment = Left;
focus_flags = CanHasFocus | NextByArrowsHorizontal | NextByTab | FocusOnMouseOrWheel; focus_flags = CanHasFocus | NextByArrowsHorizontal | NextByTab | FocusOnMouseOrWheel;
lhei = offset = cur = 0; lhei = offset = cur = 0;
mouse_sel = false; mouse_sel = false;
selection_mode = sm; selection_mode = sm;
scroll = new TileScrollBar(); scroll = new TileScrollBar();
scroll->size_policy = Ignore; scroll->size_policy = Ignore;
addTile(scroll); addTile(scroll);
} }
@@ -139,26 +138,26 @@ TileList::TileList(const PIString & n, SelectionMode sm): PIScreenTile(n) {
void TileList::sizeHint(int & w, int & h) const { void TileList::sizeHint(int & w, int & h) const {
w = h = 0; w = h = 0;
for (const auto & r: content) piForeachC (Row & r, content)
w = piMaxi(w, r.first.size_s()); w = piMaxi(w, r.first.size_s());
h = 3; h = 3;
} }
void TileList::resizeEvent(int w, int h) { void TileList::resizeEvent(int w, int h) {
scroll->x_ = x_ + width_ - 1; scroll->x_ = x_ + width_ - 1;
scroll->y_ = y_; scroll->y_ = y_;
scroll->width_ = 1; scroll->width_ = 1;
scroll->height_ = height_; scroll->height_ = height_;
} }
void TileList::drawEvent(PIScreenDrawer * d) { void TileList::drawEvent(PIScreenDrawer * d) {
lhei = height_ - 2; lhei = height_ - 2;
int is = piClampi(offset, 0, piMaxi(0, content.size_s() - 1)), ie = piClampi(offset + lhei, 0, content.size_s()); int is = piClampi(offset, 0, piMaxi(0, content.size_s() - 1)), ie = piClampi(offset + lhei, 0, content.size_s());
if (is > 0) d->drawText(x_, y_, PIString(" /\\ ").repeat(width_ / 4), Green, Default, Bold); if (is > 0) d->drawText(x_, y_, PIString(" /\\ ").repeat(width_ / 4), Green, Default, Bold);
if (ie < content.size_s()) d->drawText(x_, y_ + height_ - 1, PIString(" \\/ ").repeat(width_ / 4), Green, Default, Bold); if (ie < content.size_s()) d->drawText(x_, y_ + height_ - 1, PIString(" \\/ ").repeat(width_ / 4), Green, Default, Bold);
// piCout << is << ie << offset << lhei << content.size_s(); //piCout << is << ie << offset << lhei << content.size_s();
for (int i = is; i < ie; ++i) { for (int i = is; i < ie; ++i) {
Row & r(content[i]); Row & r(content[i]);
bool sel = i == cur && has_focus; bool sel = i == cur && has_focus;
@@ -173,7 +172,7 @@ void TileList::drawEvent(PIScreenDrawer * d) {
case Right: rx = x_ + width_ - 1 - r.first.size_s(); break; case Right: rx = x_ + width_ - 1 - r.first.size_s(); break;
}; };
CharFlags cf = r.second.flags; CharFlags cf = r.second.flags;
Color cc = (Color)r.second.color_char; Color cc = (Color)r.second.color_char;
if (selected[i]) { if (selected[i]) {
cf |= Bold; cf |= Bold;
cc = Yellow; cc = Yellow;
@@ -189,7 +188,9 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
lhei = height_ - 2; lhei = height_ - 2;
int oo(0), osp = piMini(3, lhei / 4); int oo(0), osp = piMini(3, lhei / 4);
switch (key.key) { switch (key.key) {
case PIKbdListener::PageUp: cur -= lhei / 2; oo -= lhei / 2; case PIKbdListener::PageUp:
cur -= lhei / 2;
oo -= lhei / 2;
case PIKbdListener::UpArrow: case PIKbdListener::UpArrow:
cur--; cur--;
oo--; oo--;
@@ -206,8 +207,7 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
switch (selection_mode) { switch (selection_mode) {
case NoSelection: return false; case NoSelection: return false;
case SingleSelection: case SingleSelection:
if (selected.isEmpty()) if (selected.isEmpty()) selected << cur;
selected << cur;
else { else {
bool add = !selected[cur]; bool add = !selected[cur];
selected.clear(); selected.clear();
@@ -216,10 +216,8 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
raiseEvent(TileEvent(SelectionChanged)); raiseEvent(TileEvent(SelectionChanged));
return true; return true;
case MultiSelection: case MultiSelection:
if (selected[cur]) if (selected[cur]) selected.remove(cur);
selected.remove(cur); else selected << cur;
else
selected << cur;
raiseEvent(TileEvent(SelectionChanged)); raiseEvent(TileEvent(SelectionChanged));
break; break;
} }
@@ -240,14 +238,17 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
if (offset >= content.size_s() - lhei) offset = content.size_s() - lhei; if (offset >= content.size_s() - lhei) offset = content.size_s() - lhei;
if (offset < 0) offset = 0; if (offset < 0) offset = 0;
return true; return true;
case PIKbdListener::Home: cur = offset = 0; return true; case PIKbdListener::Home:
cur = offset = 0;
return true;
case PIKbdListener::End: case PIKbdListener::End:
cur = content.size_s() - 1; cur = content.size_s() - 1;
offset = content.size_s() - lhei; offset = content.size_s() - lhei;
if (offset < 0) offset = 0; if (offset < 0) offset = 0;
return true; return true;
case PIKbdListener::Return: case PIKbdListener::Return:
if (cur >= 0 && cur < content.size_s()) raiseEvent(TileEvent(RowPressed, cur)); if (cur >= 0 && cur < content.size_s())
raiseEvent(TileEvent(RowPressed, cur));
return true; return true;
case '*': case '*':
if (selection_mode == TileList::MultiSelection) { if (selection_mode == TileList::MultiSelection) {
@@ -277,8 +278,12 @@ bool TileList::mouseEvent(PIKbdListener::MouseEvent me) {
if (mp < 0 || mp >= content.size_s()) return true; if (mp < 0 || mp >= content.size_s()) return true;
cur = mp; cur = mp;
switch (me.action) { switch (me.action) {
case PIKbdListener::MouseButtonPress: mouse_sel = !selected.contains(cur); break; case PIKbdListener::MouseButtonPress:
case PIKbdListener::MouseButtonDblClick: keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return)); return true; mouse_sel = !selected.contains(cur);
break;
case PIKbdListener::MouseButtonDblClick:
keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return));
return true;
default: break; default: break;
} }
if (me.buttons[PIKbdListener::MouseRight]) { if (me.buttons[PIKbdListener::MouseRight]) {
@@ -289,10 +294,8 @@ bool TileList::mouseEvent(PIKbdListener::MouseEvent me) {
raiseEvent(TileEvent(SelectionChanged)); raiseEvent(TileEvent(SelectionChanged));
break; break;
case MultiSelection: case MultiSelection:
if (mouse_sel) if (mouse_sel) selected << cur;
selected << cur; else selected.remove(cur);
else
selected.remove(cur);
raiseEvent(TileEvent(SelectionChanged)); raiseEvent(TileEvent(SelectionChanged));
break; break;
default: break; default: break;
@@ -308,7 +311,7 @@ bool TileList::wheelEvent(PIKbdListener::WheelEvent we) {
} }
// TileButton
TileButton::TileButton(const PIString & n): PIScreenTile(n) { TileButton::TileButton(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse; focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse;
@@ -324,7 +327,7 @@ void TileButton::sizeHint(int & w, int & h) const {
void TileButton::drawEvent(PIScreenDrawer * d) { void TileButton::drawEvent(PIScreenDrawer * d) {
Color cb = has_focus ? Blue : Cyan; Color cb = has_focus ? Blue : Cyan;
Color ct = has_focus ? White : Black; Color ct = has_focus ? White : Black;
int ff = has_focus ? Bold : 0; int ff = has_focus ? Bold : 0;
d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb); d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb);
d->drawText(x_, y_, "[", ct, Transparent, ff); d->drawText(x_, y_, "[", ct, Transparent, ff);
d->drawText(x_ + (width_ - text.size_s()) / 2, y_, text, ct, Transparent, ff); d->drawText(x_ + (width_ - text.size_s()) / 2, y_, text, ct, Transparent, ff);
@@ -348,25 +351,25 @@ bool TileButton::mouseEvent(PIKbdListener::MouseEvent me) {
} }
// TileButtons
TileButtons::TileButtons(const PIString & n): PIScreenTile(n) { TileButtons::TileButtons(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | FocusOnMouse; focus_flags = CanHasFocus | NextByTab | FocusOnMouse;
direction = Horizontal; direction = Horizontal;
alignment = PIScreenTypes::Center; alignment = PIScreenTypes::Center;
cur = 0; cur = 0;
} }
void TileButtons::sizeHint(int & w, int & h) const { void TileButtons::sizeHint(int & w, int & h) const {
w = h = 0; w = h = 0;
if (direction == Horizontal) { if (direction == Horizontal) {
for (const auto & b: content) piForeachC (Button & b, content)
w += b.first.size_s() + 4; w += b.first.size_s() + 4;
w += piMaxi(0, content.size_s() - 1) * 2; w += piMaxi(0, content.size_s() - 1) * 2;
h += 1; h += 1;
} else { } else {
for (const auto & b: content) piForeachC (Button & b, content)
w = piMaxi(w, b.first.size_s() + 4); w = piMaxi(w, b.first.size_s() + 4);
h += content.size_s(); h += content.size_s();
h += piMaxi(0, content.size_s() - 1); h += piMaxi(0, content.size_s() - 1);
@@ -384,11 +387,12 @@ void TileButtons::drawEvent(PIScreenDrawer * d) {
case PIScreenTypes::Right: dx = width_ - shw; break; case PIScreenTypes::Right: dx = width_ - shw; break;
default: break; default: break;
} }
if (direction == PIScreenTypes::Horizontal) cx += dx; if (direction == PIScreenTypes::Horizontal)
cx += dx;
for (int i = 0; i < content.size_s(); ++i) { for (int i = 0; i < content.size_s(); ++i) {
Color cb = Cyan; Color cb = Cyan;
Color ct = Black; Color ct = Black;
int ff = 0; int ff = 0;
if (i == cur && has_focus) { if (i == cur && has_focus) {
cb = Blue; cb = Blue;
ct = White; ct = White;
@@ -426,7 +430,9 @@ bool TileButtons::keyEvent(PIKbdListener::KeyEvent key) {
if (cur >= content.size_s()) cur = content.size_s() - 1; if (cur >= content.size_s()) cur = content.size_s() - 1;
return true; return true;
case PIKbdListener::Space: case PIKbdListener::Space:
case PIKbdListener::Return: raiseEvent(TileEvent(ButtonSelected, cur)); return true; case PIKbdListener::Return:
raiseEvent(TileEvent(ButtonSelected, cur));
return true;
}; };
return PIScreenTile::keyEvent(key); return PIScreenTile::keyEvent(key);
} }
@@ -435,7 +441,8 @@ bool TileButtons::keyEvent(PIKbdListener::KeyEvent key) {
bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) { bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) {
if (me.action == PIKbdListener::MouseMove || me.action == PIKbdListener::MouseButtonPress) { if (me.action == PIKbdListener::MouseMove || me.action == PIKbdListener::MouseButtonPress) {
for (int i = 0; i < btn_rects.size_s(); ++i) for (int i = 0; i < btn_rects.size_s(); ++i)
if (me.x >= btn_rects[i].x0 && me.x < btn_rects[i].x1 && me.y >= btn_rects[i].y0 && me.y < btn_rects[i].y1) { if (me.x >= btn_rects[i].x0 && me.x < btn_rects[i].x1 &&
me.y >= btn_rects[i].y0 && me.y < btn_rects[i].y1) {
cur = i; cur = i;
break; break;
} }
@@ -447,11 +454,11 @@ bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) {
} }
// TileCheck
TileCheck::TileCheck(const PIString & n): PIScreenTile(n) { TileCheck::TileCheck(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse; focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse;
toggled = false; toggled = false;
} }
@@ -464,7 +471,7 @@ void TileCheck::sizeHint(int & w, int & h) const {
void TileCheck::drawEvent(PIScreenDrawer * d) { void TileCheck::drawEvent(PIScreenDrawer * d) {
Color cb = has_focus ? Blue : Cyan; Color cb = has_focus ? Blue : Cyan;
Color ct = has_focus ? White : Black; Color ct = has_focus ? White : Black;
int ff = has_focus ? Bold : 0; int ff = has_focus ? Bold : 0;
PIString cs("[ ]"); PIString cs("[ ]");
if (toggled) cs[1] = '*'; if (toggled) cs[1] = '*';
d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb); d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb);
@@ -492,12 +499,12 @@ bool TileCheck::mouseEvent(PIKbdListener::MouseEvent me) {
} }
// TileProgress
TileProgress::TileProgress(const PIString & n): PIScreenTile(n) { TileProgress::TileProgress(const PIString & n): PIScreenTile(n) {
maximum = 100.; maximum = 100.;
value = 0.; value = 0.;
suffix = " %"; suffix = " %";
} }
@@ -508,7 +515,7 @@ void TileProgress::sizeHint(int & w, int & h) const {
void TileProgress::drawEvent(PIScreenDrawer * d) { void TileProgress::drawEvent(PIScreenDrawer * d) {
int v = maximum == 0. ? 0 : piClampd(piRoundd(value / maximum * 100.), 0, 100); int v = maximum == 0. ? 0 : piClampd(piRoundd(value / maximum * 100.), 0, 100);
PIString s = prefix + PIString::fromNumber(piRoundd(value)) + suffix; PIString s = prefix + PIString::fromNumber(piRoundd(value)) + suffix;
int w = piRoundd(v / 100. * width_), sx = (width_ - s.size_s()) / 2; int w = piRoundd(v / 100. * width_), sx = (width_ - s.size_s()) / 2;
d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, Cyan); d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, Cyan);
@@ -525,26 +532,28 @@ void TileProgress::drawEvent(PIScreenDrawer * d) {
} }
// TilePICout
TilePICout::TilePICout(const PIString & n): TileList(n) { TilePICout::TilePICout(const PIString & n): TileList(n) {
max_lines = 1024; max_lines = 1024;
selection_mode = TileList::SingleSelection; selection_mode = TileList::SingleSelection;
PICout::setOutputDevices(PICout::Buffer); PICout::setOutputDevices(PICout::Buffer);
PICout::setBufferActive(true);
} }
void TilePICout::drawEvent(PIScreenDrawer * d) { void TilePICout::drawEvent(PIScreenDrawer * d) {
PIString out = PICout::getBufferAndClear(); PIString out = PICout::buffer(true);
if (!out.isEmpty()) { if (!out.isEmpty()) {
PIStringList l = out.split("\n"); PIStringList l = out.split("\n");
bool scroll = (cur == content.size_s() - 1) || !has_focus; bool scroll = (cur == content.size_s() - 1) || !has_focus;
for (const auto & s: l) piForeachC (PIString & s, l)
content << TileList::Row(s.trimmed(), format); content << TileList::Row(s.trimmed(), format);
if (content.size_s() > max_lines) content.remove(0, content.size_s() - max_lines); if (content.size_s() > max_lines)
content.remove(0, content.size_s() - max_lines);
if (scroll) { if (scroll) {
offset = piMaxi(0, content.size_s() - lhei); offset = piMaxi(0, content.size_s() - lhei);
cur = content.size_s() - 1; cur = content.size_s() - 1;
} }
} }
TileList::drawEvent(d); TileList::drawEvent(d);
@@ -561,16 +570,16 @@ bool TilePICout::keyEvent(PIKbdListener::KeyEvent key) {
} }
// TileInput
TileInput::TileInput(const PIString & n): PIScreenTile(n) { TileInput::TileInput(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | FocusOnMouse; focus_flags = CanHasFocus | NextByTab | FocusOnMouse;
back_format.color_back = White; back_format.color_back = White;
format.color_char = Black; format.color_char = Black;
format.color_back = White; format.color_back = White;
max_length = 1024; max_length = 1024;
cur = offset = 0; cur = offset = 0;
inv = false; inv = false;
} }
@@ -583,8 +592,10 @@ void TileInput::sizeHint(int & w, int & h) const {
void TileInput::drawEvent(PIScreenDrawer * d) { void TileInput::drawEvent(PIScreenDrawer * d) {
PIString ps = text.mid(offset, width_ - 2); PIString ps = text.mid(offset, width_ - 2);
d->drawText(x_ + 1, y_, ps, (Color)format.color_char, Transparent, (CharFlags)format.flags); d->drawText(x_ + 1, y_, ps, (Color)format.color_char, Transparent, (CharFlags)format.flags);
if (offset > 0) d->drawText(x_, y_, "<", Green, Black, Bold); if (offset > 0)
if (text.size_s() - offset >= width_ - 2) d->drawText(x_ + width_ - 1, y_, ">", Green, Black, Bold); d->drawText(x_, y_, "<", Green, Black, Bold);
if (text.size_s() - offset >= width_ - 2)
d->drawText(x_ + width_ - 1, y_, ">", Green, Black, Bold);
if (!has_focus) return; if (!has_focus) return;
Color cb = (Color)format.color_char, cc = (Color)format.color_back; Color cb = (Color)format.color_char, cc = (Color)format.color_back;
if (tm_blink.elapsed_m() >= 650) { if (tm_blink.elapsed_m() >= 650) {
@@ -631,13 +642,14 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
reserCursor(); reserCursor();
return true; return true;
case PIKbdListener::End: case PIKbdListener::End:
cur = text.size_s(); cur = text.size_s();
offset = text.size_s() - lwid; offset = text.size_s() - lwid;
if (offset < 0) offset = 0; if (offset < 0) offset = 0;
reserCursor(); reserCursor();
return true; return true;
case PIKbdListener::Backspace: case PIKbdListener::Backspace:
if (cur > text.size_s() || text.isEmpty()) return true; if (cur > text.size_s() || text.isEmpty())
return true;
text.remove(cur - 1, 1); text.remove(cur - 1, 1);
cur--; cur--;
if (cur > text.size_s()) cur = text.size_s(); if (cur > text.size_s()) cur = text.size_s();
@@ -647,7 +659,8 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
reserCursor(); reserCursor();
return true; return true;
case PIKbdListener::Delete: case PIKbdListener::Delete:
if (cur >= text.size_s() || text.isEmpty()) return true; if (cur >= text.size_s() || text.isEmpty())
return true;
text.remove(cur, 1); text.remove(cur, 1);
if (cur < 0) cur = 0; if (cur < 0) cur = 0;
if (cur > text.size_s()) cur = text.size_s(); if (cur > text.size_s()) cur = text.size_s();
@@ -673,7 +686,8 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
case PIKbdListener::F9: case PIKbdListener::F9:
case PIKbdListener::F10: case PIKbdListener::F10:
case PIKbdListener::F11: case PIKbdListener::F11:
case PIKbdListener::F12: break; case PIKbdListener::F12:
break;
default: default:
text.insert(cur, PIChar((ushort)key.key)); text.insert(cur, PIChar((ushort)key.key));
cur++; cur++;

View File

@@ -1,60 +1,58 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Virtual terminal Virtual terminal
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piterminal.h"
#include "piincludes_p.h" #include "piincludes_p.h"
#include "piliterals_time.h" #include "piterminal.h"
#include "pisharedmemory.h" #include "pisharedmemory.h"
#ifndef MICRO_PIP #ifndef MICRO_PIP
# ifdef WINDOWS #ifdef WINDOWS
# include <windows.h> # include <windows.h>
# include <wingdi.h> # include <wingdi.h>
# include <winuser.h> # include <wincon.h>
# include <winuser.h>
#else
# include "piprocess.h"
# include <csignal>
# include <fcntl.h>
# include <sys/ioctl.h>
# if defined(QNX) || defined(BLACKBERRY)
# include <unix.h>
# else # else
# include "piprocess.h" # ifdef MAC_OS
# include <util.h>
# include <csignal> # else
# include <fcntl.h> # include <pty.h>
# include <sys/ioctl.h> # endif
# if defined(QNX) || defined(BLACKBERRY)
# include <unix.h>
# else
# ifdef MAC_OS
# include <util.h>
# else
# include <pty.h>
# endif
# endif
# ifdef ANDROID
# if __ANDROID_API__ >= 23
# define HAS_FORKPTY
# endif
# else
# define HAS_FORKPTY
# endif
# endif # endif
# ifdef ANDROID
# if __ANDROID_API__ >= 23
# define HAS_FORKPTY
# endif
# else
# define HAS_FORKPTY
# endif
#endif
// extern PIMutex PICout::__mutex__; //extern PIMutex PICout::__mutex__;
# ifdef WINDOWS #ifdef WINDOWS
# define PIPE_BUFFER_SIZE 1024 # define PIPE_BUFFER_SIZE 1024
enum PITerminalAuxMessageType { enum PITerminalAuxMessageType {
mtKey = 1, mtKey = 1,
mtResize, mtResize,
@@ -67,22 +65,22 @@ struct PITerminalAuxData {
int size_y; int size_y;
int cells_size; int cells_size;
}; };
# else #else
# define BUFFER_SIZE 4096 # define BUFFER_SIZE 4096
enum DECType { enum DECType {
CKM = 1 CKM = 1
}; };
# endif #endif
PRIVATE_DEFINITION_START(PITerminal) PRIVATE_DEFINITION_START(PITerminal)
# ifdef WINDOWS #ifdef WINDOWS
PISharedMemory * shm; PISharedMemory * shm;
HANDLE hConBuf; HANDLE hConBuf;
STARTUPINFOA si; STARTUPINFOA si;
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
HANDLE pipe; HANDLE pipe;
# else #else
PIString shell; PIString shell;
PIByteArray read_buf, tmp_buf; PIByteArray read_buf, tmp_buf;
PIScreenTypes::CellFormat cur_format, line_format; PIScreenTypes::CellFormat cur_format, line_format;
@@ -94,21 +92,21 @@ PRIVATE_DEFINITION_START(PITerminal)
PIString esc_seq; PIString esc_seq;
bool is_esc_seq, last_read; bool is_esc_seq, last_read;
PIMap<int, bool> DEC; PIMap<int, bool> DEC;
PIVector<PIVector<PIScreenTypes::Cell>> cells_save; PIVector<PIVector<PIScreenTypes::Cell> > cells_save;
# endif #endif
PRIVATE_DEFINITION_END(PITerminal) PRIVATE_DEFINITION_END(PITerminal)
# ifdef WINDOWS #ifdef WINDOWS
int writePipe(HANDLE pipe, const PIByteArray & ba) { int writePipe(HANDLE pipe, const PIByteArray & ba) {
DWORD wrote[2]; DWORD wrote[2];
int sz = ba.size_s(); int sz = ba.size_s();
WriteFile(pipe, &sz, 4, &(wrote[0]), 0); WriteFile(pipe, &sz, 4, &(wrote[0]), 0);
WriteFile(pipe, ba.data(), ba.size_s(), &(wrote[1]), 0); WriteFile(pipe, ba.data(), ba.size_s(), &(wrote[1]), 0);
// piCout << "send" << ba.size_s(); //piCout << "send" << ba.size_s();
return int(wrote[0] + wrote[1]); return int(wrote[0] + wrote[1]);
} }
# endif #endif
PITerminal::PITerminal(): PIThread() { PITerminal::PITerminal(): PIThread() {
@@ -116,41 +114,42 @@ PITerminal::PITerminal(): PIThread() {
initPrivate(); initPrivate();
cursor_blink = false; cursor_blink = false;
cursor_x = cursor_y = 0; cursor_x = cursor_y = 0;
dsize_x = 80; dsize_x = 80;
dsize_y = 24; dsize_y = 24;
# ifdef WINDOWS #ifdef WINDOWS
PRIVATE->shm = 0; PRIVATE->shm = 0;
# endif #endif
} }
PITerminal::~PITerminal() { PITerminal::~PITerminal() {
if (isRunning()) stop(); if (isRunning())
PIThread::waitForFinish(1_s); stop();
PIThread::waitForFinish(10);
destroy(); destroy();
# ifdef WINDOWS #ifdef WINDOWS
if (PRIVATE->shm) delete PRIVATE->shm; if (PRIVATE->shm) delete PRIVATE->shm;
# endif #endif
} }
void PITerminal::write(const PIByteArray & d) { void PITerminal::write(const PIByteArray & d) {
# ifdef WINDOWS #ifdef WINDOWS
PIByteArray msg; PIByteArray msg;
PIVector<PIKbdListener::KeyEvent> ke; PIVector<PIKbdListener::KeyEvent> ke;
for (int i = 0; i < d.size_s(); ++i) for (int i = 0; i < d.size_s(); ++i)
ke << PIKbdListener::KeyEvent(d[i]); ke << PIKbdListener::KeyEvent(d[i]);
msg << int(mtKey) << ke; msg << int(mtKey) << ke;
writePipe(PRIVATE->pipe, msg); writePipe(PRIVATE->pipe, msg);
# else #else
# ifdef HAS_FORKPTY # ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return; if (PRIVATE->fd == 0) return;
// ssize_t wrote = 0; //ssize_t wrote = 0;
// wrote = //wrote =
::write(PRIVATE->fd, d.data(), d.size_s()); ::write(PRIVATE->fd, d.data(), d.size_s());
// piCout << "wrote" << wrote << d; //piCout << "wrote" << wrote << d;
# endif
# endif # endif
#endif
cursor_tm.reset(); cursor_tm.reset();
cursor_blink = true; cursor_blink = true;
} }
@@ -158,16 +157,15 @@ void PITerminal::write(const PIByteArray & d) {
void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m) { void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m) {
PIByteArray ba; PIByteArray ba;
# ifdef WINDOWS #ifdef WINDOWS
switch (k) { switch (k) {
case PIKbdListener::Tab: ba << uchar('\t'); break; case PIKbdListener::Tab: ba << uchar('\t'); break;
case PIKbdListener::Return: ba << uchar('\r') << uchar('\n'); break; case PIKbdListener::Return: ba << uchar('\r') << uchar('\n'); break;
case PIKbdListener::Space: ba << uchar(' '); break; case PIKbdListener::Space: ba << uchar(' '); break;
default: break; default: break;
} }
// piCout << "write" << ba.size(); //piCout << "write" << ba.size();
if (!ba.isEmpty()) if (!ba.isEmpty()) write(ba);
write(ba);
else { else {
PIByteArray msg; PIByteArray msg;
PIVector<PIKbdListener::KeyEvent> ke; PIVector<PIKbdListener::KeyEvent> ke;
@@ -175,20 +173,19 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
msg << int(mtKey) << ke; msg << int(mtKey) << ke;
writePipe(PRIVATE->pipe, msg); writePipe(PRIVATE->pipe, msg);
} }
# else #else
int term = PRIVATE->term_type; int term = PRIVATE->term_type;
int flags = 0; int flags = 0;
switch (k) { switch (k) {
case PIKbdListener::Tab: ba << uchar('\t'); break; case PIKbdListener::Tab: ba << uchar('\t'); break;
case PIKbdListener::Return: ba << uchar('\n'); break; case PIKbdListener::Return: ba << uchar('\n'); break;
case PIKbdListener::Esc: ba << uchar('\e'); break; case PIKbdListener::Esc: ba << uchar('\e'); break;
case PIKbdListener::Space: ba << uchar(' '); break; case PIKbdListener::Space: ba << uchar(' '); break;
case PIKbdListener::Backspace: ba << uchar(0x7f); break; case PIKbdListener::Backspace: ba << uchar(0x7f); break;
case PIKbdListener::UpArrow: case PIKbdListener::UpArrow:
case PIKbdListener::DownArrow: case PIKbdListener::DownArrow:
case PIKbdListener::RightArrow: case PIKbdListener::RightArrow:
case PIKbdListener::LeftArrow: case PIKbdListener::LeftArrow: if (PRIVATE->DEC.value(CKM, false)) flags = 1;
if (PRIVATE->DEC.value(CKM, false)) flags = 1;
/*case PIKbdListener::Home: //break; /*case PIKbdListener::Home: //break;
case PIKbdListener::End: //break; case PIKbdListener::End: //break;
case PIKbdListener::PageUp: //ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break; case PIKbdListener::PageUp: //ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break;
@@ -209,55 +206,55 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
case PIKbdListener::F12: //break; case PIKbdListener::F12: //break;
*/ */
default: { default: {
// piCout << flags; //piCout << flags;
// int mod = 0; //int mod = 0;
if (m[PIKbdListener::Shift]) m |= 1; if (m[PIKbdListener::Shift]) m |= 1;
if (m[PIKbdListener::Alt]) m |= 2; if (m[PIKbdListener::Alt]) m |= 2;
if (m[PIKbdListener::Ctrl]) m |= 4; if (m[PIKbdListener::Ctrl]) m |= 4;
for (int i = 0;; ++i) { for (int i = 0; ; ++i) {
const PIKbdListener::EscSeq & e(PIKbdListener::esc_seq[i]); const PIKbdListener::EscSeq & e(PIKbdListener::esc_seq[i]);
if (!e.seq) break; if (!e.seq) break;
// piCout << "search" << rc[1] << esc_seq[i].seq; //piCout << "search" << rc[1] << esc_seq[i].seq;
if (e.key == k && e.mod == m) { if (e.key == k && e.mod == m) {
if (((e.vt & term) == term) || (((e.flags & flags) == flags) && (flags != 0))) { if (((e.vt & term) == term) || (((e.flags & flags) == flags) && (flags != 0))) {
// piCout << "found key" << PIString(e.seq).replaceAll("\e", "\\e"); //piCout << "found key" << PIString(e.seq).replaceAll("\e", "\\e");
PIByteArray d = ("\e" + PIString(e.seq)).toByteArray(); PIByteArray d = ("\e" + PIString(e.seq)).toByteArray();
write(d); write(d);
break; break;
} }
} }
} }
} break; } break;
} }
// piCout << "write" << ba.size(); //piCout << "write" << ba.size();
if (!ba.isEmpty()) write(ba); if (!ba.isEmpty()) write(ba);
# endif #endif
cursor_tm.reset(); cursor_tm.reset();
cursor_blink = true; cursor_blink = true;
} }
void PITerminal::write(PIKbdListener::KeyEvent ke) { void PITerminal::write(PIKbdListener::KeyEvent ke) {
if (isSpecialKey(ke.key)) if (isSpecialKey(ke.key)) write((PIKbdListener::SpecialKey)ke.key, ke.modifiers);
write((PIKbdListener::SpecialKey)ke.key, ke.modifiers);
else { else {
PIByteArray ba; PIByteArray ba;
# ifdef WINDOWS #ifdef WINDOWS
ba << uchar(PIChar((ushort)ke.key).toConsole1Byte()); ba << uchar(PIChar((ushort)ke.key).toConsole1Byte());
# else #else
ba = PIString(PIChar((ushort)ke.key)).toUTF8(); ba = PIString(PIChar((ushort)ke.key)).toUTF8();
# endif #endif
write(ba); write(ba);
} }
} }
PIVector<PIVector<PIScreenTypes::Cell>> PITerminal::content() { PIVector<PIVector<PIScreenTypes::Cell> > PITerminal::content() {
readConsole(); readConsole();
PIVector<PIVector<PIScreenTypes::Cell>> ret = cells; PIVector<PIVector<PIScreenTypes::Cell> > ret = cells;
if (cursor_blink && cursor_visible) if (cursor_blink && cursor_visible)
if (cursor_x >= 0 && cursor_x < size_x) if (cursor_x >= 0 && cursor_x < size_x)
if (cursor_y >= 0 && cursor_y < size_y) ret[cursor_y][cursor_x].format.flags ^= PIScreenTypes::Inverse; if (cursor_y >= 0 && cursor_y < size_y)
ret[cursor_y][cursor_x].format.flags ^= PIScreenTypes::Inverse;
return ret; return ret;
} }
@@ -298,56 +295,56 @@ bool PITerminal::isSpecialKey(int k) {
void PITerminal::initPrivate() { void PITerminal::initPrivate() {
# ifdef WINDOWS #ifdef WINDOWS
PRIVATE->hConBuf = INVALID_HANDLE_VALUE; PRIVATE->hConBuf = INVALID_HANDLE_VALUE;
PRIVATE->pipe = INVALID_HANDLE_VALUE; PRIVATE->pipe = INVALID_HANDLE_VALUE;
PRIVATE->pi.hProcess = 0; PRIVATE->pi.hProcess = 0;
# else #else
PRIVATE->shell = "/bin/bash"; PRIVATE->shell = "/bin/bash";
PRIVATE->read_buf.reserve(BUFFER_SIZE); PRIVATE->read_buf.reserve(BUFFER_SIZE);
PRIVATE->read_buf.fill(0); PRIVATE->read_buf.fill(0);
PRIVATE->fd = PRIVATE->cur_x = PRIVATE->cur_y = 0; PRIVATE->fd = PRIVATE->cur_x = PRIVATE->cur_y = 0;
PRIVATE->save_cur_x = PRIVATE->save_cur_y = 0; PRIVATE->save_cur_x = PRIVATE->save_cur_y = 0;
PRIVATE->pid = 0; PRIVATE->pid = 0;
PRIVATE->term_type = 0; PRIVATE->term_type = 0;
PRIVATE->is_esc_seq = false; PRIVATE->is_esc_seq = false;
PRIVATE->last_read = true; PRIVATE->last_read = true;
PRIVATE->esc_seq.clear(); PRIVATE->esc_seq.clear();
PRIVATE->cur_format = PIScreenTypes::CellFormat(); PRIVATE->cur_format = PIScreenTypes::CellFormat();
# endif #endif
cursor_blink = cursor_visible = true; cursor_blink = cursor_visible = true;
size_x = size_y = 0; size_x = size_y = 0;
} }
void PITerminal::readConsole() { void PITerminal::readConsole() {
# ifdef WINDOWS #ifdef WINDOWS
if (!PRIVATE->shm) return; if (!PRIVATE->shm) return;
PITerminalAuxData data; PITerminalAuxData data;
PRIVATE->shm->read(&data, sizeof(data)); PRIVATE->shm->read(&data, sizeof(data));
if (data.cells_size <= 4) return; if (data.cells_size <= 4) return;
cursor_x = data.cursor_x; cursor_x = data.cursor_x;
cursor_y = data.cursor_y; cursor_y = data.cursor_y;
size_x = data.size_x; size_x = data.size_x;
size_y = data.size_y; size_y = data.size_y;
PIByteArray ba; PIByteArray ba;
ba.resize(data.cells_size); ba.resize(data.cells_size);
PRIVATE->shm->read(ba.data(), ba.size_s(), sizeof(data)); PRIVATE->shm->read(ba.data(), ba.size_s(), sizeof(data));
ba >> cells; ba >> cells;
# endif #endif
// piCout << cursor_x << cursor_y; //piCout << cursor_x << cursor_y;
} }
void PITerminal::getCursor(int & x, int & y) { void PITerminal::getCursor(int & x, int & y) {
# ifdef WINDOWS #ifdef WINDOWS
if (!PRIVATE->shm) return; if (!PRIVATE->shm) return;
int sz = 0; int sz = 0;
PRIVATE->shm->read(&sz, 4); PRIVATE->shm->read(&sz, 4);
# else #else
x = PRIVATE->cur_x; x = PRIVATE->cur_x;
y = PRIVATE->cur_y; y = PRIVATE->cur_y;
# endif #endif
} }
@@ -373,16 +370,16 @@ void PITerminal::run() {
cursor_tm.reset(); cursor_tm.reset();
cursor_blink = !cursor_blink; cursor_blink = !cursor_blink;
} }
# ifndef WINDOWS #ifndef WINDOWS
# ifdef HAS_FORKPTY # ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return; if (PRIVATE->fd == 0) return;
PRIVATE->tmp_buf.resize(BUFFER_SIZE); PRIVATE->tmp_buf.resize(BUFFER_SIZE);
int readed = ::read(PRIVATE->fd, PRIVATE->tmp_buf.data(), BUFFER_SIZE - PRIVATE->read_buf.size_s()); int readed = ::read(PRIVATE->fd, PRIVATE->tmp_buf.data(), BUFFER_SIZE - PRIVATE->read_buf.size_s());
bool used = false; bool used = false;
if (readed > 0) { if (readed > 0) {
PRIVATE->last_read = true; PRIVATE->last_read = true;
// piCoutObj << "readed" << readed << PIString(PRIVATE->tmp_buf.resized(readed)).replaceAll("\e", "\\e"); //piCoutObj << "readed" << readed << PIString(PRIVATE->tmp_buf.resized(readed)).replaceAll("\e", "\\e");
// piCoutObj << "readed" << readed << (PRIVATE->tmp_buf.resized(readed)); //piCoutObj << "readed" << readed << (PRIVATE->tmp_buf.resized(readed));
PRIVATE->read_buf.append(PRIVATE->tmp_buf.resized(readed)); PRIVATE->read_buf.append(PRIVATE->tmp_buf.resized(readed));
for (;;) { for (;;) {
int ind = -1; int ind = -1;
@@ -398,27 +395,28 @@ void PITerminal::run() {
} }
bool parse = PRIVATE->read_buf.size_s() >= BUFFER_SIZE; bool parse = PRIVATE->read_buf.size_s() >= BUFFER_SIZE;
if (PRIVATE->read_buf.size_s() == 1) if (PRIVATE->read_buf.size_s() == 1)
if (PRIVATE->read_buf[0] < 0x80) parse = true; if (PRIVATE->read_buf[0] < 0x80)
parse = true;
if (parse) { if (parse) {
parseInput(PIString::fromUTF8(PRIVATE->read_buf)); parseInput(PIString(PRIVATE->read_buf));
PRIVATE->read_buf.clear(); PRIVATE->read_buf.clear();
} }
// printf("%s", PRIVATE->read_buf.data()); //printf("%s", PRIVATE->read_buf.data());
} }
if (!used && !PRIVATE->last_read && !PRIVATE->read_buf.isEmpty()) { if (!used && !PRIVATE->last_read && !PRIVATE->read_buf.isEmpty()) {
parseInput(PIString::fromUTF8(PRIVATE->read_buf)); parseInput(PIString(PRIVATE->read_buf));
PRIVATE->read_buf.clear(); PRIVATE->read_buf.clear();
} }
PRIVATE->last_read = false; PRIVATE->last_read = false;
# endif
# endif # endif
#endif
} }
# ifndef WINDOWS #ifndef WINDOWS
void PITerminal::parseInput(const PIString & s) { void PITerminal::parseInput(const PIString & s) {
// piCoutObj << s.replaceAll("\e", "\\e"); //piCoutObj << s.replaceAll("\e", "\\e");
// printf("%s", s.data()); //printf("%s", s.data());
for (int i = 0; i < s.size_s(); ++i) { for (int i = 0; i < s.size_s(); ++i) {
if (s[i].unicode16Code() == 0) break; if (s[i].unicode16Code() == 0) break;
if (PRIVATE->is_esc_seq) { if (PRIVATE->is_esc_seq) {
@@ -431,7 +429,7 @@ void PITerminal::parseInput(const PIString & s) {
if (isCompleteEscSeq(PRIVATE->esc_seq)) { if (isCompleteEscSeq(PRIVATE->esc_seq)) {
PRIVATE->is_esc_seq = false; PRIVATE->is_esc_seq = false;
applyEscSeq(PRIVATE->esc_seq); applyEscSeq(PRIVATE->esc_seq);
// piCoutObj << PRIVATE->esc_seq; //piCoutObj << PRIVATE->esc_seq;
} }
} }
} else { } else {
@@ -446,15 +444,14 @@ void PITerminal::parseInput(const PIString & s) {
} }
if (s[i] == '\r') continue; if (s[i] == '\r') continue;
if (s[i] == '\n') { if (s[i] == '\n') {
// piCoutObj << "new line"; //piCoutObj << "new line";
for (int i = PRIVATE->cur_x; i < size_x; ++i) for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format;
cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format;
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
PRIVATE->cur_x = 0; PRIVATE->cur_x = 0;
moveCursor(0, 1); moveCursor(0, 1);
continue; continue;
} }
// piCoutObj << "char" << s[i] << s[i].unicode16Code() << "at" << PRIVATE->cur_x << PRIVATE->cur_y; //piCoutObj << "char" << s[i] << s[i].unicode16Code() << "at" << PRIVATE->cur_x << PRIVATE->cur_y;
cells[PRIVATE->cur_y][PRIVATE->cur_x].symbol = s[i]; cells[PRIVATE->cur_y][PRIVATE->cur_x].symbol = s[i];
cells[PRIVATE->cur_y][PRIVATE->cur_x].format = PRIVATE->cur_format; cells[PRIVATE->cur_y][PRIVATE->cur_x].format = PRIVATE->cur_format;
moveCursor(1, 0); moveCursor(1, 0);
@@ -478,10 +475,10 @@ bool PITerminal::isCompleteEscSeq(const PIString & es) {
void PITerminal::applyEscSeq(PIString es) { void PITerminal::applyEscSeq(PIString es) {
piCoutObj << es; piCoutObj << es;
if (es.size_s() < 2) return; if (es.size_s() < 2) return;
// PIScreenTypes::Cell line_cell = PIScreenTypes::Cell(' ', PRIVATE->line_format); // PIScreenTypes::Cell line_cell = PIScreenTypes::Cell(' ', PRIVATE->line_format);
PIScreenTypes::Cell def_cell = PIScreenTypes::Cell(' ', PRIVATE->cur_format); PIScreenTypes::Cell def_cell = PIScreenTypes::Cell(' ', PRIVATE->cur_format);
if (es[1] == '?' && es.size_s() >= 2) { if (es[1] == '?' && es.size_s() >= 2) {
char a = es.takeRight(1)[0].toAscii(); char a = es.takeRight(1)[0].toAscii();
bool val = false; bool val = false;
if (a == 'l') val = false; if (a == 'l') val = false;
if (a == 'h') val = true; if (a == 'h') val = true;
@@ -501,8 +498,7 @@ void PITerminal::applyEscSeq(PIString es) {
case 1047: case 1047:
if (val) { if (val) {
PRIVATE->cells_save = cells; PRIVATE->cells_save = cells;
for (int i = 0; i < size_y; ++i) for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell);
cells[i].fill(def_cell);
} else { } else {
cells = PRIVATE->cells_save; cells = PRIVATE->cells_save;
} }
@@ -517,7 +513,7 @@ void PITerminal::applyEscSeq(PIString es) {
return; return;
} }
PIStringList args = es.split(";"); PIStringList args = es.split(";");
for (const auto & a: args) { piForeachC (PIString & a, args) {
int av = a.toInt(); int av = a.toInt();
switch (av) { switch (av) {
case 0: PRIVATE->cur_format = PIScreenTypes::CellFormat(); break; case 0: PRIVATE->cur_format = PIScreenTypes::CellFormat(); break;
@@ -528,14 +524,8 @@ void PITerminal::applyEscSeq(PIString es) {
default: { default: {
bool col = false, target = false; bool col = false, target = false;
int cid = av % 10; int cid = av % 10;
if (av >= 30 && av <= 37) { if (av >= 30 && av <= 37) {col = true; target = false;}
col = true; if (av >= 40 && av <= 47) {col = true; target = true;}
target = false;
}
if (av >= 40 && av <= 47) {
col = true;
target = true;
}
if (col) { if (col) {
int cfl = 0; int cfl = 0;
switch (cid) { switch (cid) {
@@ -554,13 +544,13 @@ void PITerminal::applyEscSeq(PIString es) {
PRIVATE->cur_format.color_char = cfl; PRIVATE->cur_format.color_char = cfl;
break; break;
} }
} break; } break;
} }
} }
/*if ((PRIVATE->cur_format.flags & PIScreenTypes::Inverse) == PIScreenTypes::Inverse) { /*if ((PRIVATE->cur_format.flags & PIScreenTypes::Inverse) == PIScreenTypes::Inverse) {
uchar t = PRIVATE->cur_format.color_char; uchar t = PRIVATE->cur_format.color_char;
PRIVATE->cur_format.color_char = PRIVATE->cur_format.color_back; PRIVATE->cur_format.color_char = PRIVATE->cur_format.color_back;
PRIVATE->cur_format.color_back = t; PRIVATE->cur_format.color_back = t;
}*/ }*/
} }
if (es.back() == 'r') { if (es.back() == 'r') {
@@ -589,37 +579,33 @@ void PITerminal::applyEscSeq(PIString es) {
int x(0), y(0); int x(0), y(0);
if (!args[0].isEmpty()) y = args[0].toInt() - 1; if (!args[0].isEmpty()) y = args[0].toInt() - 1;
if (!args[1].isEmpty()) x = args[1].toInt() - 1; if (!args[1].isEmpty()) x = args[1].toInt() - 1;
// piCoutObj << x << y; //piCoutObj << x << y;
PRIVATE->cur_x = piClamp(x, 0, size_x - 1); PRIVATE->cur_x = piClamp(x, 0, size_x - 1);
PRIVATE->cur_y = piClamp(y, 0, size_y - 1); PRIVATE->cur_y = piClamp(y, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'A') { // cursor up if (es.back() == 'A') { // cursor up
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'B') { // cursor down if (es.back() == 'B') { // cursor down
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'C' || es.back() == 'a') { // cursor forward, next column if (es.back() == 'C' || es.back() == 'a') { // cursor forward, next column
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1);
PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'D') { // cursor back if (es.back() == 'D') { // cursor back
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1);
PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'G' || es.back() == '`') { // goto column if (es.back() == 'G' || es.back() == '`') { // goto column
@@ -630,92 +616,66 @@ void PITerminal::applyEscSeq(PIString es) {
} }
if (es.back() == 'd') { // goto line if (es.back() == 'd') { // goto line
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; PRIVATE->cur_x = 0;
PRIVATE->cur_x = 0; PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1);
PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'E' || es.back() == 'e') { // next line if (es.back() == 'E' || es.back() == 'e') { // next line
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; PRIVATE->cur_x = 0;
PRIVATE->cur_x = 0; PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'F') { // previous line if (es.back() == 'F') { // previous line
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; PRIVATE->cur_x = 0;
PRIVATE->cur_x = 0; PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'L') { // insert lines if (es.back() == 'L') { // insert lines
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; for (int i = piClamp(size_y - 1, PRIVATE->win_y0, PRIVATE->win_y1); i >= piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); --i) cells[i] = cells[i - v];
for (int i = piClamp(size_y - 1, PRIVATE->win_y0, PRIVATE->win_y1); for (int j = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); ++j)
i >= piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); for (int i = 0; i < PRIVATE->cur_x; ++i) cells[j][i] = def_cell;
--i)
cells[i] = cells[i - v];
for (int j = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1);
j < piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1);
++j)
for (int i = 0; i < PRIVATE->cur_x; ++i)
cells[j][i] = def_cell;
} }
if (es.back() == 'M') { // delete lines if (es.back() == 'M') { // delete lines
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; for (int i = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1); i < piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); ++i) cells[i] = cells[i + v];
for (int i = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1);
i < piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1);
++i)
cells[i] = cells[i + v];
for (int j = piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(size_y, PRIVATE->win_y0, PRIVATE->win_y1); ++j) for (int j = piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(size_y, PRIVATE->win_y0, PRIVATE->win_y1); ++j)
for (int i = 0; i < PRIVATE->cur_x; ++i) for (int i = 0; i < PRIVATE->cur_x; ++i) cells[j][i] = def_cell;
cells[j][i] = def_cell;
} }
if (es.back() == 'P') { // delete characters if (es.back() == 'P') { // delete characters
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; for (int i = PRIVATE->cur_x; i < size_x - v; ++i) cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i + v];
for (int i = PRIVATE->cur_x; i < size_x - v; ++i) for (int i = size_x - v; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i + v];
for (int i = size_x - v; i < size_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
} }
if (es.back() == '@') { // delete characters if (es.back() == '@') { // delete characters
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; for (int i = size_x - 1; i >= PRIVATE->cur_x + v; --i) cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i - v];
for (int i = size_x - 1; i >= PRIVATE->cur_x + v; --i) for (int i = PRIVATE->cur_x; i < PRIVATE->cur_x + v; ++i) cells[PRIVATE->cur_y][i] = def_cell;
cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i - v];
for (int i = PRIVATE->cur_x; i < PRIVATE->cur_x + v; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
} }
if (es.back() == 'J') { // erase data if (es.back() == 'J') { // erase data
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt();
switch (v) { switch (v) {
case 0: case 0:
for (int i = PRIVATE->cur_x; i < size_x; ++i) for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
cells[PRIVATE->cur_y][i] = def_cell; for (int i = PRIVATE->cur_y + 1; i < size_y; ++i) cells[i].fill(def_cell);
for (int i = PRIVATE->cur_y + 1; i < size_y; ++i)
cells[i].fill(def_cell);
break; break;
case 1: case 1:
for (int i = 0; i <= PRIVATE->cur_x; ++i) for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
cells[PRIVATE->cur_y][i] = def_cell; for (int i = 0; i < PRIVATE->cur_y; ++i) cells[i].fill(def_cell);
for (int i = 0; i < PRIVATE->cur_y; ++i)
cells[i].fill(def_cell);
break; break;
case 2: case 2:
for (int i = 0; i < size_y; ++i) for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell);
cells[i].fill(def_cell); //PRIVATE->cur_x = PRIVATE->cur_y = 0;
// PRIVATE->cur_x = PRIVATE->cur_y = 0;
break; break;
} }
} }
@@ -724,14 +684,14 @@ void PITerminal::applyEscSeq(PIString es) {
int v = es.toInt(); int v = es.toInt();
switch (v) { switch (v) {
case 0: case 0:
for (int i = PRIVATE->cur_x; i < size_x; ++i) for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
cells[PRIVATE->cur_y][i] = def_cell;
break; break;
case 1: case 1:
for (int i = 0; i <= PRIVATE->cur_x; ++i) for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
cells[PRIVATE->cur_y][i] = def_cell; break;
case 2:
cells[PRIVATE->cur_y].fill(def_cell);
break; break;
case 2: cells[PRIVATE->cur_y].fill(def_cell); break;
} }
} }
} }
@@ -745,12 +705,12 @@ void PITerminal::moveCursor(int dx, int dy) {
if (PRIVATE->cur_y < 0) PRIVATE->cur_y = 0; if (PRIVATE->cur_y < 0) PRIVATE->cur_y = 0;
if (PRIVATE->cur_x >= size_x) { if (PRIVATE->cur_x >= size_x) {
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
PRIVATE->cur_x = 0; PRIVATE->cur_x = 0;
PRIVATE->cur_y++; PRIVATE->cur_y++;
} }
if (PRIVATE->cur_y >= size_y) { if (PRIVATE->cur_y >= size_y) {
int scroll = piMini(PRIVATE->cur_y - size_y + 1, size_y - 1); int scroll = piMini(PRIVATE->cur_y - size_y + 1, size_y - 1);
// piCout << "scroll" << size_x << size_y << size_y - scroll - 1; //piCout << "scroll" << size_x << size_y << size_y - scroll - 1;
PRIVATE->cur_y = size_y - 1; PRIVATE->cur_y = size_y - 1;
for (int y = 0; y < size_y - scroll; ++y) for (int y = 0; y < size_y - scroll; ++y)
cells[y] = cells[y + scroll]; cells[y] = cells[y + scroll];
@@ -761,76 +721,58 @@ void PITerminal::moveCursor(int dx, int dy) {
int PITerminal::termType(const PIString & t) { int PITerminal::termType(const PIString & t) {
if (t == "xterm") if (t == "xterm") return PIKbdListener::vt_xterm;
return PIKbdListener::vt_xterm; else if (t == "linux") return PIKbdListener::vt_linux;
else if (t == "linux")
return PIKbdListener::vt_linux;
return PIKbdListener::vt_none; return PIKbdListener::vt_none;
} }
# endif #endif
bool PITerminal::initialize() { bool PITerminal::initialize() {
destroy(); destroy();
# ifdef WINDOWS #ifdef WINDOWS
/*SECURITY_ATTRIBUTES sa; /*SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = true; sa.bInheritHandle = true;
sa.lpSecurityDescriptor = 0; sa.lpSecurityDescriptor = 0;
if (!CreatePipe(&(PRIVATE->pipe_in[0]), &(PRIVATE->pipe_in[1]), &sa, 0)) { if (!CreatePipe(&(PRIVATE->pipe_in[0]), &(PRIVATE->pipe_in[1]), &sa, 0)) {
piCoutObj << "CreatePipe error," << errorString(); piCoutObj << "CreatePipe error," << errorString();
initPrivate(); initPrivate();
return false; return false;
} }
PRIVATE->hConBuf = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, &sa, CONSOLE_TEXTMODE_BUFFER, 0); PRIVATE->hConBuf = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, &sa, CONSOLE_TEXTMODE_BUFFER, 0);
if (PRIVATE->hConBuf == INVALID_HANDLE_VALUE) { if (PRIVATE->hConBuf == INVALID_HANDLE_VALUE) {
piCoutObj << "CreateConsoleScreenBuffer error," << errorString(); piCoutObj << "CreateConsoleScreenBuffer error," << errorString();
destroy(); destroy();
return false; return false;
}*/ }*/
// CreatePipe(&(PRIVATE->pipe_out[0]), &(PRIVATE->pipe_out[1]), &sa, 0); //CreatePipe(&(PRIVATE->pipe_out[0]), &(PRIVATE->pipe_out[1]), &sa, 0);
// SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0); //SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0);
// SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0); //SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0);
// GetStartupInfoA(&PRIVATE->si); //GetStartupInfoA(&PRIVATE->si);
piZeroMemory(PRIVATE->si); memset(&PRIVATE->si, 0, sizeof(PRIVATE->si));
PRIVATE->si.cb = sizeof(STARTUPINFO); PRIVATE->si.cb = sizeof(STARTUPINFO);
// PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES; //PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES;
PRIVATE->si.dwFlags |= STARTF_USESHOWWINDOW; PRIVATE->si.dwFlags |= STARTF_USESHOWWINDOW;
PRIVATE->si.dwFlags |= STARTF_USECOUNTCHARS; PRIVATE->si.dwFlags |= STARTF_USECOUNTCHARS;
// PRIVATE->si.hStdInput = PRIVATE->pipe; //PRIVATE->si.hStdInput = PRIVATE->pipe;
// PRIVATE->si.hStdOutput = PRIVATE->hConBuf; //PRIVATE->si.hStdOutput = PRIVATE->hConBuf;
// PRIVATE->si.hStdError = PRIVATE->hConBuf; //PRIVATE->si.hStdError = PRIVATE->hConBuf;
PRIVATE->si.wShowWindow = SW_HIDE; PRIVATE->si.wShowWindow = SW_HIDE;
PRIVATE->si.dwXCountChars = 80; PRIVATE->si.dwXCountChars = 80;
PRIVATE->si.dwYCountChars = 24; PRIVATE->si.dwYCountChars = 24;
piZeroMemory(PRIVATE->pi); memset(&PRIVATE->pi, 0, sizeof(PRIVATE->pi));
PIString shmh = PIString::fromNumber(randomi() % 10000); PIString shmh = PIString::fromNumber(randomi() % 10000);
PIString pname = "\\\\.\\pipe\\piterm" + shmh; PIString pname = "\\\\.\\pipe\\piterm" + shmh;
PIString cmd = "piterminal \"" + shmh + "\" \"" + pname + "\""; PIString cmd = "piterminal \"" + shmh + "\" \"" + pname + "\"";
if (!CreateProcessA(0, if(!CreateProcessA(0, (LPSTR)cmd.dataAscii(), 0, 0, false, CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, 0, 0, &PRIVATE->si, &PRIVATE->pi)) {
(LPSTR)cmd.dataAscii(),
0,
0,
false,
CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
0,
0,
&PRIVATE->si,
&PRIVATE->pi)) {
piCoutObj << "CreateProcess error," << errorString(); piCoutObj << "CreateProcess error," << errorString();
destroy(); destroy();
return false; return false;
} }
PRIVATE->pipe = CreateNamedPipeA((LPSTR)pname.dataAscii(), PRIVATE->pipe = CreateNamedPipe((LPSTR)pname.dataAscii(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 2, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 1000, NULL);
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
2,
PIPE_BUFFER_SIZE,
PIPE_BUFFER_SIZE,
1000,
NULL);
if (PRIVATE->pipe == INVALID_HANDLE_VALUE) { if (PRIVATE->pipe == INVALID_HANDLE_VALUE) {
piCoutObj << "CreateNamedPipe error," << errorString(); piCoutObj << "CreateNamedPipe error," << errorString();
destroy(); destroy();
@@ -850,32 +792,31 @@ bool PITerminal::initialize() {
return false; return false;
} }
if (PRIVATE->shm) delete PRIVATE->shm; if (PRIVATE->shm) delete PRIVATE->shm;
PRIVATE->shm = new PISharedMemory("piterm_aux" + shmh, 1024 * 1024); PRIVATE->shm = new PISharedMemory("piterm_aux" + shmh, 1024*1024);
CloseHandle(PRIVATE->pi.hThread); CloseHandle(PRIVATE->pi.hThread);
resize(dsize_x, dsize_y); resize(dsize_x, dsize_y);
# else #else
# ifdef HAS_FORKPTY # ifdef HAS_FORKPTY
char pty[256]; char pty[256]; memset(pty, 0, 256);
piZeroMemory(pty, 256);
winsize ws; winsize ws;
ws.ws_col = dsize_x; ws.ws_col = dsize_x;
ws.ws_row = dsize_y; ws.ws_row = dsize_y;
PIStringList env = PIProcess::currentEnvironment(); PIStringList env = PIProcess::currentEnvironment();
for (const auto & e: env) piForeachC (PIString & e, env)
if (e.startsWith("TERM=")) { if (e.startsWith("TERM=")) {
PRIVATE->term_type = termType(e.mid(5).trim().toLowerCase()); PRIVATE->term_type = termType(e.mid(5).trim().toLowerCase());
// piCout << PRIVATE->term_type; //piCout << PRIVATE->term_type;
break; break;
} }
pid_t fr = forkpty(&(PRIVATE->fd), pty, 0, &ws); pid_t fr = forkpty(&(PRIVATE->fd), pty, 0, &ws);
// piCoutObj << fr << PRIVATE->fd << pty; //piCoutObj << fr << PRIVATE->fd << pty;
if (fr == 0) { if (fr == 0) {
char ** argv = new char *[2]; char ** argv = new char*[2];
PIByteArray shell = PRIVATE->shell.toByteArray(); PIByteArray shell = PRIVATE->shell.toByteArray();
argv[0] = new char[shell.size() + 1]; argv[0] = new char[shell.size() + 1];
memcpy(argv[0], shell.data(), shell.size()); memcpy(argv[0], shell.data(), shell.size());
argv[0][shell.size()] = 0; argv[0][shell.size()] = 0;
argv[1] = 0; argv[1] = 0;
execvp(argv[0], argv); execvp(argv[0], argv);
delete[] argv[0]; delete[] argv[0];
delete[] argv; delete[] argv;
@@ -888,77 +829,79 @@ bool PITerminal::initialize() {
} }
PRIVATE->pid = fr; PRIVATE->pid = fr;
fcntl(PRIVATE->fd, F_SETFL, O_NONBLOCK); fcntl(PRIVATE->fd, F_SETFL, O_NONBLOCK);
/* /*
tcgetattr(PRIVATE->fd, &PRIVATE->desc); tcgetattr(PRIVATE->fd, &PRIVATE->desc);
PRIVATE->desc.c_oflag = PRIVATE->desc.c_lflag = PRIVATE->desc.c_cflag = 0; PRIVATE->desc.c_oflag = PRIVATE->desc.c_lflag = PRIVATE->desc.c_cflag = 0;
PRIVATE->desc.c_iflag = IGNBRK; PRIVATE->desc.c_iflag = IGNBRK;
PRIVATE->desc.c_cflag = CLOCAL | HUPCL; PRIVATE->desc.c_cflag = CLOCAL | HUPCL;
PRIVATE->desc.c_cflag |= (CSIZE & CS8); PRIVATE->desc.c_cflag |= (CSIZE & CS8);
PRIVATE->desc.c_cflag |= CREAD; PRIVATE->desc.c_cflag |= CREAD;
PRIVATE->desc.c_cc[VMIN] = 1; PRIVATE->desc.c_cc[VMIN] = 1;
PRIVATE->desc.c_cc[VTIME] = 1; PRIVATE->desc.c_cc[VTIME] = 1;
cfsetispeed(&PRIVATE->desc, B38400); cfsetispeed(&PRIVATE->desc, B38400);
cfsetospeed(&PRIVATE->desc, B38400); cfsetospeed(&PRIVATE->desc, B38400);
if (tcsetattr(PRIVATE->fd, TCSANOW, &PRIVATE->desc) < 0) { if (tcsetattr(PRIVATE->fd, TCSANOW, &PRIVATE->desc) < 0) {
piCoutObj << "Can`t set attributes for \"" << pty << "\""; piCoutObj << "Can`t set attributes for \"" << pty << "\"";
destroy(); destroy();
return false; return false;
} }
*/ */
size_x = dsize_x; size_x = dsize_x;
size_y = dsize_y; size_y = dsize_y;
resize(size_x, size_y); resize(size_x, size_y);
} }
# endif
# endif # endif
#endif
cursor_blink = false; cursor_blink = false;
cursor_tm.reset(); cursor_tm.reset();
start(25_Hz); start(40);
return true; return true;
} }
void PITerminal::destroy() { void PITerminal::destroy() {
// piCout << "destroy ..."; //piCout << "destroy ...";
stop(); stop();
waitForFinish(1_s); waitForFinish(1000);
# ifdef WINDOWS #ifdef WINDOWS
if (PRIVATE->pi.hProcess) { if (PRIVATE->pi.hProcess) {
// piCout << "term"; //piCout << "term";
// TerminateProcess(PRIVATE->pi.hProcess, 0); //TerminateProcess(PRIVATE->pi.hProcess, 0);
GenerateConsoleCtrlEvent(CTRL_C_EVENT, PRIVATE->pi.dwProcessId); GenerateConsoleCtrlEvent(CTRL_C_EVENT, PRIVATE->pi.dwProcessId);
CloseHandle(PRIVATE->pi.hProcess); CloseHandle(PRIVATE->pi.hProcess);
} }
if (PRIVATE->pipe != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->pipe); if (PRIVATE->pipe != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->pipe);
if (PRIVATE->hConBuf != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->hConBuf); if (PRIVATE->hConBuf != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->hConBuf);
// piCout << "destroy" << size_y; //piCout << "destroy" << size_y;
# else #else
# ifdef HAS_FORKPTY # ifdef HAS_FORKPTY
if (PRIVATE->pid != 0) kill(PRIVATE->pid, SIGKILL); if (PRIVATE->pid != 0)
if (PRIVATE->fd != 0) ::close(PRIVATE->fd); kill(PRIVATE->pid, SIGKILL);
# endif if (PRIVATE->fd != 0)
::close(PRIVATE->fd);
# endif # endif
#endif
initPrivate(); initPrivate();
} }
bool PITerminal::resize(int cols, int rows) { bool PITerminal::resize(int cols, int rows) {
bool ret = true; bool ret = true;
dsize_x = cols; dsize_x = cols;
dsize_y = rows; dsize_y = rows;
# ifdef WINDOWS #ifdef WINDOWS
if (PRIVATE->pipe == INVALID_HANDLE_VALUE) return false; if (PRIVATE->pipe == INVALID_HANDLE_VALUE) return false;
PIByteArray msg; PIByteArray msg;
msg << int(mtResize) << dsize_x << dsize_y; msg << int(mtResize) << dsize_x << dsize_y;
writePipe(PRIVATE->pipe, msg); writePipe(PRIVATE->pipe, msg);
# else #else
# ifdef HAS_FORKPTY # ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return false; if (PRIVATE->fd == 0) return false;
size_x = dsize_x; size_x = dsize_x;
size_y = dsize_y; size_y = dsize_y;
// piCout << "resize" << PRIVATE->fd << size_x << size_y; //piCout << "resize" << PRIVATE->fd << size_x << size_y;
winsize ws; winsize ws;
ws.ws_col = cols; ws.ws_col = cols;
ws.ws_row = rows; ws.ws_row = rows;
@@ -968,8 +911,8 @@ bool PITerminal::resize(int cols, int rows) {
PRIVATE->cells_save.resize(size_y); PRIVATE->cells_save.resize(size_y);
for (int i = 0; i < size_y; ++i) for (int i = 0; i < size_y; ++i)
PRIVATE->cells_save[i].resize(size_x); PRIVATE->cells_save[i].resize(size_x);
# endif
# endif # endif
#endif
cells.resize(size_y); cells.resize(size_y);
for (int i = 0; i < size_y; ++i) for (int i = 0; i < size_y; ++i)
cells[i].resize(size_x); cells[i].resize(size_x);

View File

@@ -1,297 +1,297 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PIP Authentication API PIP Authentication API
Andrey Bychkov work.a.b@yandex.ru Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piauth.h" #include "piauth.h"
#define PIAUTH_NOISE_MAX_SIZE 256 #define PIAUTH_NOISE_MAX_SIZE 256
PIAuth::PIAuth(const PIByteArray & sign): PIObject() { PIAuth::PIAuth(const PIByteArray & sign) : PIObject() {
setName("Client"); setName("Client");
role = Client; role = Client;
state = NotConnected; state = NotConnected;
sign_sk = sign; sign_sk = sign;
sign_pk = crypt.extractSignPublicKey(sign); sign_pk = crypt.extractSignPublicKey(sign);
} }
void PIAuth::setServerPassword(const PIString & ps) { void PIAuth::setServerPassword(const PIString & ps) {
pass_hash = crypt.passwordHash(ps, PIString("PIAuth").toByteArray()); pass_hash = crypt.passwordHash(ps, PIString("PIAuth").toByteArray());
} }
void PIAuth::stop() { void PIAuth::stop() {
role = Client; role = Client;
state = NotConnected; state = NotConnected;
auth_sign.clear(); auth_sign.clear();
box_sk.clear(); box_sk.clear();
box_pk.clear(); box_pk.clear();
my_pk.clear(); my_pk.clear();
} }
void PIAuth::startClient() { void PIAuth::startClient() {
role = Client; role = Client;
state = AuthProbe; state = AuthProbe;
} }
PIByteArray PIAuth::startServer() { PIByteArray PIAuth::startServer() {
setName("Server"); setName("Server");
role = Server; role = Server;
state = AuthProbe; state = AuthProbe;
PIByteArray ba; PIByteArray ba;
crypt.generateKeypair(my_pk, box_sk); crypt.generateKeypair(my_pk, box_sk);
PIByteArray noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE + 128); PIByteArray noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE+128);
ba << (int)state << custom_info << sign_pk << my_pk << noise; ba << (int)state << custom_info << sign_pk << my_pk << noise;
PIByteArray sign = crypt.signMessage(ba, sign_sk); PIByteArray sign = crypt.signMessage(ba, sign_sk);
ba << sign; ba << sign;
return ba; return ba;
} }
PIAuth::State PIAuth::receive(PIByteArray & ba) { PIAuth::State PIAuth::receive(PIByteArray & ba) {
if (ba.size() < sizeof(int)) return disconnect(ba, "invalid data size"); if (ba.size() < sizeof(int)) return disconnect(ba, "invalid data size");
State rstate; State rstate;
int s; int s;
ba >> s; ba >> s;
rstate = (State)s; rstate = (State)s;
// if (state != rstate) return disconect(ba); // if (state != rstate) return disconect(ba);
// client side //client side
if (role == Client) { if (role == Client) {
if (state == AuthProbe && rstate == AuthProbe) { if (state == AuthProbe && rstate == AuthProbe) {
if (ba.size() < sizeof(int) * 5) return disconnect(ba, "invalid data size"); if (ba.size() < sizeof(int)*5) return disconnect(ba, "invalid data size");
PIByteArray rinfo; PIByteArray rinfo;
PIByteArray rsign; PIByteArray rsign;
PIByteArray rsign_pk; PIByteArray rsign_pk;
PIByteArray noise; PIByteArray noise;
ba >> rinfo >> rsign_pk >> box_pk >> noise >> rsign; ba >> rinfo >> rsign_pk >> box_pk >> noise >> rsign;
if (rsign_pk.isEmpty() || box_pk.isEmpty() || rsign.isEmpty()) return disconnect(ba, "invalid key size"); if (rsign_pk.isEmpty() || box_pk.isEmpty() || rsign.isEmpty()) return disconnect(ba, "invalid key size");
PIByteArray tba; PIByteArray tba;
tba << (int)rstate << rinfo << rsign_pk << box_pk << noise; tba << (int)rstate << rinfo << rsign_pk << box_pk << noise;
if (!crypt.verifySign(tba, rsign, rsign_pk)) return disconnect(ba, "Incorrect sign"); if (!crypt.verifySign(tba, rsign, rsign_pk)) return disconnect(ba, "Incorrect sign");
bool auth = false; bool auth = false;
if (isAuthorizedKey(rsign_pk)) { if (isAuthorizedKey(rsign_pk)) {
auth = true; auth = true;
} else { } else {
authorize(rinfo, &auth); authorize(rinfo, &auth);
if (auth) auth_pkeys << rsign_pk; if (auth) auth_pkeys << rsign_pk;
} }
if (!auth) return disconnect(ba, "Unauthorised"); if (!auth) return disconnect(ba, "Unauthorised");
ba.clear(); ba.clear();
auth_sign = rsign_pk; auth_sign = rsign_pk;
crypt.generateKeypair(my_pk, box_sk); crypt.generateKeypair(my_pk, box_sk);
tba.clear(); tba.clear();
tba << sign_pk << my_pk << box_pk; tba << sign_pk << my_pk << box_pk;
PIByteArray sign = crypt.signMessage(tba, sign_sk); PIByteArray sign = crypt.signMessage(tba, sign_sk);
tba << sign; tba << sign;
tba = crypt.crypt(tba, box_pk, box_sk); tba = crypt.crypt(tba, box_pk, box_sk);
state = AuthReply; state = AuthReply;
noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE); noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
ba << (int)state << tba << my_pk << noise; ba << (int)state << tba << my_pk << noise;
sign = crypt.signMessage(ba, sign_sk); sign = crypt.signMessage(ba, sign_sk);
ba << sign; ba << sign;
return state; return state;
} }
if (state == AuthReply && rstate == PassRequest) { if (state == AuthReply && rstate == PassRequest) {
PIByteArray ctba, tba; PIByteArray ctba, tba;
PIByteArray noise; PIByteArray noise;
PIByteArray rsign, rsign_pk; PIByteArray rsign, rsign_pk;
ba >> ctba >> rsign; ba >> ctba >> rsign;
bool ok = false; bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok); tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted"); if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear(); ba.clear();
ba << (int)rstate << ctba; ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign"); if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
ctba.clear(); ctba.clear();
tba >> rsign_pk >> noise >> ctba; tba >> rsign_pk >> noise >> ctba;
if (rsign_pk != auth_sign || ctba != my_pk) return disconnect(ba, "Invalid public key"); if (rsign_pk != auth_sign || ctba != my_pk) return disconnect(ba, "Invalid public key");
PIString ps; PIString ps;
PIByteArray ph; PIByteArray ph;
passwordRequest(&ps); passwordRequest(&ps);
if (ps.isEmpty()) return disconnect(ba, "Canceled by user"); if (ps.isEmpty()) return disconnect(ba, "Canceled by user");
ph = crypt.passwordHash(ps, PIString("PIAuth").toByteArray()); ph = crypt.passwordHash(ps, PIString("PIAuth").toByteArray());
ps.fill(PIChar()); ps.fill(PIChar());
tba.clear(); tba.clear();
tba << ph << auth_sign << sign_pk; tba << ph << auth_sign << sign_pk;
tba = crypt.crypt(tba, box_pk, box_sk); tba = crypt.crypt(tba, box_pk, box_sk);
ba.clear(); ba.clear();
state = PassRequest; state = PassRequest;
ba << (int)state << tba; ba << (int)state << tba;
rsign = crypt.signMessage(ba, sign_sk); rsign = crypt.signMessage(ba, sign_sk);
ba << rsign; ba << rsign;
return state; return state;
} }
if ((state == AuthReply && rstate == KeyExchange) || (state == PassRequest && rstate == KeyExchange)) { if ((state == AuthReply && rstate == KeyExchange) || (state == PassRequest && rstate == KeyExchange)) {
PIByteArray tba, ctba; PIByteArray tba, ctba;
PIByteArray rsign; PIByteArray rsign;
ba >> ctba >> rsign; ba >> ctba >> rsign;
bool ok = false; bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok); tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted"); if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear(); ba.clear();
ba << (int)rstate << ctba; ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign"); if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
tba >> secret_key; tba >> secret_key;
if (secret_key.size() != crypt.sizeKey()) return disconnect(ba, "Invalid key"); if (secret_key.size() != crypt.sizeKey()) return disconnect(ba, "Invalid key");
ba.clear(); ba.clear();
state = Connected; state = Connected;
connected(PIString()); connected(PIString());
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE); ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state; return state;
} }
if (state == Connected && rstate == Connected) { if (state == Connected && rstate == Connected) {
ba.clear(); ba.clear();
state = Connected; state = Connected;
connected(PIString()); connected(PIString());
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE); ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state; return state;
} }
} }
// server side // server side
if (role == Server) { if (role == Server) {
if (state == AuthProbe && rstate == AuthReply) { if (state == AuthProbe && rstate == AuthReply) {
if (ba.size() < sizeof(int) * 4) return disconnect(ba, "invalid data size"); if (ba.size() < sizeof(int)*4) return disconnect(ba, "invalid data size");
PIByteArray ctba, tba; PIByteArray ctba, tba;
PIByteArray noise; PIByteArray noise;
PIByteArray rsign1, rsign2; PIByteArray rsign1, rsign2;
PIByteArray rsign_pk; PIByteArray rsign_pk;
PIByteArray pk, mpk; PIByteArray pk, mpk;
ba >> ctba >> pk >> noise >> rsign1; ba >> ctba >> pk >> noise >> rsign1;
bool ok = false; bool ok = false;
tba = crypt.decrypt(ctba, pk, box_sk, &ok); tba = crypt.decrypt(ctba, pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted"); if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
if (tba.size() < sizeof(int) * 3) return disconnect(tba, "invalid data size"); if (tba.size() < sizeof(int)*3) return disconnect(tba, "invalid data size");
tba >> rsign_pk >> box_pk >> mpk >> rsign2; tba >> rsign_pk >> box_pk >> mpk >> rsign2;
if (pk != box_pk || mpk != my_pk) return disconnect(ba, "Invalid public key"); if (pk != box_pk || mpk != my_pk) return disconnect(ba, "Invalid public key");
ba.clear(); ba.clear();
ba << (int)rstate << ctba << box_pk << noise; ba << (int)rstate << ctba << box_pk << noise;
if (!crypt.verifySign(ba, rsign1, rsign_pk)) return disconnect(ba, "Incorrect sign"); if (!crypt.verifySign(ba, rsign1, rsign_pk)) return disconnect(ba, "Incorrect sign");
ba.clear(); ba.clear();
ba << rsign_pk << box_pk << my_pk; ba << rsign_pk << box_pk << my_pk;
if (!crypt.verifySign(ba, rsign2, rsign_pk)) return disconnect(ba, "Incorrect sign"); if (!crypt.verifySign(ba, rsign2, rsign_pk)) return disconnect(ba, "Incorrect sign");
auth_sign = rsign_pk; auth_sign = rsign_pk;
if (isAuthorizedKey(rsign_pk)) { if (isAuthorizedKey(rsign_pk)) {
state = KeyExchange; state = KeyExchange;
ba = createSKMessage(); ba = createSKMessage();
return state; return state;
} else { } else {
ba.clear(); ba.clear();
tba.clear(); tba.clear();
state = PassRequest; state = PassRequest;
noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE); noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
tba << sign_pk << noise << box_pk; tba << sign_pk << noise << box_pk;
tba = crypt.crypt(tba, box_pk, box_sk); tba = crypt.crypt(tba, box_pk, box_sk);
ba << (int)state << tba; ba << (int)state << tba;
rsign1 = crypt.signMessage(ba, sign_sk); rsign1 = crypt.signMessage(ba, sign_sk);
ba << rsign1; ba << rsign1;
return state; return state;
} }
} }
if (state == PassRequest && rstate == PassRequest) { if (state == PassRequest && rstate == PassRequest) {
PIByteArray tba, ctba; PIByteArray tba, ctba;
PIByteArray rsign_pk, rsign, mpk; PIByteArray rsign_pk, rsign, mpk;
ba >> ctba >> rsign; ba >> ctba >> rsign;
bool ok = false; bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok); tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted"); if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear(); ba.clear();
ba << (int)rstate << ctba; ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign"); if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
ctba.clear(); ctba.clear();
tba >> ctba >> mpk >> rsign_pk; tba >> ctba >> mpk >> rsign_pk;
if (rsign_pk != auth_sign || mpk != sign_pk) return disconnect(ba, "Invalid public key"); if (rsign_pk != auth_sign || mpk != sign_pk) return disconnect(ba, "Invalid public key");
bool auth = (ctba == pass_hash); bool auth = (ctba == pass_hash);
if (ctba.isEmpty() || pass_hash.isEmpty()) auth = false; if (ctba.isEmpty() || pass_hash.isEmpty()) auth = false;
passwordCheck(auth); passwordCheck(auth);
if (!auth) { if (!auth) {
// piSleep(1); // piSleep(1);
return disconnect(ba, "Invalid password"); return disconnect(ba, "Invalid password");
} }
state = KeyExchange; state = KeyExchange;
ba = createSKMessage(); ba = createSKMessage();
return state; return state;
} }
if ((state == KeyExchange && rstate == Connected) || (state == Connected && rstate == Connected)) { if ((state == KeyExchange && rstate == Connected) || (state == Connected && rstate == Connected)) {
ba.clear(); ba.clear();
PIByteArray rinfo; PIByteArray rinfo;
ba >> rinfo; ba >> rinfo;
bool ok = false; bool ok = false;
rinfo = crypt.decrypt(rinfo, secret_key, &ok); rinfo = crypt.decrypt(rinfo, secret_key, &ok);
if (!ok) return disconnect(ba, "Error while exchange keys"); if (!ok) return disconnect(ba, "Error while exchange keys");
state = Connected; state = Connected;
connected(PIString::fromUTF8(rinfo)); connected(rinfo);
ba << (int)state << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE); ba << (int)state << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state; return state;
} }
} }
return disconnect(ba, "invalid state " + PIString::fromNumber((int)state)); return disconnect(ba, "invalid state " + PIString::fromNumber((int)state));
} }
PIByteArray PIAuth::getSecretKey() { PIByteArray PIAuth::getSecretKey() {
if (state == Connected) return secret_key; if (state == Connected) return secret_key;
return PIByteArray(); return PIByteArray();
} }
PIByteArray PIAuth::generateSign(const PIByteArray & seed) { PIByteArray PIAuth::generateSign(const PIByteArray & seed) {
PIByteArray pk, sk; PIByteArray pk, sk;
PICrypt::generateSignKeys(pk, sk, seed); PICrypt::generateSignKeys(pk, sk, seed);
return sk; return sk;
} }
PIAuth::State PIAuth::disconnect(PIByteArray & ba, const PIString & error) { PIAuth::State PIAuth::disconnect(PIByteArray & ba, const PIString & error) {
if (!error.isEmpty()) piCoutObj << error; if (!error.isEmpty()) piCoutObj << error;
auth_sign.clear(); auth_sign.clear();
box_sk.clear(); box_sk.clear();
box_pk.clear(); box_pk.clear();
my_pk.clear(); my_pk.clear();
secret_key.clear(); secret_key.clear();
ba.clear(); ba.clear();
state = NotConnected; state = NotConnected;
disconnected(error); disconnected(error);
return state; return state;
} }
bool PIAuth::isAuthorizedKey(const PIByteArray & pkey) { bool PIAuth::isAuthorizedKey(const PIByteArray & pkey) {
for (int i = 0; i < auth_pkeys.size_s(); ++i) { for (int i=0; i<auth_pkeys.size_s(); ++i) {
if (pkey == auth_pkeys[i]) return true; if (pkey == auth_pkeys[i]) return true;
} }
return false; return false;
} }
PIByteArray PIAuth::createSKMessage() { PIByteArray PIAuth::createSKMessage() {
secret_key = crypt.generateKey(); secret_key = crypt.generateKey();
PIByteArray tba; PIByteArray tba;
PIByteArray noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE); PIByteArray noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
tba << secret_key << noise; tba << secret_key << noise;
tba = crypt.crypt(tba, box_pk, box_sk); tba = crypt.crypt(tba, box_pk, box_sk);
PIByteArray ret; PIByteArray ret;
ret << (int)state << tba; ret << (int)state << tba;
PIByteArray sign = crypt.signMessage(ret, sign_sk); PIByteArray sign = crypt.signMessage(ret, sign_sk);
ret << sign; ret << sign;
return ret; return ret;
} }

View File

@@ -1,376 +1,448 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Cryptographic class using lib Sodium Cryptographic class using lib Sodium
Andrey Bychkov work.a.b@yandex.ru Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "picrypt.h" #include "picrypt.h"
#ifdef PIP_CRYPT
#include "pitranslator.h" # include <sodium.h>
#include <sodium.h> #endif
#define PICRYPT_DISABLED_WARNING piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and rebuild pip";
namespace {
constexpr char hash_def_key[] = "_picrypt_\0\0\0\0\0\0\0"; const char hash_def_key[] = "_picrypt_\0\0\0\0\0\0\0";
constexpr int hash_def_key_size = 9; const int hash_def_key_size = 9;
} // namespace
PICrypt::PICrypt() {
PICrypt::PICrypt() { #ifdef PIP_CRYPT
if (!init()) { if (!init()) piCout << "[PICrypt]" << "Error while initialize sodium!";
piCout << "[PICrypt]" nonce_.resize(crypto_secretbox_NONCEBYTES);
<< "Error while initialize sodium!"_tr("PICrypt"); key_.resize(crypto_secretbox_KEYBYTES);
} randombytes_buf(key_.data(), key_.size());
nonce_.resize(crypto_secretbox_NONCEBYTES); randombytes_buf(nonce_.data(), nonce_.size());
key_.resize(crypto_secretbox_KEYBYTES); #else
randombytes_buf(key_.data(), key_.size()); PICRYPT_DISABLED_WARNING
randombytes_buf(nonce_.data(), nonce_.size()); #endif
} }
PICrypt::~PICrypt() {
key_.fill(0); bool PICrypt::setKey(const PIByteArray & _key) {
nonce_.fill(0); if (_key.size() != key_.size()) return false;
} key_ = _key;
return true;
}
bool PICrypt::setKey(const PIByteArray & _key) {
if (_key.size() != key_.size()) return false;
key_ = _key; PIByteArray PICrypt::setKey(const PIString & secret) {
return true; PIByteArray hash;
} #ifdef PIP_CRYPT
hash.resize(crypto_generichash_BYTES);
PIByteArray s(secret.data(), secret.size());
bool PICrypt::setKey(const PIString & secret) {; crypto_generichash(hash.data(), hash.size(), s.data(), s.size(), (const uchar*)hash_def_key, hash_def_key_size);
key_ = hash(secret); hash.resize(key_.size());
return key_.isNotEmpty(); setKey(hash);
} #endif
return hash;
}
PIByteArray PICrypt::crypt(const PIByteArray & data) {
PIByteArray ret;
ret.resize(data.size() + crypto_secretbox_MACBYTES); PIByteArray PICrypt::crypt(const PIByteArray & data) {
randombytes_buf(nonce_.data(), nonce_.size()); PIByteArray ret;
if (crypto_secretbox_easy(ret.data(), data.data(), data.size(), nonce_.data(), key_.data()) != 0) { #ifdef PIP_CRYPT
ret.clear(); ret.resize(data.size() + crypto_secretbox_MACBYTES);
} else { randombytes_buf(nonce_.data(), nonce_.size());
ret.append(nonce_); crypto_secretbox_easy(ret.data(), data.data(), data.size(), nonce_.data(), key_.data());
} ret.append(nonce_);
return ret; #endif
} return ret;
}
PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) {
if (!init()) { PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) {
key.fill(0); PIByteArray ret;
return PIByteArray(); #ifdef PIP_CRYPT
} if (key.size() != crypto_secretbox_KEYBYTES)
if (key.size() != crypto_secretbox_KEYBYTES) key.resize(crypto_secretbox_KEYBYTES, ' '); key.resize(crypto_secretbox_KEYBYTES, ' ');
PIByteArray n; //return PIByteArray();
n.resize(crypto_secretbox_NONCEBYTES); if (!init()) return ret;
PIByteArray ret; PIByteArray n;
ret.resize(data.size() + crypto_secretbox_MACBYTES); ret.resize(data.size() + crypto_secretbox_MACBYTES);
randombytes_buf(n.data(), n.size()); n.resize(crypto_secretbox_NONCEBYTES);
if (crypto_secretbox_easy(ret.data(), data.data(), data.size(), n.data(), key.data()) != 0) { randombytes_buf(n.data(), n.size());
ret.clear(); crypto_secretbox_easy(ret.data(), data.data(), data.size(), n.data(), key.data());
} else { ret.append(n);
ret.append(n); #else
} PICRYPT_DISABLED_WARNING
key.fill(0); #endif
return ret; return ret;
} }
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool * ok) { PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool *ok) {
if (crypt_data.size() < nonce_.size() + crypto_secretbox_MACBYTES) { PIByteArray ret;
if (ok) *ok = false; #ifdef PIP_CRYPT
return PIByteArray(); if (crypt_data.size() < nonce_.size() + crypto_secretbox_MACBYTES) {
} if (ok) *ok = false;
const ullong data_size = crypt_data.size() - nonce_.size(); return PIByteArray();
PIByteArray ret; }
ret.resize(data_size - crypto_secretbox_MACBYTES); ret.resize(crypt_data.size() - nonce_.size() - crypto_secretbox_MACBYTES);
memcpy(nonce_.data(), crypt_data.data(data_size), nonce_.size()); memcpy(nonce_.data(), crypt_data.data(crypt_data.size() - nonce_.size()), nonce_.size());
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), data_size, nonce_.data(), key_.data()) != 0) { if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - nonce_.size(), nonce_.data(), key_.data()) != 0) {
// Bad key if (ok) *ok = false;
if (ok) *ok = false; // piCout << "[PICrypt]" << "bad key_";
ret.clear(); return PIByteArray();
} else if (ok) { }
*ok = true; #endif
} if (ok) *ok = true;
return ret; return ret;
} }
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bool * ok) { PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bool *ok) {
if (!init()) { PIByteArray ret;
key.fill(0); #ifdef PIP_CRYPT
return PIByteArray(); if (key.size() != crypto_secretbox_KEYBYTES)
} key.resize(crypto_secretbox_KEYBYTES, ' ');
if (crypt_data.size() < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES) { /*if (ok) *ok = false;
if (ok) *ok = false; return PIByteArray();
key.fill(0); }*/
return PIByteArray(); if (crypt_data.size() < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES) {
} if (ok) *ok = false;
if (key.size() != crypto_secretbox_KEYBYTES) key.resize(crypto_secretbox_KEYBYTES, ' '); return PIByteArray();
PIByteArray n; }
n.resize(crypto_secretbox_NONCEBYTES); if (!init()) return ret;
const ullong data_size = crypt_data.size() - n.size(); PIByteArray n;
PIByteArray ret; n.resize(crypto_secretbox_NONCEBYTES);
ret.resize(data_size - crypto_secretbox_MACBYTES); ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES);
memcpy(n.data(), crypt_data.data(data_size), n.size()); memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size());
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), data_size, n.data(), key.data()) != 0) { if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), key.data()) != 0) {
// Bad key if (ok) *ok = false;
if (ok) *ok = false; // piCout << "[PICrypt]" << "bad key_";
ret.clear(); return PIByteArray();
} else if (ok) { } else if (ok) *ok = true;
*ok = true; #else
} PICRYPT_DISABLED_WARNING
key.fill(0); #endif
return ret; return ret;
} }
PIByteArray PICrypt::hash(PIString secret) { PIByteArray PICrypt::hash(const PIString & secret) {
if (!init()) return {}; PIByteArray hash;
PIByteArray s = secret.toUTF8(); #ifdef PIP_CRYPT
PIByteArray h = hash(s); if (!init()) return hash;
memset(const_cast<char *>(secret.data()), 0, s.size()); hash.resize(crypto_generichash_BYTES);
secret.fill('\0'); PIByteArray s(secret.data(), secret.size());
s.fill(0); crypto_generichash(hash.data(), hash.size(), s.data(), s.size(),(const uchar*)hash_def_key, hash_def_key_size);
return h; #else
} PICRYPT_DISABLED_WARNING
#endif
return hash;
PIByteArray PICrypt::hash(const PIByteArray & data) { }
if (!init()) return {};
PIByteArray h;
h.resize(crypto_generichash_BYTES); PIByteArray PICrypt::hash(const PIByteArray & data) {
crypto_generichash(h.data(), h.size(), data.data(), data.size(), (const uchar *)hash_def_key, hash_def_key_size); PIByteArray hash;
return h; #ifdef PIP_CRYPT
} if (!init()) return hash;
hash.resize(crypto_generichash_BYTES);
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), (const uchar*)hash_def_key, hash_def_key_size);
PIByteArray PICrypt::hash(const PIByteArray & data, const unsigned char * key, size_t keylen) { #else
PIByteArray hash; PICRYPT_DISABLED_WARNING
if (!init()) return hash; #endif
hash.resize(crypto_generichash_BYTES); return hash;
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), key, keylen); }
return hash;
}
PIByteArray PICrypt::hash(const PIByteArray & data, const unsigned char *key, size_t keylen) {
PIByteArray hash;
size_t PICrypt::sizeHash() { #ifdef PIP_CRYPT
return crypto_generichash_BYTES; if (!init()) return hash;
} hash.resize(crypto_generichash_BYTES);
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), key, keylen);
#else
ullong PICrypt::shorthash(const PIString & s, PIByteArray key) { PICRYPT_DISABLED_WARNING
ullong hash = 0; #endif
if (!init()) { return hash;
key.fill(0); }
return hash;
}
if (crypto_shorthash_BYTES != sizeof(hash)) size_t PICrypt::sizeHash() {
piCout << "[PICrypt]" #ifdef PIP_CRYPT
<< "internal error: bad hash size"_tr("PICrypt"); return crypto_generichash_BYTES;
if (key.size() != crypto_shorthash_KEYBYTES) { #else
piCout << "[PICrypt]" PICRYPT_DISABLED_WARNING
<< "invalid key size %1, should be %2, filled with zeros"_tr("PICrypt").arg(key.size()).arg(crypto_shorthash_KEYBYTES); #endif
key.resize(crypto_shorthash_KEYBYTES, 0); return 0;
} }
PIByteArray in(s.data(), s.size());
crypto_shorthash((uchar *)&hash, in.data(), in.size(), key.data());
key.fill(0); ullong PICrypt::shorthash(const PIString& s, PIByteArray key) {
return hash; ullong hash = 0;
} #ifdef PIP_CRYPT
if (crypto_shorthash_BYTES != sizeof(hash)) piCout << "[PICrypt]" << "internal error: bad hash size";
if (!init()) return hash;
PIByteArray PICrypt::generateKey() { if (key.size() != crypto_shorthash_KEYBYTES) {
return generateRandomBuff(sizeKey()); piCout << "[PICrypt]" << "invalid key size" << key.size() << ", shoud be" << crypto_shorthash_KEYBYTES << ", filled zeros";
} key.resize(crypto_shorthash_KEYBYTES, 0);
}
PIByteArray in(s.data(), s.size());
PIByteArray PICrypt::generateRandomBuff(int size) { crypto_shorthash((uchar *)&hash, in.data(), in.size(), key.data());
PIByteArray hash; #else
if (!init() || size <= 0) return hash; PICRYPT_DISABLED_WARNING
hash.resize(size); #endif
randombytes_buf(hash.data(), hash.size()); return hash;
return hash; }
}
PIByteArray PICrypt::generateKey() {
size_t PICrypt::sizeKey() { PIByteArray hash;
return crypto_secretbox_KEYBYTES; #ifdef PIP_CRYPT
} if (!init()) return hash;
hash.resize(crypto_secretbox_KEYBYTES);
randombytes_buf(hash.data(), hash.size());
size_t PICrypt::sizeCrypt() { #else
return crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; PICRYPT_DISABLED_WARNING
} #endif
return hash;
}
bool PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key) {
if (!init()) return false;
public_key.resize(crypto_sign_PUBLICKEYBYTES); PIByteArray PICrypt::generateRandomBuff(int size) {
secret_key.resize(crypto_sign_SECRETKEYBYTES); PIByteArray hash;
return crypto_sign_keypair(public_key.data(), secret_key.data()) == 0; #ifdef PIP_CRYPT
} if (!init() || size <= 0) return hash;
hash.resize(size);
randombytes_buf(hash.data(), hash.size());
bool PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) { #else
if (!init() || seed.isEmpty()) return false; PICRYPT_DISABLED_WARNING
public_key.resize(crypto_sign_PUBLICKEYBYTES); #endif
secret_key.resize(crypto_sign_SECRETKEYBYTES); return hash;
return crypto_sign_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data()) == 0; }
}
size_t PICrypt::sizeKey() {
PIByteArray PICrypt::extractSignPublicKey(const PIByteArray & secret_key) { #ifdef PIP_CRYPT
PIByteArray pk; return crypto_secretbox_KEYBYTES;
if (!init() || secret_key.size() != crypto_sign_SECRETKEYBYTES) return pk; #else
pk.resize(crypto_sign_PUBLICKEYBYTES); PICRYPT_DISABLED_WARNING
if (crypto_sign_ed25519_sk_to_pk(pk.data(), secret_key.data()) != 0) { #endif
pk.clear(); return 0;
} }
return pk;
}
size_t PICrypt::sizeCrypt() {
#ifdef PIP_CRYPT
PIByteArray PICrypt::signMessage(const PIByteArray & data, const PIByteArray & secret_key) { return crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES;
PIByteArray sign; #else
if (!init()) return sign; PICRYPT_DISABLED_WARNING
sign.resize(crypto_sign_BYTES); #endif
if (crypto_sign_detached(sign.data(), 0, data.data(), data.size(), secret_key.data()) != 0) { return 0;
sign.clear(); }
}
return sign;
} void PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key) {
#ifdef PIP_CRYPT
if (!init()) return;
bool PICrypt::verifySign(const PIByteArray & data, const PIByteArray & signature, const PIByteArray & public_key) { public_key.resize(crypto_sign_PUBLICKEYBYTES);
if (!init()) return false; secret_key.resize(crypto_sign_SECRETKEYBYTES);
return (crypto_sign_verify_detached(signature.data(), data.data(), data.size(), public_key.data()) == 0); crypto_sign_keypair(public_key.data(), secret_key.data());
return false; #else
} PICRYPT_DISABLED_WARNING
#endif
}
bool PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key) {
if (!init()) return false;
public_key.resize(crypto_box_PUBLICKEYBYTES); void PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) {
secret_key.resize(crypto_box_SECRETKEYBYTES); #ifdef PIP_CRYPT
return crypto_box_keypair(public_key.data(), secret_key.data()) == 0; if (!init() || seed.isEmpty()) return;
} public_key.resize(crypto_sign_PUBLICKEYBYTES);
secret_key.resize(crypto_sign_SECRETKEYBYTES);
crypto_sign_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data());
bool PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) { #else
if (!init()) return false; PICRYPT_DISABLED_WARNING
public_key.resize(crypto_box_PUBLICKEYBYTES); #endif
secret_key.resize(crypto_box_SECRETKEYBYTES); }
return crypto_box_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data()) == 0;
}
PIByteArray PICrypt::extractSignPublicKey(const PIByteArray & secret_key) {
PIByteArray pk;
PIByteArray PICrypt::crypt(const PIByteArray & data, const PIByteArray & public_key, const PIByteArray & secret_key) { #ifdef PIP_CRYPT
if (!init()) return PIByteArray(); if (!init() || secret_key.size() != crypto_sign_SECRETKEYBYTES) return pk;
if (public_key.size() != crypto_box_PUBLICKEYBYTES) return PIByteArray(); pk.resize(crypto_sign_PUBLICKEYBYTES);
if (secret_key.size() != crypto_box_SECRETKEYBYTES) return PIByteArray(); crypto_sign_ed25519_sk_to_pk(pk.data(), secret_key.data());
PIByteArray n; #else
n.resize(crypto_box_NONCEBYTES); PICRYPT_DISABLED_WARNING
PIByteArray ret; #endif
ret.resize(data.size() + crypto_box_MACBYTES); return pk;
randombytes_buf(n.data(), n.size()); }
if (crypto_box_easy(ret.data(), data.data(), data.size(), n.data(), public_key.data(), secret_key.data()) != 0) {
return PIByteArray();
} PIByteArray PICrypt::signMessage(const PIByteArray & data, PIByteArray secret_key) {
ret.append(n); PIByteArray sign;
return ret; #ifdef PIP_CRYPT
} if (!init()) return sign;
sign.resize(crypto_sign_BYTES);
crypto_sign_detached(sign.data(), 0, data.data(), data.size(), secret_key.data());
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray & public_key, const PIByteArray & secret_key, bool * ok) { #else
if (!init()) { PICRYPT_DISABLED_WARNING
if (ok) *ok = false; #endif
return PIByteArray(); return sign;
} }
if (public_key.size() != crypto_box_PUBLICKEYBYTES) {
if (ok) *ok = false;
return PIByteArray(); bool PICrypt::verifySign(const PIByteArray & data, const PIByteArray & signature, PIByteArray public_key) {
} #ifdef PIP_CRYPT
if (secret_key.size() != crypto_box_SECRETKEYBYTES) { if (!init()) return false;
if (ok) *ok = false; return (crypto_sign_verify_detached(signature.data(), data.data(), data.size(), public_key.data()) == 0);
return PIByteArray(); #else
} PICRYPT_DISABLED_WARNING
if (crypt_data.size() < crypto_box_NONCEBYTES + crypto_box_MACBYTES) { #endif
if (ok) *ok = false; return false;
return PIByteArray(); }
}
PIByteArray n;
n.resize(crypto_secretbox_NONCEBYTES); void PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key) {
const ullong data_size = crypt_data.size() - n.size(); #ifdef PIP_CRYPT
PIByteArray ret; if (!init()) return;
ret.resize(data_size - crypto_secretbox_MACBYTES); public_key.resize(crypto_box_PUBLICKEYBYTES);
memcpy(n.data(), crypt_data.data(data_size), n.size()); secret_key.resize(crypto_box_SECRETKEYBYTES);
if (crypto_box_open_easy(ret.data(), crypt_data.data(), data_size, n.data(), public_key.data(), secret_key.data()) != 0) { crypto_box_keypair(public_key.data(), secret_key.data());
// Bad key #else
if (ok) *ok = false; PICRYPT_DISABLED_WARNING
ret.clear(); #endif
} else if (ok) { }
*ok = true;
}
return ret; void PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) {
} #ifdef PIP_CRYPT
if (!init()) return;
public_key.resize(crypto_box_PUBLICKEYBYTES);
PIByteArray PICrypt::passwordHash(PIString password, const PIByteArray & seed) { secret_key.resize(crypto_box_SECRETKEYBYTES);
#ifdef crypto_pwhash_ALG_ARGON2I13 crypto_box_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data());
PIByteArray pass = password.toUTF8(); #else
PIByteArray n = hash(seed); PICRYPT_DISABLED_WARNING
PIByteArray ph; #endif
ph.resize(crypto_box_SEEDBYTES); }
n.resize(crypto_pwhash_SALTBYTES);
int r = crypto_pwhash(ph.data(),
ph.size(), PIByteArray PICrypt::crypt(const PIByteArray & data, const PIByteArray & public_key, const PIByteArray & secret_key) {
(const char *)pass.data(), PIByteArray ret;
pass.size(), #ifdef PIP_CRYPT
n.data(), if (!init()) return ret;
crypto_pwhash_argon2i_opslimit_moderate(), if (public_key.size() != crypto_box_PUBLICKEYBYTES)
crypto_pwhash_argon2i_memlimit_moderate(), return ret;
crypto_pwhash_ALG_ARGON2I13); if (secret_key.size() != crypto_box_SECRETKEYBYTES)
pass.fill(0); return ret;
memset(const_cast<char *>(password.data()), 0, pass.size()); PIByteArray n;
password.fill('\0'); ret.resize(data.size() + crypto_box_MACBYTES);
if (r != 0) return PIByteArray(); n.resize(crypto_box_NONCEBYTES);
return ph; randombytes_buf(n.data(), n.size());
#else if (crypto_box_easy(ret.data(), data.data(), data.size(), n.data(), public_key.data(), secret_key.data()) != 0)
piCout << "[PICrypt] Error, ALG_ARGON2I13 not availible!"; return PIByteArray();
return PIByteArray(); ret.append(n);
#endif #else
} PICRYPT_DISABLED_WARNING
#endif
return ret;
PIString PICrypt::version() { }
return SODIUM_VERSION_STRING;
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray & public_key, const PIByteArray & secret_key, bool * ok) {
PIByteArray ret;
bool PICrypt::init() { #ifdef PIP_CRYPT
static bool inited = false; if (!init()) return ret;
if (inited) return true; if (public_key.size() != crypto_box_PUBLICKEYBYTES) {
// piCout << "[PICrypt]" << "init ..."; if (ok) *ok = false;
inited = sodium_init(); return ret;
if (!inited) inited = sodium_init(); }
// piCout << "[PICrypt]" << "init" << inited; if (secret_key.size() != crypto_box_SECRETKEYBYTES) {
return inited; if (ok) *ok = false;
} return ret;
}
if (crypt_data.size() < crypto_box_NONCEBYTES + crypto_box_MACBYTES) {
if (ok) *ok = false;
return ret;
}
PIByteArray n;
n.resize(crypto_secretbox_NONCEBYTES);
ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES);
memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size());
if (crypto_box_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), public_key.data(), secret_key.data()) != 0) {
if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_";
return PIByteArray();
} else if (ok) *ok = true;
#else
PICRYPT_DISABLED_WARNING
#endif
return ret;
}
PIByteArray PICrypt::passwordHash(const PIString & password, const PIByteArray & seed) {
#ifdef crypto_pwhash_ALG_ARGON2I13
// char out[crypto_pwhash_STRBYTES];
PIByteArray pass = password.toUTF8();
PIByteArray n = hash(seed);
PIByteArray ph;
ph.resize(crypto_box_SEEDBYTES);
n.resize(crypto_pwhash_SALTBYTES);
// randombytes_buf(n.data(), n.size());
// crypto_shorthash(n.data(), seed.data(), seed.size(), PIByteArray(crypto_shorthash_KEYBYTES).data());
int r = crypto_pwhash(ph.data(), ph.size(), (const char*)pass.data(), pass.size(), n.data(), crypto_pwhash_argon2i_opslimit_moderate(), crypto_pwhash_argon2i_memlimit_moderate(), crypto_pwhash_ALG_ARGON2I13);
//crypto_pwhash_str(out, (const char*)pass.data(), pass.size(), crypto_pwhash_argon2i_opslimit_moderate(), crypto_pwhash_argon2i_memlimit_moderate());
pass.fill(0);
if (r != 0) return PIByteArray();
return ph;
// PIByteArray ret;
// ret << ph << n << crypto_pwhash_argon2i_opslimit_moderate() << crypto_pwhash_argon2i_memlimit_moderate();
// return ret;
#else
return PIByteArray();
#endif
}
PIString PICrypt::version() {
#ifdef PIP_CRYPT
return SODIUM_VERSION_STRING;
#else
return PIString();
#endif
}
bool PICrypt::init() {
#ifdef PIP_CRYPT
static bool inited = false;
if (inited) return true;
//piCout << "[PICrypt]" << "init ...";
inited = sodium_init();
if (!inited)
inited = sodium_init();
//piCout << "[PICrypt]" << "init" << inited;
return inited;
#else
PICRYPT_DISABLED_WARNING
#endif
return false;
}

View File

@@ -1,48 +1,34 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Class for FFT, IFFT and Hilbert transformations Class for FFT, IFFT and Hilbert transformations
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "pifft.h" #include "pifft.h"
#include "pifft_p.h"
#include "pifft_p.h"
#define _PIFFTW_CPP(type) \
#define _PIFFTW_CPP(type) \ _PIFFTW_P_##type##_::_PIFFTW_P_##type##_() {impl = new PIFFTW_Private<type>();;} \
_PIFFTW_P_##type##_::_PIFFTW_P_##type##_() { \ _PIFFTW_P_##type##_::~_PIFFTW_P_##type##_() {delete (PIFFTW_Private<type>*)impl;} \
impl = new PIFFTW_Private<type>(); \ const PIVector<complex<type> > & _PIFFTW_P_##type##_::calcFFT(const PIVector<complex<type> > & in) {return ((PIFFTW_Private<type>*)impl)->calcFFT(in);} \
; \ const PIVector<complex<type> > & _PIFFTW_P_##type##_::calcFFTR(const PIVector<type> & in) {return ((PIFFTW_Private<type>*)impl)->calcFFT(in);} \
} \ const PIVector<complex<type> > & _PIFFTW_P_##type##_::calcFFTI(const PIVector<complex<type> > & in) {return ((PIFFTW_Private<type>*)impl)->calcFFTinverse(in);} \
_PIFFTW_P_##type##_::~_PIFFTW_P_##type##_() { \ void _PIFFTW_P_##type##_::preparePlan(int size, int op) {return ((PIFFTW_Private<type>*)impl)->preparePlan(size, op);}
delete (PIFFTW_Private<type> *)impl; \
} \ _PIFFTW_CPP(float)
const PIVector<complex<type>> & _PIFFTW_P_##type##_::calcFFT(const PIVector<complex<type>> & in) { \ _PIFFTW_CPP(double)
return ((PIFFTW_Private<type> *)impl)->calcFFT(in); \ _PIFFTW_CPP(ldouble)
} \
const PIVector<complex<type>> & _PIFFTW_P_##type##_::calcFFTR(const PIVector<type> & in) { \
return ((PIFFTW_Private<type> *)impl)->calcFFT(in); \
} \
const PIVector<complex<type>> & _PIFFTW_P_##type##_::calcFFTI(const PIVector<complex<type>> & in) { \
return ((PIFFTW_Private<type> *)impl)->calcFFTinverse(in); \
} \
void _PIFFTW_P_##type##_::preparePlan(int size, int op) { \
return ((PIFFTW_Private<type> *)impl)->preparePlan(size, op); \
}
_PIFFTW_CPP(float)
_PIFFTW_CPP(double)
_PIFFTW_CPP(ldouble)

View File

@@ -1,248 +1,180 @@
/*! \file pifft_p.h /*! \file pifft_p.h
* \brief Class for FFT, IFFT and Hilbert transformations * \brief Class for FFT, IFFT and Hilbert transformations
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Private header for fftw3 Private header for fftw3
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PIFFT_P_H #ifndef PIFFT_P_H
#define PIFFT_P_H #define PIFFT_P_H
#include "picout.h" #include "pivector.h"
#include "pimathcomplex.h" #include "picout.h"
#include "pivector.h" #if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq)
#if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq) # include "fftw3.h"
# include "fftw3.h" #else
#else # define FFTW_FORWARD 0
# define FFTW_FORWARD 0 # define FFTW_BACKWARD 0
# define FFTW_BACKWARD 0 # define FFTW_ESTIMATE 0
# define FFTW_ESTIMATE 0 # define FFTW_MEASURE 0
# define FFTW_MEASURE 0 #endif
#endif
template <typename T>
template<typename T> class PIFFTW_Private
class PIFFTW_Private { {
public: public:
explicit PIFFTW_Private() { explicit PIFFTW_Private() {
plan = 0; plan = 0;
// #ifndef PIP_FFTW //#ifndef PIP_FFTW
// piCout << "[PIFFTW]" << "Warning: PIFFTW is disabled, to enable install libfftw3-dev library and build pip with -DFFTW=1"; // piCout << "[PIFFTW]" << "Warning: PIFFTW is disabled, to enable install libfftw3-dev library and build pip with -DFFTW=1";
// #endif //#endif
p_makeThreadSafe(); p_makeThreadSafe();
} }
~PIFFTW_Private() { p_destroyPlan(plan); } ~PIFFTW_Private() {p_destroyPlan(plan);}
const PIVector<complex<T>> & calcFFT(const PIVector<complex<T>> & in) { const PIVector<complex<T> > & calcFFT(const PIVector<complex<T> > & in) {
if (prepare != PlanParams(in.size(), fo_complex)) { if (prepare != PlanParams(in.size(), fo_complex)) {
p_out.resize(in.size()); p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan"; piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED); p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_complex); prepare = PlanParams(in.size(), fo_complex);
} }
p_executePlan_c2c(plan, in.data(), p_out.data()); p_executePlan_c2c(plan, in.data(), p_out.data());
return p_out; return p_out;
} }
const PIVector<complex<T>> & calcFFT(const PIVector<T> & in) { const PIVector<complex<T> > & calcFFT(const PIVector<T> & in) {
if (prepare != PlanParams(in.size(), fo_real)) { if (prepare != PlanParams(in.size(), fo_real)) {
p_out.resize(in.size()); p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan"; piCout << "[PIFFTW]" << "creating plan";
p_createPlan_r2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_ESTIMATE | FFTW_UNALIGNED); p_createPlan_r2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_real); prepare = PlanParams(in.size(), fo_real);
} }
p_executePlan_r2c(plan, in.data(), p_out.data()); p_executePlan_r2c(plan, in.data(), p_out.data());
return p_out; return p_out;
} }
const PIVector<complex<T>> & calcFFTinverse(const PIVector<complex<T>> & in) { const PIVector<complex<T> > & calcFFTinverse(const PIVector<complex<T> > & in) {
if (prepare != PlanParams(in.size(), fo_inverse)) { if (prepare != PlanParams(in.size(), fo_inverse)) {
p_out.resize(in.size()); p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan"; piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_UNALIGNED); p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_inverse); prepare = PlanParams(in.size(), fo_inverse);
} }
p_executePlan_c2c(plan, in.data(), p_out.data()); p_executePlan_c2c(plan, in.data(), p_out.data());
return p_out; return p_out;
} }
enum FFT_Operation { enum FFT_Operation {fo_real, fo_complex, fo_inverse};
fo_real,
fo_complex, void preparePlan(int size, int op) {
fo_inverse p_inr.clear();
}; p_in.clear();
p_out.clear();
void preparePlan(int size, int op) { switch ((FFT_Operation)op) {
p_inr.clear(); case fo_real:
p_in.clear(); p_inr.resize(size);
p_out.clear(); p_out.resize(size);
switch ((FFT_Operation)op) { p_createPlan_r2c_1d(plan, size, p_inr.data(), p_out.data(), FFTW_MEASURE | FFTW_UNALIGNED);
case fo_real: break;
p_inr.resize(size); case fo_complex:
p_out.resize(size); p_in.resize(size);
p_createPlan_r2c_1d(plan, size, p_inr.data(), p_out.data(), FFTW_MEASURE | FFTW_UNALIGNED); p_out.resize(size);
break; p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_FORWARD, FFTW_MEASURE | FFTW_UNALIGNED);
case fo_complex: break;
p_in.resize(size); case fo_inverse:
p_out.resize(size); p_in.resize(size);
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_FORWARD, FFTW_MEASURE | FFTW_UNALIGNED); p_out.resize(size);
break; p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_BACKWARD, FFTW_MEASURE | FFTW_UNALIGNED);
case fo_inverse: break;
p_in.resize(size); default:
p_out.resize(size); size = 0;
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_BACKWARD, FFTW_MEASURE | FFTW_UNALIGNED); break;
break; }
default: size = 0; break; prepare = PlanParams(size, (FFT_Operation)op);
} }
prepare = PlanParams(size, (FFT_Operation)op);
} inline void p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {}
inline void p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {}
inline void p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {} inline void p_executePlan(void * plan) {}
inline void p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {} inline void p_executePlan_c2c(void * plan, const void * in, void * out) {}
inline void p_executePlan(void * plan) {} inline void p_executePlan_r2c(void * plan, const void * in, void * out) {}
inline void p_executePlan_c2c(void * plan, const void * in, void * out) {} inline void p_destroyPlan(void *& plan) {}
inline void p_executePlan_r2c(void * plan, const void * in, void * out) {} inline void p_makeThreadSafe() {}
inline void p_destroyPlan(void *& plan) {}
inline void p_makeThreadSafe() {} struct PlanParams {
PlanParams() {size = 0; op = fo_complex;}
struct PlanParams { PlanParams(int size_, FFT_Operation op_) {size = size_; op = op_;}
PlanParams() { bool isValid() {return size > 0;}
size = 0; bool operator ==(const PlanParams & v) const {return (v.size == size) && (v.op == op);}
op = fo_complex; bool operator !=(const PlanParams & v) const {return !(*this == v);}
} int size;
PlanParams(int size_, FFT_Operation op_) { FFT_Operation op;
size = size_; };
op = op_;
} PIVector<complex<T> > p_in;
bool isValid() { return size > 0; } PIVector<T> p_inr;
bool operator==(const PlanParams & v) const { return (v.size == size) && (v.op == op); } PIVector<complex<T> > p_out;
bool operator!=(const PlanParams & v) const { return !(*this == v); } void * plan;
int size; PlanParams prepare;
FFT_Operation op; };
};
PIVector<complex<T>> p_in; #ifdef PIP_FFTWf
PIVector<T> p_inr; template<> inline void PIFFTW_Private<float>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
PIVector<complex<T>> p_out; plan = fftwf_plan_dft_1d(size, (fftwf_complex *)in, (fftwf_complex *)out, dir, flags);}
void * plan; template<> inline void PIFFTW_Private<float>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
PlanParams prepare; plan = fftwf_plan_dft_r2c_1d(size, (float *)in, (fftwf_complex *)out, flags);}
}; template<> inline void PIFFTW_Private<float>::p_executePlan(void * plan) {fftwf_execute((fftwf_plan)plan);}
template<> inline void PIFFTW_Private<float>::p_executePlan_c2c(void * plan, const void * in, void * out) {fftwf_execute_dft((fftwf_plan)plan, (fftwf_complex *)in, (fftwf_complex *)out);}
template<> inline void PIFFTW_Private<float>::p_executePlan_r2c(void * plan, const void * in, void * out) {fftwf_execute_dft_r2c((fftwf_plan)plan, (float *)in, (fftwf_complex *)out);}
#ifdef PIP_FFTWf template<> inline void PIFFTW_Private<float>::p_destroyPlan(void *& plan) {if (plan) fftwf_destroy_plan((fftwf_plan)plan); plan = 0;}
template<> # ifdef PIP_FFTWf_THREADSAFE
inline void PIFFTW_Private<float>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) { template<> inline void PIFFTW_Private<float>::p_makeThreadSafe() {fftwf_make_planner_thread_safe();}
plan = fftwf_plan_dft_1d(size, (fftwf_complex *)in, (fftwf_complex *)out, dir, flags); # endif
} #endif // PIP_FFTWf
template<>
inline void PIFFTW_Private<float>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) { #ifdef PIP_FFTW
plan = fftwf_plan_dft_r2c_1d(size, (float *)in, (fftwf_complex *)out, flags); template<> inline void PIFFTW_Private<double>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
} plan = fftw_plan_dft_1d(size, (fftw_complex *)in, (fftw_complex *)out, dir, flags);}
template<> template<> inline void PIFFTW_Private<double>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
inline void PIFFTW_Private<float>::p_executePlan(void * plan) { plan = fftw_plan_dft_r2c_1d(size, (double *)in, (fftw_complex *)out, flags);}
fftwf_execute((fftwf_plan)plan); template<> inline void PIFFTW_Private<double>::p_executePlan(void * plan) {fftw_execute((fftw_plan)plan);}
} template<> inline void PIFFTW_Private<double>::p_executePlan_c2c(void * plan, const void * in, void * out) {fftw_execute_dft((fftw_plan)plan, (fftw_complex *)in, (fftw_complex *)out);}
template<> template<> inline void PIFFTW_Private<double>::p_executePlan_r2c(void * plan, const void * in, void * out) {fftw_execute_dft_r2c((fftw_plan)plan, (double *)in, (fftw_complex *)out);}
inline void PIFFTW_Private<float>::p_executePlan_c2c(void * plan, const void * in, void * out) { template<> inline void PIFFTW_Private<double>::p_destroyPlan(void *& plan) {if (plan) fftw_destroy_plan((fftw_plan)plan); plan = 0;}
fftwf_execute_dft((fftwf_plan)plan, (fftwf_complex *)in, (fftwf_complex *)out); # ifdef PIP_FFTW_THREADSAFE
} template<> inline void PIFFTW_Private<double>::p_makeThreadSafe() {fftw_make_planner_thread_safe();}
template<> # endif
inline void PIFFTW_Private<float>::p_executePlan_r2c(void * plan, const void * in, void * out) { #endif // PIP_FFTW
fftwf_execute_dft_r2c((fftwf_plan)plan, (float *)in, (fftwf_complex *)out);
} #ifdef PIP_FFTWl
template<> template<> inline void PIFFTW_Private<ldouble>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
inline void PIFFTW_Private<float>::p_destroyPlan(void *& plan) { plan = fftwl_plan_dft_1d(size, (fftwl_complex *)in, (fftwl_complex *)out, dir, flags);}
if (plan) fftwf_destroy_plan((fftwf_plan)plan); template<> inline void PIFFTW_Private<ldouble>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
plan = 0; plan = fftwl_plan_dft_r2c_1d(size, (ldouble *)in, (fftwl_complex *)out, flags);}
} template<> inline void PIFFTW_Private<ldouble>::p_executePlan(void * plan) {fftwl_execute((fftwl_plan)plan);}
# ifdef PIP_FFTWf_THREADSAFE template<> inline void PIFFTW_Private<ldouble>::p_executePlan_c2c(void * plan, const void * in, void * out) {fftwl_execute_dft((fftwl_plan)plan, (fftwl_complex *)in, (fftwl_complex *)out);}
template<> template<> inline void PIFFTW_Private<ldouble>::p_executePlan_r2c(void * plan, const void * in, void * out) {fftwl_execute_dft_r2c((fftwl_plan)plan, (ldouble *)in, (fftwl_complex *)out);}
inline void PIFFTW_Private<float>::p_makeThreadSafe() { template<> inline void PIFFTW_Private<ldouble>::p_destroyPlan(void *& plan) {if (plan) fftwl_destroy_plan((fftwl_plan)plan); plan = 0;}
fftwf_make_planner_thread_safe(); # ifdef PIP_FFTWl_THREADSAFE
} template<> inline void PIFFTW_Private<ldouble>::p_makeThreadSafe() {fftwl_make_planner_thread_safe();}
# endif # endif
#endif // PIP_FFTWf #endif // PIP_FFTWl
#ifdef PIP_FFTW
template<> #endif // PIFFT_H
inline void PIFFTW_Private<double>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
plan = fftw_plan_dft_1d(size, (fftw_complex *)in, (fftw_complex *)out, dir, flags);
}
template<>
inline void PIFFTW_Private<double>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
plan = fftw_plan_dft_r2c_1d(size, (double *)in, (fftw_complex *)out, flags);
}
template<>
inline void PIFFTW_Private<double>::p_executePlan(void * plan) {
fftw_execute((fftw_plan)plan);
}
template<>
inline void PIFFTW_Private<double>::p_executePlan_c2c(void * plan, const void * in, void * out) {
fftw_execute_dft((fftw_plan)plan, (fftw_complex *)in, (fftw_complex *)out);
}
template<>
inline void PIFFTW_Private<double>::p_executePlan_r2c(void * plan, const void * in, void * out) {
fftw_execute_dft_r2c((fftw_plan)plan, (double *)in, (fftw_complex *)out);
}
template<>
inline void PIFFTW_Private<double>::p_destroyPlan(void *& plan) {
if (plan) fftw_destroy_plan((fftw_plan)plan);
plan = 0;
}
# ifdef PIP_FFTW_THREADSAFE
template<>
inline void PIFFTW_Private<double>::p_makeThreadSafe() {
fftw_make_planner_thread_safe();
}
# endif
#endif // PIP_FFTW
#ifdef PIP_FFTWl
template<>
inline void PIFFTW_Private<ldouble>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
plan = fftwl_plan_dft_1d(size, (fftwl_complex *)in, (fftwl_complex *)out, dir, flags);
}
template<>
inline void PIFFTW_Private<ldouble>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
plan = fftwl_plan_dft_r2c_1d(size, (ldouble *)in, (fftwl_complex *)out, flags);
}
template<>
inline void PIFFTW_Private<ldouble>::p_executePlan(void * plan) {
fftwl_execute((fftwl_plan)plan);
}
template<>
inline void PIFFTW_Private<ldouble>::p_executePlan_c2c(void * plan, const void * in, void * out) {
fftwl_execute_dft((fftwl_plan)plan, (fftwl_complex *)in, (fftwl_complex *)out);
}
template<>
inline void PIFFTW_Private<ldouble>::p_executePlan_r2c(void * plan, const void * in, void * out) {
fftwl_execute_dft_r2c((fftwl_plan)plan, (ldouble *)in, (fftwl_complex *)out);
}
template<>
inline void PIFFTW_Private<ldouble>::p_destroyPlan(void *& plan) {
if (plan) fftwl_destroy_plan((fftwl_plan)plan);
plan = 0;
}
# ifdef PIP_FFTWl_THREADSAFE
template<>
inline void PIFFTW_Private<ldouble>::p_makeThreadSafe() {
fftwl_make_planner_thread_safe();
}
# endif
#endif // PIP_FFTWl
#endif // PIFFT_H

View File

@@ -1,77 +0,0 @@
#include "curl_thread_pool_p.h"
#include "pihttpclient.h"
#include "pitime.h"
#include <curl/curl.h>
CurlThreadPool::CurlThreadPool() {
piForTimes(10) {
auto * t = new PIThread([this]() { threadFunc(); }, true);
threads << t;
}
}
CurlThreadPool::~CurlThreadPool() {
exiting = true;
for (auto * t: threads)
t->stop();
{
auto cr = clients.getRef();
for (auto c: *cr)
c->abort();
}
sem.release(threads.size());
for (auto * t: threads) {
t->waitForFinish();
t->setDebug(false);
t->terminate();
}
piDeleteAllAndClear(threads);
{
auto cr = clients.getRef();
for (auto c: *cr)
delete c;
}
curl_global_cleanup();
}
void CurlThreadPool::threadFunc() {
if (exiting) return;
// piCout << "threadFuncl w ...";
sem.acquire();
// piCout << "threadFuncl wdone";
if (exiting) return;
PIHTTPClient * c = nullptr;
{
auto cr = clients.getRef();
if (cr->isEmpty()) return;
c = cr->dequeue();
// piCout << "threadFuncl get c";
}
// piCout << "threadFuncl proc c";
procClient(c);
// piCout << "threadFuncl end";
}
void CurlThreadPool::procClient(PIHTTPClient * c) {
if (c->init()) c->perform();
delete c;
}
void CurlThreadPool::registerClient(PIHTTPClient * c) {
clients.getRef()->enqueue(c);
sem.release();
// piCout << "registerClient";
}
CurlThreadPool * CurlThreadPool::instance() {
static CurlThreadPool ret;
return &ret;
}

View File

@@ -1,31 +0,0 @@
#ifndef curl_thread_pool_p_H
#define curl_thread_pool_p_H
#include "piprotectedvariable.h"
#include "pisemaphore.h"
#include "pithread.h"
class PIHTTPClient;
class CurlThreadPool {
public:
void registerClient(PIHTTPClient * c);
static CurlThreadPool * instance();
private:
NO_COPY_CLASS(CurlThreadPool)
CurlThreadPool();
~CurlThreadPool();
void threadFunc();
void procClient(PIHTTPClient * c);
PIProtectedVariable<PIQueue<PIHTTPClient *>> clients;
PISemaphore sem;
PIVector<PIThread *> threads;
std::atomic_bool exiting = {false};
};
#endif

View File

@@ -1,237 +0,0 @@
#include "pihttpclient.h"
#include "curl_thread_pool_p.h"
#include "piliterals_bytes.h"
#include "piliterals_string.h"
#include "pisystemtime.h"
#include <curl/curl.h>
#if !defined(CURL_WRITEFUNC_ERROR)
# define CURL_WRITEFUNC_ERROR 0xFFFFFFFF
#endif
int xfer_callback(void * ptr, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
return reinterpret_cast<PIHTTPClientBase *>(ptr)->__infoFunc(dltotal, dlnow, ultotal, ulnow);
}
int debug_callback(CURL * handle, curl_infotype type, char * data, size_t size, void * ptr) {
return reinterpret_cast<PIHTTPClientBase *>(ptr)->__debugFunc(type, data, size);
}
PRIVATE_DEFINITION_START(PIHTTPClient)
CURL * handle = nullptr;
curl_slist * header_list = nullptr;
PRIVATE_DEFINITION_END(PIHTTPClient)
PIHTTPClient::PIHTTPClient() {}
PIHTTPClient::~PIHTTPClient() {}
bool PIHTTPClient::init() {
if (is_cancel) return false;
PRIVATE->handle = curl_easy_init();
if (!PRIVATE->handle) return false;
auto ait = request.arguments().makeIterator();
while (ait.next()) {
if (!url.contains('?'))
url.append('?');
else
url.append('&');
url.append(ait.key().toPercentageEncoding());
url.append('=');
url.append(ait.value().toPercentageEncoding());
}
headers.clear();
auto hit = request.headers().makeIterator();
while (hit.next()) {
headers << hit.key() + ": " + hit.value();
}
for (const auto & h: headers)
PRIVATE->header_list = curl_slist_append(PRIVATE->header_list, h.dataAscii());
curl_easy_setopt(PRIVATE->handle, CURLOPT_WRITEDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_READDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_XFERINFODATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_DEBUGDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_HEADERDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_WRITEFUNCTION, writeMemoryFunc);
curl_easy_setopt(PRIVATE->handle, CURLOPT_READFUNCTION, readMemoryFunc);
curl_easy_setopt(PRIVATE->handle, CURLOPT_XFERINFOFUNCTION, xfer_callback);
curl_easy_setopt(PRIVATE->handle, CURLOPT_DEBUGFUNCTION, debug_callback);
curl_easy_setopt(PRIVATE->handle, CURLOPT_HEADERFUNCTION, headerFunc);
curl_easy_setopt(PRIVATE->handle, CURLOPT_URL, url.dataUTF8());
curl_easy_setopt(PRIVATE->handle, CURLOPT_CUSTOMREQUEST, PIHTTP::methodName(request.method()));
curl_easy_setopt(PRIVATE->handle, CURLOPT_HTTPHEADER, PRIVATE->header_list);
curl_easy_setopt(PRIVATE->handle, CURLOPT_NOPROGRESS, 0L);
// curl_easy_setopt(PRIVATE->handle, CURLOPT_VERBOSE, 1L);
// curl_easy_setopt(PRIVATE->handle, CURLOPT_ERRORBUFFER, buffer_error.data());
curl_easy_setopt(PRIVATE->handle, CURLOPT_SSL_VERIFYPEER, 0L);
if (request.body().isNotEmpty()) {
curl_easy_setopt(PRIVATE->handle, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(PRIVATE->handle, CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(request.body().size()));
}
return true;
}
void PIHTTPClient::perform() {
if (!PRIVATE->handle) return;
if (!is_cancel) {
// piCout << "perform ...";
PITimeMeasurer tm;
CURLcode res = curl_easy_perform(PRIVATE->handle);
// piCout << "done" << res << "in" << tm.elapsed_m() << ", bytes" << buffer_out.size();
if (res == CURLE_OK) {
reply.setBody(std::move(buffer_out));
if (on_finish) on_finish(reply);
} else {
if (res == CURLE_ABORTED_BY_CALLBACK || is_cancel) {
// piCerr << "curl_easy_perform() failed:" << curl_easy_strerror(res);
if (on_abort) on_abort(reply);
} else {
last_error = curl_easy_strerror(res);
if (on_error) on_error(reply);
}
}
}
// piCout << last_error;
if (PRIVATE->header_list) curl_slist_free_all(PRIVATE->header_list);
curl_easy_cleanup(PRIVATE->handle);
PRIVATE->handle = nullptr;
PRIVATE->header_list = nullptr;
}
void PIHTTPClient::procHeaderLine(PIString & line) {
if (line.startsWith("HTTP"_a)) {
// HTTP/Версия КодСостояния Пояснение
line.cutLeft(5);
line.takeWord();
int code = line.takeWord().toInt();
// piCout << "code" << code;
reply.setCode(static_cast<PIHTTP::Code>(code));
return;
}
int ind = line.find(':');
if (ind < 0) return;
PIString hname = line.takeLeft(ind);
line.cutLeft(1).trim();
reply.addHeader(hname, line);
}
size_t PIHTTPClient::writeMemoryFunc(void * contents, size_t size, size_t nmemb, void * ptr) {
size_t bytes = size * nmemb;
// piCout << "writeMemoryFunc" << bytes;
auto client = reinterpret_cast<PIHTTPClient *>(ptr);
if (client->is_cancel) return CURL_WRITEFUNC_ERROR;
client->buffer_out.append(contents, bytes);
return bytes;
}
size_t PIHTTPClient::readMemoryFunc(void * contents, size_t size, size_t nmemb, void * ptr) {
size_t bytes = size * nmemb;
// piCout << "readMemoryFunc" << bytes;
auto client = reinterpret_cast<PIHTTPClient *>(ptr);
if (client->is_cancel) return CURL_READFUNC_ABORT;
const auto & buffer(client->request.body());
if (buffer.isEmpty()) return 0;
// piCout << bytes;
ssize_t ret = piClamp<ssize_t>(bytes, 0, buffer.size_s() - client->read_pos);
if (ret < 0) ret = 0;
if (ret > 0) memcpy(contents, buffer.data(client->read_pos), ret);
return ret;
}
size_t PIHTTPClient::headerFunc(char * contents, size_t size, size_t nmemb, void * ptr) {
size_t bytes = size * nmemb;
auto client = reinterpret_cast<PIHTTPClient *>(ptr);
if (client->is_cancel) return CURL_WRITEFUNC_ERROR;
PIString line = PIString::fromUTF8(contents, bytes).trim();
if (line.isNotEmpty()) client->procHeaderLine(line);
return bytes;
}
int PIHTTPClient::infoFunc(ssize_t dltotal, ssize_t dlnow, ssize_t ultotal, ssize_t ulnow) {
// piCout << "infoFunc" << dltotal << dlnow << ultotal << ulnow;
if (is_cancel) return 1;
return 0;
}
int PIHTTPClient::debugFunc(int type, char * data, size_t size) {
// piCout << "debugFunc" << type << PIString::fromUTF8(data, size);
return 0;
}
PIHTTPClient * PIHTTPClient::create(const PIString & url_, PIHTTP::Method method, const PIHTTP::MessageConst & req) {
PIHTTPClient * ret = new PIHTTPClient();
static_cast<PIHTTP::MessageConst &>(ret->request) = req;
ret->request.setMethod(method);
ret->reply.setMethod(method);
ret->url = url_;
return ret;
}
PIHTTPClient * PIHTTPClient::onFinish(std::function<void()> f) {
return onFinish([f](const PIHTTP::MessageConst &) { f(); });
}
PIHTTPClient * PIHTTPClient::onFinish(std::function<void(const PIHTTP::MessageConst &)> f) {
on_finish = f;
return this;
}
PIHTTPClient * PIHTTPClient::onError(std::function<void()> f) {
return onError([f](const PIHTTP::MessageConst &) { f(); });
}
PIHTTPClient * PIHTTPClient::onError(std::function<void(const PIHTTP::MessageConst &)> f) {
on_error = f;
return this;
}
PIHTTPClient * PIHTTPClient::onAbort(std::function<void()> f) {
return onAbort([f](const PIHTTP::MessageConst &) { f(); });
}
PIHTTPClient * PIHTTPClient::onAbort(std::function<void(const PIHTTP::MessageConst &)> f) {
on_abort = f;
return this;
}
void PIHTTPClient::start() {
CurlThreadPool::instance()->registerClient(this);
}
void PIHTTPClient::abort() {
is_cancel = true;
}
int PIHTTPClientBase::__infoFunc(ssize_t dltotal, ssize_t dlnow, ssize_t ultotal, ssize_t ulnow) {
return reinterpret_cast<PIHTTPClient *>(this)->infoFunc(dltotal, dlnow, ultotal, ulnow);
}
int PIHTTPClientBase::__debugFunc(int type, char * data, size_t size) {
return reinterpret_cast<PIHTTPClient *>(this)->debugFunc(type, data, size);
}

View File

@@ -1,367 +0,0 @@
#include "microhttpd_server.h"
#include "piliterals_bytes.h"
#include "piliterals_string.h"
#include "piliterals_time.h"
#include <microhttpd.h>
// clang-format off
#ifdef QNX
# include <arpa/inet.h>
# include <sys/socket.h>
# include <sys/types.h>
# ifdef BLACKBERRY
# include <netinet/in.h>
# else
# include <sys/dcmd_io-net.h>
# endif
#else
# ifdef WINDOWS
# include <io.h>
# include <winsock2.h>
# include <ws2tcpip.h>
# else
# include <netinet/in.h>
# include <sys/socket.h>
# ifdef LWIP
# include <lwip/sockets.h>
# endif
# endif
#endif
// clang-format on
using namespace PIHTTP;
struct BasicAuthCred {
bool exists = false;
PIString user;
PIString pass;
};
struct MicrohttpdServerConnection {
bool checkBasicAuth();
bool ready();
int sendReply(const MessageMutable & r);
BasicAuthCred getBasicAuthCred();
bool done = false, authorized = false;
Method method = Method::Unknown;
PIString path;
PIByteArray body;
PIMap<PIString, PIString> headers, args, post;
MHD_Connection * connection = nullptr;
MicrohttpdServer * server = nullptr;
MHD_PostProcessor * postprocessor = nullptr;
};
bool MicrohttpdServerConnection::checkBasicAuth() {
if (headers.contains(Header::Authorization)) {
auto ba_up = getBasicAuthCred();
bool ok = false; // server->callback_auth(ba_up.user, ba_up.pass);
if (server->callback_auth) ok = server->callback_auth(ba_up.user, ba_up.pass);
if (ok) {
authorized = true;
return true;
}
}
// piCout << "miss authorization";
sendReply(MessageMutable::fromCode(Code::Unauthorized)
.addHeader(Header::WWWAuthenticate, "Basic realm=\"%1\", charset=\"UTF-8\""_a.arg(server->realm))
.setBody(PIByteArray::fromAscii("Authorization required")));
// piCout << "answer sent";
return false;
}
bool MicrohttpdServerConnection::ready() {
if (!server) return false;
if (done) return true;
done = true;
MessageMutable rep;
if (method == Method::Get) {
if (path == "/favicon.ico"_a) {
// piCout << "send favicon" << server->favicon.size() << "bytes";
rep.setBody(server->favicon);
sendReply(rep);
return true;
}
}
// piCout << "ready" << (int)method << path << body.size();
MessageMutable req;
req.setMethod(method);
req.setPath(path);
req.setBody(body);
req.headers() = headers;
req.arguments() = args;
rep.setCode(Code::BadRequest);
if (server->callback) rep = server->callback(req);
MicrohttpdServer::addFixedHeaders(rep);
sendReply(rep);
// piCout << "ready ok" << (int)rep.code() << rep.body().size();
return true;
}
int MicrohttpdServerConnection::sendReply(const MessageMutable & r) {
MHD_Response * response = MHD_create_response_from_buffer(r.body().size(), (void *)r.body().data(), MHD_RESPMEM_MUST_COPY);
if (!response) {
// piCout << "null response" << r.body.size() << (void *)r.body.data();
return MHD_NO;
}
auto it = r.headers().makeIterator();
while (it.next())
MHD_add_response_header(response, it.key().dataAscii(), it.value().dataUTF8());
// piCout << "status" << r.code;
int ret = MHD_queue_response(connection, static_cast<int>(r.code()), response);
MHD_destroy_response(response);
return ret;
}
BasicAuthCred MicrohttpdServerConnection::getBasicAuthCred() {
BasicAuthCred ret;
char * p = nullptr;
auto u = MHD_basic_auth_get_username_password(connection, &p);
if (u) {
ret.user = PIString::fromUTF8(u);
ret.exists = true;
MHD_free(u);
}
if (p) {
ret.pass = PIString::fromUTF8(p);
ret.exists = true;
MHD_free(p);
}
return ret;
}
void log_callback(void * cls, const char * fmt, va_list ap) {
MicrohttpdServer * server = (MicrohttpdServer *)cls;
piCout << "log" << server;
if (!server) return;
char buffer[1_KiB];
piZeroMemory(buffer, 1_KiB);
std::vsnprintf(buffer, 1_KiB, fmt, ap);
piCout << buffer;
}
int iterate_post(void * conn_cls,
MHD_ValueKind kind,
const char * key,
const char * filename,
const char * content_type,
const char * transfer_encoding,
const char * data,
uint64_t off,
size_t size) {
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)conn_cls;
if (!conn) return MHD_NO;
conn->post[PIString::fromUTF8(key)] = PIString::fromUTF8(data);
return MHD_YES;
}
void request_completed(void * cls, MHD_Connection * connection, void ** con_cls, MHD_RequestTerminationCode toe) {
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
// piCout << "request_completed" << conn << conn->headers << conn->post << '"' << conn->body << '"';
if (!conn) return;
if (conn->postprocessor) {
MHD_destroy_post_processor(conn->postprocessor);
conn->postprocessor = nullptr;
}
conn->ready();
piDeleteSafety(conn);
}
int header_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
if (!conn) return MHD_NO;
conn->headers[PIString::fromUTF8(key)] = PIString::fromUTF8(value);
return MHD_YES;
}
int args_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
if (!conn) return MHD_NO;
conn->args[PIString::fromUTF8(key)] = PIString::fromUTF8(value);
return MHD_YES;
}
int answer_callback(void * cls,
MHD_Connection * connection,
const char * url,
const char * method,
const char * version,
const char * upload_data,
size_t * upload_data_size,
void ** con_cls) {
MicrohttpdServer * server = (MicrohttpdServer *)cls;
Method m = Method::Unknown;
if (0 == strcmp(method, "GET"))
m = Method::Get;
else if (0 == strcmp(method, "POST"))
m = Method::Post;
else if (0 == strcmp(method, "HEAD"))
m = Method::Head;
else if (0 == strcmp(method, "PUT"))
m = Method::Put;
else if (0 == strcmp(method, "DELETE"))
m = Method::Delete;
else if (0 == strcmp(method, "CONNECT"))
m = Method::Connect;
else if (0 == strcmp(method, "OPTIONS"))
m = Method::Options;
else if (0 == strcmp(method, "TRACE"))
m = Method::Trace;
else if (0 == strcmp(method, "PATCH"))
m = Method::Patch;
if (m == Method::Unknown) {
piCout << "[MicrohttpdServer]"
<< "Warning:"
<< "Unknown method!";
return MHD_NO;
}
// piCout << "answer" << url << method << (int)m << server;
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
if (!conn) {
conn = new MicrohttpdServerConnection();
conn->connection = connection;
conn->server = server;
conn->path = PIString::fromUTF8(url);
conn->method = m;
MHD_get_connection_values(connection, MHD_HEADER_KIND, (MHD_KeyValueIterator)header_iterate, *con_cls);
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, (MHD_KeyValueIterator)args_iterate, *con_cls);
if (server->isBasicAuthEnabled() && !conn->authorized) {
if (!conn->checkBasicAuth()) return MHD_YES;
}
return MHD_YES;
}
if (m == Method::Unknown) {
return conn->sendReply(MessageMutable::fromCode(Code::MethodNotAllowed));
}
if (*upload_data_size) {
if (!conn->postprocessor) {
conn->postprocessor = MHD_create_post_processor(connection, 64_KiB, (MHD_PostDataIterator)iterate_post, (void *)conn);
}
conn->body.append(upload_data, *upload_data_size);
MHD_post_process(conn->postprocessor, upload_data, *upload_data_size);
*upload_data_size = 0;
} else {
// qDebug() << "answer ok";
if (!conn->ready()) return conn->sendReply(MessageMutable::fromCode(Code::InternalServerError));
}
return MHD_YES;
}
PRIVATE_DEFINITION_START(MicrohttpdServer)
MHD_Daemon * daemon;
PRIVATE_DEFINITION_END(MicrohttpdServer)
MicrohttpdServer::MicrohttpdServer() {
PRIVATE->daemon = nullptr;
opts[Option::ConnectionLimit] = FD_SETSIZE - 4;
opts[Option::ConnectionTimeout] = 0_s;
realm = "Restricted"_a;
}
MicrohttpdServer::~MicrohttpdServer() {
stop();
}
void MicrohttpdServer::setOption(Option o, PIVariant v) {
opts[o] = std::move(v);
}
void MicrohttpdServer::setFavicon(const PIByteArray & im) {
favicon = im;
}
bool MicrohttpdServer::listen(PINetworkAddress addr) {
stop();
uint flags = 0;
#if MHD_VERSION <= 0x00095100
flags |= MHD_USE_POLL_INTERNALLY;
#else
flags |= MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD;
#endif
if (opts.value(Option::HTTPSEnabled).toBool()) flags |= MHD_USE_TLS;
mem_key = opts.value(Option::HTTPSMemKey).toByteArray();
if (mem_key.isNotEmpty()) mem_key.append(0);
mem_cert = opts.value(Option::HTTPSMemCert).toByteArray();
if (mem_cert.isNotEmpty()) mem_cert.append(0);
key_pass = opts.value(Option::HTTPSKeyPassword).toByteArray();
if (key_pass.isNotEmpty()) key_pass.append(0);
sockaddr_in sa_addr;
piZeroMemory(sa_addr);
sa_addr.sin_port = htons(addr.port());
sa_addr.sin_addr.s_addr = addr.ip();
sa_addr.sin_family = AF_INET;
PIVector<MHD_OptionItem> options;
options.append({MHD_OPTION_EXTERNAL_LOGGER, (intptr_t)log_callback, this});
options.append({MHD_OPTION_NOTIFY_COMPLETED, (intptr_t)request_completed, nullptr});
options.append({MHD_OPTION_CONNECTION_LIMIT, opts.value(Option::ConnectionLimit).toInt(), nullptr});
options.append({MHD_OPTION_CONNECTION_TIMEOUT, piRound(opts.value(Option::ConnectionTimeout).toSystemTime().toSeconds()), nullptr});
options.append({MHD_OPTION_SOCK_ADDR, 0, &sa_addr});
if (opts.value(Option::HTTPSEnabled).toBool()) {
options.append({MHD_OPTION_HTTPS_MEM_KEY, 0, mem_key.data()});
options.append({MHD_OPTION_HTTPS_MEM_CERT, 0, mem_cert.data()});
options.append({MHD_OPTION_HTTPS_KEY_PASSWORD, 0, key_pass.data()});
}
options.append({MHD_OPTION_END, 0, nullptr});
PRIVATE->daemon = MHD_start_daemon(flags,
addr.port(),
nullptr,
nullptr,
(MHD_AccessHandlerCallback)answer_callback,
this,
MHD_OPTION_ARRAY,
options.data(),
MHD_OPTION_END);
return isListen();
}
bool MicrohttpdServer::isListen() const {
return PRIVATE->daemon;
}
void MicrohttpdServer::stop() {
if (PRIVATE->daemon) {
MHD_stop_daemon(PRIVATE->daemon);
PRIVATE->daemon = nullptr;
}
}
void MicrohttpdServer::addFixedHeaders(MessageMutable & msg) {
if (!msg.headers().contains(Header::ContentType)) {
if (msg.body().isNotEmpty()) {
if (msg.body().startsWith(PIByteArray::fromAscii("<!DOCTYPE html>")))
msg.addHeader(Header::ContentType, "text/html; charset=utf-8");
else if (msg.body()[0] == '[' || msg.body()[0] == '{')
msg.addHeader(Header::ContentType, "application/json; charset=utf-8");
}
}
msg.addHeader(Header::AccessControlAllowOrigin, "*");
}

View File

@@ -1,90 +0,0 @@
#include "pihttpserver.h"
#include "piliterals_string.h"
PIHTTPServer::PIHTTPServer() {
setRequestCallback([this](const PIHTTP::MessageConst & r) -> PIHTTP::MessageMutable {
PIHTTP::MessageMutable reply;
reply.setCode(PIHTTP::Code::NotFound);
auto in_path = r.path().split("/");
in_path.removeAll("");
auto it = functions.makeReverseIterator();
bool found = false;
while (it.next()) {
if (it.value().function) {
if (it.value().method == r.method()) {
if (it.value().match(in_path)) {
reply = it.value().function(r);
found = true;
break;
}
}
}
}
if (!found && unhandled) reply = unhandled(r);
auto hit = reply_headers.makeIterator();
while (hit.next())
reply.addHeader(hit.key(), hit.value());
return reply;
});
}
PIHTTPServer::~PIHTTPServer() {
stop();
}
void PIHTTPServer::registerPath(const PIString & path, PIHTTP::Method method, RequestFunction functor) {
auto & ep(functions[path + PIString::fromNumber(static_cast<int>(method))]);
ep.path = path.split("/");
ep.method = method;
ep.function = functor;
ep.path.removeAll("");
}
void PIHTTPServer::registerUnhandled(RequestFunction functor) {
unhandled = functor;
}
void PIHTTPServer::unregisterPath(const PIString & path, PIHTTP::Method method) {
auto pl = path.split("/");
pl.removeAll("");
auto it = functions.makeIterator();
while (it.next()) {
if (it.value().method == method) {
if (it.value().path == pl) {
functions.remove(it.key());
break;
}
}
}
}
void PIHTTPServer::unregisterPath(const PIString & path) {
auto pl = path.split("/");
pl.removeAll("");
auto it = functions.makeIterator();
PIStringList keys;
while (it.next()) {
if (it.value().path == pl) {
keys << it.key();
}
}
for (const auto & k: keys)
functions.remove(k);
}
bool PIHTTPServer::Endpoint::match(const PIStringList & in_path) const {
if (in_path.size() != path.size()) return false;
for (int i = 0; i < path.size_s(); ++i) {
if (path[i] == "*"_a) continue;
if (path[i] != in_path[i]) return false;
}
return true;
}

View File

@@ -1,270 +1,266 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Broadcast for all interfaces, including loopback Broadcast for all interfaces, including loopback
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "pibroadcast.h" #include "pibroadcast.h"
#include "piliterals_time.h" /** \class PIBroadcast
* \brief Broadcast for all interfaces, including loopback
/** \class PIBroadcast *
* \brief Broadcast for all interfaces, including loopback * \section PIBroadcast_synopsis Synopsis
* * %PIBroadcast used as multichannel IO device. It can use
* \section PIBroadcast_synopsis Synopsis * multicast, broadcast and loopback ethernet channels to
* %PIBroadcast used as multichannel IO device. It can use * send/receive packets. \a send() function send packet to
* multicast, broadcast and loopback ethernet channels to * all initialized ethernets. \a receiveEvent() raised on
* send/receive packets. \a send() function send packet to * packet received by any ethernet. All multi/broadcast
* all initialized ethernets. \a receiveEvent() raised on * ethernets created for all current addresses, obtained
* packet received by any ethernet. All multi/broadcast * by \a PIEthernets::allAddresses().
* ethernets created for all current addresses, obtained *
* by \a PIEthernets::allAddresses(). * * \a Multicast ethernets use \a multicastGroup() and \a multicastPort()
* * * \a Broadcast ethernets use \a broadcastPort()
* * \a Multicast ethernets use \a multicastGroup() and \a multicastPort() * * \a Loopback ethernet use \a loopbackPortsCount() started from \a loopbackPort()
* * \a Broadcast ethernets use \a broadcastPort() *
* * \a Loopback ethernet use \a loopbackPortsCount() started from \a loopbackPort() * %PIBroadcast starts thread, which every 3 seconds check if
* * current \a PIEthernet::allAddresses() was changed and call
* %PIBroadcast starts thread, which every 3 seconds check if * \a reinit() if it necessary.
* current \a PIEthernet::allAddresses() was changed and call *
* \a reinit() if it necessary. */
*
*/ #define MULTICAST_TTL 4
#define MULTICAST_TTL 4
PIBroadcast::PIBroadcast(bool send_only): PIThread(), PIEthUtilBase() {
_channels = All;
PIBroadcast::PIBroadcast(bool send_only): PIThread(), PIEthUtilBase() { eth_lo = 0;
_channels = All; mcast_address.set("232.13.3.14", 14100);
eth_lo = 0; lo_port = 14200;
mcast_address.set("232.13.3.14", 14100); lo_pcnt = 5;
lo_port = 14200; _started = false;
lo_pcnt = 5; _send_only = send_only;
_started = false; _reinit = true;
_send_only = send_only; }
_reinit = true;
}
PIBroadcast::~PIBroadcast() {
PIThread::stop();
PIBroadcast::~PIBroadcast() { mcast_mutex.unlock();
PIThread::stopAndWait(); destroyAll();
// mcast_mutex.unlock(); }
destroyAll();
}
void PIBroadcast::setChannels(PIBroadcast::Channels ch) {
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::setChannels(PIBroadcast::Channels ch) { _channels = ch;
PIMutexLocker ml(mcast_mutex); _reinit = true;
_channels = ch; }
_reinit = true;
}
void PIBroadcast::setMulticastGroup(const PIString & mg) {
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::setMulticastGroup(const PIString & mg) { mcast_address.setIP(mg);
PIMutexLocker ml(mcast_mutex); _reinit = true;
mcast_address.setIP(mg); }
_reinit = true;
}
void PIBroadcast::setMulticastPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::setMulticastPort(ushort port) { mcast_address.setPort(port);
PIMutexLocker ml(mcast_mutex); _reinit = true;
mcast_address.setPort(port); }
_reinit = true;
}
void PIBroadcast::setMulticastAddress(const PIEthernet::Address & addr) {
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::setMulticastAddress(const PINetworkAddress & addr) { mcast_address = addr;
PIMutexLocker ml(mcast_mutex); _reinit = true;
mcast_address = addr; }
_reinit = true;
}
void PIBroadcast::setBroadcastPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::setBroadcastPort(ushort port) { bcast_port = port;
PIMutexLocker ml(mcast_mutex); _reinit = true;
bcast_port = port; }
_reinit = true;
}
void PIBroadcast::setLoopbackPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::setLoopbackPort(ushort port) { lo_port = port;
PIMutexLocker ml(mcast_mutex); _reinit = true;
lo_port = port; }
_reinit = true;
}
void PIBroadcast::setLoopbackPortsCount(int count) {
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::setLoopbackPortsCount(int count) { lo_pcnt = count;
PIMutexLocker ml(mcast_mutex); _reinit = true;
lo_pcnt = count; }
_reinit = true;
}
void PIBroadcast::destroyAll() {
piForeach (PIEthernet * e, eth_mcast) {
void PIBroadcast::destroyAll() { e->stopThreadedRead();
for (auto * e: eth_mcast) { delete e;
e->stopAndWait(); }
piDeleteSafety(e); eth_mcast.clear();
} if (eth_lo) {
eth_mcast.clear(); eth_lo->stopThreadedRead();
if (eth_lo) { delete eth_lo;
eth_lo->stopAndWait(); eth_lo = 0;
piDeleteSafety(eth_lo); }
} }
}
void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
void PIBroadcast::initAll(PIVector<PINetworkAddress> al) { PIMutexLocker ml(mcast_mutex);
PIMutexLocker ml(mcast_mutex); destroyAll();
destroyAll(); _reinit = false;
_reinit = false; prev_al = al;
prev_al = al; al.removeAll(PIEthernet::Address("127.0.0.1"));
al.removeAll(PINetworkAddress("127.0.0.1")); al << mcast_address;
al << mcast_address; eth_mcast.clear();
eth_mcast.clear(); PIEthernet::InterfaceList ifaces = PIEthernet::interfaces();
PIEthernet::InterfaceList ifaces = PIEthernet::interfaces(); piForeachC (PIEthernet::Address & a, al) {
for (const auto & a: al) { PIEthernet * ce = 0;
PIEthernet * ce = 0; //piCout << "mcast try" << a;
// piCout << "mcast try" << a; if (_channels[Multicast]) {
if (_channels[Multicast]) { ce = new PIEthernet();
ce = new PIEthernet(); ce->setDebug(false);
ce->setDebug(false); ce->setName("PIMulticast_" + a.toString());
ce->setName("PIMulticast_" + a.toString()); ce->setParameters(0);
ce->setParameters(0); ce->setSendAddress(mcast_address);
ce->setSendAddress(mcast_address); ce->setMulticastTTL(MULTICAST_TTL);
ce->setMulticastTTL(MULTICAST_TTL); if (!_send_only) {
if (!_send_only) { ce->setReadAddress(a.ipString(), mcast_address.port());
ce->setReadAddress(a.ipString(), mcast_address.port()); ce->joinMulticastGroup(mcast_address.ipString());
ce->joinMulticastGroup(mcast_address.ipString()); //piCout << "mcast " << ce->readAddress() << ce->sendAddress();
// piCout << "mcast " << ce->readAddress() << ce->sendAddress(); if (ce->open()) {
if (ce->open()) { eth_mcast << ce;
eth_mcast << ce; CONNECTU(ce, threadedReadEvent, this, mcastRead);
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mcastRead); } else {
} else { delete ce;
delete ce; }
} } else {
} else { eth_mcast << ce;
eth_mcast << ce; }
} }
}
if (_channels[Broadcast]) {
if (_channels[Broadcast]) { ce = new PIEthernet();
ce = new PIEthernet(); ce->setDebug(false);
ce->setDebug(false); ce->setName("PIMulticast_" + a.toString());
ce->setName("PIMulticast_" + a.toString()); ce->setParameters(PIEthernet::Broadcast);
ce->setParameters(PIEthernet::Broadcast); const PIEthernet::Interface * cint = ifaces.getByAddress(a.ipString());
const PIEthernet::Interface * cint = ifaces.getByAddress(a.ipString()); PIEthernet::Address nm((cint == 0) ? "255.255.255.0" : cint->netmask);
PINetworkAddress nm((cint == 0) ? "255.255.255.0" : cint->netmask); ce->setSendAddress(PIEthernet::getBroadcast(a, nm).ipString(), bcast_port);
ce->setSendAddress(PIEthernet::getBroadcast(a, nm).ipString(), bcast_port); if (!_send_only) {
if (!_send_only) { ce->setReadAddress(PIEthernet::Address(a.ip(), bcast_port));
ce->setReadAddress(PINetworkAddress(a.ip(), bcast_port)); //piCout << "bcast " << ce->readAddress() << ce->sendAddress();
// piCout << "bcast " << ce->readAddress() << ce->sendAddress(); if (ce->open()) {
if (ce->open()) { eth_mcast << ce;
eth_mcast << ce; CONNECTU(ce, threadedReadEvent, this, mcastRead);
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mcastRead); } else {
} else { delete ce;
delete ce; }
} } else {
} else { eth_mcast << ce;
eth_mcast << ce; }
} }
} }
}
if (_channels[Loopback]) {
if (_channels[Loopback]) { eth_lo = new PIEthernet();
eth_lo = new PIEthernet(); eth_lo->setDebug(false);
eth_lo->setDebug(false); eth_lo->setName("PIMulticast_loopback");
eth_lo->setName("PIMulticast_loopback"); if (!_send_only) {
if (!_send_only) { eth_lo->setParameter(PIEthernet::ReuseAddress, false);
eth_lo->setParameter(PIEthernet::ReuseAddress, false); CONNECTU(eth_lo, threadedReadEvent, this, mcastRead);
CONNECT2(void, const uchar *, ssize_t, eth_lo, threadedReadEvent, this, mcastRead); for (int i = 0; i < lo_pcnt; ++i) {
for (int i = 0; i < lo_pcnt; ++i) { eth_lo->setReadAddress("127.0.0.1", lo_port + i);
eth_lo->setReadAddress("127.0.0.1", lo_port + i); if (eth_lo->open()) {
if (eth_lo->open()) { //piCout << "bind local to" << (lo_port + i);
// piCout << "bind local to" << (lo_port + i); break;
break; }
} }
} }
} }
} }
}
void PIBroadcast::send(const PIByteArray & data) {
void PIBroadcast::send(const PIByteArray & data) { if (!isRunning()) {
/*if (!isRunning()) { reinit();
reinit(); PIThread::start(3000);
PIThread::start(3000); }
}*/ PIByteArray cd = cryptData(data);
PIByteArray cd = cryptData(data); if (cd.isEmpty()) return;
if (cd.isEmpty()) return; PIMutexLocker ml(mcast_mutex);
PIMutexLocker ml(mcast_mutex); piForeach (PIEthernet * e, eth_mcast) e->send(cd);
for (auto * e: eth_mcast) if (eth_lo) {
e->send(cd); for (int i = 0; i < lo_pcnt; ++i) {
if (eth_lo) { eth_lo->send("127.0.0.1", lo_port + i, cd);
for (int i = 0; i < lo_pcnt; ++i) { }
eth_lo->send("127.0.0.1", lo_port + i, cd); }
} }
}
}
void PIBroadcast::startRead() {
if (!isRunning()) {
void PIBroadcast::startRead() { _started = false;
if (!isRunning()) { reinit();
_started = false; PIThread::start(3000);
reinit(); }
PIThread::start(3_s); if (_send_only) return;
} PIMutexLocker ml(mcast_mutex);
if (_send_only) return; piForeach (PIEthernet * e, eth_mcast) e->startThreadedRead();
PIMutexLocker ml(mcast_mutex); if (eth_lo) eth_lo->startThreadedRead();
for (auto * e: eth_mcast) _started = true;
e->startThreadedRead(); }
if (eth_lo) eth_lo->startThreadedRead();
_started = true;
} void PIBroadcast::stopRead() {
if (isRunning()) stop();
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::stopRead() { piForeach (PIEthernet * e, eth_mcast) e->stopThreadedRead();
if (isRunning()) stopAndWait(); if (eth_lo) eth_lo->stopThreadedRead();
PIMutexLocker ml(mcast_mutex); _started = false;
for (auto * e: eth_mcast) }
e->stopAndWait();
if (eth_lo) eth_lo->stopAndWait();
_started = false; void PIBroadcast::reinit() {
} initAll(PIEthernet::allAddresses());
if (_started) startRead();
}
void PIBroadcast::reinit() {
initAll(PIEthernet::allAddresses());
if (_started) startRead(); void PIBroadcast::mcastRead(uchar * data, int size) {
} PIByteArray cd = decryptData(PIByteArray(data, size));
if (cd.isEmpty()) return;
received(cd);
void PIBroadcast::mcastRead(const uchar * data, ssize_t size) { receiveEvent(cd);
PIByteArray cd = decryptData(PIByteArray(data, size)); }
if (cd.isEmpty()) return;
received(cd);
receiveEvent(cd); void PIBroadcast::run() {
} PIVector<PIEthernet::Address> al = PIEthernet::allAddresses();
mcast_mutex.lock();
bool r = _reinit, ac = (al != prev_al);
void PIBroadcast::run() { mcast_mutex.unlock();
PIVector<PINetworkAddress> al = PIEthernet::allAddresses(); if (ac || r) reinit();
mcast_mutex.lock(); if (ac) addressesChanged();
bool r = _reinit, ac = (al != prev_al); }
mcast_mutex.unlock();
if (ac || r) reinit();
if (ac) addressesChanged();
}

View File

@@ -1,131 +1,121 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Base class for ethernet utils Base class for ethernet utils
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piethutilbase.h" #include "piethutilbase.h"
#ifdef PIP_CRYPT
#include "pitranslator.h" # include "picrypt.h"
#ifdef PIP_CRYPT #endif
# include "picrypt.h"
#endif /** \class PIEthUtilBase
* \brief Base class for ethernet utils
/** \class PIEthUtilBase *
* \brief Base class for ethernet utils * \section PIEthUtilBase_synopsis Synopsis
* * %PIEthUtilBase provides crypt layer for derived classes:
* \section PIEthUtilBase_synopsis Synopsis * \a PIStreamPacker and \a PIBroadcast. All input and output
* %PIEthUtilBase provides crypt layer for derived classes: * (sended and received) data can be decrypted/encrypted by this layer.
* \a PIStreamPacker and \a PIBroadcast. All input and output *
* (sended and received) data can be decrypted/encrypted by this layer. * By default crypt layer is disabled.
* *
* By default crypt layer is disabled. * You can separetely enable it and set ready-to-use
* * key by \a setCryptEnabled() and \a setCryptKey(). Or you can
* You can separetely enable it and set ready-to-use * use \a createCryptKey() to generate key from your passphrase
* key by \a setCryptEnabled() and \a setCryptKey(). Or you can * and automatic enable crypt layer.
* use \a createCryptKey() to generate key from your passphrase *
* and automatic enable crypt layer. * \note To use crypt layer, PIP should be built with crypt module,
* * otherwise your in/out data will be lost.
* \note To use crypt layer, PIP should be built with crypt module, *
* otherwise your in/out data will be lost. * You can use this class as base for your own classes. Use \a cryptData()
* * and \a decryptData() when send and receive your data.
* You can use this class as base for your own classes. Use \a cryptData() *
* and \a decryptData() when send and receive your data. */
*
*/
PIEthUtilBase::PIEthUtilBase() {
_crypt = false;
PIEthUtilBase::PIEthUtilBase() { }
_crypt = false;
}
PIEthUtilBase::~PIEthUtilBase() {
}
PIEthUtilBase::~PIEthUtilBase() {}
void PIEthUtilBase::setCryptEnabled(bool on) {
void PIEthUtilBase::setCryptEnabled(bool on) { _crypt = on;
_crypt = on; }
}
void PIEthUtilBase::cryptEnable() {
void PIEthUtilBase::cryptEnable() { setCryptEnabled(true);
setCryptEnabled(true); }
}
void PIEthUtilBase::cryptDisable() {
void PIEthUtilBase::cryptDisable() { setCryptEnabled(false);
setCryptEnabled(false); }
}
bool PIEthUtilBase::isCryptEnabled() const {
bool PIEthUtilBase::isCryptEnabled() const { return _crypt;
return _crypt; }
}
void PIEthUtilBase::setCryptKey(const PIByteArray & k) {
void PIEthUtilBase::setCryptKey(const PIByteArray & k) { _key = k;
_key = k; setCryptEnabled(true);
setCryptEnabled(true); }
}
void PIEthUtilBase::createCryptKey(const PIString & k) {
void PIEthUtilBase::createCryptKey(const PIString & k) { #ifdef PIP_CRYPT
#ifdef PIP_CRYPT _key = PICrypt::hash("sodium_bug");
_key = PICrypt::hash("sodium_bug"); _key = PICrypt::hash(k);
_key = PICrypt::hash(k); #else
#else piCout << "[PIEthUtilBase] PICrypt wasn`t built!";
piCout << "[PIEthUtilBase]" #endif
<< "PICrypt wasn`t built!"_tr("PIEthUtilBase"); _crypt = true;
#endif }
_crypt = true;
}
PIByteArray PIEthUtilBase::cryptKey() const {
return _key;
PIByteArray PIEthUtilBase::cryptKey() const { }
return _key;
}
PIByteArray PIEthUtilBase::cryptData(const PIByteArray & data) {
if (!_crypt) return data;
PIByteArray PIEthUtilBase::cryptData(const PIByteArray & data) { return
if (!_crypt) return data; #ifdef PIP_CRYPT
return PICrypt::crypt(data, _key);
#ifdef PIP_CRYPT #else
PICrypt::crypt(data, _key); PIByteArray();
#else #endif
PIByteArray(); }
#endif
}
PIByteArray PIEthUtilBase::decryptData(const PIByteArray & data) {
if (!_crypt) return data;
PIByteArray PIEthUtilBase::decryptData(const PIByteArray & data) { #ifdef PIP_CRYPT
if (!_crypt) return data; bool ok = false;
#ifdef PIP_CRYPT PIByteArray ret = PICrypt::decrypt(data, _key, &ok);
bool ok = false; if (!ok) return PIByteArray();
PIByteArray ret = PICrypt::decrypt(data, _key, &ok); return ret;
if (!ok) return PIByteArray(); #else
return ret; return PIByteArray();
#else #endif
return PIByteArray(); }
#endif
}
size_t PIEthUtilBase::cryptSizeAddition() {
#ifdef PIP_CRYPT
return PICrypt::sizeCrypt();
#else
return 0;
#endif
}

View File

@@ -1,199 +0,0 @@
/*
PIP - Platform Independent Primitives
PIPackedTCP
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pipackedtcp.h"
#include "piethernet.h"
#include "piliterals.h"
/** \class PIPackedTCP pipackedtcp.h
* \brief
* TCP packed channel
*
* \details
* \section PITCP_sec0 Synopsis
* %PIEthernet designed to work with IPv4 network via two protocols:
* UDP and TCP. This class allow you send and receive packets to/from
* another computer through network. Also it supports broadcast and
* multicast extensions.
*
* */
PIPackedTCP::PIPackedTCP(Role role, const PINetworkAddress & addr): m_role(role) {
setMode(PIIODevice::ReadWrite);
packer.setCryptEnabled(false);
CONNECTL(&packer, packetReceiveEvent, [this](PIByteArray & data) {
PIMutexLocker ml(rec_mutex);
rec_queue.enqueue(data);
});
init();
setAddress(addr);
}
PIPackedTCP::~PIPackedTCP() {
stopAndWait();
if (client) client->stopAndWait();
if (eth) eth->stopAndWait();
piDeleteSafety(eth);
}
void PIPackedTCP::setAddress(const PINetworkAddress & addr) {
m_addr = addr;
setPath(m_addr.toString());
}
bool PIPackedTCP::isConnected() const {
if (m_role == Client) {
return eth->isConnected();
} else {
if (client) return client->isConnected();
}
return false;
}
bool PIPackedTCP::isConnecting() const {
if (m_role == Client) {
return eth->isConnecting();
} else {
if (client) return client->isConnecting();
}
return false;
}
void PIPackedTCP::init() {
if (client) client->stopAndWait();
if (eth) eth->stopAndWait();
piDeleteSafety(eth);
eth = new PIEthernet(m_role == Client ? PIEthernet::TCP_Client : PIEthernet::TCP_Server);
if (m_role == Client) {
eth->setReopenTimeout(100_ms);
packer.assignDevice(eth);
CONNECTL(eth, connected, [this]() {
packer.clear();
connected();
});
CONNECTL(eth, disconnected, [this](bool) {
packer.clear();
eth->connect(path(), true);
disconnected();
});
} else {
CONNECTL(eth, newConnection, [this](PIEthernet * c) {
if (client) client->stopAndWait();
piDeleteSafety(client);
client = c;
// piCout << "Server connected" << client;
packer.assignDevice(client);
CONNECTL(client, disconnected, [this](bool) {
// packer.assignDevice(nullptr); WTF?
packer.clear();
disconnected();
});
client->startThreadedRead();
connected();
});
}
}
PIIODevice::DeviceInfoFlags PIPackedTCP::deviceInfoFlags() const {
return PIIODevice::Reliable;
}
PIString PIPackedTCP::constructFullPathDevice() const {
return PIString(m_role == Client ? "client" : "server") + ":" + path();
}
void PIPackedTCP::configureFromFullPathDevice(const PIString & full_path) {
PIStringList pl = full_path.split(":");
if (pl.size() >= 1) {
PIString p = pl[0].toLowerCase().left(1);
if (p == "c") m_role = Client;
if (p == "s") m_role = Server;
init();
}
PINetworkAddress addr("0.0.0.0", 13362);
if (pl.size() >= 2) {
if (pl[1].isNotEmpty()) addr.setIP(pl[1]);
}
if (pl.size() >= 3) {
if (pl[2].isNotEmpty()) addr.setPort(pl[2].toInt());
}
setAddress(addr);
}
ssize_t PIPackedTCP::readDevice(void * read_to, ssize_t max_size) {
PIMutexLocker ml(rec_mutex);
if (rec_queue.isNotEmpty()) {
auto d = rec_queue.dequeue();
auto sz = piMin(max_size, d.size_s());
if (read_to) memcpy(read_to, d.data(), sz);
return sz;
}
return 0;
}
ssize_t PIPackedTCP::writeDevice(const void * data, ssize_t max_size) {
if (!isConnected()) return 0;
packer.send(PIByteArray(data, max_size));
// piCout << m_role << "write" << eth;
return max_size;
/*if (m_role == Client) {
return eth->write(data, max_size);
} else {
if (client) return client->write(data, max_size);
}*/
}
bool PIPackedTCP::openDevice() {
if (m_role == Client) {
if (eth->isConnected()) return true;
if (eth->isConnecting()) return false;
packer.clear();
bool ret = eth->connect(path(), false);
eth->startThreadedRead();
return ret;
} else {
return eth->listen(path(), false);
}
return false;
}
bool PIPackedTCP::closeDevice() {
if (client) {
client->close();
client->stopAndWait();
piDeleteSafety(client);
// packer.assignDevice(nullptr); WTF?
}
return eth->close();
}

View File

@@ -1,176 +1,202 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Simple packet wrap aroud any PIIODevice Simple packet wrap aroud any PIIODevice
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef __GNUC__ #ifdef __GNUC__
# pragma GCC diagnostic push # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnonnull" # pragma GCC diagnostic ignored "-Wnonnull"
#endif #endif
#include "pistreampacker.h" #include "pistreampacker.h"
#include "piiodevice.h"
#include "piiodevice.h" #ifdef __GNUC__
#include "pitranslator.h" # pragma GCC diagnostic pop
#ifdef __GNUC__ #endif
# pragma GCC diagnostic pop
#endif /** \class PIStreamPacker
* \brief Simple packet wrap aroud any PIIODevice
/** \class PIStreamPacker *
* \brief Simple packet wrap aroud any PIIODevice * \section PIStreamPacker_synopsis Synopsis
* * %PIStreamPacker provides simple pack/unpack logic for any data packets.
* \section PIStreamPacker_synopsis Synopsis *
* %PIStreamPacker provides simple pack/unpack logic for any data packets. * When you call \a send() function data splited into several
* * parts, \a packetSign() prepended to first part and \a sendRequest()
* When you call \a send() function data splited into several * event raised several times.
* parts, \a packetSign() prepended to first part and \a sendRequest() *
* event raised several times. * When your device receive some data, call \a received() function.
* * \a packetReceiveEvent() event will be raised when packet will be
* When your device receive some data, call \a received() function. * collected.
* \a packetReceiveEvent() event will be raised when packet will be *
* collected. * Use \a assignDevice() to connect device to this %PIStreamPacker.
* *
* Use \a assignDevice() to connect device to this %PIStreamPacker. */
*
*/
PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() {
crypt_frag = crypt_size = false;
PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() { aggressive_optimization = true;
packet_size = -1; packet_size = -1;
if (dev) assignDevice(dev); size_crypted_size = sizeof(int);
} crypt_frag_size = 1024*1024;
max_packet_size = 1400;
void PIStreamPacker::clear() { packet_sign = 0xAFBE;
packet.clear(); assignDevice(dev);
packet_size = -1; }
stream.clear();
}
void PIStreamPacker::setCryptSizeEnabled(bool on) {
crypt_size = on;
void PIStreamPacker::send(const PIByteArray & data) { if (crypt_size) {
if (data.isEmpty()) return; PIByteArray ba; ba << int(0);
PIByteArray cd = cryptData(data); size_crypted_size = cryptData(ba).size_s();
// piCout << "crypt" << data.size() << "->" << cd.size() << key().size(); } else
PIByteArray hdr, part; size_crypted_size = sizeof(int);
hdr << packet_sign; }
if (crypt_size) {
PIByteArray crsz;
crsz << int(cd.size_s()); void PIStreamPacker::clear() {
hdr.append(cryptData(crsz)); packet.clear();
} else packet_size = -1;
hdr << int(cd.size_s()); stream.clear();
cd.insert(0, hdr); }
int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
for (int i = 0; i < pcnt; ++i) {
if (i == pcnt - 1) void PIStreamPacker::send(const PIByteArray & data) {
part = PIByteArray(cd.data(pst), cd.size_s() - pst); if (data.isEmpty()) return;
else PIByteArray cd;
part = PIByteArray(cd.data(pst), max_packet_size); if (crypt_frag) {
// piCout << "send" << part.size(); int fcnt = (data.size_s() - 1) / crypt_frag_size + 1, fst = 0;
sendRequest(part); //piCout << "crypt_frag send" << fcnt << "frags";
pst += max_packet_size; PIByteArray frag;
} for (int i = 0; i < fcnt; ++i) {
} if (i == fcnt - 1) frag = PIByteArray(data.data(fst), data.size_s() - fst);
else frag = PIByteArray(data.data(fst), crypt_frag_size);
fst += crypt_frag_size;
void PIStreamPacker::received(const uchar * readed, ssize_t size) { cd << cryptData(frag);
if (size <= 0) return; }
received(PIByteArray(readed, size)); } else {
} cd = cryptData(data);
}
//piCout << "crypt" << data.size() << "->" << cd.size() << key().size();
void PIStreamPacker::received(const PIByteArray & data) { PIByteArray hdr, part;
stream.append(data); hdr << packet_sign;
// piCout << "rec" << data.size(); if (crypt_size) {
while (!stream.isEmpty()) { PIByteArray crsz; crsz << int(cd.size_s());
int hdr_size = sizeof(packet_sign) + sizeCryptedSize(); hdr.append(cryptData(crsz));
if (packet_size < 0) { } else
if (stream.size_s() < hdr_size) return; hdr << int(cd.size_s());
ushort sign(0); cd.insert(0, hdr);
memcpy(&sign, stream.data(), 2); int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
if (sign != packet_sign) { for (int i = 0; i < pcnt; ++i) {
if (aggressive_optimization) if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst);
stream.clear(); else part = PIByteArray(cd.data(pst), max_packet_size);
else //piCout << "send" << part.size();
stream.pop_front(); sendRequest(part);
continue; pst += max_packet_size;
} }
int sz = -1; }
if (crypt_size) {
PIByteArray crsz(sizeCryptedSize());
memcpy(crsz.data(), stream.data(2), crsz.size()); void PIStreamPacker::received(uchar * readed, int size) {
crsz = decryptData(crsz); received(PIByteArray(readed, size));
if (crsz.size() < sizeof(sz)) { }
if (aggressive_optimization)
stream.clear();
else void PIStreamPacker::received(const PIByteArray & data) {
stream.pop_front(); stream.append(data);
continue; //piCout << "rec" << data.size();
} while (!stream.isEmpty()) {
crsz >> sz; int hdr_size = sizeof(packet_sign) + size_crypted_size;
} else { if (packet_size < 0) {
memcpy(&sz, stream.data(2), sizeCryptedSize()); if (stream.size_s() < hdr_size) return;
} ushort sign(0);
if (sz < 0) { memcpy(&sign, stream.data(), 2);
if (aggressive_optimization) if (sign != packet_sign) {
stream.clear(); if (aggressive_optimization) stream.clear();
else else stream.pop_front();
stream.pop_front(); continue;
continue; }
} int sz = -1;
stream.remove(0, hdr_size); if (crypt_size) {
packet.clear(); PIByteArray crsz((uint)size_crypted_size);
packet_size = sz; memcpy(crsz.data(), stream.data(2), size_crypted_size);
if (packet_size == 0) crsz = decryptData(crsz);
packet_size = -1; if (crsz.size() < sizeof(sz)) {
else if (aggressive_optimization) stream.clear();
startPacketReceive(packet_size); else stream.pop_front();
continue; continue;
} else { }
int ps = piMini(stream.size_s(), packet_size - packet.size_s()); crsz >> sz;
packet.append(stream.data(), ps); } else {
stream.remove(0, ps); memcpy(&sz, stream.data(2), size_crypted_size);
if (packet.size_s() == packet_size) { }
PIByteArray cd = decryptData(packet); if (sz < 0) {
// piCout << "decrypt" << packet.size() << "->" << cd.size() << key().size(); if (aggressive_optimization) stream.clear();
if (!cd.isEmpty()) { else stream.pop_front();
endPacketReceive(); continue;
packetReceived(cd); }
packetReceiveEvent(cd); stream.remove(0, hdr_size);
} packet.clear();
packet.clear(); packet_size = sz;
packet_size = -1; if (packet_size == 0)
} packet_size = -1;
} continue;
} } else {
} int ps = piMini(stream.size_s(), packet_size - packet.size_s());
packet.append(stream.data(), ps);
stream.remove(0, ps);
void PIStreamPacker::assignDevice(PIIODevice * dev) { if (packet.size_s() == packet_size) {
if (!dev) { PIByteArray cd;
piCoutObj << "Error! device is NULL"; if (crypt_frag) {
return; //piCout << "decrypt frags ..." << packet_size;
} while (packet.size_s() >= 4) {
if (!dev->infoFlags()[PIIODevice::Reliable]) { //piCout << "decrypt frags take data ...";
piCoutObj << "Warning! Not recommended to use with non-reliable device"_tr("PIStreamPacker") << dev; PIByteArray frag;
} //piCout << "decrypt frags take data done" << frag.size_s();
CONNECT2(void, const uchar *, ssize_t, dev, threadedReadEvent, this, received); packet >> frag;
CONNECT1(void, PIByteArray, this, sendRequest, dev, write); if (frag.isEmpty()) {
} //piCout << "decrypt frags corrupt, break";
cd.clear();
uint PIStreamPacker::sizeCryptedSize() { break;
return sizeof(int) + (crypt_size ? cryptSizeAddition() : 0); }
} cd.append(decryptData(frag));
//piCout << "decrypt frags add" << frag.size_s();
}
//piCout << "decrypt frags done" << cd.size();
} else {
cd = decryptData(packet);
}
//piCout << "decrypt" << packet.size() << "->" << cd.size() << key().size();
if (!cd.isEmpty()) {
packetReceived(cd);
packetReceiveEvent(cd);
}
packet.clear();
packet_size = -1;
}
}
}
}
void PIStreamPacker::assignDevice(PIIODevice * dev) {
if (!dev) return;
if (!dev->infoFlags()[PIIODevice::Reliable])
piCoutObj << "Warning! Not recommended to use with non-reliable" << dev;
CONNECTU(dev, threadedReadEvent, this, received);
CONNECTU(this, sendRequest, dev, write);
}

View File

@@ -1,20 +1,20 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PILuaProgram PILuaProgram
Andrey Bychkov work.a.b@yandex.ru Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piluaprogram.h" #include "piluaprogram.h"
@@ -50,3 +50,4 @@ luabridge::LuaRef PILuaProgram::getGlobal(const PIString & name) {
luabridge::Namespace PILuaProgram::getGlobalNamespace() { luabridge::Namespace PILuaProgram::getGlobalNamespace() {
return luabridge::getGlobalNamespace(PRIVATE->lua_state); return luabridge::getGlobalNamespace(PRIVATE->lua_state);
} }

View File

@@ -1,60 +0,0 @@
/*
PIP - Platform Independent Primitives
Module includes
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//! \defgroup Application Application
//! \~\brief
//! \~english Application-level classes.
//! \~russian Классы уровня "приложение".
//!
//! \~\details
//! \~english \section cmake_module_Application Building with CMake
//! \~russian \section cmake_module_Application Сборка с использованием CMake
//!
//! \~\code
//! find_package(PIP REQUIRED)
//! target_link_libraries([target] PIP)
//! \endcode
//!
//! \~english \par Common
//! \~russian \par Общее
//!
//! \~english
//! These files provides some classes for help to create application
//!
//! \~russian
//! Эти файлы предоставляют классы для облегчения создания приложения
//!
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//!
#ifndef PIAPPLICATIONMODULE_H
#define PIAPPLICATIONMODULE_H
#include "picli.h"
#include "pilog.h"
#include "pisingleapplication.h"
#include "pisystemmonitor.h"
#include "pitranslator.h"
#endif

View File

@@ -1,256 +0,0 @@
/*
PIP - Platform Independent Primitives
Command-Line Parser
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "picli.h"
#include "pisysteminfo.h"
#include "pitranslator.h"
//! \class PICLI picli.h
//! \details
//! \~english \section PICLI_sec0 Synopsis
//! \~russian \section PICLI_sec0 Краткий обзор
//! \~english
//! This class provide handy parsing of command-line arguments. First you should add
//! arguments to %PICLI with function \a addArgument(). Then you can check if there
//! is some argument in application command-line with function \a hasArgument(),
//! or obtain argument value by \a argumentValue().
//!
//! \~russian
//! Этот класс предоставляет удобный механизм для разбора аргументов командной строки.
//! Сперва необходимо добавить аргументы в %PICLI с помощью методов \a addArgument().
//! Далее можно проверять аргументы на наличие в командной строке методом \a hasArgument(),
//! а также получать их значения при помощи \a argumentValue().
//!
//! \~english \section PICLI_sec1 Example
//! \~russian \section PICLI_sec1 Пример
//! \~\code
//! int main(int argc, char ** argv) {
//! PICLI cli(argc, argv);
//! cli.addArgument("console");
//! cli.addArgument("debug");
//! cli.addArgument("Value", "v", "value", true);
//! if (cli.hasArgument("console"))
//! piCout << "console active";
//! if (cli.hasArgument("debug"))
//! piCout << "debug active";
//! piCout << "Value =" << cli.argumentValue("Value");
//! return 0;
//! }
//! \endcode
//!
//! \~english These executions are similar:
//! \~russian Эти вызовы будут идентичны:
//!
//! \~\code
//! a.out -cd -v 10
//! a.out --value 10 -dc
//! a.out -c -v 10 -d
//! a.out --console -d -v 10
//! a.out --debug -c --value 10
//! \endcode
//!
PICLI::PICLI(int argc, char * argv[]) {
for (int i = 0; i < argc; ++i)
_args_raw << argv[i];
if (argc > 0) PISystemInfo::instance()->execCommand = argv[0];
}
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);
for (auto & 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;
for (auto & a: _args) {
if ((a.short_key != '\0') && (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 << "Arguments overflow, \"%1\" ignored"_tr("PICLI").arg(cra);
}
if (last == 0 ? false : last->has_value) {
last->value = cra;
last = 0;
}
}
}
}
needParse = false;
}
void PICLI::addArgument(const PIString & name, bool value) {
_args << Argument(name, name[0], name, value);
needParse = true;
}
void PICLI::addArgument(const PIString & name, const PIChar & shortKey, bool value) {
_args << Argument(name, shortKey, name, value);
needParse = true;
}
void PICLI::addArgument(const PIString & name, const char * shortKey, bool value) {
_args << Argument(name, PIChar::fromUTF8(shortKey), name, value);
needParse = true;
}
void PICLI::addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value) {
_args << Argument(name, shortKey, fullKey, value);
needParse = true;
}
void PICLI::addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value) {
_args << Argument(name, PIChar::fromUTF8(shortKey), fullKey, value);
needParse = true;
}
PIString PICLI::rawArgument(int index) {
parse();
return _args_raw[index];
}
PIString PICLI::mandatoryArgument(int index) {
parse();
return _args_mand[index];
}
PIString PICLI::optionalArgument(int index) {
parse();
return _args_opt[index];
}
const PIStringList & PICLI::rawArguments() {
parse();
return _args_raw;
}
const PIStringList & PICLI::mandatoryArguments() {
parse();
return _args_mand;
}
const PIStringList & PICLI::optionalArguments() {
parse();
return _args_opt;
}
PIString PICLI::programCommand() {
parse();
return _args_raw.isNotEmpty() ? _args_raw.front() : PIString();
}
bool PICLI::hasArgument(const PIString & name) {
parse();
for (const auto & i: _args)
if (i.name == name && i.found) return true;
return false;
}
PIString PICLI::argumentValue(const PIString & name) {
parse();
for (const auto & i: _args)
if (i.name == name && i.found) return i.value;
return PIString();
}
PIString PICLI::argumentShortKey(const PIString & name) {
for (const auto & i: _args)
if (i.name == name) return PIString(i.short_key);
return PIString();
}
PIString PICLI::argumentFullKey(const PIString & name) {
for (const auto & i: _args)
if (i.name == name) return i.full_key;
return PIString();
}
void PICLI::setShortKeyPrefix(const PIString & prefix) {
_prefix_short = prefix;
needParse = true;
}
void PICLI::setFullKeyPrefix(const PIString & prefix) {
_prefix_full = prefix;
needParse = true;
}
void PICLI::setMandatoryArgumentsCount(const int count) {
_count_mand = count;
needParse = true;
}
void PICLI::setOptionalArgumentsCount(const int count) {
_count_opt = count;
needParse = true;
}

View File

@@ -1,136 +0,0 @@
/*! \file picli.h
* \ingroup Application
* \~\brief
* \~english Command-Line parser
* \~russian Парсер командной строки
*/
/*
PIP - Platform Independent Primitives
Command-Line Parser
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICLI_H
#define PICLI_H
#include "piset.h"
#include "pistringlist.h"
//! \ingroup Application
//! \~\brief
//! \~english Command-Line parser.
//! \~russian Парсер командной строки.
class PIP_EXPORT PICLI {
public:
//! \~english Constructs %PICLI from "argc" and "argv" from "int main()" method.
//! \~russian Создает %PICLI из "argc" и "argv" из метода "int main()".
PICLI(int argc, char * argv[]);
//! \~english Add argument with name "name", short key = name first letter and full key = name.
//! \~russian Добавляет аргумент с именем "name", коротким ключом = первой букве имени и полным ключом = имени.
void addArgument(const PIString & name, bool value = false);
//! \~english Add argument with name "name", short key = "shortKey" and full key = name.
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени.
void addArgument(const PIString & name, const PIChar & shortKey, bool value = false);
//! \~english Add argument with name "name", short key = "shortKey" and full key = name.
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени.
void addArgument(const PIString & name, const char * shortKey, bool value = false);
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey".
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey".
void addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value = false);
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey".
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey".
void addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value = false);
//! \~english Returns unparsed command-line argument by index "index". Index 0 is program execute command.
//! \~russian Возвращает исходный аргумент командной строки по индексу "index". Индекс 0 это команда вызова программы.
PIString rawArgument(int index);
PIString mandatoryArgument(int index);
PIString optionalArgument(int index);
//! \~english Returns unparsed command-line arguments.
//! \~russian Возвращает исходные аргументы командной строки.
const PIStringList & rawArguments();
const PIStringList & mandatoryArguments();
const PIStringList & optionalArguments();
//! \~english Returns program execute command without arguments.
//! \~russian Возвращает команду вызова программы без аргументов.
PIString programCommand();
//! \~english Returns if argument "name" found.
//! \~russian Возвращает найден ли аргумент "name".
bool hasArgument(const PIString & name);
//! \~english Returns argument "name" value, or empty string if this is no value.
//! \~russian Возвращает значение аргумента "name" или пустую строку, если значения нет.
PIString argumentValue(const PIString & name);
//! \~english Returns short key of argument "name", or empty string if this is no argument.
//! \~russian Возвращает короткий ключ аргумента "name" или пустую строку, если аргумента нет.
PIString argumentShortKey(const PIString & name);
//! \~english Returns full key of argument "name", or empty string if this is no argument.
//! \~russian Возвращает полный ключ аргумента "name" или пустую строку, если аргумента нет.
PIString argumentFullKey(const PIString & name);
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);
void setFullKeyPrefix(const PIString & prefix);
void setMandatoryArgumentsCount(const int count);
void setOptionalArgumentsCount(const int count);
bool debug() const { return debug_; }
void setDebug(bool debug) { debug_ = debug; }
PIConstChars className() const { return "PICLI"; }
PIString name() const { return PIStringAscii("CLI"); }
private:
struct Argument {
Argument() {}
Argument(const PIString & n, const PIChar & s, const PIString & f, bool v) {
name = n;
short_key = s;
full_key = f;
has_value = v;
}
PIString name;
PIChar short_key;
PIString full_key;
PIString value;
bool has_value = false, found = false;
};
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 = 0, _count_opt = 0;
bool needParse = true, debug_ = true;
};
#endif // PICLI_H

View File

@@ -1,247 +0,0 @@
/*
PIP - Platform Independent Primitives
High-level log
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pilog.h"
#include "pidir.h"
#include "piliterals_string.h"
#include "piliterals_time.h"
#include "pitime.h"
//! \class PILog pilog.h
//! \details
//! \~english \section PILog_sec0 Synopsis
//! \~russian \section PILog_sec0 Краткий обзор
//! \~english
//! This class provides log with optional file and console output.
//!
//! \~russian
//! Этот класс предоставляет лог с опциональным выводом в файл и консоль.
//!
PILog::PILog(): PIThread(), log_ts(&log_file) {
setName("PILog");
split_time = 8_h;
timestamp_format = "yyyy-MM-dd hh:mm:ss.zzz";
setLineFormat("t - c: m");
id_by_cat[Level::Info] = PICout::registerExternalBufferID();
id_by_cat[Level::Debug] = PICout::registerExternalBufferID();
id_by_cat[Level::Warning] = PICout::registerExternalBufferID();
id_by_cat[Level::Error] = PICout::registerExternalBufferID();
CONNECTU(PICout::Notifier::object(), finished, this, coutDone);
}
PILog::~PILog() {
stop();
}
void PILog::setDir(const PIString & d) {
stopAndWait();
log_dir = d;
if (output[File]) {
PIDir::make(log_dir);
newFile();
}
start();
}
void PILog::setLineFormat(const PIString & f) {
line_format = f;
line_format_p = line_format;
line_format_p.replace("t", "${t}").replace("c", "${c}").replace("m", "${m}");
}
void PILog::setLevel(Level l) {
max_level = l;
}
PICout PILog::error(PIObject * context) {
return makePICout(context, Level::Error);
}
PICout PILog::warning(PIObject * context) {
return makePICout(context, Level::Warning);
}
PICout PILog::info(PIObject * context) {
return makePICout(context, Level::Info);
}
PICout PILog::debug(PIObject * context) {
return makePICout(context, Level::Debug);
}
void PILog::stop() {
while (true) {
log_mutex.lock();
bool done = queue.isEmpty();
log_mutex.unlock();
if (done) break;
piMinSleep();
}
PIThread::stopAndWait();
}
PIStringList PILog::readAllLogs() const {
PIMap<PISystemTime, PIString> names;
auto dir = PIDir(log_dir);
auto fil = dir.entries();
for (auto fi: fil) {
if (!fi.isFile()) continue;
if (!fi.name().contains(".log.")) continue;
names[PIDateTime::current().fromString(fi.baseName(), "yyyy_MM_dd__hh_mm_ss").toSystemTime()] = dir.relative(fi.path);
}
PIStringList ret;
PIString cur_filename = dir.relative(log_file.path());
auto it = names.makeIterator();
bool was_own = false;
auto readFile = [&ret](PIFile * f) {
PIIOTextStream ts(f);
PIString line;
while (!ts.isEnd()) {
line = ts.readLine().trim();
if (line.isNotEmpty()) ret << line;
}
};
while (it.next()) {
PIFile * f = nullptr;
bool own = true;
if (it.value() == cur_filename) {
log_mutex.lock();
f = &log_file;
f->seekToBegin();
own = false;
was_own = true;
} else {
f = new PIFile(log_dir + "/" + it.value(), PIIODevice::ReadOnly);
}
readFile(f);
if (own)
delete f;
else {
f->seekToEnd();
log_mutex.unlock();
}
}
if (!was_own) {
log_mutex.lock();
log_file.seekToBegin();
readFile(&log_file);
log_file.seekToEnd();
log_mutex.unlock();
}
return ret;
}
void PILog::coutDone(int id, PIString * buffer) {
if (!buffer) return;
if (!id_by_cat.containsValue(id)) return;
auto cat = id_by_cat.key(id, PILog::Level::Debug);
if (cat > max_level) return;
enqueue(*buffer, cat);
delete buffer;
}
PICout PILog::makePICout(PIObject * context, Level cat) {
auto buffer = new PIString();
if (context) {
*buffer = "["_a + context->className();
if (context->name().isNotEmpty()) *buffer += " \"" + context->name() + "\"";
*buffer += "] ";
}
return PICout::withExternalBufferAndID(buffer, id_by_cat.value(cat), PICoutManipulators::AddSpaces);
}
void PILog::enqueue(const PIString & msg, Level cat) {
auto t = PIDateTime::fromSystemTime(PISystemTime::current());
PIMutexLocker ml(log_mutex);
queue.enqueue({cat, t, msg});
}
PIString PILog::entryToString(const Entry & e) const {
static PIStringList categories{"error", "warn ", "info ", "debug"};
PIString t = e.time.toString(timestamp_format);
PIString ret = line_format_p;
ret.replace("${t}", t).replace("${c}", categories[static_cast<int>(e.cat)]).replace("${m}", e.msg);
return ret;
}
void PILog::newFile() {
PIString aname = log_name;
if (aname.isNotEmpty()) aname += "__";
log_file.open(log_dir + "/" + aname + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss") + ".log." +
PIString::fromNumber(++part_number),
PIIODevice::ReadWrite);
}
void PILog::run() {
if (output[File]) {
if (split_tm.elapsed() >= split_time) {
split_tm.reset();
newFile();
}
}
log_mutex.lock();
if (queue.isEmpty()) {
log_mutex.unlock();
piMSleep(20);
return;
}
log_mutex.unlock();
while (true) {
log_mutex.lock();
if (queue.isEmpty()) {
log_mutex.unlock();
return;
}
auto qi = queue.dequeue();
log_mutex.unlock();
auto str = entryToString(qi);
if (log_file.isOpened()) log_ts << str << "\n";
if (output[Console]) {
PICout out(qi.cat == Level::Error ? piCerr : piCout);
if (color_console) {
switch (qi.cat) {
case Level::Error: out << PICoutManipulators::Red; break;
case Level::Warning: out << PICoutManipulators::Yellow; break;
default: break;
}
}
out << str;
}
}
}

View File

@@ -1,181 +0,0 @@
/*! \file pilog.h
* \ingroup Application
* \~\brief
* \~english High-level log
* \~russian Высокоуровневый лог
*/
/*
PIP - Platform Independent Primitives
High-level log
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIlog_H
#define PIlog_H
#include "pifile.h"
#include "piiostream.h"
#include "pithread.h"
//! \ingroup Application
//! \~\brief
//! \~english High-level log
//! \~russian Высокоуровневый лог
class PIP_EXPORT PILog: public PIThread {
PIOBJECT_SUBCLASS(PILog, PIThread)
public:
PILog();
~PILog();
//! \~english Message category
//! \~russian Категория сообщения
enum class Level {
Error /** \~english Error \~russian Ошибка */,
Warning /** \~english Warning \~russian Предупреждение */,
Info /** \~english Information \~russian Информация */,
Debug /** \~english Debug \~russian Отладка */,
};
//! \~english Output channel
//! \~russian Канал вывода
enum Output {
File /** \~english File \~russian Файл */ = 0x1,
Console /** \~english Console \~russian Консоль */ = 0x2,
All /** \~english All \~russian Все */ = 0xFF,
};
//! \~english Set output channel \"o\" to \"on\".
//! \~russian Установить канал вывода \"o\" в \"on\".
void setOutput(Output o, bool on = true) { output.setFlag(o, on); }
//! \~english Returns prefix for filename.
//! \~russian Возвращает префикс имени файла.
PIString logName() const { return log_name; }
//! \~english Set prefix for filename. Should be set \b before \a setDir()!
//! \~russian Устанавливает префикс имени файла. Должен быть установлен \b до вызова \a setDir()!
void setLogName(const PIString & n) { log_name = n; }
//! \~english Returns if color for console output enabled.
//! \~russian Возвращает использовать ли цвет для вывода в консоль.
bool colorConsole() const { return color_console; }
//! \~english Set color for console output enabled. True by default.
//! \~russian Устанавливает использовать ли цвет для вывода в консоль. Включено по умолчанию.
void setColorConsole(bool yes) { color_console = yes; }
//! \~english Returns directory for log files.
//! \~russian Возвращает директорию для файлов.
PIString dir() const { return log_dir; }
//! \~english Set directory for log files. Should be set \b after \a setLogName()!
//! \~russian Устанавливает директорию для файлов. Должна быть установлена \b после вызова \a setLogName()!
void setDir(const PIString & d);
//! \~english Returns lifetime for file.
//! \~russian Возвращает время жизни файла.
PISystemTime fileSplitTime() const { return split_time; }
//! \~english Set lifetime for file. Each "st" interval new file will be created.
//! \~russian Устанавливает время жизни файла. Каждый интервал "st" будет создан новый файл.
void setFileSplitTime(PISystemTime st) { split_time = st; }
//! \~english Returns timestamp format for line.
//! \~russian Возвращает формат метки времени для строки.
PIString timestampFormat() const { return timestamp_format; }
//! \~english Set timestamp format for line. Default is "yyyy-MM-dd hh:mm:ss.zzz".
//! \~russian Устанавливает формат метки времени для строки. По умолчанию "yyyy-MM-dd hh:mm:ss.zzz".
void setTimestampFormat(const PIString & f) { timestamp_format = f; }
//! \~english Returns line format.
//! \~russian Возвращает формат строки.
PIString lineFormat() const { return line_format; }
//! \~english Set line format. "t" is timestamp, "c" is category and "m" is message. Default is "t - c: m".
//! \~russian Устанавливает формат строки. "t" - метка времени, "c" - категория и "m" - сообщение. По умолчанию "t - c: m".
void setLineFormat(const PIString & f);
//! \~english Returns maximum level.
//! \~russian Возвращает максимальную категорию.
Level level() const { return max_level; }
//! \~english Set maximum level. All levels greater than \"l\" will be ignored. Default is \a Level::Debug.
//! \~russian Устанавливает максимальную категорию. Все сообщения с большей категорией, чем \"l\", будут игнорироваться. По умолчанию \a
//! Level::Debug.
void setLevel(Level l);
//! \~english Returns \a PICout for \a Level::Error level.
//! \~russian Возвращает \a PICout для категории \a Level::Error.
PICout error(PIObject * context = nullptr);
//! \~english Returns \a PICout for \a Level::Warning level.
//! \~russian Возвращает \a PICout для категории \a Level::Warning.
PICout warning(PIObject * context = nullptr);
//! \~english Returns \a PICout for \a Level::Info level.
//! \~russian Возвращает \a PICout для категории \a Level::Info.
PICout info(PIObject * context = nullptr);
//! \~english Returns \a PICout for \a Level::Debug level.
//! \~russian Возвращает \a PICout для категории \a Level::Debug.
PICout debug(PIObject * context = nullptr);
//! \~english Write all queued lines and stop. Also called in destructor.
//! \~russian Записывает все строки из очереди и останавливается. Также вызывается в деструкторе.
void stop();
//! \~english Read all previous and current log content and returns them as %PIStringList.
//! \~russian Читает все предыдущие и текущий логи и возвращает их как %PIStringList.
PIStringList readAllLogs() const;
private:
EVENT_HANDLER2(void, coutDone, int, id, PIString *, buff);
PICout makePICout(PIObject * context, Level cat);
void enqueue(const PIString & msg, Level cat = Level::Debug);
struct Entry {
Level cat;
PIDateTime time;
PIString msg;
};
PIString entryToString(const Entry & e) const;
void newFile();
void run() override;
mutable PIMutex log_mutex;
mutable PIFile log_file;
PIIOTextStream log_ts;
PITimeMeasurer split_tm;
PISystemTime split_time;
PIString log_dir, timestamp_format, line_format, line_format_p, log_name;
PIQueue<Entry> queue;
PIMap<Level, int> id_by_cat;
Level max_level = Level::Debug;
PIFlags<Output> output = All;
bool color_console = true;
int part_number = -1, cout_id = -1;
};
#endif

View File

@@ -1,116 +0,0 @@
/*
PIP - Platform Independent Primitives
Translation support
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pitranslator.h"
#include "pidir.h"
#include "pifile.h"
#include "piliterals_string.h"
#include "pitranslator_p.h"
#include "pivaluetree_conversions.h"
//! \class PITranslator pitranslator.h
//! \details
//! \~english \section PITranslator_sec0 Synopsis
//! \~russian \section PITranslator_sec0 Краткий обзор
//! \~english
//!
//! \~russian
//!
PRIVATE_DEFINITION_START(PITranslator)
PITranslatorPrivate::Translation content;
PRIVATE_DEFINITION_END(PITranslator)
PIString PITranslator::tr(const PIString & in, const PIString & context) {
return instance()->PRIVATEWB->content.translate(in, context);
}
void PITranslator::clear() {
instance()->PRIVATEWB->content.clear();
}
void PITranslator::loadLang(const PIString & short_lang, PIString dir) {
if (dir.isEmpty()) dir = PIDir::current().absolute("lang");
clear();
auto files = PIDir(dir).entries();
for (const auto & f: files) {
if (!f.baseName().endsWith(short_lang)) continue;
loadFile(f.path);
}
piCout << "Loaded %1 string for lang \"%2\""_a.arg(instance()->PRIVATEWB->content.count()).arg(short_lang);
/*auto s = instance();
auto vt = PIValueTreeConversions::fromText(getBuiltinConfig());
auto lang = vt.child(short_lang.toLowerCase().trim());
for (const auto & cn: lang.children()) {
auto c = s->PRIVATEWB->content.createContext(cn.name());
for (const auto & s: cn.children())
c->add(s.name(), s.value().toString());
}*/
}
void PITranslator::loadConfig(const PIString & content) {
auto s = instance();
auto lang = PIValueTreeConversions::fromText(content);
for (const auto & cn: lang.children()) {
auto c = s->PRIVATEWB->content.createContext(cn.name());
for (const auto & s: cn.children())
c->add(s.name(), s.value().toString());
}
auto c = s->PRIVATEWB->content.createContext("");
for (const auto & s: lang.children()) {
if (s.hasChildren()) continue;
c->add(s.name(), s.value().toString());
}
}
bool PITranslator::load(const PIByteArray & content) {
return instance()->PRIVATEWB->content.load(content);
}
bool PITranslator::loadFile(const PIString & path) {
PIFile f(path, PIIODevice::ReadOnly);
if (f.isClosed()) return false;
if (!PITranslatorPrivate::checkHeader(&f)) return false;
auto data = f.readAll();
data.remove(0, PITranslatorPrivate::headerSize());
return load(data);
}
PITranslator::PITranslator() {}
PITranslator::~PITranslator() {
PRIVATE->content.clear();
}
PITranslator * PITranslator::instance() {
static PITranslator ret;
return &ret;
}

View File

@@ -1,98 +0,0 @@
/*! \file pitranslator.h
* \ingroup Application
* \~\brief
* \~english Translation support
* \~russian Поддержка перевода
*/
/*
PIP - Platform Independent Primitives
Translation support
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pitranslator_H
#define pitranslator_H
#include "pistring.h"
#define piTr PITranslator::tr
#define piTrNoOp PITranslator::trNoOp
//! \ingroup Application
//! \~\brief
//! \~english Translation support
//! \~russian Поддержка перевода
class PIP_EXPORT PITranslator {
public:
static PIString tr(const PIString & in, const PIString & context = {});
static PIString tr(const char * in, const PIString & context = {}) { return tr(PIString::fromUTF8(in), context); }
static PIString trNoOp(const PIString & in, const PIString & context = {}) { return in; }
static PIString trNoOp(const char * in, const PIString & context = {}) { return trNoOp(PIString::fromUTF8(in), context); }
static void clear();
static void loadLang(const PIString & short_lang, PIString dir = {});
static void loadConfig(const PIString & content);
static bool load(const PIByteArray & content);
static bool loadFile(const PIString & path);
private:
PITranslator();
~PITranslator();
NO_COPY_CLASS(PITranslator)
PRIVATE_DECLARATION(PIP_EXPORT)
static PITranslator * instance();
};
class PIStringContextTr {
public:
PIStringContextTr(PIString && s): _s(s) {}
operator PIString() const { return PITranslator::tr(_s); }
PIString operator()(const PIString & ctx = {}) const { return PITranslator::tr(_s, ctx); }
private:
PIString _s;
};
class PIStringContextTrNoOp {
public:
PIStringContextTrNoOp(PIString && s): _s(s) {}
operator PIString() const { return _s; }
PIString operator()(const PIString & ctx = {}) const { return _s; }
private:
PIString _s;
};
//! \~\brief
//! \~english Translate string with \a PITranslator::tr()
//! \~russian Перевести строку с помощью \a PITranslator::tr()
inline PIStringContextTr operator""_tr(const char * v, size_t sz) {
return PIStringContextTr(PIString::fromUTF8(v, sz));
}
//! \~\brief
//! \~english Translate string with \a PITranslator::tr()
//! \~russian Перевести строку с помощью \a PITranslator::tr()
inline PIStringContextTrNoOp operator""_trNoOp(const char * v, size_t sz) {
return PIStringContextTrNoOp(PIString::fromUTF8(v, sz));
}
#endif

View File

@@ -1,124 +0,0 @@
/*
PIP - Platform Independent Primitives
Translation private
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pitranslator_p.h"
#include "pichunkstream.h"
#include "piiodevice.h"
constexpr int currentVersion = 1;
const PIByteArray fileHeader("PIPBTF", 6);
void PITranslatorPrivate::Context::add(const PIMap<uint, PIString> & sm) {
auto it = sm.makeIterator();
while (it.next())
strings[it.key()] = it.value();
}
void PITranslatorPrivate::Translation::clear() {
piDeleteAll(contexts.values());
contexts.clear();
lang.clear();
}
PITranslatorPrivate::Context * PITranslatorPrivate::Translation::createContext(const PIString & context) {
return createContext(context.hash());
}
PITranslatorPrivate::Context * PITranslatorPrivate::Translation::createContext(uint hash) {
auto & ret(contexts[hash]);
if (!ret) ret = new Context();
return ret;
}
PIString PITranslatorPrivate::Translation::translate(const PIString & in, const PIString & context) {
auto c = contexts.value(context.hash());
if (!c) return in;
return c->strings.value(in.hash(), in);
}
bool PITranslatorPrivate::Translation::load(const PIByteArray & data) {
if (data.size_s() <= 4) return false;
PIChunkStream cs(data);
Context * ctx = nullptr;
PIMap<uint, PIString> strings;
while (!cs.atEnd()) {
switch (cs.read()) {
case 1: {
int version = cs.getData<int>();
if (version != currentVersion) {
piCout << "Invalid translation version!";
return false;
}
} break;
case 3: {
uint ctx_hash = cs.getData<uint>();
ctx = createContext(ctx_hash);
} break;
case 4: {
cs.get(strings);
if (ctx) ctx->add(strings);
} break;
}
}
return true;
}
int PITranslatorPrivate::Translation::count() const {
int ret = 0;
auto cit = contexts.makeIterator();
while (cit.next())
ret += cit.value()->strings.size_s();
return ret;
}
PIByteArray PITranslatorPrivate::Translation::save() {
PIChunkStream cs;
cs.add(1, currentVersion).add(2, lang);
auto cit = contexts.makeIterator();
while (cit.next()) {
cs.add(3, cit.key()).add(4, cit.value()->strings);
}
return cs.data();
}
int PITranslatorPrivate::headerSize() {
return fileHeader.size_s();
}
bool PITranslatorPrivate::checkHeader(PIIODevice * d) {
if (!d) return false;
return d->read(fileHeader.size_s()) == fileHeader;
}
void PITranslatorPrivate::writeHeader(PIIODevice * d) {
if (!d) return;
d->write(fileHeader);
}

View File

@@ -1,53 +0,0 @@
/*
PIP - Platform Independent Primitives
Translation private
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pitranslator_p_H
#define pitranslator_p_H
#include "pistring.h"
class PIIODevice;
namespace PITranslatorPrivate {
struct PIP_EXPORT Context {
void add(const PIString & in, const PIString & out) { strings[in.hash()] = out; }
void add(const PIMap<uint, PIString> & sm);
PIMap<uint, PIString> strings;
};
struct PIP_EXPORT Translation {
void clear();
Context * createContext(const PIString & context);
Context * createContext(uint hash);
PIString translate(const PIString & in, const PIString & context);
bool load(const PIByteArray & data);
int count() const;
PIByteArray save();
PIString lang;
PIMap<uint, Context *> contexts;
};
PIP_EXPORT int headerSize();
PIP_EXPORT bool checkHeader(PIIODevice * d);
PIP_EXPORT void writeHeader(PIIODevice * d);
} // namespace PITranslatorPrivate
#endif

View File

@@ -1,69 +0,0 @@
/*! \file piclientserver_client.h
* \ingroup ClientServer
* \~\brief
* \~english
* \~russian
*/
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef piclientserver_client_H
#define piclientserver_client_H
#include "piclientserver_client_base.h"
namespace PIClientServer {
// ServerClient
class PIP_CLIENT_SERVER_EXPORT ServerClient: public ClientBase {
friend class Server;
NO_COPY_CLASS(ServerClient);
public:
ServerClient() {}
protected:
virtual void aboutDelete() {}
private:
void createForServer(Server * parent, PIEthernet * tcp_);
};
// Client
class PIP_CLIENT_SERVER_EXPORT Client: public ClientBase {
NO_COPY_CLASS(Client);
public:
Client();
~Client();
void connect(PINetworkAddress addr);
protected:
private:
};
} // namespace PIClientServer
#endif

View File

@@ -1,88 +0,0 @@
/*! \file piclientserver_client_base.h
* \ingroup ClientServer
* \~\brief
* \~english
* \~russian
*/
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef piclientserver_client_base_H
#define piclientserver_client_base_H
#include "pidiagnostics.h"
#include "pip_client_server_export.h"
#include "pistreampacker.h"
class PIEthernet;
namespace PIClientServer {
class Server;
class ClientInterface {};
// template<bool EnableDiagnostics = false>
class PIP_CLIENT_SERVER_EXPORT ClientBase {
friend class Server;
NO_COPY_CLASS(ClientBase);
public:
ClientBase();
virtual ~ClientBase();
const PIEthernet * getTCP() const { return tcp; }
void close();
void stopAndWait();
int write(const void * d, const size_t s);
int write(const PIByteArray & ba) { return write(ba.data(), ba.size()); }
void enableDiagnostics();
PIDiagnostics::State diagnostics() const;
int receivePacketProgress() const;
const PIStreamPackerConfig & configuration() const { return stream.configuration(); }
PIStreamPackerConfig & configuration() { return stream.configuration(); }
void setConfiguration(const PIStreamPackerConfig & config) { stream.setConfiguration(config); }
protected:
virtual void readed(PIByteArray data) {}
virtual void connected() {}
virtual void disconnected() {}
virtual void receivePacketStart(int size) {}
virtual void receivePacketEnd() {}
void init();
bool own_tcp = false;
std::atomic_bool can_write = {true};
PIEthernet * tcp = nullptr;
private:
void destroy();
PIStreamPacker stream;
mutable PIMutex write_mutex;
PIDiagnostics * diag = nullptr;
};
} // namespace PIClientServer
#endif

View File

@@ -1,79 +0,0 @@
/*! \file piclientserver_server.h
* \ingroup ClientServer
* \~\brief
* \~english
* \~russian
*/
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef piclientserver_server_H
#define piclientserver_server_H
#include "pimutex.h"
#include "pinetworkaddress.h"
#include "pip_client_server_export.h"
#include "pistreampacker.h"
#include "pithreadnotifier.h"
class PIEthernet;
class PIThread;
namespace PIClientServer {
class ServerClient;
class PIP_CLIENT_SERVER_EXPORT Server: public PIStreamPackerConfig {
friend class ServerClient;
NO_COPY_CLASS(Server);
public:
Server();
virtual ~Server();
void listen(PINetworkAddress addr);
void listenAll(ushort port) { listen({0, port}); }
void stopServer();
void closeAll();
int getMaxClients() const { return max_clients; }
void setMaxClients(int new_max_clients);
int clientsCount() const;
void forEachClient(std::function<void(ServerClient *)> func);
void setClientFactory(std::function<ServerClient *()> f) { client_factory = f; }
private:
void newClient(ServerClient * c);
void clientDisconnected(ServerClient * c);
std::function<ServerClient *()> client_factory;
std::atomic_bool is_closing = {false};
PIEthernet * tcp_server = nullptr;
PIThread * clean_thread = nullptr;
PIThreadNotifier clean_notifier;
PIVector<ServerClient *> clients;
mutable PIMutex clients_mutex;
int max_clients = 1000;
};
} // namespace PIClientServer
#endif

View File

@@ -1,57 +0,0 @@
/*
PIP - Platform Independent Primitives
Module includes
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//! \defgroup ClientServer ClientServer
//! \~\brief
//! \~english TCP Client-Server
//! \~russian TCP Клиент-Сервер
//!
//! \~\details
//! \~english \section cmake_module_ClientServer Building with CMake
//! \~russian \section cmake_module_ClientServer Сборка с использованием CMake
//!
//! \~\code
//! find_package(PIP REQUIRED)
//! target_link_libraries([target] PIP::ClientServer)
//! \endcode
//!
//! \~english \par Common
//! \~russian \par Общее
//!
//! \~english
//! These files provides server with clients dispatching for server-side and client for client-side.
//!
//! \~russian
//! Эти файлы предоставляют сервер с диспетчеризацией клиентов для серверной стороны и клиента для клиентской стороны.
//!
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//!
#ifndef PICLIENTSERVERMODULE_H
#define PICLIENTSERVERMODULE_H
#include "piclientserver_client.h"
#include "piclientserver_server.h"
#endif

View File

@@ -5,22 +5,22 @@
* \~russian Базовый класс для PICloudClient и PICloudServer * \~russian Базовый класс для PICloudClient и PICloudServer
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud Base - Base class for PICloudClient and PICloud Server PICloud Base - Base class for PICloudClient and PICloud Server
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PICLOUDBASE_H #ifndef PICLOUDBASE_H
@@ -31,7 +31,8 @@
#include "pistreampacker.h" #include "pistreampacker.h"
class PIP_CLOUD_EXPORT PICloudBase { class PIP_CLOUD_EXPORT PICloudBase
{
public: public:
PICloudBase(); PICloudBase();

View File

@@ -5,22 +5,22 @@
* \~russian Клиент PICloud * \~russian Клиент PICloud
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud Client PICloud Client
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PICLOUDCLIENT_H #ifndef PICLOUDCLIENT_H
@@ -32,30 +32,26 @@
//! \brief PICloudClient //! \brief PICloudClient
class PIP_CLOUD_EXPORT PICloudClient class PIP_CLOUD_EXPORT PICloudClient: public PIIODevice, public PICloudBase
: public PIIODevice {
, public PICloudBase { PIIODEVICE(PICloudClient, "")
PIIODEVICE(PICloudClient, "");
public: public:
explicit PICloudClient(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite); explicit PICloudClient(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
virtual ~PICloudClient(); virtual ~PICloudClient();
void setServerName(const PIString & server_name); void setServerName(const PIString & server_name);
void setKeepConnection(bool on); void setKeepConnection(bool on);
bool isConnected() const { return is_connected; } bool isConnected() const {return is_connected;}
ssize_t bytesAvailable() const override { return buff.size(); }
void interrupt() override;
EVENT(connected); EVENT(connected)
EVENT(disconnected); EVENT(disconnected)
protected: protected:
bool openDevice() override; bool openDevice();
bool closeDevice() override; bool closeDevice();
ssize_t readDevice(void * read_to, ssize_t max_size) override; int readDevice(void * read_to, int max_size);
ssize_t writeDevice(const void * data, ssize_t size) override; int writeDevice(const void * data, int size);
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; } DeviceInfoFlags deviceInfoFlags() const {return PIIODevice::Reliable;}
private: private:
EVENT_HANDLER1(void, _readed, PIByteArray &, data); EVENT_HANDLER1(void, _readed, PIByteArray &, data);

View File

@@ -1,20 +1,20 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Module includes Module includes
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \defgroup Cloud Cloud //! \defgroup Cloud Cloud
//! \~\brief //! \~\brief
@@ -51,8 +51,8 @@
#ifndef PICLOUDMODULE_H #ifndef PICLOUDMODULE_H
#define PICLOUDMODULE_H #define PICLOUDMODULE_H
#include "picloudtcp.h"
#include "picloudclient.h" #include "picloudclient.h"
#include "picloudserver.h" #include "picloudserver.h"
#include "picloudtcp.h"
#endif // PICLOUDMODULE_H #endif // PICLOUDMODULE_H

View File

@@ -5,22 +5,22 @@
* \~russian Сервер PICloud * \~russian Сервер PICloud
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud Server PICloud Server
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PICLOUDSERVER_H #ifndef PICLOUDSERVER_H
@@ -30,32 +30,26 @@
#include "piconditionvar.h" #include "piconditionvar.h"
class PIP_CLOUD_EXPORT PICloudServer class PIP_CLOUD_EXPORT PICloudServer: public PIIODevice, public PICloudBase
: public PIIODevice {
, public PICloudBase { PIIODEVICE(PICloudServer, "")
PIIODEVICE(PICloudServer, "");
public: public:
//! PICloudServer //! PICloudServer
explicit PICloudServer(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite); explicit PICloudServer(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
virtual ~PICloudServer(); virtual ~PICloudServer();
class Client: public PIIODevice { class Client : public PIIODevice {
PIIODEVICE(PICloudServer::Client, ""); PIIODEVICE(PICloudServer::Client, "")
friend class PICloudServer; friend class PICloudServer;
public: public:
Client(PICloudServer * srv = nullptr, uint id = 0); Client(PICloudServer * srv = nullptr, uint id = 0);
virtual ~Client(); virtual ~Client();
protected: protected:
bool openDevice() override; bool openDevice();
bool closeDevice() override; bool closeDevice();
ssize_t readDevice(void * read_to, ssize_t max_size) override; int readDevice(void * read_to, int max_size);
ssize_t writeDevice(const void * data, ssize_t size) override; int writeDevice(const void * data, int size);
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; } DeviceInfoFlags deviceInfoFlags() const {return PIIODevice::Reliable;}
ssize_t bytesAvailable() const override { return buff.size(); }
void interrupt() override;
private: private:
void pushBuffer(const PIByteArray & ba); void pushBuffer(const PIByteArray & ba);
@@ -71,14 +65,13 @@ public:
PIVector<PICloudServer::Client *> clients() const; PIVector<PICloudServer::Client *> clients() const;
EVENT1(newConnection, PICloudServer::Client *, client); EVENT1(newConnection, PICloudServer::Client * , client)
protected: protected:
bool openDevice() override; bool openDevice();
bool closeDevice() override; bool closeDevice();
ssize_t readDevice(void * read_to, ssize_t max_size) override; int readDevice(void * read_to, int max_size);
ssize_t writeDevice(const void * data, ssize_t max_size) override; int writeDevice(const void * data, int max_size);
void interrupt() override;
private: private:
EVENT_HANDLER1(void, _readed, PIByteArray &, ba); EVENT_HANDLER1(void, _readed, PIByteArray &, ba);
@@ -87,13 +80,9 @@ private:
int sendData(const PIByteArray & data, uint client_id); int sendData(const PIByteArray & data, uint client_id);
PIVector<Client *> clients_; PIVector<Client *> clients_;
PIVector<Client *> removed_clients_;
PIMap<uint, Client *> index_clients; PIMap<uint, Client *> index_clients;
PIThread ping_timer; PITimer ping_timer;
PIConditionVariable cvar;
PIMutex open_mutex;
mutable PIMutex clients_mutex; mutable PIMutex clients_mutex;
std::atomic_bool is_deleted;
}; };
#endif // PICLOUDSERVER_H #endif // PICLOUDSERVER_H

View File

@@ -5,30 +5,30 @@
* \~russian TCP слой PICloud * \~russian TCP слой PICloud
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud TCP transport PICloud TCP transport
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PICLOUDTCP_H #ifndef PICLOUDTCP_H
#define PICLOUDTCP_H #define PICLOUDTCP_H
#include "pimutex.h"
#include "pip_cloud_export.h" #include "pip_cloud_export.h"
#include "pistring.h" #include "pistring.h"
#include "pimutex.h"
class PIEthernet; class PIEthernet;
@@ -37,6 +37,7 @@ class PIStreamPacker;
namespace PICloud { namespace PICloud {
class PIP_CLOUD_EXPORT TCP { class PIP_CLOUD_EXPORT TCP {
public: public:
enum Version { enum Version {
@@ -46,21 +47,21 @@ public:
enum Role { enum Role {
InvalidRole = 0, InvalidRole = 0,
Server = 1, Server = 1,
Client = 2, Client = 2,
}; };
enum Type { enum Type {
InvalidType = 0, InvalidType = 0,
Connect = 1, Connect = 1,
Disconnect = 2, Disconnect = 2,
Data = 3, Data = 3,
Ping = 4, Ping = 4,
}; };
TCP(PIStreamPacker * s); TCP(PIStreamPacker * s);
void setRole(Role r); void setRole(Role r);
Role role() const { return (Role)header.role; } Role role() const {return (Role)header.role;}
void setServerName(const PIString & server_name_); void setServerName(const PIString & server_name_);
PIString serverName() const; PIString serverName() const;
@@ -81,8 +82,8 @@ private:
struct Header { struct Header {
Header(); Header();
uchar version; // PICloud::Version uchar version; // PICloud::Version
uchar type; // PICloud::Type uchar type; // PICloud::Type
uchar role; // PICloud::Role uchar role; // PICloud::Role
}; };
Header header; Header header;
@@ -90,8 +91,9 @@ private:
PIString server_name; PIString server_name;
PIStreamPacker * streampacker; PIStreamPacker * streampacker;
PIMutex mutex_send; PIMutex mutex_send;
}; };
} // namespace PICloud }
#endif // PICLOUDTCP_H #endif // PICLOUDTCP_H

View File

@@ -1,85 +1,62 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
C++ code info structs C++ code info structs
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "picodeinfo.h" #include "picodeinfo.h"
#include "pivariant.h" #include "pivariant.h"
PIString PICodeInfo::EnumInfo::memberName(int value_) const { PIString PICodeInfo::EnumInfo::memberName(int value_) const {
for (const auto & e: members) piForeachC (PICodeInfo::EnumeratorInfo & e, members)
if (e.value == value_) return e.name.toString(); if (e.value == value_)
return e.name.toString();
return PIString(); return PIString();
} }
int PICodeInfo::EnumInfo::memberValue(const PIString & name_) const { int PICodeInfo::EnumInfo::memberValue(const PIString & name_) const {
for (const auto & e: members) piForeachC (PICodeInfo::EnumeratorInfo & e, members)
if (e.name.toString() == name_) return e.value; if (e.name.toString() == name_)
return e.value;
return -1; return -1;
} }
PIVariantTypes::Enum PICodeInfo::EnumInfo::toPIVariantEnum() { PIVariantTypes::Enum PICodeInfo::EnumInfo::toPIVariantEnum() {
PIVariantTypes::Enum en(name.toString()); PIVariantTypes::Enum en(name.toString());
for (auto m: members) for (auto m: members) en << m.toPIVariantEnumerator();
en << m.toPIVariantEnumerator();
if (!en.isEmpty()) en.selectValue(members.front().value); if (!en.isEmpty()) en.selectValue(members.front().value);
return en; return en;
} }
PIMap<PIConstChars, PICodeInfo::ClassInfo * > * PICodeInfo::classesInfo;
PIMap<PIConstChars, PICodeInfo::EnumInfo * > * PICodeInfo::enumsInfo;
PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * PICodeInfo::accessValueFunctions;
PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * PICodeInfo::accessTypeFunctions;
bool __PICodeInfoInitializer__::_inited_ = false;
PIVariant PICodeInfo::getMemberAsVariant(const void * p, const char * class_name, const char * member_name) { PIVariant PICodeInfo::getMemberAsVariant(const void * p, const char * class_name, const char * member_name) {
if (!p || !class_name || !member_name) return PIVariant(); if (!p || !class_name || !member_name || !accessTypeFunctions || !accessValueFunctions) return PIVariant();
AccessTypeFunction atf = PICODEINFO::accessTypeFunctions().value(class_name, (AccessTypeFunction) nullptr); AccessTypeFunction atf = accessTypeFunctions->value(class_name, (AccessTypeFunction)0);
AccessValueFunction avf = PICODEINFO::accessValueFunctions().value(class_name, (AccessValueFunction) nullptr); AccessValueFunction avf = accessValueFunctions->value(class_name, (AccessValueFunction)0);
if (!atf || !avf) return PIVariant(); if (!atf || !avf) return PIVariant();
return PIVariant::fromValue(avf(p, member_name), PIStringAscii(atf(member_name))); return PIVariant::fromValue(avf(p, member_name), PIStringAscii(atf(member_name)));
} }
PICodeInfo::__Storage__::__Storage__() {
classesInfo = new PIMap<PIConstChars, ClassInfo *>;
enumsInfo = new PIMap<PIConstChars, EnumInfo *>;
accessValueFunctions = new PIMap<PIConstChars, AccessValueFunction>;
accessTypeFunctions = new PIMap<PIConstChars, AccessTypeFunction>;
(*enumsInfo)[""] = new EnumInfo();
}
PICodeInfo::__Storage__::~__Storage__() {
piDeleteAll(classesInfo->values());
piDeleteAll(enumsInfo->values());
piDeleteSafety(classesInfo);
piDeleteSafety(enumsInfo);
piDeleteSafety(accessValueFunctions);
piDeleteSafety(accessTypeFunctions);
}
PICodeInfo::__Storage__ * PICodeInfo::__Storage__::instance() {
static __Storage__ ret;
return &ret;
}
PICodeInfo::ClassInfoInterface classesInfo;
PICodeInfo::EnumsInfoInterface enumsInfo;
PICodeInfo::AccessValueFunctionInterface accessValueFunctions;
PICodeInfo::AccessTypeFunctionInterface accessTypeFunctions;

View File

@@ -1,26 +1,26 @@
/*! \file picodeinfo.h /*! \file picodeinfo.h
* \ingroup Code * \ingroup Code
* \~\brief * \~\brief
* \~english C++ code info structs. See \ref code_model. * \~english C++ code info structs
* \~russian Структуры для C++ кода. Подробнее \ref code_model. * \~russian Структуры для C++ кода
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
C++ code info structs C++ code info structs
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
@@ -34,181 +34,72 @@
class PIVariant; class PIVariant;
//! \~english Namespace contains structures for code generation. See \ref code_model.
//! \~russian Пространство имен содержит структуры для кодогенерации. Подробнее \ref code_model.
namespace PICodeInfo { namespace PICodeInfo {
//! \~english
//! Type modifiers
//! \~russian
//! Модификаторы типа
enum TypeFlag { enum TypeFlag {
NoFlag, NoFlag,
Const /** const */ = 0x01, Const = 0x01,
Static /** static */ = 0x02, Static = 0x02,
Mutable /** mutable */ = 0x04, Mutable = 0x04,
Volatile /** volatile */ = 0x08, Volatile = 0x08,
Inline /** inline */ = 0x10, Inline = 0x10,
Virtual /** virtual */ = 0x20, Virtual = 0x20,
Extern /** extern */ = 0x40 Extern = 0x40
}; };
typedef PIFlags<PICodeInfo::TypeFlag> TypeFlags; typedef PIFlags<PICodeInfo::TypeFlag> TypeFlags;
typedef PIMap<PIString, PIString> MetaMap; typedef PIMap<PIString, PIString> MetaMap;
typedef PIByteArray (*AccessValueFunction)(const void *, const char *); typedef PIByteArray(*AccessValueFunction)(const void *, const char *);
typedef const char * (*AccessTypeFunction)(const char *); typedef const char*(*AccessTypeFunction)(const char *);
//! \~english Type information
//! \~russian Информация о типе
struct PIP_EXPORT TypeInfo { struct PIP_EXPORT TypeInfo {
TypeInfo(const PIConstChars & n = PIConstChars(), const PIConstChars & t = PIConstChars(), PICodeInfo::TypeFlags f = 0, int b = -1) { TypeInfo(const PIConstChars & n = PIConstChars(), const PIConstChars & t = PIConstChars(), PICodeInfo::TypeFlags f = 0, int b = -1) {name = n; type = t; flags = f; bits = b;}
name = n; bool isBitfield() const {return bits > 0;}
type = t;
flags = f;
bits = b;
}
//! \~english Returns if variable if bitfield
//! \~russian Возвращает битовым ли полем является переменная
bool isBitfield() const { return bits > 0; }
//! \~english Custom PIMETA content
//! \~russian Произвольное содержимое PIMETA
MetaMap meta; MetaMap meta;
//! \~english Name
//! \~russian Имя
PIConstChars name; PIConstChars name;
//! \~english Type
//! \~russian Тип
PIConstChars type; PIConstChars type;
//! \~english Modifiers
//! \~russian Модификаторы
PICodeInfo::TypeFlags flags; PICodeInfo::TypeFlags flags;
//! \~english Bitfield variable bit count
//! \~russian Количество бит битового поля
int bits; int bits;
}; };
//! \~english Method information
//! \~russian Информация о методе
struct PIP_EXPORT FunctionInfo { struct PIP_EXPORT FunctionInfo {
//! \~english Custom PIMETA content
//! \~russian Произвольное содержимое PIMETA
MetaMap meta; MetaMap meta;
//! \~english Name
//! \~russian Имя
PIConstChars name; PIConstChars name;
//! \~english Return type
//! \~russian Возвращаемые тип
TypeInfo return_type; TypeInfo return_type;
//! \~english Arguments types
//! \~russian Типы аргументов
PIVector<PICodeInfo::TypeInfo> arguments; PIVector<PICodeInfo::TypeInfo> arguments;
}; };
//! \~english Class or struct information
//! \~russian Информация о классе или структуре
struct PIP_EXPORT ClassInfo { struct PIP_EXPORT ClassInfo {
ClassInfo() { has_name = true; } ClassInfo() {has_name = true;}
//! \~english Custom PIMETA content
//! \~russian Произвольное содержимое PIMETA
MetaMap meta; MetaMap meta;
//! \~english Has name or not
//! \~russian Имеет или нет имя
bool has_name; bool has_name;
//! \~english Type
//! \~russian Тип
PIConstChars type; PIConstChars type;
//! \~english Name
//! \~russian Имя
PIConstChars name; PIConstChars name;
//! \~english Parent names
//! \~russian Имена родителей
PIVector<PIConstChars> parents; PIVector<PIConstChars> parents;
//! \~english Variables
//! \~russian Переменные
PIVector<PICodeInfo::TypeInfo> variables; PIVector<PICodeInfo::TypeInfo> variables;
//! \~english Methods
//! \~russian Методы
PIVector<PICodeInfo::FunctionInfo> functions; PIVector<PICodeInfo::FunctionInfo> functions;
PIVector<PICodeInfo::ClassInfo * > children_info;
//! \~english Subclass list
//! \~russian Список наследников
PIVector<PICodeInfo::ClassInfo *> children_info;
}; };
//! \~english Enumerator information
//! \~russian Информация об элементе перечисления
struct PIP_EXPORT EnumeratorInfo { struct PIP_EXPORT EnumeratorInfo {
EnumeratorInfo(const PIConstChars & n = PIConstChars(), int v = 0) { EnumeratorInfo(const PIConstChars & n = PIConstChars(), int v = 0) {name = n; value = v;}
name = n; PIVariantTypes::Enumerator toPIVariantEnumerator() {return PIVariantTypes::Enumerator(value, name.toString());}
value = v;
}
PIVariantTypes::Enumerator toPIVariantEnumerator() { return PIVariantTypes::Enumerator(value, name.toString()); }
//! \~english Custom PIMETA content
//! \~russian Произвольное содержимое PIMETA
MetaMap meta; MetaMap meta;
//! \~english Name
//! \~russian Имя
PIConstChars name; PIConstChars name;
//! \~english Value
//! \~russian Значение
int value; int value;
}; };
//! \~english Enum information
//! \~russian Информация о перечислении
struct PIP_EXPORT EnumInfo { struct PIP_EXPORT EnumInfo {
//! \~english Returns member name with value "value"
//! \~russian Возвращает имя элемента со значением "value"
PIString memberName(int value) const; PIString memberName(int value) const;
//! \~english Returns member value with name "name"
//! \~russian Возвращает значение элемента с именем "name"
int memberValue(const PIString & name) const; int memberValue(const PIString & name) const;
//! \~english Returns as PIVariantTypes::Enum
//! \~russian Возвращает как PIVariantTypes::Enum
PIVariantTypes::Enum toPIVariantEnum(); PIVariantTypes::Enum toPIVariantEnum();
//! \~english Custom PIMETA content
//! \~russian Произвольное содержимое PIMETA
MetaMap meta; MetaMap meta;
//! \~english Name
//! \~russian Имя
PIConstChars name; PIConstChars name;
//! \~english Members
//! \~russian Элементы
PIVector<PICodeInfo::EnumeratorInfo> members; PIVector<PICodeInfo::EnumeratorInfo> members;
}; };
inline PICout operator<<(PICout s, const PICodeInfo::TypeInfo & v) { inline PICout operator <<(PICout s, const PICodeInfo::TypeInfo & v) {
if (v.flags[Inline]) s << "inline "; if (v.flags[Inline]) s << "inline ";
if (v.flags[Virtual]) s << "virtual "; if (v.flags[Virtual]) s << "virtual ";
if (v.flags[Mutable]) s << "mutable "; if (v.flags[Mutable]) s << "mutable ";
@@ -216,26 +107,22 @@ inline PICout operator<<(PICout s, const PICodeInfo::TypeInfo & v) {
if (v.flags[Static]) s << "static "; if (v.flags[Static]) s << "static ";
if (v.flags[Const]) s << "const "; if (v.flags[Const]) s << "const ";
s << v.type; s << v.type;
if (!v.name.isEmpty()) s << " " << v.name; if (!v.name.isEmpty())
s << " " << v.name;
return s; return s;
} }
inline PICout operator<<(PICout s, const PICodeInfo::EnumeratorInfo & v) { inline PICout operator <<(PICout s, const PICodeInfo::EnumeratorInfo & v) {s << v.name << " = " << v.value << " Meta" << v.meta; return s;}
s << v.name << " = " << v.value << " Meta" << v.meta;
return s;
}
inline PICout operator<<(PICout s, const PICodeInfo::ClassInfo & v) { inline PICout operator <<(PICout s, const PICodeInfo::ClassInfo & v) {
s.saveAndSetControls(0); s.setControl(0, true);
s << "class " << v.name; s << "class " << v.name;
if (!v.parents.isEmpty()) { if (!v.parents.isEmpty()) {
s << ": "; s << ": ";
bool first = true; bool first = true;
for (const auto & i: v.parents) { for (const auto & i: v.parents) {
if (first) if (first) first = false;
first = false; else s << ", ";
else
s << ", ";
s << i; s << i;
} }
} }
@@ -244,132 +131,51 @@ inline PICout operator<<(PICout s, const PICodeInfo::ClassInfo & v) {
s << PICoutManipulators::Tab << i.return_type << " " << i.name << "("; s << PICoutManipulators::Tab << i.return_type << " " << i.name << "(";
bool fa = true; bool fa = true;
for (const auto & a: i.arguments) { for (const auto & a: i.arguments) {
if (fa) if (fa) fa = false;
fa = false; else s << ", ";
else
s << ", ";
s << a; s << a;
} }
s << ") Meta" << i.meta << ";\n"; s << ") Meta" << i.meta << ";\n";
} }
if (!v.functions.isEmpty() && !v.variables.isEmpty()) s << "\n"; if (!v.functions.isEmpty() && !v.variables.isEmpty())
s << "\n";
for (const auto & i: v.variables) { for (const auto & i: v.variables) {
s << PICoutManipulators::Tab << i << " Meta" << i.meta << ";\n"; s << PICoutManipulators::Tab << i << " Meta" << i.meta << ";\n";
} }
s << "}\n"; s << "}\n";
s.restoreControls(); s.restoreControl();
return s; return s;
} }
inline PICout operator<<(PICout s, const PICodeInfo::EnumInfo & v) { inline PICout operator <<(PICout s, const PICodeInfo::EnumInfo & v) {
s.saveAndSetControls(0); s.setControl(0, true);
s << "enum " << v.name << " Meta" << v.meta << " {\n"; s << "enum " << v.name << " Meta" << v.meta << " {\n";
for (const auto & i: v.members) { for (const auto & i: v.members) {
bool f = true; bool f = true;
if (f) if (f) f = false;
f = false; else s << ", ";
else
s << ", ";
s << PICoutManipulators::Tab << i << "\n"; s << PICoutManipulators::Tab << i << "\n";
} }
s << "}\n"; s << "}\n";
s.restoreControls(); s.restoreControl();
return s; return s;
} }
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::ClassInfo * > * classesInfo;
class PIP_EXPORT __Storage__ { extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::EnumInfo * > * enumsInfo;
__Storage__(); extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * accessValueFunctions;
~__Storage__(); extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * accessTypeFunctions;
public:
static __Storage__ * instance();
PIMap<PIConstChars, PICodeInfo::ClassInfo *> * classesInfo;
PIMap<PIConstChars, PICodeInfo::EnumInfo *> * enumsInfo;
PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * accessValueFunctions;
PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * accessTypeFunctions;
private:
NO_COPY_CLASS(__Storage__)
};
class PIP_EXPORT __StorageAccess__ {
public:
//! \~english Getter for single storage of PICodeInfo::ClassInfo, access by name
//! \~russian Доступ к единому хранилищу PICodeInfo::ClassInfo, доступ по имени
static const PIMap<PIConstChars, PICodeInfo::ClassInfo *> & classes() { return *(__Storage__::instance()->classesInfo); }
//! \~english Getter for single storage of PICodeInfo::EnumInfo, access by name
//! \~russian Доступ к единому хранилищу хранилище PICodeInfo::EnumInfo, доступ по имени
static const PIMap<PIConstChars, PICodeInfo::EnumInfo *> & enums() { return *(__Storage__::instance()->enumsInfo); }
static const PIMap<PIConstChars, PICodeInfo::AccessValueFunction> & accessValueFunctions() {
return *(__Storage__::instance()->accessValueFunctions);
}
static const PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> & accessTypeFunctions() {
return *(__Storage__::instance()->accessTypeFunctions);
}
};
#define PICODEINFO PICodeInfo::__StorageAccess__
class PIP_EXPORT ClassInfoInterface {
public:
const PIMap<PIConstChars, PICodeInfo::ClassInfo *> * operator->() const DEPRECATEDM("use PICODEINFO::classes()") {
return __Storage__::instance()->classesInfo;
}
};
static ClassInfoInterface classesInfo;
class PIP_EXPORT EnumsInfoInterface {
public:
const PIMap<PIConstChars, PICodeInfo::EnumInfo *> * operator->() const DEPRECATEDM("use PICODEINFO::enums()") {
return __Storage__::instance()->enumsInfo;
}
};
static EnumsInfoInterface enumsInfo;
class PIP_EXPORT AccessValueFunctionInterface {
public:
const PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * operator->() const DEPRECATEDM("use PICODEINFO::accessValueFunctions()") {
return __Storage__::instance()->accessValueFunctions;
}
};
static AccessValueFunctionInterface accessValueFunctions;
class PIP_EXPORT AccessTypeFunctionInterface {
public:
const PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * operator->() const DEPRECATEDM("use PICODEINFO::accessTypeFunctions()") {
return __Storage__::instance()->accessTypeFunctions;
}
};
static AccessTypeFunctionInterface accessTypeFunctions;
STATIC_INITIALIZER_BEGIN
NO_UNUSED(classesInfo);
NO_UNUSED(enumsInfo);
NO_UNUSED(accessValueFunctions);
NO_UNUSED(accessTypeFunctions);
STATIC_INITIALIZER_END
inline PIByteArray getMemberValue(const void * p, const char * class_name, const char * member_name) { inline PIByteArray getMemberValue(const void * p, const char * class_name, const char * member_name) {
if (!p || !class_name || !member_name) return PIByteArray(); if (!p || !class_name || !member_name || !accessValueFunctions) return PIByteArray();
AccessValueFunction af = PICODEINFO::accessValueFunctions().value(class_name, (AccessValueFunction)0); AccessValueFunction af = accessValueFunctions->value(class_name, (AccessValueFunction)0);
if (!af) return PIByteArray(); if (!af) return PIByteArray();
return af(p, member_name); return af(p, member_name);
} }
inline const char * getMemberType(const char * class_name, const char * member_name) { inline const char * getMemberType(const char * class_name, const char * member_name) {
if (!class_name || !member_name) return ""; if (!class_name || !member_name || !accessTypeFunctions) return "";
AccessTypeFunction af = PICODEINFO::accessTypeFunctions().value(class_name, (AccessTypeFunction)0); AccessTypeFunction af = accessTypeFunctions->value(class_name, (AccessTypeFunction)0);
if (!af) return ""; if (!af) return "";
return af(member_name); return af(member_name);
} }
@@ -377,15 +183,27 @@ inline const char * getMemberType(const char * class_name, const char * member_n
PIP_EXPORT PIVariant getMemberAsVariant(const void * p, const char * class_name, const char * member_name); PIP_EXPORT PIVariant getMemberAsVariant(const void * p, const char * class_name, const char * member_name);
template<typename T, typename std::enable_if<std::is_assignable<T &, const T &>::value, int>::type = 0> template<typename T, typename std::enable_if< std::is_assignable<T&, const T&>::value, int>::type = 0>
void serialize(PIByteArray & ret, const T & v) { void serialize(PIByteArray & ret, const T & v) {ret << v;}
ret << v;
}
template<typename T, typename std::enable_if<!std::is_assignable<T &, const T &>::value, int>::type = 0> template<typename T, typename std::enable_if<!std::is_assignable<T&, const T&>::value, int>::type = 0>
void serialize(PIByteArray & ret, const T & v) {} void serialize(PIByteArray & ret, const T & v) {}
} // namespace PICodeInfo }
class PIP_EXPORT __PICodeInfoInitializer__ {
public:
__PICodeInfoInitializer__() {
if (_inited_) return;
_inited_ = true;
PICodeInfo::classesInfo = new PIMap<PIConstChars, PICodeInfo::ClassInfo * >;
PICodeInfo::enumsInfo = new PIMap<PIConstChars, PICodeInfo::EnumInfo * >;
PICodeInfo::accessValueFunctions = new PIMap<PIConstChars, PICodeInfo::AccessValueFunction>;
PICodeInfo::accessTypeFunctions = new PIMap<PIConstChars, PICodeInfo::AccessTypeFunction>;
}
static bool _inited_;
};
static __PICodeInfoInitializer__ __picodeinfoinitializer__;
#endif // PICODEINFO_H #endif // PICODEINFO_H

View File

@@ -1,20 +1,20 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Module includes Module includes
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \defgroup Code Code //! \defgroup Code Code
//! \~\brief //! \~\brief
@@ -35,11 +35,9 @@
//! //!
//! \~english //! \~english
//! These files provides parsing C++ code and storage to use results of \a pip_cmg utility. //! These files provides parsing C++ code and storage to use results of \a pip_cmg utility.
//! See \ref code_model.
//! //!
//! \~russian //! \~russian
//! Эти файлы обеспечивают разбор C++ кода и хранение результатов работы утилиты \a pip_cmg. //! Эти файлы обеспечивают разбор C++ кода и хранение результатов работы утилиты \a pip_cmg.
//! Подробнее \ref code_model.
//! //!
//! \~\authors //! \~\authors
//! \~english //! \~english

View File

@@ -1,25 +1,26 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
C++ code parser C++ code parser
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "picodeparser.h" #include "picodeparser.h"
PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const { PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
PIStringList arg_vals; PIStringList arg_vals;
while (!args_.isEmpty()) { while (!args_.isEmpty()) {
@@ -31,32 +32,29 @@ PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
PIString ca; PIString ca;
if (bi >= 0 && bi < ci) { if (bi >= 0 && bi < ci) {
ca = args_.left(args_.takeLeft(bi).toInt()); ca = args_.left(args_.takeLeft(bi).toInt());
ci -= ca.size_s(); ci -= ca.size_s(); bi -= ca.size_s();
bi -= ca.size_s();
ca += '(' + args_.takeRange('(', ')') + ')'; ca += '(' + args_.takeRange('(', ')') + ')';
} else { } else {
ca = args_.takeLeft(ci); ca = args_.takeLeft(ci);
} }
arg_vals << ca; arg_vals << ca;
args_.trim(); args_.trim(); args_.takeLeft(1); args_.trim();
args_.takeLeft(1);
args_.trim();
} }
if (args.size() != arg_vals.size()) { if (args.size() != arg_vals.size()) {
piCout << ("Error: in expansion of macro \"" + name + '(' + args.join(", ") + ")\": expect") << args.size() << "arguments but takes" piCout << ("Error: in expansion of macro \"" + name + '(' + args.join(", ") + ")\": expect")
<< arg_vals.size() << "!"; << args.size() << "arguments but takes" << arg_vals.size() << "!";
if (ok != 0) *ok = false; if (ok != 0) *ok = false;
return PIString(); return PIString();
} }
PIString ret = value; PIString ret = value;
for (int i = 0; i < args.size_s(); ++i) { for (int i = 0; i < args.size_s(); ++i) {
const PIString &an(args[i]), av(arg_vals[i]); const PIString & an(args[i]), av(arg_vals[i]);
int ind(-1); int ind(-1);
while ((ind = ret.find(an, ind + 1)) >= 0) { while ((ind = ret.find(an, ind + 1)) >= 0) {
PIChar ppc, pc, nc; PIChar ppc, pc, nc;
if (ind > 1) ppc = ret[ind - 2]; if (ind > 1) ppc = ret[ind - 2];
if (ind > 0) pc = ret[ind - 1]; if (ind > 0) pc = ret[ind - 1];
if (ind + an.size_s() < ret.size_s()) nc = ret.mid(ind + an.size_s(), 1)[0]; if (ind + an.size_s() < ret.size_s()) nc = ret.mid(ind + an.size_s(),1)[0];
if (ppc != '#' && pc == '#' && !_isCChar(nc)) { // to chars if (ppc != '#' && pc == '#' && !_isCChar(nc)) { // to chars
ind--; ind--;
ret.replace(ind, an.size_s() + 1, '\"' + av + '\"'); ret.replace(ind, an.size_s() + 1, '\"' + av + '\"');
@@ -74,8 +72,9 @@ PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
} }
PICodeParser::PICodeParser() { PICodeParser::PICodeParser() {
macros_iter = 32; macros_iter = 32;
with_includes = true; with_includes = true;
clear(); clear();
includes << ""; includes << "";
@@ -86,67 +85,63 @@ void PICodeParser::parseFile(const PIString & file, bool follow_includes) {
clear(); clear();
parseFileInternal(file, follow_includes); parseFileInternal(file, follow_includes);
/*piCout << "\n\n"; /*piCout << "\n\n";
for (const auto * c: entities) { piForeachC (Entity * c, entities) {
piCout << ""; piCout << "";
piCout << c->type << c->name << c->parent_scope << c->parents << c->children << c->meta; piCout << c->type << c->name << c->parent_scope << c->parents << c->children << c->meta;
if (c->parent_scope) if (c->parent_scope)
piCout << "parent" << c->parent_scope->name; piCout << "parent" << c->parent_scope->name;
piCout << "Functions:"; piCout << "Functions:";
for (const auto & m: c->functions) piForeachC (Member & m, c->functions)
piCout << m.type << m.name << m.meta; piCout << m.type << m.name << m.meta;
piCout << "Members:"; piCout << "Members:";
for (const auto & m: c->members) piForeachC (Member & m, c->members)
piCout << m.type << m.name << m.meta; piCout << m.type << m.name << m.meta;
} }
piCout << "\n\nDefines:"; piCout << "\n\nDefines:";
for (const auto & m: defines) piForeachC (Define & m, defines)
piCout << PIStringAscii("define") << m.first << m.second; piCout << PIStringAscii("define") << m.first << m.second;
piCout << "\n\nMacros:"; piCout << "\n\nMacros:";
for (const auto & m: macros) piForeachC (Macro & m, macros)
piCout << "Macro:" << m.name << m.args << m.value; piCout << "Macro:" << m.name << m.args << m.value;
piCout << "\n\nClasses:"; piCout << "\n\nClasses:";
piCout << "\n\nEnums:"; piCout << "\n\nEnums:";
for (const auto & c: enums) { piForeachC (Enum & c, enums) {
piCout << PIStringAscii("enum") << c.name << c.meta; piCout << PIStringAscii("enum") << c.name << c.meta;
for (const auto & e: c.members) piForeachC (EnumeratorInfo & e, c.members)
piCout << " " << e.name << '=' << e.value << e.meta; piCout << " " << e.name << '=' << e.value << e.meta;
} }
piCout << "\n\nTypedefs:"; piCout << "\n\nTypedefs:";
for (const auto & c: typedefs) piForeachC (Typedef & c, typedefs)
piCout << PIStringAscii("typedef") << c;*/ piCout << PIStringAscii("typedef") << c;*/
} }
void PICodeParser::parseFiles(const PIStringList & files, bool follow_includes) { void PICodeParser::parseFiles(const PIStringList & files, bool follow_includes) {
clear(); clear();
for (const auto & f: files) piForeachC (PIString & f, files)
parseFileInternal(f, follow_includes); parseFileInternal(f, follow_includes);
/*piCout << "\n\nDefines:"; /*piCout << "\n\nDefines:";
for (const auto & m: defines) piForeachC (Define & m, defines)
piCout << PIStringAscii("define") << m.first << m.second; piCout << PIStringAscii("define") << m.first << m.second;
piCout << "\n\nMacros:"; piCout << "\n\nMacros:";
for (const auto & m: macros) piForeachC (Macro & m, macros)
piCout << "Macro:" << m.name << m.args << m.value; piCout << "Macro:" << m.name << m.args << m.value;
piCout << "\n\nClasses:"; piCout << "\n\nClasses:";
for (const auto * c: entities) piForeachC (Entity * c, entities)
piCout << PIStringAscii("class") << c->name << c->parents; piCout << PIStringAscii("class") << c->name << c->parents;
piCout << "\n\nEnums:"; piCout << "\n\nEnums:";
for (const auto & c: enums) piForeachC (Enum & c, enums)
piCout << PIStringAscii("enum") << c.name << c.members; piCout << PIStringAscii("enum") << c.name << c.members;
piCout << "\n\nTypedefs:"; piCout << "\n\nTypedefs:";
for (const auto & c: typedefs) piForeachC (Typedef & c, typedefs)
piCout << PIStringAscii("typedef") << c;*/ piCout << PIStringAscii("typedef") << c;*/
} }
void PICodeParser::parseFileContent(PIString fc) {
parseFileContent(fc, false);
}
bool PICodeParser::isEnum(const PIString & name) { bool PICodeParser::isEnum(const PIString & name) {
for (const auto & e: enums) piForeachC (Enum & e, enums)
if (e.name == name) return true; if (e.name == name)
return true;
return false; return false;
} }
@@ -154,19 +149,19 @@ bool PICodeParser::isEnum(const PIString & name) {
bool PICodeParser::parseFileInternal(const PIString & file, bool follow_includes) { bool PICodeParser::parseFileInternal(const PIString & file, bool follow_includes) {
if (proc_files[file]) return true; if (proc_files[file]) return true;
with_includes = follow_includes; with_includes = follow_includes;
cur_file = file; cur_file = file;
PIFile f(file, PIIODevice::ReadOnly); PIFile f(file, PIIODevice::ReadOnly);
int ii = 0; int ii = 0;
while (!f.isOpened() && ii < (includes.size_s() - 1)) { while (!f.isOpened() && ii < (includes.size_s() - 1)) {
f.setPath(includes[++ii] + '/' + file); f.setPath(includes[++ii] + '/' + file);
// piCout << "try" << f.path(); //piCout << "try" << f.path();
f.open(PIIODevice::ReadOnly); f.open(PIIODevice::ReadOnly);
} }
if (!f.isOpened()) { if (!f.isOpened()) {
piCout << ("Error: can`t open file \"" + file + "\"!"); piCout << ("Error: can`t open file \"" + file + "\"!");
return false; return false;
} }
// piCout << "add" << file; //piCout << "add" << file;
proc_files << f.path(); proc_files << f.path();
PIString fc = PIString::fromUTF8(f.readAll()); PIString fc = PIString::fromUTF8(f.readAll());
piCout << "parsing" << f.path() << "..."; piCout << "parsing" << f.path() << "...";
@@ -179,8 +174,7 @@ bool PICodeParser::parseFileInternal(const PIString & file, bool follow_includes
void PICodeParser::clear() { void PICodeParser::clear() {
for (auto * i: entities) piForeach (Entity * i, entities) delete i;
delete i;
defines.clear(); defines.clear();
macros.clear(); macros.clear();
enums.clear(); enums.clear();
@@ -190,145 +184,40 @@ void PICodeParser::clear() {
cur_namespace.clear(); cur_namespace.clear();
main_file.clear(); main_file.clear();
evaluator.clearCustomVariables(); evaluator.clearCustomVariables();
cur_def_vis = Global; cur_def_vis = Global;
anon_num = 0; anon_num = 0;
PIStringList defs = PIStringAscii(PICODE_DEFINES).split(","); PIStringList defs = PIStringAscii(PICODE_DEFINES).split(",");
for (const auto & d: defs) piForeachC (PIString & d, defs)
defines << Define(d, ""); defines << Define(d, "");
defines << Define(PIStringAscii("PICODE"), "") << custom_defines; defines << Define(PIStringAscii("PICODE"), "") << custom_defines;
macros << Macro(PIStringAscii("PIOBJECT"), "", PIStringList() << "name") macros << Macro(PIStringAscii("PIOBJECT"), "", PIStringList() << "name")
<< Macro(PIStringAscii("PIOBJECT_PARENT"), "", PIStringList() << "parent") << Macro(PIStringAscii("PIOBJECT_PARENT"), "", PIStringList() << "parent")
<< Macro(PIStringAscii("PIOBJECT_SUBCLASS"), << Macro(PIStringAscii("PIOBJECT_SUBCLASS"), "", PIStringList() << "name" << "parent")
"",
PIStringList() << "name"
<< "parent")
<< Macro(PIStringAscii("PIIODEVICE"), "", PIStringList() << "name") << Macro(PIStringAscii("PIIODEVICE"), "", PIStringList() << "name")
<< Macro(PIStringAscii("NO_COPY_CLASS"), "", PIStringList() << "name") << Macro(PIStringAscii("PRIVATE_DECLARATION")) << Macro(PIStringAscii("NO_COPY_CLASS"), "", PIStringList() << "name")
<< Macro(PIStringAscii("PRIVATE_DECLARATION"))
<< Macro(PIStringAscii("EVENT"), "void name();", PIStringList() << "name") << Macro(PIStringAscii("EVENT" ), "void name();", PIStringList() << "name")
<< Macro(PIStringAscii("EVENT0"), "void name();", PIStringList() << "name") << Macro(PIStringAscii("EVENT0"), "void name();", PIStringList() << "name")
<< Macro(PIStringAscii("EVENT1"), << Macro(PIStringAscii("EVENT1"), "void name(a0 n0);", PIStringList() << "name" << "a0" << "n0")
"void name(a0 n0);", << Macro(PIStringAscii("EVENT2"), "void name(a0 n0, a1 n1);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1")
PIStringList() << "name" << Macro(PIStringAscii("EVENT3"), "void name(a0 n0, a1 n1, a2 n2);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2")
<< "a0" << Macro(PIStringAscii("EVENT4"), "void name(a0 n0, a1 n1, a2 n2, a3 n3);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2" << "a3" << "n3")
<< "n0")
<< Macro(PIStringAscii("EVENT2"),
"void name(a0 n0, a1 n1);",
PIStringList() << "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1")
<< Macro(PIStringAscii("EVENT3"),
"void name(a0 n0, a1 n1, a2 n2);",
PIStringList() << "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2")
<< Macro(PIStringAscii("EVENT4"),
"void name(a0 n0, a1 n1, a2 n2, a3 n3);",
PIStringList() << "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2"
<< "a3"
<< "n3")
<< Macro(PIStringAscii("EVENT_HANDLER"), << Macro(PIStringAscii("EVENT_HANDLER" ), "ret name()", PIStringList() << "ret" << "name")
"ret name()", << Macro(PIStringAscii("EVENT_HANDLER0"), "ret name()", PIStringList() << "ret" << "name")
PIStringList() << "ret" << Macro(PIStringAscii("EVENT_HANDLER1"), "ret name(a0 n0)", PIStringList() << "ret" << "name" << "a0" << "n0")
<< "name") << Macro(PIStringAscii("EVENT_HANDLER2"), "ret name(a0 n0, a1 n1)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1")
<< Macro(PIStringAscii("EVENT_HANDLER0"), << Macro(PIStringAscii("EVENT_HANDLER3"), "ret name(a0 n0, a1 n1, a2 n2)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2")
"ret name()", << Macro(PIStringAscii("EVENT_HANDLER4"), "ret name(a0 n0, a1 n1, a2 n2, a3 n3)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2" << "a3" << "n3")
PIStringList() << "ret"
<< "name")
<< Macro(PIStringAscii("EVENT_HANDLER1"),
"ret name(a0 n0)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0")
<< Macro(PIStringAscii("EVENT_HANDLER2"),
"ret name(a0 n0, a1 n1)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1")
<< Macro(PIStringAscii("EVENT_HANDLER3"),
"ret name(a0 n0, a1 n1, a2 n2)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2")
<< Macro(PIStringAscii("EVENT_HANDLER4"),
"ret name(a0 n0, a1 n1, a2 n2, a3 n3)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2"
<< "a3"
<< "n3")
<< Macro(PIStringAscii("EVENT_VHANDLER"), << Macro(PIStringAscii("EVENT_VHANDLER" ), "virtual ret name()", PIStringList() << "ret" << "name")
"virtual ret name()", << Macro(PIStringAscii("EVENT_VHANDLER0"), "virtual ret name()", PIStringList() << "ret" << "name")
PIStringList() << "ret" << Macro(PIStringAscii("EVENT_VHANDLER1"), "virtual ret name(a0 n0)", PIStringList() << "ret" << "name" << "a0" << "n0")
<< "name") << Macro(PIStringAscii("EVENT_VHANDLER2"), "virtual ret name(a0 n0, a1 n1)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1")
<< Macro(PIStringAscii("EVENT_VHANDLER0"), << Macro(PIStringAscii("EVENT_VHANDLER3"), "virtual ret name(a0 n0, a1 n1, a2 n2)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2")
"virtual ret name()", << Macro(PIStringAscii("EVENT_VHANDLER4"), "virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2" << "a3" << "n3")
PIStringList() << "ret" ;
<< "name")
<< Macro(PIStringAscii("EVENT_VHANDLER1"),
"virtual ret name(a0 n0)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0")
<< Macro(PIStringAscii("EVENT_VHANDLER2"),
"virtual ret name(a0 n0, a1 n1)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1")
<< Macro(PIStringAscii("EVENT_VHANDLER3"),
"virtual ret name(a0 n0, a1 n1, a2 n2)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2")
<< Macro(PIStringAscii("EVENT_VHANDLER4"),
"virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2"
<< "a3"
<< "n3");
} }
@@ -343,14 +232,13 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
static const PIString s_typedef = PIStringAscii("typedef"); static const PIString s_typedef = PIStringAscii("typedef");
static const PIString s_namespace = PIStringAscii("namespace"); static const PIString s_namespace = PIStringAscii("namespace");
static const PIString s_template = PIStringAscii("template"); static const PIString s_template = PIStringAscii("template");
static const PIString s_L = PIStringAscii("$L");
bool mlc = false, cc = false; bool mlc = false, cc = false;
int mls = 0, ole = -1, /*ccs = 0,*/ end = 0; int mls = 0, ole = -1, /*ccs = 0,*/ end = 0;
char c = 0, pc = 0; char c = 0, pc = 0;
PIString pfc, line, ccmn, tmp; PIString pfc, line, ccmn, tmp;
PIMap<PIString, PIString> cchars; PIMap<PIString, PIString> cchars;
/// Remove comments, join multiline '*' and replace '*' to $n (cchars) /// Remove comments, join multiline '*' and replace '*' to $n (cchars)
fc.replaceAll("\r\n", '\n'); fc.replaceAll("\r\n", '\n');
fc.replaceAll('\r', '\n'); fc.replaceAll('\r', '\n');
@@ -359,76 +247,57 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
if (i > 0) pc = c; if (i > 0) pc = c;
c = fc[i].toAscii(); c = fc[i].toAscii();
if (c == '"' && !mlc && pc != '\'') { if (c == '"' && !mlc && pc != '\'') {
if (i > 0) if (i > 0) if (fc[i - 1] == '\\') continue;
if (fc[i - 1] == '\\') continue;
cc = !cc; cc = !cc;
continue; continue;
} }
if (i > 0) if (i > 0)
if (c == '\\' && fc[i - 1].toAscii() != '\\') { if (c == '\\' && fc[i - 1].toAscii() != '\\') {
fc.cutMid(i, 1); fc.cutMid(i, 2);
fc.replace(i, 1, s_L); --i;
++i;
continue; continue;
} }
if (cc) continue; if (cc) continue;
if (fc.mid(i, 2) == "/*") { if (fc.mid(i, 2) == "/*") {mlc = true; mls = i; ++i; continue;}
mlc = true; if (fc.mid(i, 2) == "*/" && mlc) {mlc = false; fc.cutMid(mls, i - mls + 2); i = mls - 1; continue;}
mls = i; if (fc.mid(i, 2) == "//" && !mlc) {ole = fc.find('\n', i); fc.cutMid(i, ole < 0 ? -1 : ole - i); --i; continue;}
++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;
}
} }
pfc = procMacros(fc); pfc = procMacros(fc);
pfc.removeAll(s_L);
if (main) return true; if (main) return true;
bool replaced = true; bool replaced = true;
int replaced_cnt = 0; int replaced_cnt = 0;
while (replaced) { while (replaced) {
// piCout << "MACRO iter" << replaced_cnt; //piCout << "MACRO iter" << replaced_cnt;
if (replaced_cnt >= macros_iter) { if (replaced_cnt >= macros_iter) {
piCout << "Error: recursive macros detected!"; piCout << "Error: recursive macros detected!";
break; // return false; break;//return false;
} }
replaced_cnt++; replaced_cnt++;
replaced = false; replaced = false;
for (const auto & d: defines) { piForeachC (Define & d, defines) {
int ind(-1); int ind(-1);
while ((ind = pfc.find(d.first, ind + 1)) >= 0) { while ((ind = pfc.find(d.first, ind + 1)) >= 0) {
PIChar pc, nc; PIChar pc, nc;
if (ind > 0) pc = pfc[ind - 1]; if (ind > 0) pc = pfc[ind - 1];
if (ind + d.first.size_s() < pfc.size_s()) nc = pfc.mid(ind + d.first.size_s(), 1)[0]; if (ind + d.first.size_s() < pfc.size_s()) nc = pfc.mid(ind + d.first.size_s(),1)[0];
if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue; if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue;
pfc.replace(ind, d.first.size_s(), d.second); pfc.replace(ind, d.first.size_s(), d.second);
ind -= d.first.size_s() - d.second.size_s(); ind -= d.first.size_s() - d.second.size_s();
replaced = true; replaced = true;
} }
} }
for (const auto & m: macros) { piForeachC (Macro & m, macros) {
int ind(-1); int ind(-1);
while ((ind = pfc.find(m.name, ind + 1)) >= 0) { while ((ind = pfc.find(m.name, ind + 1)) >= 0) {
PIChar pc, nc; PIChar pc, nc;
if (ind > 0) pc = pfc[ind - 1]; if (ind > 0) pc = pfc[ind - 1];
if (ind + m.name.size_s() < pfc.size_s()) nc = pfc.mid(ind + m.name.size_s(), 1)[0]; if (ind + m.name.size_s() < pfc.size_s()) nc = pfc.mid(ind + m.name.size_s(),1)[0];
if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue; if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue;
PIString ret, range; PIString ret, range; bool ok(false);
bool ok(false);
range = pfc.mid(ind + m.name.size_s()).takeRange('(', ')'); range = pfc.mid(ind + m.name.size_s()).takeRange('(', ')');
ret = m.expand(range, &ok); ret = m.expand(range, &ok);
if (!ok) return false; if (!ok) return false;
int rlen = pfc.find(range, ind + m.name.size_s()) + range.size_s() + 1 - ind; int rlen = pfc.find(range, ind + m.name.size_s()) + range.size_s() + 1 - ind;
pfc.replace(ind, rlen, ret); pfc.replace(ind, rlen, ret);
@@ -439,10 +308,9 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
} }
replaceMeta(pfc); replaceMeta(pfc);
// piCout << PICoutManipulators::NewLine << "file" << cur_file << pfc; //piCout << PICoutManipulators::NewLine << "file" << cur_file << pfc;
int pl = -1; int pl = -1;
cur_def_vis = Global;
while (!pfc.isEmpty()) { while (!pfc.isEmpty()) {
pfc.trim(); pfc.trim();
int nl = pfc.size_s(); int nl = pfc.size_s();
@@ -453,7 +321,6 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
PIString prev_namespace = cur_namespace, ccmn; PIString prev_namespace = cur_namespace, ccmn;
cur_namespace += pfc.takeCWord() + s_ns; cur_namespace += pfc.takeCWord() + s_ns;
ccmn = pfc.takeRange('{', '}'); ccmn = pfc.takeRange('{', '}');
// piCout << "namespace" << cur_namespace;
parseClass(0, ccmn, true); parseClass(0, ccmn, true);
cur_namespace = prev_namespace; cur_namespace = prev_namespace;
continue; continue;
@@ -463,25 +330,14 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
pfc.takeRange('<', '>'); pfc.takeRange('<', '>');
bool def = !isDeclaration(pfc, 0, &end); bool def = !isDeclaration(pfc, 0, &end);
pfc.cutLeft(end); pfc.cutLeft(end);
if (def) if (def) pfc.takeRange('{', '}');
pfc.takeRange('{', '}'); else pfc.takeSymbol();
else
pfc.takeSymbol();
continue; continue;
} }
if (pfc.left(5) == s_class || pfc.left(6) == s_struct || pfc.left(5) == s_union) { if (pfc.left(5) == s_class || pfc.left(6) == s_struct || pfc.left(5) == s_union) {
int dind = pfc.find('{', 0), find = pfc.find(';', 0); int dind = pfc.find('{', 0), find = pfc.find(';', 0);
// piCout << pfc.left(6) << dind << find; if (dind < 0 && find < 0) {pfc.cutLeft(6); continue;}
if (dind < 0 && find < 0) { if (dind < 0 || find < dind) {pfc.cutLeft(6); continue;}
pfc.cutLeft(6);
continue;
}
if (dind < 0 || find < dind) {
// piCout << "skip FC" << (find + 1) << pfc.left(find + 1);
pfc.cutLeft(find + 1);
// pfc.cutLeft(6);
continue;
}
ccmn = pfc.left(dind) + s_bo + pfc.mid(dind).takeRange('{', '}') + s_bc; ccmn = pfc.left(dind) + s_bo + pfc.mid(dind).takeRange('{', '}') + s_bc;
pfc.remove(0, ccmn.size()); pfc.remove(0, ccmn.size());
parseClass(0, ccmn, false); parseClass(0, ccmn, false);
@@ -492,13 +348,6 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
tmp = pfc.takeCWord(); tmp = pfc.takeCWord();
pfc.trim(); pfc.trim();
MetaMap meta = maybeMeta(pfc); MetaMap meta = maybeMeta(pfc);
if (tmp == s_class || tmp == s_struct) {
tmp = pfc.takeCWord();
pfc.trim();
MetaMap smeta = maybeMeta(pfc);
meta << smeta;
}
// piCout << "pfc E" << cur_namespace << "," << tmp;
parseEnum(0, cur_namespace + tmp, pfc.takeRange('{', '}'), meta); parseEnum(0, cur_namespace + tmp, pfc.takeRange('{', '}'), meta);
pfc.takeSymbol(); pfc.takeSymbol();
continue; continue;
@@ -506,10 +355,8 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
if (pfc.left(7) == s_typedef) { if (pfc.left(7) == s_typedef) {
pfc.cutLeft(7); pfc.cutLeft(7);
typedefs << parseTypedef(pfc.takeLeft(pfc.find(';'))); typedefs << parseTypedef(pfc.takeLeft(pfc.find(';')));
if (typedefs.back().first.isEmpty()) if (typedefs.back().first.isEmpty()) typedefs.pop_back();
typedefs.pop_back(); else root_.typedefs << typedefs.back();
else
root_.typedefs << typedefs.back();
pfc.takeSymbol(); pfc.takeSymbol();
continue; continue;
} }
@@ -527,7 +374,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
} }
parseMember(&root_, str); parseMember(&root_, str);
} }
return true; return true;
} }
@@ -536,49 +383,43 @@ PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc)
static const PIString s_ss = PIStringAscii(" "); static const PIString s_ss = PIStringAscii(" ");
static const PIString s_M = PIStringAscii("$M"); static const PIString s_M = PIStringAscii("$M");
static const PIString s_class = PIStringAscii("class"); static const PIString s_class = PIStringAscii("class");
PIString cd = fc.trimmed().removeAll('\n').replaceAll('\t', ' ').replaceAll(s_ss, ' '), pn; PIString cd = fc.trimmed().removeAll('\n').replaceAll('\t', ' ').replaceAll(s_ss, ' '), pn;
MetaMap meta; MetaMap meta;
int ind = cd.find(s_M); int ind = cd.find(s_M);
if (ind >= 0) { if (ind >= 0) {
meta = tmp_meta.value(cd.takeMid(ind, 5)); meta = tmp_meta.value(cd.takeMid(ind, 5));
cd.replaceAll(s_ss, ' '); cd.replaceAll(s_ss, ' ');
} }
// piCout << "found class <****\n" << cd << "\n****>"; //piCout << "found class <****\n" << cd << "\n****>";
ind = cd.find(':'); ind = cd.find(':');
PIVector<Entity *> parents; PIVector<Entity * > parents;
if (ind > 0) { if (ind > 0) {
PIStringList pl = cd.takeMid(ind + 1).trim().split(','); PIStringList pl = cd.takeMid(ind + 1).trim().split(',');
cd.cutRight(1); cd.cutRight(1);
Entity * pe = 0; Entity * pe = 0;
for (const auto & p: pl) { piForeachC (PIString & p, pl) {
if (p.contains(' ')) if (p.contains(' ')) pn = p.mid(p.find(' ') + 1);
pn = p.mid(p.find(' ') + 1); else pn = p;
else
pn = p;
pe = findEntityByName(pn); pe = findEntityByName(pn);
if (pe == 0) if (pe == 0) ;//{piCout << "Error: can`t find" << pn;}
; //{piCout << "Error: can`t find" << pn;} else parents << pe;
else
parents << pe;
} }
} }
PIString typename_ = cd.left(6).trim(); PIString typename_ = cd.left(6).trim();
bool is_class = typename_ == s_class; bool is_class = typename_ == s_class;
Visibility vis = cur_def_vis; cur_def_vis = (is_class ? Private : Public);
cur_def_vis = (is_class ? Private : Public); PIString cn = cd.mid(6).trim();
PIString cn = cd.mid(6).trim(); bool has_name = !cn.isEmpty();
bool has_name = !cn.isEmpty();
if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>'; if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>';
// piCout << "found " << typename_ << cn; //piCout << "found " << typename_ << cn;
if (cn.isEmpty()) return nullptr; if (cn.isEmpty()) return 0;
Entity * e = new Entity(); Entity * e = new Entity();
e->meta = meta; e->meta = meta;
e->name = cur_namespace + cn; e->name = cur_namespace + cn;
e->type = typename_; e->type = typename_;
e->has_name = has_name; e->has_name = has_name;
e->parents = parents; e->parents = parents;
e->visibility = vis; e->file = cur_file;
e->file = cur_file;
entities << e; entities << e;
return e; return e;
} }
@@ -597,44 +438,37 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
static const PIString s_typedef = PIStringAscii("typedef"); static const PIString s_typedef = PIStringAscii("typedef");
static const PIString s_namespace = PIStringAscii("namespace"); static const PIString s_namespace = PIStringAscii("namespace");
static const PIString s_template = PIStringAscii("template"); static const PIString s_template = PIStringAscii("template");
Visibility prev_vis = cur_def_vis; Visibility prev_vis = cur_def_vis;
int dind = fc.find('{'), find = fc.find(';'), end = 0; int dind = fc.find('{'), find = fc.find(';'), end = 0;
if (dind < 0 && find < 0) return; if (dind < 0 && find < 0) return;
// piCout << "parse class <****\n" << fc << "\n****>"; if (dind < 0 || find < dind) {
fc.left(find);
return;
}
//piCout << "parse class <****\n" << fc << "\n****>";
Entity * ce = parent; Entity * ce = parent;
if (!is_namespace) { if (!is_namespace) {
ce = parseClassDeclaration(fc.takeLeft(dind)); ce = parseClassDeclaration(fc.takeLeft(dind));
fc.trim().cutLeft(1).cutRight(1).trim(); fc.trim().cutLeft(1).cutRight(1).trim();
} }
// piCout << "found class <****\n" << fc << "\n****>"; //piCout << "found class <****\n" << fc << "\n****>";
///if (!ce) return PIString();
if (ce) { if (ce) {
if (parent) parent->children << ce; if (parent) parent->children << ce;
ce->parent_scope = parent; ce->parent_scope = parent;
} }
int ps = -1; int ps = -1;
bool def = false; bool def = false;
PIString prev_namespace = cur_namespace, stmp; PIString prev_namespace = cur_namespace, stmp;
if (ce) cur_namespace = ce->name + s_ns; if (ce) cur_namespace += ce->name + s_ns;
// piCout << "parse class" << (ce ? ce->name : "NULL") << "namespace" << cur_namespace; //piCout << "parse class" << ce->name << "namespace" << cur_namespace;
// piCout << "\nparse class" << ce->name << "namespace" << cur_namespace; //piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
while (!fc.isEmpty()) { while (!fc.isEmpty()) {
PIString cw = fc.takeCWord(), tmp; PIString cw = fc.takeCWord(), tmp;
// piCout << "\ntaked word" << cw; //piCout << "\ntaked word" << cw;
if (cw == s_public) { if (cw == s_public ) {cur_def_vis = Public; fc.cutLeft(1); continue;}
cur_def_vis = Public; if (cw == s_protected) {cur_def_vis = Protected; fc.cutLeft(1); continue;}
fc.cutLeft(1); if (cw == s_private ) {cur_def_vis = Private; fc.cutLeft(1); continue;}
continue;
}
if (cw == s_protected) {
cur_def_vis = Protected;
fc.cutLeft(1);
continue;
}
if (cw == s_private) {
cur_def_vis = Private;
fc.cutLeft(1);
continue;
}
if (cw == s_namespace) { if (cw == s_namespace) {
PIString prev_namespace = cur_namespace, ccmn; PIString prev_namespace = cur_namespace, ccmn;
cur_namespace += fc.takeCWord() + s_ns; cur_namespace += fc.takeCWord() + s_ns;
@@ -644,16 +478,15 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
continue; continue;
} }
if (cw == s_class || cw == s_struct || cw == s_union) { if (cw == s_class || cw == s_struct || cw == s_union) {
// piCout << cw << isDeclaration(fc, 0, &end);
if (isDeclaration(fc, 0, &end)) { if (isDeclaration(fc, 0, &end)) {
fc.cutLeft(end); fc.cutLeft(end);
fc.takeSymbol(); fc.takeSymbol();
continue; continue;
} }
tmp = fc.takeLeft(fc.find('{')); tmp = fc.takeLeft(fc.find('{'));
stmp = fc.takeRange('{', '}'); stmp = fc.takeRange('{', '}');
fc.takeSymbol(); fc.takeSymbol();
stmp = cw + ' ' + tmp + '{' + stmp + '}'; stmp = cw + ' ' + tmp + '{' + stmp + '}';
parseClass(ce, stmp, false); parseClass(ce, stmp, false);
continue; continue;
} }
@@ -661,27 +494,18 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
tmp = fc.takeCWord(); tmp = fc.takeCWord();
fc.trim(); fc.trim();
MetaMap meta = maybeMeta(fc); MetaMap meta = maybeMeta(fc);
if (tmp == s_class || tmp == s_struct) {
tmp = fc.takeCWord();
fc.trim();
MetaMap smeta = maybeMeta(fc);
meta << smeta;
}
// piCout << "pc E" << cur_namespace << "," << tmp;
parseEnum(ce, cur_namespace + tmp, fc.takeRange('{', '}'), meta); parseEnum(ce, cur_namespace + tmp, fc.takeRange('{', '}'), meta);
fc.takeSymbol(); fc.takeSymbol();
continue; continue;
} }
if (cw == s_friend) { if (cw == s_friend) {fc.cutLeft(fc.find(';') + 1); continue;}
fc.cutLeft(fc.find(';') + 1);
continue;
}
if (cw == s_typedef) { if (cw == s_typedef) {
if (ce) { if (ce) {
ce->typedefs << parseTypedef(fc.takeLeft(fc.find(';'))); ce->typedefs << parseTypedef(fc.takeLeft(fc.find(';')));
typedefs << ce->typedefs.back(); typedefs << ce->typedefs.back();
typedefs.back().first.insert(0, cur_namespace); typedefs.back().first.insert(0, cur_namespace);
if (ce->typedefs.back().first.isEmpty()) ce->typedefs.pop_back(); if (ce->typedefs.back().first.isEmpty())
ce->typedefs.pop_back();
} }
fc.takeSymbol(); fc.takeSymbol();
continue; continue;
@@ -690,25 +514,20 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
fc.takeRange('<', '>'); fc.takeRange('<', '>');
def = !isDeclaration(fc, 0, &end); def = !isDeclaration(fc, 0, &end);
fc.cutLeft(end); fc.cutLeft(end);
if (def) if (def) fc.takeRange('{', '}');
fc.takeRange('{', '}'); else fc.takeSymbol();
else
fc.takeSymbol();
continue; continue;
} }
def = !isDeclaration(fc, 0, &end); def = !isDeclaration(fc, 0, &end);
tmp = (cw + fc.takeLeft(end)).trim(); tmp = (cw + fc.takeLeft(end)).trim();
if (!tmp.isEmpty() && ce) parseMember(ce, tmp); if (!tmp.isEmpty() && ce)
if (def) parseMember(ce, tmp);
fc.takeRange('{', '}'); if (def) fc.takeRange('{', '}');
else else fc.takeSymbol();
fc.takeSymbol(); if (ps == fc.size_s()) {fc.cutLeft(1);}
if (ps == fc.size_s()) {
fc.cutLeft(1);
}
ps = fc.size_s(); ps = fc.size_s();
} }
cur_def_vis = prev_vis; cur_def_vis = prev_vis;
cur_namespace = prev_namespace; cur_namespace = prev_namespace;
} }
@@ -717,7 +536,7 @@ PICodeParser::MetaMap PICodeParser::parseMeta(PIString & fc) {
PICodeParser::MetaMap ret; PICodeParser::MetaMap ret;
if (fc.isEmpty()) return ret; if (fc.isEmpty()) return ret;
PIStringList ml = fc.split(','); PIStringList ml = fc.split(',');
for (const auto & m: ml) { piForeachC (PIString & m, ml) {
int i = m.find('='); int i = m.find('=');
if (i < 0) { if (i < 0) {
ret[m.trimmed()] = PIString(); ret[m.trimmed()] = PIString();
@@ -728,61 +547,55 @@ PICodeParser::MetaMap PICodeParser::parseMeta(PIString & fc) {
ret[m.left(i).trim()] = mv; ret[m.left(i).trim()] = mv;
} }
} }
// piCout << ms << ret; //piCout << ms << ret;
return ret; return ret;
} }
bool PICodeParser::parseEnum(Entity * parent, const PIString & name, PIString fc, const MetaMap & meta) { bool PICodeParser::parseEnum(Entity * parent, const PIString & name, PIString fc, const MetaMap & meta) {
static const PIString s_ss = PIStringAscii(" "); static const PIString s_ss = PIStringAscii(" ");
static const PIString s_M = PIStringAscii("$M"); static const PIString s_M = PIStringAscii("$M");
// piCout << PIStringAscii("enum") << name << fc; //piCout << PIStringAscii("enum") << name << fc;
Enum e(name); Enum e(name);
e.meta = meta; e.meta = meta;
PIStringList vl(fc.split(',')); PIStringList vl(fc.split(','));
PIString vn; PIString vn;
int cv = -1, ind = 0; int cv = -1, ind = 0;
for (auto & v: vl) { piForeach (PIString & v, vl) {
MetaMap meta; MetaMap meta;
int mi = v.find(s_M); int mi = v.find(s_M);
if (mi >= 0) { if (mi >= 0) {
meta = tmp_meta.value(v.takeMid(mi, 5)); meta = tmp_meta.value(v.takeMid(mi, 5));
v.replaceAll(s_ss, ' '); v.replaceAll(s_ss, ' ');
} }
vn = v; vn = v; ind = v.find('=');
ind = v.find('='); if (ind > 0) {cv = v.right(v.size_s() - ind - 1).toInt(); vn = v.left(ind);}
if (ind > 0) {
cv = v.right(v.size_s() - ind - 1).toInt();
vn = v.left(ind);
}
if (ind < 0) ++cv; if (ind < 0) ++cv;
e.members << EnumeratorInfo(vn.trim(), cv, meta); e.members << EnumeratorInfo(vn.trim(), cv, meta);
} }
if (!e.members.isEmpty()) if (!e.members.isEmpty())
if (e.members.back().name.isEmpty()) e.members.pop_back(); if (e.members.back().name.isEmpty())
e.members.pop_back();
enums << e; enums << e;
return true; return true;
} }
PICodeParser::Typedef PICodeParser::parseTypedef(PIString fc) { PICodeParser::Typedef PICodeParser::parseTypedef(PIString fc) {
// piCout << "parse typedef" << fc; //piCout << "parse typedef" << fc;
Typedef td; Typedef td;
fc.replaceAll('\t', ' '); fc.replaceAll('\t', ' ');
if (fc.contains('(')) { if (fc.contains('(')) {
int start = fc.find('('), end = fc.find(')'); int start = fc.find('('), end = fc.find(')');
td.first = fc.takeMid(start + 1, end - start - 1).trim(); td.first = fc.takeMid(start + 1, end - start - 1).trim();
if (td.first.left(1) == PIChar('*')) { if (td.first.left(1) == PIChar('*')) {td.first.cutLeft(1).trim(); fc.insert(start + 1, '*');}
td.first.cutLeft(1).trim();
fc.insert(start + 1, '*');
}
td.second = fc.trim(); td.second = fc.trim();
} else { } else {
td.first = fc.takeMid(fc.findLast(' ')).trim(); td.first = fc.takeMid(fc.findLast(' ')).trim();
td.second = fc.trim(); td.second = fc.trim();
} }
// piCout << "found typedef" << td; //piCout << "found typedef" << td;
return td; return td;
} }
@@ -818,26 +631,22 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
if (fc.trim().isEmpty()) return true; if (fc.trim().isEmpty()) return true;
if (fc.find(s_operator) >= 0) return true; if (fc.find(s_operator) >= 0) return true;
tmp_temp.clear(); tmp_temp.clear();
// piCout << "parse member" << fc; //piCout << "parse member" << fc;
int ts = fc.find('<'), te = 0; int ts = fc.find('<'), te = 0;
PIString ctemp, crepl; PIString ctemp, crepl;
while (ts >= 0) { while (ts >= 0) {
ctemp = fc.mid(ts).takeRange('<', '>'); ctemp = fc.mid(ts).takeRange('<', '>');
if (ctemp.isEmpty()) { if (ctemp.isEmpty()) {te = ts + 1; ts = fc.find('<', te); continue;}
te = ts + 1;
ts = fc.find('<', te);
continue;
}
crepl = s_T + PIString::fromNumber(tmp_temp.size_s()).expandLeftTo(3, '0'); crepl = s_T + PIString::fromNumber(tmp_temp.size_s()).expandLeftTo(3, '0');
fc.replace(ts, ctemp.size_s() + 2, crepl); fc.replace(ts, ctemp.size_s() + 2, crepl);
tmp_temp[crepl] = '<' + ctemp + '>'; tmp_temp[crepl] = '<' + ctemp + '>';
ts = fc.find('<', te); ts = fc.find('<', te);
} }
fc.replaceAll('\n', ' ').replaceAll('\t', ' ').replaceAll(s_ss, ' ').replaceAll(s_cs, ',').replaceAll(s_sb, '(').replaceAll(s_sM, s_M); fc.replaceAll('\n', ' ').replaceAll('\t', ' ').replaceAll(s_ss, ' ').replaceAll(s_cs, ',').replaceAll(s_sb, '(').replaceAll(s_sM, s_M);
// piCout << "parse member" << fc; //piCout << "parse member" << fc;
PIStringList tl, al; PIStringList tl, al;
Member me; Member me;
// piCout << fc; //piCout << fc;
if (fc.contains('(')) { if (fc.contains('(')) {
MetaMap meta; MetaMap meta;
int ind = fc.find(s_M); int ind = fc.find(s_M);
@@ -847,16 +656,16 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
} }
fc.cutRight(fc.size_s() - fc.findLast(')') - 1); fc.cutRight(fc.size_s() - fc.findLast(')') - 1);
te = fc.find('('); te = fc.find('(');
// piCout << fc; //piCout << fc;
for (ts = te - 1; ts >= 0; --ts) for (ts = te - 1; ts >= 0; --ts)
if (!_isCChar(fc[ts]) && !(fc[ts].isDigit())) break; if (!_isCChar(fc[ts]) && !(fc[ts].isDigit())) break;
// piCout << "takeMid" << ts + 1 << te - ts - 1; //piCout << "takeMid" << ts + 1 << te - ts - 1;
me.meta = meta; me.meta = meta;
me.name = fc.takeMid(ts + 1, te - ts - 1); me.name = fc.takeMid(ts + 1, te - ts - 1);
if (me.name == parent->name) return true; if (me.name == parent->name) return true;
me.arguments_full = fc.takeMid(ts + 2).cutRight(1).split(','); me.arguments_full = fc.takeMid(ts + 2).cutRight(1).split(',');
me.type = fc.cutRight(1).trim(); me.type = fc.cutRight(1).trim();
me.visibility = cur_def_vis; me.visibility = cur_def_vis;
if (me.type.find(s_inline_s) >= 0) { if (me.type.find(s_inline_s) >= 0) {
me.attributes |= Inline; me.attributes |= Inline;
me.type.removeAll(s_inline_s); me.type.removeAll(s_inline_s);
@@ -871,18 +680,20 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
} }
normalizeEntityNamespace(me.type); normalizeEntityNamespace(me.type);
int i = 0; int i = 0;
// piCout << me.arguments_full; //piCout << me.arguments_full;
for (auto & a: me.arguments_full) piForeach (PIString & a, me.arguments_full)
if ((i = a.find('=')) > 0) a.cutRight(a.size_s() - i).trim(); if ((i = a.find('=')) > 0)
a.cutRight(a.size_s() - i).trim();
for (int j = 0; j < me.arguments_full.size_s(); ++j) for (int j = 0; j < me.arguments_full.size_s(); ++j)
if (me.arguments_full[j] == s_void) { if (me.arguments_full[j] == s_void) {
me.arguments_full.remove(j); me.arguments_full.remove(j);
--j; --j;
} }
me.arguments_type = me.arguments_full; me.arguments_type = me.arguments_full;
for (auto & a: me.arguments_type) { piForeach (PIString & a, me.arguments_type) {
crepl.clear(); crepl.clear();
if (a.contains('[')) crepl = a.takeMid(a.find('['), a.findLast(']') - a.find('[') + 1); if (a.contains('['))
crepl = a.takeMid(a.find('['), a.findLast(']') - a.find('[') + 1);
for (ts = a.size_s() - 1; ts >= 0; --ts) for (ts = a.size_s() - 1; ts >= 0; --ts)
if (!_isCChar(a[ts]) && !(a[ts].isDigit())) break; if (!_isCChar(a[ts]) && !(a[ts].isDigit())) break;
a.cutRight(a.size_s() - ts - 1); a.cutRight(a.size_s() - ts - 1);
@@ -891,34 +702,31 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
a.trim(); a.trim();
} }
restoreTmpTemp(&me); restoreTmpTemp(&me);
// piCout << "func" << me.type << me.name << me.arguments_full << me.arguments_type; //piCout << "func" << me.type << me.name << me.arguments_full << me.arguments_type;
parent->functions << me; parent->functions << me;
} else { } else {
if (fc.endsWith(';')) fc.cutRight(1); if (fc.endsWith(';')) fc.cutRight(1);
// piCout << "member" << fc; //piCout << "member" << fc;
if (fc.startsWith(s_using) || !(fc.contains(' ') || fc.contains('\t') || fc.contains('\n'))) return true; if (fc.startsWith(s_using) || !(fc.contains(' ') || fc.contains('\t') || fc.contains('\n'))) return true;
int bits = extractMemberBits(fc); int bits = extractMemberBits(fc);
tl = fc.split(','); tl = fc.split(',');
// piCout << "member" << fc << tl; //piCout << "member" << fc << tl;
// piCout << "member after eb" << fc << ", bits =" << bits; //piCout << "member after eb" << fc << ", bits =" << bits;
if (tl.isEmpty()) return true; if (tl.isEmpty()) return true;
for (auto & v: tl) piForeach (PIString & v, tl)
removeAssignment(v); removeAssignment(v);
bool vn = true; bool vn = true;
ctemp = tl.front().trim(); ctemp = tl.front().trim();
PIString meta_t; PIString meta_t;
if (ctemp.contains(s_M)) { if (ctemp.contains(s_M)) {
meta_t = ctemp.takeMid(ctemp.find(s_M), 5); meta_t = ctemp.takeMid(ctemp.find(s_M), 5);
ctemp.trim(); ctemp.trim();
} }
for (ts = ctemp.size_s() - 1; ts > 0; --ts) { for (ts = ctemp.size_s() - 1; ts > 0; --ts) {
if (vn) { if (vn) {if (!_isCChar(ctemp[ts]) && !ctemp[ts].isDigit() && ctemp[ts] != '[' && ctemp[ts] != ']') vn = false;}
if (!_isCChar(ctemp[ts]) && !ctemp[ts].isDigit() && ctemp[ts] != '[' && ctemp[ts] != ']') vn = false; else {if (_isCChar(ctemp[ts]) || ctemp[ts].isDigit()) break;}
} else {
if (_isCChar(ctemp[ts]) || ctemp[ts].isDigit()) break;
}
} }
me.type = ctemp.takeLeft(ts + 1); me.type = ctemp.takeLeft(ts + 1);
me.visibility = cur_def_vis; me.visibility = cur_def_vis;
ctemp += meta_t; ctemp += meta_t;
restoreTmpTemp(&me); restoreTmpTemp(&me);
@@ -946,21 +754,21 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
type.trim(); type.trim();
normalizeEntityNamespace(type); normalizeEntityNamespace(type);
tl[0] = ctemp.trim(); tl[0] = ctemp.trim();
// piCout << "vars" << tl; //piCout << "vars" << tl;
for (const auto & v: tl) { piForeachC (PIString & v, tl) {
crepl.clear(); crepl.clear();
me.name = v.trimmed(); me.name = v.trimmed();
me.type = type; me.type = type;
restoreTmpMeta(&me); restoreTmpMeta(&me);
if (me.name.isEmpty()) continue; if (me.name.isEmpty()) continue;
if (me.name.contains('[')) crepl = me.name.takeMid(me.name.find('['), me.name.findLast(']') - me.name.find('[') + 1); if (me.name.contains('['))
crepl = me.name.takeMid(me.name.find('['), me.name.findLast(']') - me.name.find('[') + 1);
while (!me.name.isEmpty()) { while (!me.name.isEmpty()) {
if (me.name.front() == PIChar('*') || me.name.front() == PIChar('&')) { if (me.name.front() == PIChar('*') || me.name.front() == PIChar('&')) {
me.type += me.name.takeLeft(1); me.type += me.name.takeLeft(1);
me.name.trim(); me.name.trim();
} else } else break;
break;
} }
me.is_type_ptr = (me.type.right(1) == PIChar(']') || me.type.right(1) == PIChar('*')); me.is_type_ptr = (me.type.right(1) == PIChar(']') || me.type.right(1) == PIChar('*'));
me.type += crepl; me.type += crepl;
@@ -970,12 +778,12 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
if (cdim.isEmpty()) break; if (cdim.isEmpty()) break;
me.dims << cdim; me.dims << cdim;
} }
// PICout(PICoutManipulators::AddAll) << "var" << me.type << me.name << me.bits; //PICout(PICoutManipulators::AddAll) << "var" << me.type << me.name << me.bits;
// piCout << "var" << v << me.type << me.name << me.bits; //piCout << "var" << v << me.type << me.name << me.bits;
parent->members << me; parent->members << me;
} }
} }
// piCout << "parse member" << fc; //piCout << "parse member" << fc;
return true; return true;
} }
@@ -1007,25 +815,13 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
break; break;
} }
n.push_front(' '); n.push_front(' ');
if (n.find(s_s_const_s) >= 0) { if (n.find(s_s_const_s) >= 0) {n.replaceAll(s_s_const_s, ""); pref += s_const_s;}
n.replaceAll(s_s_const_s, ""); if (n.find(s_s_static_s) >= 0) {n.replaceAll(s_s_static_s, ""); pref += s_static_s;}
pref += s_const_s; if (n.find(s_s_mutable_s) >= 0) {n.replaceAll(s_s_mutable_s, ""); pref += s_mutable_s;}
} if (n.find(s_s_volatile_s) >= 0) {n.replaceAll(s_s_volatile_s, ""); pref += s_volatile_s;}
if (n.find(s_s_static_s) >= 0) {
n.replaceAll(s_s_static_s, "");
pref += s_static_s;
}
if (n.find(s_s_mutable_s) >= 0) {
n.replaceAll(s_s_mutable_s, "");
pref += s_mutable_s;
}
if (n.find(s_s_volatile_s) >= 0) {
n.replaceAll(s_s_volatile_s, "");
pref += s_volatile_s;
}
n.trim(); n.trim();
int f = 0; int f = 0;
for (const auto * e: entities) { piForeachC (Entity * e, entities) {
if (e->name == n) { if (e->name == n) {
n = (pref + n + suff).trim(); n = (pref + n + suff).trim();
return; return;
@@ -1037,20 +833,20 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
return; return;
} }
} }
for (const auto & e: enums) { piForeachC (Enum & e, enums) {
if ((f = e.name.find(n)) >= 0) if ((f = e.name.find(n)) >= 0)
if (e.name.at(f - 1) == PIChar(':')) if (e.name.at(f - 1) == PIChar(':'))
if (e.name.find(cur_namespace) >= 0) { if (e.name.find(cur_namespace) >= 0) {
// piCout << "change" << n << "to" << e.name + suff; //piCout << "change" << n << "to" << e.name + suff;
n = pref + e.name + suff; n = pref + e.name + suff;
return; return;
} }
} }
for (const auto & e: typedefs) { piForeachC (Typedef & e, typedefs) {
if ((f = e.first.find(n)) >= 0) if ((f = e.first.find(n)) >= 0)
if (e.first.at(f - 1) == PIChar(':')) if (e.first.at(f - 1) == PIChar(':'))
if (e.first.find(cur_namespace) >= 0) { if (e.first.find(cur_namespace) >= 0) {
// piCout << "change" << n << "to" << e.name + suff; //piCout << "change" << n << "to" << e.name + suff;
n = pref + e.first + suff; n = pref + e.first + suff;
return; return;
} }
@@ -1061,12 +857,12 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
void PICodeParser::restoreTmpTemp(Member * e) { void PICodeParser::restoreTmpTemp(Member * e) {
static const PIString s_T = PIStringAscii("$T"); static const PIString s_T = PIStringAscii("$T");
int i = 0; int i = 0;
for (auto & a: e->arguments_full) { piForeach (PIString & a, e->arguments_full) {
while ((i = a.find(s_T)) >= 0) while ((i = a.find(s_T)) >= 0)
a.replace(i, 5, tmp_temp[a.mid(i, 5)]); a.replace(i, 5, tmp_temp[a.mid(i, 5)]);
} }
for (auto & a: e->arguments_type) { piForeach (PIString & a, e->arguments_type) {
while ((i = a.find(s_T)) >= 0) while ((i = a.find(s_T)) >= 0)
a.replace(i, 5, tmp_temp[a.mid(i, 5)]); a.replace(i, 5, tmp_temp[a.mid(i, 5)]);
} }
@@ -1077,7 +873,7 @@ void PICodeParser::restoreTmpTemp(Member * e) {
void PICodeParser::restoreTmpMeta(PICodeParser::Member * e) { void PICodeParser::restoreTmpMeta(PICodeParser::Member * e) {
static const PIString s_M = PIStringAscii("$M"); static const PIString s_M = PIStringAscii("$M");
int i = e->name.find(s_M); int i = e->name.find(s_M);
if (i < 0) return; if (i < 0) return;
e->meta = tmp_meta[e->name.takeMid(i, 5)]; e->meta = tmp_meta[e->name.takeMid(i, 5)];
} }
@@ -1099,7 +895,7 @@ bool PICodeParser::macroCondition(const PIString & mif, PIString mifcond) {
static const PIString s_ifndef = PIStringAscii("ifndef"); static const PIString s_ifndef = PIStringAscii("ifndef");
static const PIString s_if = PIStringAscii("if"); static const PIString s_if = PIStringAscii("if");
static const PIString s_elif = PIStringAscii("elif"); static const PIString s_elif = PIStringAscii("elif");
// piCout << "macroCondition" << mif << mifcond; //piCout << "macroCondition" << mif << mifcond;
if (mif == s_ifdef) return isDefineExists(mifcond); if (mif == s_ifdef) return isDefineExists(mifcond);
if (mif == s_ifndef) return !isDefineExists(mifcond); if (mif == s_ifndef) return !isDefineExists(mifcond);
if (mif == s_if || mif == s_elif) { if (mif == s_if || mif == s_elif) {
@@ -1118,65 +914,52 @@ double PICodeParser::procMacrosCond(PIString fc) {
char cc, nc; char cc, nc;
PIString ce; PIString ce;
fc.removeAll(s_defined); fc.removeAll(s_defined);
// piCout << "procMacrosCond" << fc; //piCout << "procMacrosCond" << fc;
while (!fc.isEmpty()) { while (!fc.isEmpty()) {
cc = fc[0].toAscii(); cc = fc[0].toAscii();
nc = (fc.size() > 1 ? fc[1].toAscii() : 0); nc = (fc.size() > 1 ? fc[1].toAscii() : 0);
if (cc == '!') { if (cc == '!') {neg = true; fc.pop_front(); continue;}
neg = true; if (cc == '(') {br = true; brv = procMacrosCond(fc.takeRange('(', ')'));}
fc.pop_front(); if (cc == '&' && nc == '&') {fc.remove(0, 2); oper = 1; continue;}
continue; if (cc == '|' && nc == '|') {fc.remove(0, 2); oper = 2; 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) { if (!br) {
ce = fc.takeCWord(); ce = fc.takeCWord();
if (ce.isEmpty()) ce = fc.takeNumber(); if (ce.isEmpty()) ce = fc.takeNumber();
} }
if (first) { if (first) {
first = false; first = false;
ret = br ? brv : defineValue(ce); ret = br ? brv : defineValue(ce);
if (neg) ret = -ret; if (neg) ret = -ret;
} else { } else {
// piCout << "oper" << oper << "with" << ce; //piCout << "oper" << oper << "with" << ce;
if (!br) brv = defineValue(ce); if (!br) brv = defineValue(ce);
switch (oper) { switch (oper) {
case 1: ret = ret && (neg ? -brv : brv); break; case 1: ret = ret && (neg ? -brv : brv); break;
case 2: ret = ret || (neg ? -brv : brv); break; case 2: ret = ret || (neg ? -brv : brv); break;
} }
} }
if (ps == fc.size_s()) fc.cutLeft(1); if (ps == fc.size_s()) fc.cutLeft(1);
ps = fc.size_s(); ps = fc.size_s();
br = neg = false; br = neg = false;
} }
// piCout << "return" << ret; //piCout << "return" << ret;
return ret; return ret;
} }
bool PICodeParser::isDefineExists(const PIString & dn) { bool PICodeParser::isDefineExists(const PIString & dn) {
for (const auto & d: defines) { piForeachC (Define & d, defines) {
if (d.first == dn) return true; if (d.first == dn)
return true;
} }
return false; return false;
} }
double PICodeParser::defineValue(const PIString & dn) { double PICodeParser::defineValue(const PIString & dn) {
for (const auto & d: defines) { piForeachC (Define & d, defines) {
if (d.first == dn) return d.second.isEmpty() ? 1. : d.second.toDouble(); if (d.first == dn)
return d.second.isEmpty() ? 1. : d.second.toDouble();
} }
return dn.toDouble(); return dn.toDouble();
} }
@@ -1193,33 +976,28 @@ void PICodeParser::replaceMeta(PIString & dn) {
ms = dn.findRange('(', ')', '\\', s + 6, &ml); ms = dn.findRange('(', ')', '\\', s + 6, &ml);
if (ms < 0) return; if (ms < 0) return;
PIString meta = dn.mid(ms, ml).trim(); PIString meta = dn.mid(ms, ml).trim();
PIString rm = s_M + PIString::fromNumber(tmp_meta.size_s()).expandLeftTo(3, '0'); PIString rm = s_M + PIString::fromNumber(tmp_meta.size_s()).expandLeftTo(3, '0');
dn.replace(s, ms + ml + 1 - s, rm); dn.replace(s, ms + ml + 1 - s, rm);
// piCout << "FOUND META \"" << meta << '\"'; //piCout << "FOUND META \"" << meta << '\"';
tmp_meta[rm] = parseMeta(meta); tmp_meta[rm] = parseMeta(meta);
s = dn.find(s_PIMETA); s = dn.find(s_PIMETA);
} }
} }
PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) { PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) {
for (auto * e: entities) piForeach (Entity * e, entities)
if (e->name == en) return e; if (e->name == en)
return e;
return 0; return 0;
} }
bool PICodeParser::isDeclaration(const PIString & fc, int start, int * end) { bool PICodeParser::isDeclaration(const PIString & fc, int start, int * end) {
int dind = fc.find('{', start), find = fc.find(';', start); int dind = fc.find('{', start), find = fc.find(';', start);
// piCout << "isDeclaration" << dind << find << fc.left(10); //piCout << "isDeclaration" << dind << find << fc.left(10);
if (dind < 0 && find < 0) { if (dind < 0 && find < 0) {if (end) *end = -1; return true;}
if (end) *end = -1; if (dind < 0 || find < dind) {if (end) *end = find; return true;}
return true;
}
if (dind < 0 || find < dind) {
if (end) *end = find;
return true;
}
if (end) *end = dind; if (end) *end = dind;
return false; return false;
} }
@@ -1232,7 +1010,7 @@ bool PICodeParser::isMainFile(const PIString & fc) {
if (csi < 0) csi = fc.find(PIStringAscii("\tmain"), si); if (csi < 0) csi = fc.find(PIStringAscii("\tmain"), si);
if (csi < 0) csi = fc.find(PIStringAscii("\nmain"), si); if (csi < 0) csi = fc.find(PIStringAscii("\nmain"), si);
if (csi < 0) return false; if (csi < 0) return false;
si = csi; si = csi;
int fi = fc.find('(', si + 5); int fi = fc.find('(', si + 5);
if (fi < 0) return false; if (fi < 0) return false;
if (fi - si < 10) { if (fi - si < 10) {
@@ -1253,85 +1031,72 @@ PIString PICodeParser::procMacros(PIString fc) {
static const PIString s_elif = PIStringAscii("elif"); static const PIString s_elif = PIStringAscii("elif");
static const PIString s_else = PIStringAscii("else"); static const PIString s_else = PIStringAscii("else");
static const PIString s_endif = PIStringAscii("endif"); static const PIString s_endif = PIStringAscii("endif");
static const PIString s_L = PIStringAscii("$L");
if (fc.isEmpty()) return PIString(); if (fc.isEmpty()) return PIString();
int ifcnt = 0; int ifcnt = 0;
bool grab = false, skip = false, cond_ok = false; bool grab = false, skip = false, cond_ok = false;
PIString pfc, nfc, line, mif, mifcond; PIString pfc, nfc, line, mif, mifcond;
// piCout << "procMacros\n<******" << fc << "\n******>"; //piCout << "procMacros\n<******" << fc << "\n******>";
fc += '\n'; fc += '\n';
while (!fc.isEmpty()) { while (!fc.isEmpty()) {
line = fc.takeLine().trimmed(); line = fc.takeLine().trimmed();
if (line.left(1) == PIChar('#')) { if (line.left(1) == PIChar('#')) {
mifcond = line.mid(1); mifcond = line.mid(1);
mif = mifcond.takeCWord(); mif = mifcond.takeCWord();
// piCout << mif; //piCout << mif;
// piCout << "mif mifcond" << mif << mifcond << ifcnt; //piCout << "mif mifcond" << mif << mifcond << ifcnt;
if (skip || grab) { if (skip || grab) {
if (mif.left(2) == s_if) ifcnt++; if (mif.left(2) == s_if) ifcnt++;
if (mif.left(5) == s_endif) { if (mif.left(5) == s_endif) {
if (ifcnt > 0) if (ifcnt > 0) ifcnt--;
ifcnt--;
else { else {
// piCout << "main endif" << skip << grab; //piCout << "main endif" << skip << grab;
if (grab) pfc += procMacros(nfc); if (grab) pfc << procMacros(nfc);
skip = grab = false; skip = grab = false;
continue; continue;
} }
} }
if (mif.left(4) == s_elif && ifcnt == 0) { if (mif.left(4) == s_elif && ifcnt == 0) {
// piCout << "main elif" << skip << grab << cond_ok; //piCout << "main elif" << skip << grab << cond_ok;
if (cond_ok) { if (cond_ok) {
if (grab) { if (grab) {
pfc += procMacros(nfc); pfc << procMacros(nfc);
skip = true; skip = true; grab = false;
grab = false;
} }
continue; continue;
} }
if (skip) { if (skip) {
// piCout << "check elif" << skip << grab << cond_ok; //piCout << "check elif" << skip << grab << cond_ok;
if (!macroCondition(mif, mifcond.trimmed())) continue; if (!macroCondition(mif, mifcond.trimmed())) continue;
// piCout << "check elif ok"; //piCout << "check elif ok";
skip = false; skip = false; grab = cond_ok = true;
grab = cond_ok = true;
continue; continue;
} }
continue; continue;
} }
if (mif.left(4) == s_else && ifcnt == 0) { if (mif.left(4) == s_else && ifcnt == 0) {
// piCout << "main else" << skip << grab; //piCout << "main else" << skip << grab;
if (grab) pfc += procMacros(nfc); if (grab) pfc << procMacros(nfc);
if (skip && !cond_ok) { if (skip && !cond_ok) {skip = false; grab = true;}
skip = false; else {skip = true; grab = false;}
grab = true;
} else {
skip = true;
grab = false;
}
continue; continue;
} }
if (grab) nfc += line + '\n'; if (grab) nfc << line << '\n';
continue; continue;
} }
if (mif.left(2) == s_if) { if (mif.left(2) == s_if) {
// piCout << "main if"; //piCout << "main if";
skip = grab = cond_ok = false; skip = grab = cond_ok = false;
if (macroCondition(mif, mifcond.trimmed())) if (macroCondition(mif, mifcond.trimmed())) grab = cond_ok = true;
grab = cond_ok = true; else skip = true;
else
skip = true;
ifcnt = 0; ifcnt = 0;
nfc.clear(); nfc.clear();
} else { } else {
parseDirective(line.cutLeft(1).trim()); parseDirective(line.cutLeft(1).trim());
// return false; /// WARNING: now skip errors //return false; /// WARNING: now skip errors
} }
} else { } else {
if (grab) if (grab) nfc << line << '\n';
nfc += line + '\n'; else if (!skip) pfc << line << '\n';
else if (!skip)
pfc += line + '\n';
} }
} }
return pfc; return pfc;
@@ -1339,15 +1104,13 @@ PIString PICodeParser::procMacros(PIString fc) {
bool PICodeParser::parseDirective(PIString d) { bool PICodeParser::parseDirective(PIString d) {
static const PIString s_include = PIStringAscii("include"); static const PIString s_include = PIStringAscii("include");
static const PIString s_define = PIStringAscii("define"); static const PIString s_define = PIStringAscii("define");
static const PIString s_undef = PIStringAscii("undef"); static const PIString s_undef = PIStringAscii("undef");
static const PIString s_PIMETA = PIStringAscii("PIMETA"); static const PIString s_PIMETA = PIStringAscii("PIMETA");
static const PIString s_L = PIStringAscii("$L");
if (d.isEmpty()) return true; if (d.isEmpty()) return true;
d.replaceAll(s_L, '\n');
PIString dname = d.takeCWord(); PIString dname = d.takeCWord();
// piCout << "parseDirective" << d; //piCout << "parseDirective" << d;
if (dname == s_include) { if (dname == s_include) {
d.replaceAll('<', '\"').replaceAll('>', '\"'); d.replaceAll('<', '\"').replaceAll('>', '\"');
PIString cf = cur_file, ifc = d.takeRange('\"', '\"'); PIString cf = cur_file, ifc = d.takeRange('\"', '\"');
@@ -1359,7 +1122,7 @@ bool PICodeParser::parseDirective(PIString d) {
} }
if (dname == s_define) { if (dname == s_define) {
PIString mname = d.takeCWord(); PIString mname = d.takeCWord();
// piCout << mname; //piCout << mname;
if (mname == s_PIMETA) return true; if (mname == s_PIMETA) return true;
if (d.left(1) == PIChar('(')) { // macro if (d.left(1) == PIChar('(')) { // macro
PIStringList args = d.takeRange('(', ')').split(',').trim(); PIStringList args = d.takeRange('(', ')').split(',').trim();
@@ -1384,10 +1147,7 @@ bool PICodeParser::parseDirective(PIString d) {
if (dname == s_undef) { if (dname == s_undef) {
PIString mname = d.takeCWord(); PIString mname = d.takeCWord();
for (int i = 0; i < defines.size_s(); ++i) for (int i = 0; i < defines.size_s(); ++i)
if (defines[i].first == mname) { if (defines[i].first == mname) {defines.remove(i); --i;}
defines.remove(i);
--i;
}
return true; return true;
} }
return true; return true;

View File

@@ -5,59 +5,49 @@
* \~russian Разбор C++ кода * \~russian Разбор C++ кода
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
C++ code parser C++ code parser
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PICODEPARSER_H #ifndef PICODEPARSER_H
#define PICODEPARSER_H #define PICODEPARSER_H
#include "pievaluator.h"
#include "pifile.h" #include "pifile.h"
#include "pievaluator.h"
inline bool _isCChar(const PIChar & c) { inline bool _isCChar(const PIChar & c) {return (c.isAlpha() || (c.toAscii() == '_'));}
return (c.isAlpha() || (c.toAscii() == '_')); inline bool _isCChar(const PIString & c) {if (c.isEmpty()) return false; return _isCChar(c[0]);}
}
inline bool _isCChar(const PIString & c) {
if (c.isEmpty()) return false;
return _isCChar(c[0]);
}
class PIP_EXPORT PICodeParser { class PIP_EXPORT PICodeParser {
public: public:
PICodeParser(); PICodeParser();
enum Visibility { enum Visibility {Global, Public, Protected, Private};
Global,
Public,
Protected,
Private
};
enum Attribute { enum Attribute {
NoAttributes = 0x0, NoAttributes = 0x0,
Const = 0x01, Const = 0x01,
Static = 0x02, Static = 0x02,
Mutable = 0x04, Mutable = 0x04,
Volatile = 0x08, Volatile = 0x08,
Inline = 0x10, Inline = 0x10,
Virtual = 0x20, Virtual = 0x20,
Extern = 0x40 Extern = 0x40
}; };
typedef PIFlags<Attribute> Attributes; typedef PIFlags<Attribute> Attributes;
typedef PIPair<PIString, PIString> Define; typedef PIPair<PIString, PIString> Define;
typedef PIPair<PIString, PIString> Typedef; typedef PIPair<PIString, PIString> Typedef;
@@ -65,25 +55,25 @@ public:
struct PIP_EXPORT Macro { struct PIP_EXPORT Macro {
Macro(const PIString & n = PIString(), const PIString & v = PIString(), const PIStringList & a = PIStringList()) { Macro(const PIString & n = PIString(), const PIString & v = PIString(), const PIStringList & a = PIStringList()) {
name = n; name = n;
value = v; value = v;
args = a; args = a;
} }
PIString expand(PIString args_, bool * ok = 0) const; PIString expand(PIString args_, bool * ok = 0) const;
PIString name; PIString name;
PIString value; PIString value;
PIStringList args; PIStringList args;
}; };
struct PIP_EXPORT Member { struct PIP_EXPORT Member {
Member() { Member() {
visibility = Global; visibility = Global;
size = 0; size = 0;
bits = -1; bits = -1;
is_type_ptr = false; is_type_ptr = false;
attributes = NoAttributes; attributes = NoAttributes;
} }
bool isBitfield() const { return bits > 0; } bool isBitfield() const {return bits > 0;}
MetaMap meta; MetaMap meta;
PIString type; PIString type;
PIString name; PIString name;
@@ -96,12 +86,12 @@ public:
int size; int size;
int bits; int bits;
}; };
struct PIP_EXPORT Entity { struct PIP_EXPORT Entity {
Entity() { Entity() {
visibility = Global; visibility = Global;
has_name = true; has_name = true;
size = 0; size = 0;
parent_scope = 0; parent_scope = 0;
} }
MetaMap meta; MetaMap meta;
@@ -112,52 +102,49 @@ public:
int size; int size;
bool has_name; bool has_name;
Entity * parent_scope; Entity * parent_scope;
PIVector<Entity *> parents; PIVector<Entity * > parents;
PIVector<Entity *> children; PIVector<Entity * > children;
PIVector<Member> functions; PIVector<Member> functions;
PIVector<Member> members; PIVector<Member> members;
PIVector<Typedef> typedefs; PIVector<Typedef> typedefs;
}; };
struct PIP_EXPORT EnumeratorInfo { struct PIP_EXPORT EnumeratorInfo {
EnumeratorInfo(const PIString & n = PIString(), int v = 0, const MetaMap & m = MetaMap()) { EnumeratorInfo(const PIString & n = PIString(), int v = 0, const MetaMap & m = MetaMap()) {name = n; value = v; meta = m;}
name = n;
value = v;
meta = m;
}
MetaMap meta; MetaMap meta;
PIString name; PIString name;
int value; int value;
}; };
struct PIP_EXPORT Enum { struct PIP_EXPORT Enum {
Enum(const PIString & n = PIString()) { name = n; } Enum(const PIString & n = PIString()) {
name = n;
}
MetaMap meta; MetaMap meta;
PIString name; PIString name;
PIVector<EnumeratorInfo> members; PIVector<EnumeratorInfo> members;
}; };
void parseFile(const PIString & file, bool follow_includes = true); void parseFile(const PIString & file, bool follow_includes = true);
void parseFiles(const PIStringList & files, bool follow_includes = true); void parseFiles(const PIStringList & files, bool follow_includes = true);
void parseFileContent(PIString fc);
void includeDirectory(const PIString & dir) {includes << dir;}
void includeDirectory(const PIString & dir) { includes << dir; } void addDefine(const PIString & def_name, const PIString & def_value) {custom_defines << Define(def_name, def_value);}
void addDefine(const PIString & def_name, const PIString & def_value) { custom_defines << Define(def_name, def_value); }
bool isEnum(const PIString & name); bool isEnum(const PIString & name);
Entity * findEntityByName(const PIString & en); Entity * findEntityByName(const PIString & en);
PIStringList parsedFiles() const { return PIStringList(proc_files.toVector()); } PIStringList parsedFiles() const {return PIStringList(proc_files.toVector());}
PIString mainFile() const { return main_file; } PIString mainFile() const {return main_file;}
const PICodeParser::Entity * global() const { return &root_; } const PICodeParser::Entity * global() const {return &root_;}
int macrosSubstitutionMaxIterations() const { return macros_iter; } int macrosSubstitutionMaxIterations() const {return macros_iter;}
void setMacrosSubstitutionMaxIterations(int value) { macros_iter = value; } void setMacrosSubstitutionMaxIterations(int value) {macros_iter = value;}
PIVector<Define> defines, custom_defines; PIVector<Define> defines, custom_defines;
PIVector<Macro> macros; PIVector<Macro> macros;
PIVector<Enum> enums; PIVector<Enum> enums;
PIVector<Typedef> typedefs; PIVector<Typedef> typedefs;
PIVector<Entity *> entities; PIVector<Entity * > entities;
private: private:
void clear(); void clear();
bool parseFileInternal(const PIString & file, bool follow_includes); bool parseFileInternal(const PIString & file, bool follow_includes);
@@ -182,7 +169,7 @@ private:
bool isDeclaration(const PIString & fc, int start, int * end); bool isDeclaration(const PIString & fc, int start, int * end);
bool isMainFile(const PIString & fc); bool isMainFile(const PIString & fc);
void normalizeEntityNamespace(PIString & n); void normalizeEntityNamespace(PIString & n);
int macros_iter, anon_num; int macros_iter, anon_num;
bool with_includes; bool with_includes;
PIEvaluator evaluator; PIEvaluator evaluator;
@@ -194,6 +181,7 @@ private:
PIString cur_namespace; PIString cur_namespace;
PIMap<PIString, PIString> tmp_temp; PIMap<PIString, PIString> tmp_temp;
PIMap<PIString, MetaMap> tmp_meta; PIMap<PIString, MetaMap> tmp_meta;
}; };
#endif // PICODEPARSER_H #endif // PICODEPARSER_H

View File

@@ -6,22 +6,22 @@
* \~russian Сжатие с помощью zlib * \~russian Сжатие с помощью zlib
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Compress class using zlib Compress class using zlib
Andrey Bychkov work.a.b@yandex.ru Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \defgroup Compress Compress //! \defgroup Compress Compress
//! \~\brief //! \~\brief
@@ -58,8 +58,8 @@
#ifndef PICOMPRESS_H #ifndef PICOMPRESS_H
#define PICOMPRESS_H #define PICOMPRESS_H
#include "pibytearray.h"
#include "pip_compress_export.h" #include "pip_compress_export.h"
#include "pibytearray.h"
//! \~english Compress "ba" with compression level "level", return empty %PIByteArray if no compression supports //! \~english Compress "ba" with compression level "level", return empty %PIByteArray if no compression supports
//! \~russian Сжимает "ba" с уровнем сжатия "level", возвращает пустой %PIByteArray если нет поддержки //! \~russian Сжимает "ba" с уровнем сжатия "level", возвращает пустой %PIByteArray если нет поддержки

View File

@@ -1,20 +1,20 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Module includes Module includes
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \defgroup Console Console //! \defgroup Console Console
//! \~\brief //! \~\brief

View File

@@ -1,34 +1,29 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Keyboard grabber for console Keyboard grabber for console
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "pikbdlistener.h"
#include "piincludes_p.h" #include "piincludes_p.h"
#include "piliterals.h" #include "pikbdlistener.h"
#include "piwaitevent_p.h"
// clang-format off
#ifndef WINDOWS #ifndef WINDOWS
# include <termios.h> # include <termios.h>
#else #else
# include <wingdi.h> # include <wingdi.h>
# include <wincon.h> # include <wincon.h>
#endif #endif
// clang-format on
/** \class PIKbdListener /** \class PIKbdListener
* \brief Keyboard console input listener * \brief Keyboard console input listener
@@ -52,82 +47,80 @@ PIKbdListener * PIKbdListener::_object = 0;
#ifndef WINDOWS #ifndef WINDOWS
// unix // unix
const PIKbdListener::EscSeq PIKbdListener::esc_seq[] = { const PIKbdListener::EscSeq PIKbdListener::esc_seq[] = {
{"OA", PIKbdListener::UpArrow, 0, 0, 1}, {"OA", PIKbdListener::UpArrow, 0, 0 , 1 },
{"OA", PIKbdListener::UpArrow, 4, 0, 0}, {"OA", PIKbdListener::UpArrow, 4, 0 , 0 },
{"[1A", PIKbdListener::UpArrow, 0, 0, 0}, {"[1A", PIKbdListener::UpArrow, 0, 0 , 0 },
{"[A", PIKbdListener::UpArrow, 0, vt_all, 0}, {"[A", PIKbdListener::UpArrow, 0, vt_all , 0 },
{"OB", PIKbdListener::DownArrow, 0, 0, 1}, {"OB", PIKbdListener::DownArrow, 0, 0 , 1 },
{"OB", PIKbdListener::DownArrow, 4, 0, 0}, {"OB", PIKbdListener::DownArrow, 4, 0 , 0 },
{"[1B", PIKbdListener::DownArrow, 0, 0, 0}, {"[1B", PIKbdListener::DownArrow, 0, 0 , 0 },
{"[B", PIKbdListener::DownArrow, 0, vt_all, 0}, {"[B", PIKbdListener::DownArrow, 0, vt_all , 0 },
{"OC", PIKbdListener::RightArrow, 0, 0, 1}, {"OC", PIKbdListener::RightArrow, 0, 0 , 1 },
{"OC", PIKbdListener::RightArrow, 4, 0, 0}, {"OC", PIKbdListener::RightArrow, 4, 0 , 0 },
{"[1C", PIKbdListener::RightArrow, 0, 0, 0}, {"[1C", PIKbdListener::RightArrow, 0, 0 , 0 },
{"[C", PIKbdListener::RightArrow, 0, vt_all, 0}, {"[C", PIKbdListener::RightArrow, 0, vt_all , 0 },
{"OD", PIKbdListener::LeftArrow, 0, 0, 1}, {"OD", PIKbdListener::LeftArrow, 0, 0 , 1 },
{"OD", PIKbdListener::LeftArrow, 4, 0, 0}, {"OD", PIKbdListener::LeftArrow, 4, 0 , 0 },
{"[1D", PIKbdListener::LeftArrow, 0, 0, 0}, {"[1D", PIKbdListener::LeftArrow, 0, 0 , 0 },
{"[D", PIKbdListener::LeftArrow, 0, vt_all, 0}, {"[D", PIKbdListener::LeftArrow, 0, vt_all , 0 },
{"[H", PIKbdListener::Home, 0, vt_xterm, 0}, {"[H", PIKbdListener::Home, 0, vt_xterm , 0 },
{"[1H", PIKbdListener::Home, 0, 0, 0}, {"[1H", PIKbdListener::Home, 0, 0 , 0 },
{"OH", PIKbdListener::Home, 0, 0, 1}, {"OH", PIKbdListener::Home, 0, 0 , 1 },
{"[1~", PIKbdListener::Home, 0, vt_linux, 0}, {"[1~", PIKbdListener::Home, 0, vt_linux , 0 },
{"[F", PIKbdListener::End, 0, vt_xterm, 0}, {"[F", PIKbdListener::End, 0, vt_xterm , 0 },
{"[1F", PIKbdListener::End, 0, 0, 0}, {"[1F", PIKbdListener::End, 0, 0 , 0 },
{"OF", PIKbdListener::End, 0, 0, 1}, {"OF", PIKbdListener::End, 0, 0 , 1 },
{"[4~", PIKbdListener::End, 0, vt_linux, 0}, {"[4~", PIKbdListener::End, 0, vt_linux , 0 },
{"[2~", PIKbdListener::Insert, 0, vt_all, 0}, {"[2~", PIKbdListener::Insert, 0, vt_all , 0 },
{"[3~", PIKbdListener::Delete, 0, vt_all, 0}, {"[3~", PIKbdListener::Delete, 0, vt_all , 0 },
{"[5~", PIKbdListener::PageUp, 0, vt_all, 0}, {"[5~", PIKbdListener::PageUp, 0, vt_all , 0 },
{"[6~", PIKbdListener::PageDown, 0, vt_all, 0}, {"[6~", PIKbdListener::PageDown, 0, vt_all , 0 },
{"[Z", PIKbdListener::Tab, 1, vt_xterm, 0}, {"[Z", PIKbdListener::Tab, 1, vt_xterm , 0 },
{"OP", PIKbdListener::F1, 0, vt_xterm, 0}, {"OP", PIKbdListener::F1, 0, vt_xterm , 0 },
{"[[A", PIKbdListener::F1, 0, vt_linux, 0}, {"[[A", PIKbdListener::F1, 0, vt_linux , 0 },
{"[11~", PIKbdListener::F1, 0, 0, 0}, {"[11~", PIKbdListener::F1, 0, 0 , 0 },
{"[25~", PIKbdListener::F1, 1, vt_linux, 0}, {"[25~", PIKbdListener::F1, 1, vt_linux , 0 },
{"OQ", PIKbdListener::F2, 0, vt_xterm, 0}, {"OQ", PIKbdListener::F2, 0, vt_xterm , 0 },
{"[[B", PIKbdListener::F2, 0, vt_linux, 0}, {"[[B", PIKbdListener::F2, 0, vt_linux , 0 },
{"[12~", PIKbdListener::F2, 0, 0, 0}, {"[12~", PIKbdListener::F2, 0, 0 , 0 },
{"[26~", PIKbdListener::F2, 1, vt_linux, 0}, {"[26~", PIKbdListener::F2, 1, vt_linux , 0 },
{"OR", PIKbdListener::F3, 0, vt_xterm, 0}, {"OR", PIKbdListener::F3, 0, vt_xterm , 0 },
{"[[C", PIKbdListener::F3, 0, vt_linux, 0}, {"[[C", PIKbdListener::F3, 0, vt_linux , 0 },
{"[13~", PIKbdListener::F3, 0, 0, 0}, {"[13~", PIKbdListener::F3, 0, 0 , 0 },
{"[28~", PIKbdListener::F3, 1, vt_linux, 0}, {"[28~", PIKbdListener::F3, 1, vt_linux , 0 },
{"OS", PIKbdListener::F4, 0, vt_xterm, 0}, {"OS", PIKbdListener::F4, 0, vt_xterm , 0 },
{"[[D", PIKbdListener::F4, 0, vt_linux, 0}, {"[[D", PIKbdListener::F4, 0, vt_linux , 0 },
{"[14~", PIKbdListener::F4, 0, 0, 0}, {"[14~", PIKbdListener::F4, 0, 0 , 0 },
{"[29~", PIKbdListener::F4, 1, vt_linux, 0}, {"[29~", PIKbdListener::F4, 1, vt_linux , 0 },
{"[[E", PIKbdListener::F5, 0, vt_linux, 0}, {"[[E", PIKbdListener::F5, 0, vt_linux , 0 },
{"OT", PIKbdListener::F5, 0, 0, 0}, {"OT", PIKbdListener::F5, 0, 0 , 0 },
{"[15~", PIKbdListener::F5, 0, vt_xterm, 0}, {"[15~", PIKbdListener::F5, 0, vt_xterm , 0 },
{"[31~", PIKbdListener::F5, 1, vt_linux, 0}, {"[31~", PIKbdListener::F5, 1, vt_linux , 0 },
{"OU", PIKbdListener::F6, 0, 0, 0}, {"OU", PIKbdListener::F6, 0, 0 , 0 },
{"[17~", PIKbdListener::F6, 0, vt_all, 0}, {"[17~", PIKbdListener::F6, 0, vt_all , 0 },
{"[32~", PIKbdListener::F6, 1, vt_linux, 0}, {"[32~", PIKbdListener::F6, 1, vt_linux , 0 },
{"OV", PIKbdListener::F7, 0, 0, 0}, {"OV", PIKbdListener::F7, 0, 0 , 0 },
{"[18~", PIKbdListener::F7, 0, vt_all, 0}, {"[18~", PIKbdListener::F7, 0, vt_all , 0 },
{"[33~", PIKbdListener::F7, 1, vt_linux, 0}, {"[33~", PIKbdListener::F7, 1, vt_linux , 0 },
{"OW", PIKbdListener::F8, 0, 0, 0}, {"OW", PIKbdListener::F8, 0, 0 , 0 },
{"[19~", PIKbdListener::F8, 0, vt_all, 0}, {"[19~", PIKbdListener::F8, 0, vt_all , 0 },
{"[34~", PIKbdListener::F8, 1, vt_linux, 0}, {"[34~", PIKbdListener::F8, 1, vt_linux , 0 },
{"OX", PIKbdListener::F9, 0, 0, 0}, {"OX", PIKbdListener::F9, 0, 0 , 0 },
{"[20~", PIKbdListener::F9, 0, vt_all, 0}, {"[20~", PIKbdListener::F9, 0, vt_all , 0 },
{"[35~", PIKbdListener::F9, 1, vt_linux, 0}, {"[35~", PIKbdListener::F9, 1, vt_linux , 0 },
{"OY", PIKbdListener::F10, 0, 0, 0}, {"OY", PIKbdListener::F10, 0, 0 , 0 },
{"[21~", PIKbdListener::F10, 0, vt_all, 0}, {"[21~", PIKbdListener::F10, 0, vt_all , 0 },
{"[36~", PIKbdListener::F10, 1, vt_linux, 0}, {"[36~", PIKbdListener::F10, 1, vt_linux , 0 },
{"OZ", PIKbdListener::F11, 0, 0, 0}, {"OZ", PIKbdListener::F11, 0, 0 , 0 },
{"[23~", PIKbdListener::F11, 0, vt_all, 0}, {"[23~", PIKbdListener::F11, 0, vt_all , 0 },
{"O[", PIKbdListener::F12, 0, 0, 0}, {"O[", PIKbdListener::F12, 0, 0 , 0 },
{"[24~", PIKbdListener::F12, 0, vt_all, 0}, {"[24~", PIKbdListener::F12, 0, vt_all , 0 },
// End // End
{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
}; };
void setupTerminal(bool on) { void setupTerminal(bool on) {
printf("\e[?1000"); printf("\e[?1000"); printf(on ? "h" : "l");
printf(on ? "h" : "l"); printf("\e[?1002"); printf(on ? "h" : "l");
printf("\e[?1002");
printf(on ? "h" : "l");
fflush(0); fflush(0);
} }
#endif #endif
@@ -135,7 +128,7 @@ void setupTerminal(bool on) {
PRIVATE_DEFINITION_START(PIKbdListener) PRIVATE_DEFINITION_START(PIKbdListener)
#ifdef WINDOWS #ifdef WINDOWS
void *hIn, *hOut; void * hIn, * hOut;
DWORD smode, tmode; DWORD smode, tmode;
CONSOLE_SCREEN_BUFFER_INFO sbi; CONSOLE_SCREEN_BUFFER_INFO sbi;
#else #else
@@ -146,34 +139,32 @@ PRIVATE_DEFINITION_START(PIKbdListener)
#else #else
int int
#endif #endif
ret; ret;
PIWaitEvent event;
PRIVATE_DEFINITION_END(PIKbdListener) PRIVATE_DEFINITION_END(PIKbdListener)
PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread() { PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread() {
setName("keyboard_listener"_a); setName("keyboard_listener");
_object = this; _object = this;
#ifdef WINDOWS #ifdef WINDOWS
PRIVATE->hIn = GetStdHandle(STD_INPUT_HANDLE); PRIVATE->hIn = GetStdHandle(STD_INPUT_HANDLE);
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE); PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleMode(PRIVATE->hIn, &PRIVATE->smode); GetConsoleMode(PRIVATE->hIn, &PRIVATE->smode);
#else #else
tcgetattr(0, &PRIVATE->sterm); tcgetattr(0, &PRIVATE->sterm);
#endif #endif
ret_func = slot; is_active = true;
kbddata_ = _d; ret_func = slot;
kbddata_ = _d;
dbl_interval = 400; dbl_interval = 400;
PRIVATE->event.create(); PIKbdListener::exiting = exit_enabled = false;
PIKbdListener::exiting = false;
if (startNow) start(); if (startNow) start();
} }
PIKbdListener::~PIKbdListener() { PIKbdListener::~PIKbdListener() {
stop(); terminate();
if (!waitForFinish(100_ms)) terminate(); end();
PRIVATE->event.destroy();
} }
@@ -200,9 +191,9 @@ PIKbdListener::KeyModifiers getModifiers(DWORD v, bool * shift = 0) {
bool shi = v & SHIFT_PRESSED; bool shi = v & SHIFT_PRESSED;
bool alt = v & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED); bool alt = v & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED);
if (ctrl) ret |= PIKbdListener::Ctrl; if (ctrl) ret |= PIKbdListener::Ctrl;
if (shi) ret |= PIKbdListener::Shift; if (shi) ret |= PIKbdListener::Shift;
if (alt) ret |= PIKbdListener::Alt; if (alt) ret |= PIKbdListener::Alt;
// if (meta) ret |= PIKbdListener::Meta; //if (meta) ret |= PIKbdListener::Meta;
if (v & CAPSLOCK_ON) shi = !shi; if (v & CAPSLOCK_ON) shi = !shi;
if (shift) *shift = shi; if (shift) *shift = shi;
return ret; return ret;
@@ -210,7 +201,7 @@ PIKbdListener::KeyModifiers getModifiers(DWORD v, bool * shift = 0) {
PIKbdListener::MouseButtons getButtons(DWORD v) { PIKbdListener::MouseButtons getButtons(DWORD v) {
PIKbdListener::MouseButtons ret; PIKbdListener::MouseButtons ret;
if (v & FROM_LEFT_1ST_BUTTON_PRESSED) ret |= PIKbdListener::MouseLeft; if (v & FROM_LEFT_1ST_BUTTON_PRESSED) ret |= PIKbdListener::MouseLeft;
if (v & RIGHTMOST_BUTTON_PRESSED) ret |= PIKbdListener::MouseRight; if (v & RIGHTMOST_BUTTON_PRESSED) ret |= PIKbdListener::MouseRight;
if (v & FROM_LEFT_2ND_BUTTON_PRESSED) ret |= PIKbdListener::MouseMiddle; if (v & FROM_LEFT_2ND_BUTTON_PRESSED) ret |= PIKbdListener::MouseMiddle;
return ret; return ret;
} }
@@ -218,159 +209,77 @@ PIKbdListener::MouseButtons getButtons(DWORD v) {
void PIKbdListener::readKeyboard() { void PIKbdListener::readKeyboard() {
ke.key = 0; ke.key = 0;
ke.modifiers = 0; ke.modifiers = 0;
char rc[8]; memset(rc, 0, 8);
piZeroMemory(rc, 8);
#ifdef WINDOWS #ifdef WINDOWS
INPUT_RECORD ir; INPUT_RECORD ir;
ReadConsoleInput(PRIVATE->hIn, &ir, 1, &(PRIVATE->ret)); ReadConsoleInput(PRIVATE->hIn, &ir, 1, &(PRIVATE->ret));
//piCout << ir.EventType;
switch (ir.EventType) { switch (ir.EventType) {
case KEY_EVENT: { case KEY_EVENT: {
KEY_EVENT_RECORD ker = ir.Event.KeyEvent; KEY_EVENT_RECORD ker = ir.Event.KeyEvent;
if (ker.bKeyDown) { if (ker.bKeyDown) {
bool shift = false; bool shift = false;
ke.modifiers = getModifiers(ker.dwControlKeyState, &shift); ke.modifiers = getModifiers(ker.dwControlKeyState, &shift);
// piCout << "key" << int(ker.wVirtualKeyCode) << int(ker.uChar.AsciiChar); //piCout << "key" << int(ker.wVirtualKeyCode) << int(ker.uChar.AsciiChar);
switch (ker.wVirtualKeyCode) { switch (ker.wVirtualKeyCode) {
case 8: case 8: PRIVATE->ret = 1; ke.key = Backspace; break;
PRIVATE->ret = 1; case 33: PRIVATE->ret = 1; ke.key = PageUp; break;
ke.key = Backspace; case 34: PRIVATE->ret = 1; ke.key = PageDown; break;
break; case 35: PRIVATE->ret = 1; ke.key = End; break;
case 33: case 36: PRIVATE->ret = 1; ke.key = Home; break;
PRIVATE->ret = 1; case 37: PRIVATE->ret = 1; ke.key = LeftArrow; break;
ke.key = PageUp; case 38: PRIVATE->ret = 1; ke.key = UpArrow; break;
break; case 39: PRIVATE->ret = 1; ke.key = RightArrow; break;
case 34: case 40: PRIVATE->ret = 1; ke.key = DownArrow; break;
PRIVATE->ret = 1; case 45: PRIVATE->ret = 1; ke.key = Insert; break;
ke.key = PageDown; case 46: PRIVATE->ret = 1; ke.key = Delete; break;
break;
case 35:
PRIVATE->ret = 1;
ke.key = End;
break;
case 36:
PRIVATE->ret = 1;
ke.key = Home;
break;
case 37:
PRIVATE->ret = 1;
ke.key = LeftArrow;
break;
case 38:
PRIVATE->ret = 1;
ke.key = UpArrow;
break;
case 39:
PRIVATE->ret = 1;
ke.key = RightArrow;
break;
case 40:
PRIVATE->ret = 1;
ke.key = DownArrow;
break;
case 45:
PRIVATE->ret = 1;
ke.key = Insert;
break;
case 46:
PRIVATE->ret = 1;
ke.key = Delete;
break;
case '\r': case '\r':
case '\n': case '\n': PRIVATE->ret = 1; ke.key = Return; break;
PRIVATE->ret = 1; case ' ': PRIVATE->ret = 1; ke.key = Space; break;
ke.key = Return; case '\t': PRIVATE->ret = 1; ke.key = Tab; break;
break; case 112: PRIVATE->ret = 1; ke.key = F1; break;
case ' ': case 113: PRIVATE->ret = 1; ke.key = F2; break;
PRIVATE->ret = 1; case 114: PRIVATE->ret = 1; ke.key = F3; break;
ke.key = Space; case 115: PRIVATE->ret = 1; ke.key = F4; break;
break; case 116: PRIVATE->ret = 1; ke.key = F5; break;
case '\t': case 117: PRIVATE->ret = 1; ke.key = F6; break;
PRIVATE->ret = 1; case 118: PRIVATE->ret = 1; ke.key = F7; break;
ke.key = Tab; case 119: PRIVATE->ret = 1; ke.key = F8; break;
break; case 120: PRIVATE->ret = 1; ke.key = F9; break;
case 112: case 121: PRIVATE->ret = 1; ke.key = F10; break;
PRIVATE->ret = 1; case 122: PRIVATE->ret = 1; ke.key = F11; break;
ke.key = F1; case 123: PRIVATE->ret = 1; ke.key = F12; break;
break;
case 113:
PRIVATE->ret = 1;
ke.key = F2;
break;
case 114:
PRIVATE->ret = 1;
ke.key = F3;
break;
case 115:
PRIVATE->ret = 1;
ke.key = F4;
break;
case 116:
PRIVATE->ret = 1;
ke.key = F5;
break;
case 117:
PRIVATE->ret = 1;
ke.key = F6;
break;
case 118:
PRIVATE->ret = 1;
ke.key = F7;
break;
case 119:
PRIVATE->ret = 1;
ke.key = F8;
break;
case 120:
PRIVATE->ret = 1;
ke.key = F9;
break;
case 121:
PRIVATE->ret = 1;
ke.key = F10;
break;
case 122:
PRIVATE->ret = 1;
ke.key = F11;
break;
case 123:
PRIVATE->ret = 1;
ke.key = F12;
break;
default: default:
PRIVATE->ret = 1; PRIVATE->ret = 1;
rc[0] = 1; rc[0] = 1;
{ {
PIChar ch = PIChar::fromConsole(ker.uChar.AsciiChar); PIChar ch = PIChar::fromConsole(ker.uChar.AsciiChar);
if (shift) ch = ch.toUpper(); if (shift) ch = ch.toUpper();
ke.key = ch.unicode16Code(); ke.key = ch.unicode16Code();
} }
break; break;
} }
if (ke.key == 0) { if (ke.key == 0) {piMSleep(10); return;}
piMSleep(10); } else {piMSleep(10); return;}
return;
}
} else {
piMSleep(10);
return;
} }
} break; break;
case MOUSE_EVENT: { case MOUSE_EVENT: {
MOUSE_EVENT_RECORD mer = ir.Event.MouseEvent; MOUSE_EVENT_RECORD mer = ir.Event.MouseEvent;
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
me.modifiers = getModifiers(mer.dwControlKeyState); me.modifiers = getModifiers(mer.dwControlKeyState);
MouseButtons mb = getButtons(mer.dwButtonState); MouseButtons mb = getButtons(mer.dwButtonState);
if (mer.dwEventFlags & MOUSE_WHEELED) { if (mer.dwEventFlags & MOUSE_WHEELED) {
memcpy((void *)(&we), (const void *)(&me), sizeof(me)); memcpy((void*)(&we), (const void*)(&me), sizeof(me));
we.action = MouseWheel; we.action = MouseWheel;
we.direction = short((mer.dwButtonState >> 16) & 0xFFFF) > 0; we.direction = short((mer.dwButtonState >> 8) & 0xFFFF) > 0;
//piCout << "wheel" << we.direction;
wheelEvent(we, kbddata_); wheelEvent(we, kbddata_);
break; break;
} else { } else {
me.x = mer.dwMousePosition.X; me.x = mer.dwMousePosition.X;
me.y = mer.dwMousePosition.Y - PRIVATE->sbi.srWindow.Top; me.y = mer.dwMousePosition.Y - PRIVATE->sbi.srWindow.Top;
bool move = mer.dwEventFlags & MOUSE_MOVED; bool move = mer.dwEventFlags & MOUSE_MOVED;
if (move) { if (move) {
if (me.action == MouseButtonRelease) { if (me.action == MouseButtonRelease) {
@@ -388,44 +297,38 @@ void PIKbdListener::readKeyboard() {
prev_p_me = me; prev_p_me = me;
} }
tm_dbl.reset(); tm_dbl.reset();
} else if (mb < me.buttons)
me.action = MouseButtonRelease;
else {
if (mb != 0) piCoutObj << "WTF";
break;
} }
else if (mb < me.buttons) me.action = MouseButtonRelease;
else {if (mb != 0) piCoutObj << "WTF"; break;}
} }
me.buttons = mb; me.buttons = mb;
if (piCompareBinary(&prev_me, &me, sizeof(me))) break; if (piCompareBinary(&prev_me, &me, sizeof(me)))
memcpy((void *)(&prev_me), (const void *)(&me), sizeof(me)); break;
// PIString _s[] = {"press", "release", "dbl click", "move"}; memcpy((void*)(&prev_me), (const void*)(&me), sizeof(me));
// piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y; //PIString _s[] = {"press", "release", "dbl click", "move"};
//piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
mouseEvent(me, kbddata_); mouseEvent(me, kbddata_);
break; break;
} }
} break; }
default: piMSleep(10); return; break;
default:
piMSleep(10);
return;
} }
#else #else
tcsetattr(0, TCSANOW, &PRIVATE->tterm); tcsetattr(0, TCSANOW, &PRIVATE->tterm);
if (!PRIVATE->event.wait(0)) return;
PRIVATE->ret = read(0, rc, 8); PRIVATE->ret = read(0, rc, 8);
/*piCout << "key" << PIString(rc).replaceAll("\e", "\\e"); /*piCout << "key" << PIString(rc).replaceAll("\e", "\\e");
for (int i = 0; i < PRIVATE->ret; ++i) for (int i = 0; i < PRIVATE->ret; ++i)
PICout(0) << PICoutManipulators::Hex << int(((uchar * )&rc)[i]) << ' '; PICout(0) << PICoutManipulators::Hex << int(((uchar * )&rc)[i]) << ' ';
PICout(0) << "\n"; PICout(0) << "\n";
std::cout << PRIVATE->ret << " chars "; std::cout << PRIVATE->ret << " chars ";
for (int i = 0; i < PRIVATE->ret; ++i) for (int i = 0; i < PRIVATE->ret; ++i)
std::cout << "'" << (char)(rc[i]) << "' " << (int)(uchar)(rc[i]); std::cout << "'" << (char)(rc[i]) << "' " << (int)(uchar)(rc[i]);
std::cout << std::endl;*/ std::cout << std::endl;*/
if (rc[0] == 0) { if (rc[0] == 0) {piMSleep(10); return;}
piMSleep(10); if (PRIVATE->ret < 0 || PRIVATE->ret > 7) {piMSleep(10); return;}
return;
}
if (PRIVATE->ret < 0 || PRIVATE->ret > 7) {
piMSleep(10);
return;
}
if (PRIVATE->ret == 1) { if (PRIVATE->ret == 1) {
if (rc[0] == 8) if (rc[0] == 8)
ke.key = Backspace; ke.key = Backspace;
@@ -440,26 +343,25 @@ void PIKbdListener::readKeyboard() {
// 8 - ctrl+alt+shift 7 // 8 - ctrl+alt+shift 7
if (rc[0] == '\e') { // search for Alt if (rc[0] == '\e') { // search for Alt
if (PRIVATE->ret == 2) { if (PRIVATE->ret == 2) {
mod = 2; mod = 2;
ke.key = PIChar::fromConsole(rc[1]).unicode16Code(); ke.key = PIChar::fromConsole(rc[1]).unicode16Code();
} else { // escape-seq } else {// escape-seq
if (rc[1] == '\e') { // search for Alt if (rc[1] == '\e') { // search for Alt
for (int i = 1; i < 7; ++i) for (int i = 1; i < 7; ++i) rc[i] = rc[i + 1];
rc[i] = rc[i + 1];
mod = 2; mod = 2;
PRIVATE->ret--; PRIVATE->ret--;
} }
if (rc[1] == '[') { if (rc[1] == '[') {
if (rc[2] == 'M') { // mouse if (rc[2] == 'M') { // mouse
if (PRIVATE->ret >= 5) { if (PRIVATE->ret >= 5) {
me.x = uchar(rc[4] - '!'); me.x = uchar(rc[4] - '!');
me.y = uchar(rc[5] - '!'); me.y = uchar(rc[5] - '!');
int b = rc[3] & 0x7, a = rc[3] & 0x60; int b = rc[3] & 0x7, a = rc[3] & 0x60;
if (a == 0x60) { if (a == 0x60) {
memcpy((void *)(&we), (const void *)(&me), sizeof(me)); memcpy((void*)(&we), (const void*)(&me), sizeof(me));
we.action = MouseWheel; we.action = MouseWheel;
we.direction = (b == 0); we.direction = (b == 0);
// piCout << "wheel" << we.direction; //piCout << "wheel" << we.direction;
wheelEvent(we, kbddata_); wheelEvent(we, kbddata_);
} else { } else {
switch (b) { switch (b) {
@@ -470,7 +372,7 @@ void PIKbdListener::readKeyboard() {
} }
if (a == 0x20) { if (a == 0x20) {
if (b == 3) { if (b == 3) {
me.action = MouseButtonRelease; me.action = MouseButtonRelease;
me.buttons = 0; me.buttons = 0;
} else { } else {
if (tm_dbl.elapsed_m() <= dbl_interval && prev_p_me.x == me.x && prev_p_me.y == me.y) if (tm_dbl.elapsed_m() <= dbl_interval && prev_p_me.x == me.x && prev_p_me.y == me.y)
@@ -483,19 +385,18 @@ void PIKbdListener::readKeyboard() {
} }
} }
if (a == 0x40) me.action = MouseMove; if (a == 0x40) me.action = MouseMove;
// PIString _s[] = {"press", "release", "dbl click", "move"}; //PIString _s[] = {"press", "release", "dbl click", "move"};
// piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y; //piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
mouseEvent(me, kbddata_); mouseEvent(me, kbddata_);
} }
// piCout << me.x << me.y << PICoutManipulators::Hex << b << a; //piCout << me.x << me.y << PICoutManipulators::Hex << b << a;
} }
return; return;
} else { } else {
for (int i = 2; i < 7; ++i) // search for modifier for (int i = 2; i < 7; ++i) // search for modifier
if (rc[i] == ';') { if (rc[i] == ';') {
mod |= rc[i + 1] - '0' - 1; mod |= rc[i + 1] - '0' - 1;
for (int j = i; j < 6; ++j) for (int j = i; j < 6; ++j) rc[j] = rc[j + 2];
rc[j] = rc[j + 2];
rc[6] = rc[7] = 0; rc[6] = rc[7] = 0;
PRIVATE->ret -= 2; PRIVATE->ret -= 2;
break; break;
@@ -505,15 +406,14 @@ void PIKbdListener::readKeyboard() {
if (PRIVATE->ret >= 3 && rc[1] == 'O') { // search for modifier (F1-F4) if (PRIVATE->ret >= 3 && rc[1] == 'O') { // search for modifier (F1-F4)
if (rc[2] >= '1' && rc[2] <= '8') { if (rc[2] >= '1' && rc[2] <= '8') {
mod |= rc[2] - '0' - 1; mod |= rc[2] - '0' - 1;
for (int j = 2; j < 6; ++j) for (int j = 2; j < 6; ++j) rc[j] = rc[j + 1];
rc[j] = rc[j + 1];
rc[7] = 0; rc[7] = 0;
PRIVATE->ret--; PRIVATE->ret--;
} }
} }
for (int i = 0;; ++i) { for (int i = 0; ; ++i) {
if (!esc_seq[i].seq) break; if (!esc_seq[i].seq) break;
// piCout << "search" << rc[1] << esc_seq[i].seq; //piCout << "search" << rc[1] << esc_seq[i].seq;
if (strcmp(esc_seq[i].seq, &(rc[1])) == 0) { if (strcmp(esc_seq[i].seq, &(rc[1])) == 0) {
ke.key = esc_seq[i].key; ke.key = esc_seq[i].key;
mod |= esc_seq[i].mod; mod |= esc_seq[i].mod;
@@ -525,16 +425,18 @@ void PIKbdListener::readKeyboard() {
if (mod & 0x1) ke.modifiers |= Shift; if (mod & 0x1) ke.modifiers |= Shift;
if (mod & 0x2) ke.modifiers |= Alt; if (mod & 0x2) ke.modifiers |= Alt;
if (mod & 0x4) ke.modifiers |= Ctrl; if (mod & 0x4) ke.modifiers |= Ctrl;
// if (mod & 0x8) ke.modifiers |= Meta; //if (mod & 0x8) ke.modifiers |= Meta;
} }
/*cout << "wo mods (" << mod << ")\n"; /*cout << "wo mods (" << mod << ")\n";
for (int i = 0; i < PRIVATE->ret; ++i) for (int i = 0; i < PRIVATE->ret; ++i)
cout << "'" << (char)(rc[i]) << "' "; cout << "'" << (char)(rc[i]) << "' ";
cout << endl;*/ cout << endl;*/
} }
if (ke.key == 0 && PRIVATE->ret > 1) ke.key = PIChar::fromSystem(rc).unicode16Code(); if (ke.key == 0 && PRIVATE->ret > 1)
ke.key = PIChar(rc).unicode16Code();
#endif #endif
if ((rc[0] == '\n' || rc[0] == '\r') && PRIVATE->ret == 1) ke.key = Return; if ((rc[0] == '\n' || rc[0] == '\r') && PRIVATE->ret == 1)
ke.key = Return;
if (exit_enabled && ke.key == exit_key) { if (exit_enabled && ke.key == exit_key) {
PIKbdListener::exiting = true; PIKbdListener::exiting = true;
return; return;
@@ -546,20 +448,8 @@ void PIKbdListener::readKeyboard() {
} }
void PIKbdListener::stop() {
PIThread::stop();
PRIVATE->event.interrupt();
}
bool PIKbdListener::stopAndWait(PISystemTime timeout) {
stop();
return waitForFinish(timeout);
}
void PIKbdListener::end() { void PIKbdListener::end() {
// cout << "list end" << endl; //cout << "list end" << endl;
#ifdef WINDOWS #ifdef WINDOWS
SetConsoleMode(PRIVATE->hIn, PRIVATE->smode); SetConsoleMode(PRIVATE->hIn, PRIVATE->smode);
#else #else

View File

@@ -5,91 +5,83 @@
* \~russian Консольный захват клавиатуры * \~russian Консольный захват клавиатуры
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Keyboard grabber for console Keyboard grabber for console
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PIKBDLISTENER_H #ifndef PIKBDLISTENER_H
#define PIKBDLISTENER_H #define PIKBDLISTENER_H
#include "pithread.h" #include "pithread.h"
#include "pitime.h"
#define WAIT_FOR_EXIT \ #define WAIT_FOR_EXIT while (!PIKbdListener::exiting) piMSleep(PIP_MIN_MSLEEP*5); // TODO: rewrite with condvar
while (!PIKbdListener::exiting) \
piMSleep(PIP_MIN_MSLEEP * 5); \
if (PIKbdListener::instance()) { \
if (!PIKbdListener::instance()->stopAndWait(PISystemTime::fromSeconds(1))) PIKbdListener::instance()->terminate(); \
}
class PIP_EXPORT PIKbdListener: public PIThread { class PIP_EXPORT PIKbdListener: public PIThread
PIOBJECT_SUBCLASS(PIKbdListener, PIThread); {
PIOBJECT_SUBCLASS(PIKbdListener, PIThread)
friend class PIConsole; friend class PIConsole;
friend class PITerminal; friend class PITerminal;
public: public:
//! Special keyboard keys //! Special keyboard keys
enum SpecialKey { enum SpecialKey {
Tab /** Tab key */ = 0x09, Tab /** Tab key */ = 0x09,
Return /** Enter key */ = 0x0a, Return /** Enter key */ = 0x0a,
Esc /** Escape key */ = 0x1b, Esc /** Escape key */ = 0x1b,
Space /** Space key */ = 0x20, Space /** Space key */ = 0x20,
Backspace /** Backspace key */ = 0x7f, Backspace /** Backspace key */ = 0x7f,
UpArrow /** Up arrow key */ = -1, UpArrow /** Up arrow key */ = -1,
DownArrow /** Down arrow key */ = -2, DownArrow /** Down arrow key */ = -2,
RightArrow /** Right arrow key */ = -3, RightArrow /** Right arrow key */ = -3,
LeftArrow /** Left arrow key */ = -4, LeftArrow /** Left arrow key */ = -4,
Home /** Home key */ = -5, Home /** Home key */ = -5,
End /** End key */ = -6, End /** End key */ = -6,
PageUp /** Page up key */ = -7, PageUp /** Page up key */ = -7,
PageDown /** Page down key */ = -8, PageDown /** Page down key */ = -8,
Insert /** Delete key */ = -9, Insert /** Delete key */ = -9,
Delete /** Delete key */ = -10, Delete /** Delete key */ = -10,
F1 /** F1 key */ = -11, F1 /** F1 key */ = -11,
F2 /** F2 key */ = -12, F2 /** F2 key */ = -12,
F3 /** F3 key */ = -13, F3 /** F3 key */ = -13,
F4 /** F4 key */ = -14, F4 /** F4 key */ = -14,
F5 /** F5 key */ = -15, F5 /** F5 key */ = -15,
F6 /** F6 key */ = -16, F6 /** F6 key */ = -16,
F7 /** F7 key */ = -17, F7 /** F7 key */ = -17,
F8 /** F8 key */ = -18, F8 /** F8 key */ = -18,
F9 /** F9 key */ = -19, F9 /** F9 key */ = -19,
F10 /** F10 key */ = -20, F10 /** F10 key */ = -20,
F11 /** F11 key */ = -21, F11 /** F11 key */ = -21,
F12 /** F12 key */ = -22 F12 /** F12 key */ = -22
}; };
//! Keyboard modifiers //! Keyboard modifiers
enum KeyModifier { enum KeyModifier {
Ctrl /** Control key */ = 0x1, Ctrl /** Control key */ = 0x1,
Shift /** Shift key */ = 0x2, Shift /** Shift key */ = 0x2,
Alt /** Alt key */ = 0x4 Alt /** Alt key */ = 0x4
// Meta /** Meta (windows) key */ = 0x8 //Meta /** Meta (windows) key */ = 0x8
}; };
typedef PIFlags<KeyModifier> KeyModifiers; typedef PIFlags<KeyModifier> KeyModifiers;
//! This struct contains information about pressed keyboard key //! This struct contains information about pressed keyboard key
struct PIP_EXPORT KeyEvent { struct PIP_EXPORT KeyEvent {
KeyEvent(int k = 0, KeyModifiers m = 0) { KeyEvent(int k = 0, KeyModifiers m = 0) {key = k; modifiers = m;}
key = k;
modifiers = m;
}
//! Pressed key. It can be simple \b char or special key (see PIKbdListener::SpecialKey) //! Pressed key. It can be simple \b char or special key (see PIKbdListener::SpecialKey)
int key; int key;
@@ -100,8 +92,8 @@ public:
//! Mouse buttons //! Mouse buttons
enum MouseButton { enum MouseButton {
MouseLeft /** Left button */ = 0x01, MouseLeft /** Left button */ = 0x01,
MouseRight /** Right button */ = 0x02, MouseRight /** Right button */ = 0x02,
MouseMiddle /** Middle button */ = 0x04 MouseMiddle /** Middle button */ = 0x04
}; };
@@ -118,12 +110,7 @@ public:
//! This struct contains information about mouse action //! This struct contains information about mouse action
struct PIP_EXPORT MouseEvent { struct PIP_EXPORT MouseEvent {
MouseEvent(MouseAction a = MouseButtonPress, MouseButtons b = 0, KeyModifiers m = 0) { MouseEvent(MouseAction a = MouseButtonPress, MouseButtons b = 0, KeyModifiers m = 0) {x = y = 0; action = a; buttons = b; modifiers = m;}
x = y = 0;
action = a;
buttons = b;
modifiers = m;
}
//! Event X coordinate in view-space, from 0 //! Event X coordinate in view-space, from 0
int x; int x;
@@ -143,7 +130,7 @@ public:
//! This struct contains information about mouse wheel action //! This struct contains information about mouse wheel action
struct PIP_EXPORT WheelEvent: public MouseEvent { struct PIP_EXPORT WheelEvent: public MouseEvent {
WheelEvent(): MouseEvent() { direction = false; } WheelEvent(): MouseEvent() {direction = false;}
//! Wheel direction, /b true - up, /b fasle - down //! Wheel direction, /b true - up, /b fasle - down
bool direction; bool direction;
@@ -158,52 +145,43 @@ public:
//! Returns custom data //! Returns custom data
void * data() { return kbddata_; } void * data() {return kbddata_;}
//! Set custom data to "_data" //! Set custom data to "_data"
void setData(void * _data) { kbddata_ = _data; } void setData(void * _data) {kbddata_ = _data;}
//! Set external function to "slot" //! Set external function to "slot"
void setSlot(KBFunc slot) { ret_func = slot; } void setSlot(KBFunc slot) {ret_func = slot;}
//! Set external function to "slot" //! Set external function to "slot"
void setSlot(std::function<void(KeyEvent)> slot) { void setSlot(std::function<void(KeyEvent)> slot) {ret_func = [slot](KeyEvent e, void *){slot(e);};}
ret_func = [slot](KeyEvent e, void *) { slot(e); };
}
//! Returns if exit key if awaiting //! Returns if exit key if awaiting
bool exitCaptured() const { return exit_enabled; } bool exitCaptured() const {return exit_enabled;}
//! Returns exit key, default 'Q' //! Returns exit key, default 'Q'
int exitKey() const { return exit_key; } int exitKey() const {return exit_key;}
double doubleClickInterval() const { return dbl_interval; } double doubleClickInterval() const {return dbl_interval;}
void setDoubleClickInterval(double v) { dbl_interval = v; } void setDoubleClickInterval(double v) {dbl_interval = v;}
void readKeyboard(); void readKeyboard();
void stop();
bool stopAndWait(PISystemTime timeout = {});
//! Returns if keyboard listening is active (not running!) //! Returns if keyboard listening is active (not running!)
bool isActive() { return is_active; } bool isActive() {return is_active;}
EVENT_HANDLER(void, enableExitCapture) { enableExitCapture('Q'); } EVENT_HANDLER( void, enableExitCapture) {enableExitCapture('Q');}
EVENT_HANDLER1(void, enableExitCapture, int, key) { EVENT_HANDLER1(void, enableExitCapture, int, key) {exit_enabled = true; exit_key = key;}
exit_enabled = true; EVENT_HANDLER(void, disableExitCapture) {exit_enabled = false;}
exit_key = key; EVENT_HANDLER(void, setActive) {setActive(true);}
}
EVENT_HANDLER(void, disableExitCapture) { exit_enabled = false; }
EVENT_HANDLER(void, setActive) { setActive(true); }
EVENT_HANDLER1(void, setActive, bool, yes); EVENT_HANDLER1(void, setActive, bool, yes);
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void *, data); EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
EVENT2(mouseEvent, PIKbdListener::MouseEvent, mouse, void *, data); EVENT2(mouseEvent, PIKbdListener::MouseEvent, mouse, void * , data)
EVENT2(wheelEvent, PIKbdListener::WheelEvent, wheel, void *, data); EVENT2(wheelEvent, PIKbdListener::WheelEvent, wheel, void * , data)
//! \handlers //! \handlers
//! \{ //! \{
//! \fn void enableExitCapture(int key = 'Q') //! \fn void enableExitCapture(int key = 'Q')
//! \brief Enable exit key "key" awaiting //! \brief Enable exit key "key" awaiting
@@ -214,22 +192,22 @@ public:
//! \fn void setActive(bool yes = true) //! \fn void setActive(bool yes = true)
//! \brief Set keyboard listening is active or not //! \brief Set keyboard listening is active or not
//! \} //! \}
//! \events //! \events
//! \{ //! \{
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data) //! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data)
//! \brief Raise on key "key" pressed, "data" is custom data //! \brief Raise on key "key" pressed, "data" is custom data
//! \} //! \}
static bool exiting; static bool exiting;
static PIKbdListener * instance() { return _object; } static PIKbdListener * instance() {return _object;}
private: private:
void begin() override; void begin();
void run() override { readKeyboard(); } void run() {readKeyboard();}
void end() override; void end();
#ifndef WINDOWS #ifndef WINDOWS
struct PIP_EXPORT EscSeq { struct PIP_EXPORT EscSeq {
@@ -247,7 +225,7 @@ private:
vt_none, vt_none,
vt_xterm = 0x1, vt_xterm = 0x1,
vt_linux = 0x2, vt_linux = 0x2,
vt_all = 0xFF vt_all = 0xFF
}; };
static const EscSeq esc_seq[]; static const EscSeq esc_seq[];
@@ -256,50 +234,26 @@ private:
PRIVATE_DECLARATION(PIP_EXPORT) PRIVATE_DECLARATION(PIP_EXPORT)
KBFunc ret_func; KBFunc ret_func;
int exit_key; int exit_key;
bool exit_enabled = false, is_active = true; bool exit_enabled, is_active;
void * kbddata_; void * kbddata_;
char rc[8];
double dbl_interval; double dbl_interval;
PITimeMeasurer tm_dbl; PITimeMeasurer tm_dbl;
KeyEvent ke; KeyEvent ke;
MouseEvent me, prev_me, prev_p_me; MouseEvent me, prev_me, prev_p_me;
WheelEvent we; WheelEvent we;
static PIKbdListener * _object; static PIKbdListener * _object;
}; };
//! \relatesalso PIBinaryStream inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::KeyEvent & v) {s << v.key << v.modifiers; return s;}
//! \~english Store operator inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::MouseEvent & v) {s << v.x << v.y << (int)v.action << v.buttons << v.modifiers; return s;}
//! \~russian Оператор сохранения inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::WheelEvent & v) {s << (*(PIKbdListener::MouseEvent*)&v) << (uchar)v.direction; return s;}
BINARY_STREAM_WRITE(PIKbdListener::MouseEvent) {
s << v.x << v.y << v.action << v.buttons << v.modifiers;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Restore operator
//! \~russian Оператор извлечения
BINARY_STREAM_READ(PIKbdListener::MouseEvent) {
s >> v.x >> v.y >> v.action >> v.buttons >> v.modifiers;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Store operator
//! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIKbdListener::WheelEvent) {
s << (*(PIKbdListener::MouseEvent *)&v) << v.direction;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Restore operator
//! \~russian Оператор извлечения
BINARY_STREAM_READ(PIKbdListener::WheelEvent) {
s >> (*(PIKbdListener::MouseEvent *)&v) >> v.direction;
return s;
}
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::KeyEvent & v) {s >> v.key >> v.modifiers; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::MouseEvent & v) {int a(0); s >> v.x >> v.y >> a >> v.buttons >> v.modifiers; v.action = (PIKbdListener::MouseAction)a; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::WheelEvent & v) {uchar d(0); s >> (*(PIKbdListener::MouseEvent*)&v) >> d; v.direction = d; return s;}
REGISTER_PIVARIANTSIMPLE(PIKbdListener::KeyEvent) REGISTER_PIVARIANTSIMPLE(PIKbdListener::KeyEvent)
REGISTER_PIVARIANTSIMPLE(PIKbdListener::MouseEvent) REGISTER_PIVARIANTSIMPLE(PIKbdListener::MouseEvent)

View File

@@ -5,105 +5,104 @@
* \~russian Консольный тайловый менеджер * \~russian Консольный тайловый менеджер
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Console GUI Console GUI
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PISCREEN_H #ifndef PISCREEN_H
#define PISCREEN_H #define PISCREEN_H
#include "pip_console_export.h" #include "pip_console_export.h"
#include "piscreendrawer.h"
#include "piscreentile.h" #include "piscreentile.h"
#include "piscreendrawer.h"
class PIP_CONSOLE_EXPORT PIScreen class PIP_CONSOLE_EXPORT PIScreen: public PIThread, public PIScreenTypes::PIScreenBase
: public PIThread {
, public PIScreenTypes::PIScreenBase { PIOBJECT_SUBCLASS(PIScreen, PIThread)
PIOBJECT_SUBCLASS(PIScreen, PIThread);
class SystemConsole; class SystemConsole;
public: public:
//! Constructs %PIScreen with key handler "slot" and if "startNow" start it //! Constructs %PIScreen with key handler "slot" and if "startNow" start it
PIScreen(bool startNow = true, PIKbdListener::KBFunc slot = 0); PIScreen(bool startNow = true, PIKbdListener::KBFunc slot = 0);
~PIScreen(); ~PIScreen();
//! Directly call function from \a PIKbdListener //! Directly call function from \a PIKbdListener
void enableExitCapture(int key = 'Q') { listener->enableExitCapture(key); } void enableExitCapture(int key = 'Q') {listener->enableExitCapture(key);}
//! Directly call function from \a PIKbdListener //! Directly call function from \a PIKbdListener
void disableExitCapture() { listener->disableExitCapture(); } void disableExitCapture() {listener->disableExitCapture();}
//! Directly call function from \a PIKbdListener //! Directly call function from \a PIKbdListener
bool exitCaptured() const { return listener->exitCaptured(); } bool exitCaptured() const {return listener->exitCaptured();}
//! Directly call function from \a PIKbdListener //! Directly call function from \a PIKbdListener
int exitKey() const { return listener->exitKey(); } int exitKey() const {return listener->exitKey();}
int windowWidth() const {return console.width;}
int windowHeight() const {return console.height;}
int windowWidth() const { return console.width; } bool isMouseEnabled() const {return mouse_;}
int windowHeight() const { return console.height; }
bool isMouseEnabled() const { return mouse_; }
void setMouseEnabled(bool on); void setMouseEnabled(bool on);
PIScreenTile * rootTile() { return &root; } PIScreenTile * rootTile() {return &root;}
PIScreenTile * tileByName(const PIString & name); PIScreenTile * tileByName(const PIString & name);
void setDialogTile(PIScreenTile * t); void setDialogTile(PIScreenTile * t);
PIScreenTile * dialogTile() const { return tile_dialog; } PIScreenTile * dialogTile() const {return tile_dialog;}
PIScreenDrawer * drawer() { return &drawer_; } PIScreenDrawer * drawer() {return &drawer_;}
void clear() { drawer_.clear(); } void clear() {drawer_.clear();}
void resize(int w, int h) { console.resize(w, h); } void resize(int w, int h) {console.resize(w, h);}
EVENT_HANDLER0(void, waitForFinish); EVENT_HANDLER0(void, waitForFinish);
EVENT_HANDLER0(void, start) { start(false); } EVENT_HANDLER0(void, start) {start(false);}
EVENT_HANDLER1(void, start, bool, wait); EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();}
EVENT_HANDLER0(void, stop) { stop(false); } EVENT_HANDLER0(void, stop) {stop(false);}
EVENT_HANDLER1(void, stop, bool, clear); EVENT_HANDLER1(void, stop, bool, clear);
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void *, data); EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
EVENT2(tileEvent, PIScreenTile *, tile, PIScreenTypes::TileEvent, e); EVENT2(tileEvent, PIScreenTile * , tile, PIScreenTypes::TileEvent, e)
//! \handlers //! \handlers
//! \{ //! \{
//! \fn void waitForFinish() //! \fn void waitForFinish()
//! \brief block until finished (exit key will be pressed) //! \brief block until finished (exit key will be pressed)
//! \fn void start(bool wait = false) //! \fn void start(bool wait = false)
//! \brief Start console output and if "wait" block until finished (exit key will be pressed) //! \brief Start console output and if "wait" block until finished (exit key will be pressed)
//! \fn void stop(bool clear = false) //! \fn void stop(bool clear = false)
//! \brief Stop console output and if "clear" clear the screen //! \brief Stop console output and if "clear" clear the screen
//! \} //! \}
//! \events //! \events
//! \{ //! \{
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data) //! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data)
//! \brief Raise on key "key" pressed, "data" is pointer to %PIConsole object //! \brief Raise on key "key" pressed, "data" is pointer to %PIConsole object
//! \fn void tileEvent(PIScreenTile * tile, PIScreenTypes::TileEvent e) //! \fn void tileEvent(PIScreenTile * tile, PIScreenTypes::TileEvent e)
//! \brief Raise on some event "e" from tile "tile" //! \brief Raise on some event "e" from tile "tile"
//! \} //! \}
private: private:
class PIP_CONSOLE_EXPORT SystemConsole { class PIP_CONSOLE_EXPORT SystemConsole {
public: public:
@@ -132,23 +131,23 @@ private:
PRIVATE_DECLARATION(PIP_CONSOLE_EXPORT) PRIVATE_DECLARATION(PIP_CONSOLE_EXPORT)
int width, height, pwidth, pheight; int width, height, pwidth, pheight;
int mouse_x, mouse_y; int mouse_x, mouse_y;
PIVector<PIVector<PIScreenTypes::Cell>> cells, pcells; PIVector<PIVector<PIScreenTypes::Cell> > cells, pcells;
}; };
void begin() override; void begin();
void run() override; void run();
void end() override; void end();
void key_event(PIKbdListener::KeyEvent key); void key_event(PIKbdListener::KeyEvent key);
EVENT_HANDLER1(void, mouse_event, PIKbdListener::MouseEvent, me); EVENT_HANDLER1(void, mouse_event, PIKbdListener::MouseEvent, me);
EVENT_HANDLER1(void, wheel_event, PIKbdListener::WheelEvent, we); EVENT_HANDLER1(void, wheel_event, PIKbdListener::WheelEvent, we);
static void key_eventS(PIKbdListener::KeyEvent key, void * t) { ((PIScreen *)t)->key_event(key); } static void key_eventS(PIKbdListener::KeyEvent key, void * t) {((PIScreen*)t)->key_event(key);}
PIVector<PIScreenTile *> tiles() { return root.children(); } PIVector<PIScreenTile*> tiles() {return root.children();}
PIVector<PIScreenTile *> prepareMouse(PIKbdListener::MouseEvent * e); PIVector<PIScreenTile*> prepareMouse(PIKbdListener::MouseEvent * e);
PIVector<PIScreenTile *> tilesUnderMouse(int x, int y); PIVector<PIScreenTile*> tilesUnderMouse(int x, int y);
bool nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key = PIKbdListener::KeyEvent()); bool nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key = PIKbdListener::KeyEvent());
void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e) override; void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e);
void tileRemovedInternal(PIScreenTile * t) override; void tileRemovedInternal(PIScreenTile * t);
void tileSetFocusInternal(PIScreenTile * t) override; void tileSetFocusInternal(PIScreenTile * t);
bool mouse_; bool mouse_;
SystemConsole console; SystemConsole console;
@@ -156,7 +155,8 @@ private:
PIKbdListener * listener; PIKbdListener * listener;
PIKbdListener::KBFunc ret_func; PIKbdListener::KBFunc ret_func;
PIScreenTile root; PIScreenTile root;
PIScreenTile *tile_focus, *tile_dialog; PIScreenTile * tile_focus, * tile_dialog;
}; };

View File

@@ -5,22 +5,22 @@
* \~russian Тайл для PIScreen с API PIConsole * \~russian Тайл для PIScreen с API PIConsole
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Tile for PIScreen with PIConsole API Tile for PIScreen with PIConsole API
Andrey Bychkov work.a.b@yandex.ru Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PISCREENCONSOLE_H #ifndef PISCREENCONSOLE_H
@@ -35,15 +35,10 @@
class PIP_CONSOLE_EXPORT TileVars: public PIScreenTile { class PIP_CONSOLE_EXPORT TileVars: public PIScreenTile {
public: public:
TileVars(const PIString & n = PIString()); TileVars(const PIString & n = PIString());
protected: protected:
struct PIP_CONSOLE_EXPORT Variable { struct PIP_CONSOLE_EXPORT Variable {
Variable() { Variable() {nx = ny = type = offset = bitFrom = bitCount = size = 0; format = PIScreenTypes::CellFormat(); ptr = 0;}
nx = ny = type = offset = bitFrom = bitCount = size = 0; bool isEmpty() const {return (ptr == 0);}
format = PIScreenTypes::CellFormat();
ptr = 0;
}
bool isEmpty() const { return (ptr == 0); }
PIString name; PIString name;
PIScreenTypes::CellFormat format; PIScreenTypes::CellFormat format;
int nx; int nx;
@@ -55,26 +50,28 @@ protected:
int size; int size;
const void * ptr; const void * ptr;
/*void operator =(const Variable & src) { /*void operator =(const Variable & src) {
name = src.name; name = src.name;
format = src.format; format = src.format;
nx = src.nx; nx = src.nx;
ny = src.ny; ny = src.ny;
type = src.type; type = src.type;
offset = src.offset; offset = src.offset;
bitFrom = src.bitFrom; bitFrom = src.bitFrom;
bitCount = src.bitCount; bitCount = src.bitCount;
size = src.size; size = src.size;
ptr = src.ptr; ptr = src.ptr;
}*/ }*/
}; };
PIVector<Variable> variables; PIVector<Variable> variables;
PIScreenTypes::Alignment alignment; PIScreenTypes::Alignment alignment;
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d);
}; };
class PIP_CONSOLE_EXPORT PIScreenConsoleTile: public PIScreenTile {
class PIP_CONSOLE_EXPORT PIScreenConsoleTile : public PIScreenTile
{
public: public:
PIScreenConsoleTile(); PIScreenConsoleTile();
}; };

View File

@@ -5,22 +5,22 @@
* \~russian Отрисовщик для PIScreen * \~russian Отрисовщик для PIScreen
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Drawer for PIScreen Drawer for PIScreen
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PISCREENDRAWER_H #ifndef PISCREENDRAWER_H
@@ -30,10 +30,10 @@
#include "piscreentypes.h" #include "piscreentypes.h"
#include "pistring.h" #include "pistring.h"
class PIP_CONSOLE_EXPORT PIScreenDrawer { class PIP_CONSOLE_EXPORT PIScreenDrawer
{
friend class PIScreen; friend class PIScreen;
PIScreenDrawer(PIVector<PIVector<PIScreenTypes::Cell>> & c); PIScreenDrawer(PIVector<PIVector<PIScreenTypes::Cell> > & c);
public: public:
enum ArtChar { enum ArtChar {
LineVertical = 1, LineVertical = 1,
@@ -46,62 +46,26 @@ public:
Unchecked, Unchecked,
Checked Checked
}; };
void clear(); void clear();
void clearRect(int x0, int y0, int x1, int y1) { fillRect(x0, y0, x1, y1, ' '); } void clearRect(int x0, int y0, int x1, int y1) {fillRect(x0, y0, x1, y1, ' ');}
void drawPixel(int x, void drawPixel(int x, int y, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0);
int y, void drawLine(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0);
const PIChar & c, void drawRect(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0);
PIScreenTypes::Color col_char = PIScreenTypes::Default, void drawFrame(int x0, int y0, int x1, int y1, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0);
PIScreenTypes::Color col_back = PIScreenTypes::Default, void drawText(int x, int y, const PIString & s, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Transparent, PIScreenTypes::CharFlags flags_char = 0);
PIScreenTypes::CharFlags flags_char = 0); void fillRect(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0);
void drawLine(int x0, void fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<PIScreenTypes::Cell> > & content);
int y0,
int x1, PIChar artChar(const ArtChar type) const {return arts_.value(type, PIChar(' '));}
int y1,
const PIChar & c,
PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Default,
PIScreenTypes::CharFlags flags_char = 0);
void drawRect(int x0,
int y0,
int x1,
int y1,
const PIChar & c,
PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Default,
PIScreenTypes::CharFlags flags_char = 0);
void drawFrame(int x0,
int y0,
int x1,
int y1,
PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Default,
PIScreenTypes::CharFlags flags_char = 0);
void drawText(int x,
int y,
const PIString & s,
PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Transparent,
PIScreenTypes::CharFlags flags_char = 0);
void fillRect(int x0,
int y0,
int x1,
int y1,
const PIChar & c,
PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Default,
PIScreenTypes::CharFlags flags_char = 0);
void fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<PIScreenTypes::Cell>> & content);
PIChar artChar(const ArtChar type) const { return arts_.value(type, PIChar(' ')); } static void clear(PIVector<PIVector<PIScreenTypes::Cell> > & cells);
static void clear(PIVector<PIVector<PIScreenTypes::Cell>> & cells);
private: private:
PIVector<PIVector<PIScreenTypes::Cell>> & cells; PIVector<PIVector<PIScreenTypes::Cell> > & cells;
int width, height; int width, height;
PIMap<ArtChar, PIChar> arts_; PIMap<ArtChar, PIChar> arts_;
}; };

View File

@@ -5,66 +5,58 @@
* \~russian Базовый тайл для PIScreen * \~russian Базовый тайл для PIScreen
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Basic PIScreen tile Basic PIScreen tile
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PISCREENTILE_H #ifndef PISCREENTILE_H
#define PISCREENTILE_H #define PISCREENTILE_H
#include "pikbdlistener.h"
#include "pip_console_export.h" #include "pip_console_export.h"
#include "piscreentypes.h" #include "piscreentypes.h"
#include "pikbdlistener.h"
class PIScreenDrawer; class PIScreenDrawer;
class PIP_CONSOLE_EXPORT PIScreenTile: public PIObject { class PIP_CONSOLE_EXPORT PIScreenTile: public PIObject {
friend class PIScreen; friend class PIScreen;
PIOBJECT_SUBCLASS(PIScreenTile, PIObject); PIOBJECT_SUBCLASS(PIScreenTile, PIObject)
public: public:
PIScreenTile(const PIString & n = PIString(), PIScreenTile(const PIString & n = PIString(), PIScreenTypes::Direction d = PIScreenTypes::Vertical, PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred);
PIScreenTypes::Direction d = PIScreenTypes::Vertical,
PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred);
virtual ~PIScreenTile(); virtual ~PIScreenTile();
void addTile(PIScreenTile * t); void addTile(PIScreenTile * t);
void takeTile(PIScreenTile * t); void takeTile(PIScreenTile * t);
void removeTile(PIScreenTile * t); void removeTile(PIScreenTile * t);
PIScreenTile * parentTile() const { return parent; } PIScreenTile * parentTile() const {return parent;}
PIVector<PIScreenTile *> children(bool only_visible = false); PIVector<PIScreenTile * > children(bool only_visible = false);
PIScreenTile * childUnderMouse(int x, int y); PIScreenTile * childUnderMouse(int x, int y);
void show() { visible = true; } void show() {visible = true;}
void hide() { visible = false; } void hide() {visible = false;}
void setFocus(); void setFocus();
bool hasFocus() const { return has_focus; } bool hasFocus() const {return has_focus;}
void setMargins(int m) { marginLeft = marginRight = marginTop = marginBottom = m; } void setMargins(int m) {marginLeft = marginRight = marginTop = marginBottom = m;}
void setMargins(int l, int r, int t, int b) { void setMargins(int l, int r, int t, int b) {marginLeft = l; marginRight = r; marginTop = t; marginBottom = b;}
marginLeft = l;
marginRight = r;
marginTop = t;
marginBottom = b;
}
int x() const { return x_; }
int y() const { return y_; }
int width() const { return width_; }
int height() const { return height_; }
int x() const {return x_;}
int y() const {return y_;}
int width() const {return width_;}
int height() const {return height_;}
PIScreenTypes::Direction direction; PIScreenTypes::Direction direction;
PIScreenTypes::SizePolicy size_policy; PIScreenTypes::SizePolicy size_policy;
PIScreenTypes::FocusFlags focus_flags; PIScreenTypes::FocusFlags focus_flags;
@@ -75,41 +67,43 @@ public:
int marginLeft, marginRight, marginTop, marginBottom; int marginLeft, marginRight, marginTop, marginBottom;
int spacing; int spacing;
bool visible; bool visible;
protected: protected:
//! Returns desired tile size in "w" and "h" //! Returns desired tile size in "w" and "h"
virtual void sizeHint(int & w, int & h) const; virtual void sizeHint(int & w, int & h) const;
//! Tile has been resized to "w"x"h" //! Tile has been resized to "w"x"h"
virtual void resizeEvent(int w, int h) {} virtual void resizeEvent(int w, int h) {}
//! Draw tile with drawer "d" in world-space coordinates //! Draw tile with drawer "d" in world-space coordinates
virtual void drawEvent(PIScreenDrawer * d) {} virtual void drawEvent(PIScreenDrawer * d) {}
//! Return "true" if you process key //! Return "true" if you process key
virtual bool keyEvent(PIKbdListener::KeyEvent key) { return false; } virtual bool keyEvent(PIKbdListener::KeyEvent key) {return false;}
//! Return "true" if you process event //! Return "true" if you process event
virtual bool mouseEvent(PIKbdListener::MouseEvent me) { return false; } virtual bool mouseEvent(PIKbdListener::MouseEvent me) {return false;}
//! Return "true" if you process wheel //! Return "true" if you process wheel
virtual bool wheelEvent(PIKbdListener::WheelEvent we) { return false; } virtual bool wheelEvent(PIKbdListener::WheelEvent we) {return false;}
void raiseEvent(PIScreenTypes::TileEvent e); void raiseEvent(PIScreenTypes::TileEvent e);
void setScreen(PIScreenTypes::PIScreenBase * s); void setScreen(PIScreenTypes::PIScreenBase * s);
void deleteChildren(); void deleteChildren();
void drawEventInternal(PIScreenDrawer * d); void drawEventInternal(PIScreenDrawer * d);
void layout(); void layout();
bool needLayout() { return size_policy != PIScreenTypes::Ignore; } bool needLayout() {return size_policy != PIScreenTypes::Ignore;}
PIVector<PIScreenTile *> tiles; PIVector<PIScreenTile * > tiles;
PIScreenTile * parent; PIScreenTile * parent;
PIScreenTypes::PIScreenBase * screen; PIScreenTypes::PIScreenBase * screen;
int x_, y_, width_, height_; int x_, y_, width_, height_;
bool has_focus; bool has_focus;
private: private:
int pw, ph; int pw, ph;
}; };

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