688 Commits

Author SHA1 Message Date
cae264a77b forgot to implement PIHTTPClient headers 2024-11-28 13:13:08 +03:00
4f934fef35 PIHTTPClient fixes 2024-11-28 12:37:05 +03:00
3a159b0553 PIByteArray operators & | ^
PIDigest add BLAKE2 algorithms and HMAC
2024-11-27 18:27:51 +03:00
0c973f0216 add PIDigest with SHA and MD series 2024-11-27 14:40:39 +03:00
65d3168eb5 PICout::withExternalBufferAnd decomposed to PICout::withExternalBufferAndID and PICout::withExternalBufferAnd
PIString::toPercentageEncoding/fromPercentageEncoding
piStringify()
PIHTTPClient support arguments
some doc
2024-11-26 18:26:02 +03:00
12114b3e77 old curl fix 2024-11-25 16:02:40 +03:00
6f6b717354 pip_test 2024-11-25 15:53:12 +03:00
58b3fa64bc http server fix 2024-11-25 15:00:42 +03:00
1acaf24df9 PIHTTPServer basic auth works 2024-11-24 23:23:08 +03:00
c2c9822169 fix FindPIP.cmake 2024-11-23 17:55:59 +03:00
dff4f2b3a0 add http_client library, using libcurl
take out common http entities to http_common dir
2024-11-23 17:54:22 +03:00
bf9ad65ff0 take out "asize" from vector/dequeue to picontainers.h->calcNewSize()
minAlloc and maxPoTAlloc now can be override from CMake by PIP_CONTAINERS_MIN_ALLOC and PIP_CONTAINERS_MAX_POT_ALLOC variables
2024-11-21 20:15:18 +03:00
53ec75bf0c remove junk 2024-11-21 16:31:40 +03:00
f5270d75eb multi-utf16 fix 2024-11-21 16:28:19 +03:00
4aa596b179 last commit error 2024-11-21 00:18:57 +03:00
002f21fc9e version 4.4.1 2024-11-21 00:10:35 +03:00
9ab46e4afc version 4.4.1
PIVector and PIDeque now growth to 64 MiB with PoT, then increments size by 64 MiB
in case of large containers it significantly save memory
2024-11-21 00:10:14 +03:00
caa7880cc4 get rid of piForeach
apply some code analyzer recommendations
ICU flag now check if libicu exists
prepare for more accurate growth of containers (limited PoT, then constantly increase size)
2024-11-20 20:01:47 +03:00
24112498ce new method PILog::readAllLogs 2024-11-18 22:47:02 +03:00
c9a5ddd89f PIProtectedVariable - user now can`t mistake
PIHTTPServer improvements
2024-11-18 11:11:19 +03:00
3483edbd76 Merge pull request 'refactoring PICrypt, add PIStreamPackerConfig, delete piclientserver_config' (#184) from pisteampackerconfig into master
Reviewed-on: #184
2024-11-16 15:44:15 +03:00
fe82c12d5b fix build 2024-11-16 14:53:04 +03:00
d90c3f0991 Merge branch 'master' into pisteampackerconfig
# Conflicts:
#	libs/client_server/piclientserver_server.cpp
#	libs/crypt/picrypt.cpp
#	libs/io_utils/pistreampacker.cpp
#	main.cpp
2024-11-16 14:34:34 +03:00
f6b9131f4a test excluded for android 2024-11-15 17:14:19 +03:00
c67f7a2b64 log fix 2024-11-15 16:23:48 +03:00
047d38ea59 http includes 2024-11-15 15:47:56 +03:00
3d07795515 add_custom_command(... pip_lang) on ninja brings to resursive cmake and ninja call ( 2024-11-15 15:43:03 +03:00
ee137b2820 http server options, remove old 2024-11-15 14:18:49 +03:00
cdde340efe add microhttpd server 2024-11-14 18:15:27 +03:00
ee34e8a72e doc 2024-11-13 16:32:21 +03:00
0840d807a0 add PIReadWriteLock, PIReadLocker and PIWriteLocker 2024-11-13 13:56:16 +03:00
4655d72554 new class PISemaphore
doc for PIProtectedVariable
2024-11-12 18:50:22 +03:00
5b066cbc27 add PIProtectedVariable 2024-11-10 21:28:59 +03:00
2247473959 PICodeParser namespace fix 2024-11-07 15:43:13 +03:00
57f8c1313e first release of translation facility
* runtime - loading and translating
 * design-time - works with *.ts file (pip_tr utility)
 * compile-time - CMake macro for compile *.ts
2024-11-05 13:49:00 +03:00
73ed51e3d4 translations: multi-line and special symbols support 2024-11-03 18:12:32 +03:00
1106cde3e4 return tr for PIString 2024-11-03 14:41:31 +03:00
b43158d3a8 add PIString::lineNumber() method
add ""_tr literal to translate string by PITranslator
add pip_tr util, now useless, only can generate *.ts
add qt_support internal lib, now only works with *.ts file
pip_vtt migrate to qt_support
2024-11-03 14:39:42 +03:00
9a928f6feb add PITranslator
begin localization "ru"
2024-11-02 18:43:30 +03:00
df75efe881 version 4.3.2
fix PIKbdListener wheel on Windows
2024-11-02 14:15:09 +03:00
9f1d23ad8e version 4.3.1
PICodeParser now works with multi-line macros
2024-10-23 19:11:46 +03:00
7cd2f7a310 PIBinaryStream supports PISet 2024-10-21 13:47:28 +03:00
315966504e fix picrypt and remove crypt_frag from PIStreamPacker 2024-10-20 18:03:25 +03:00
7209eec012 author 2024-10-19 17:08:15 +03:00
992f59904a more documentation 2024-10-19 17:07:45 +03:00
9dbd7210cb PILog documentation 2024-10-19 16:58:12 +03:00
ac8efc9f88 need fix PIPackedTCP 2024-10-18 19:00:39 +03:00
92a0a9356c refactoring PICrypt, add PIStreamPackerConfig, delete piclientserver_config 2024-10-18 18:59:20 +03:00
28f3471036 version 4.3.0 2024-10-16 22:29:57 +03:00
d3d7235338 enable complex type for PIMathVectorT and PIMathMatrixT
TODO: add precision to invert and test vector
2024-10-16 22:10:28 +03:00
92a87a0c64 picloud add "-w" option for watchdog 2024-10-15 15:04:39 +03:00
cd7e053fc5 version 4.2.0
move toStdFunction() to pibase.h
refactor PIParseHelper, now it much more abstract and useful
fix PIIODevice::createFromFullPath() when whitespaces at start or end are presence
PIStreamPacker add events for start and end packet receive
PIClientServer::ClientBase add virtual methods for start and end packet receive. also one can enable diagnostics with enableDiagnostics() method
PICout now call flush() on each end of output
add PIString::entries(const PIString & str)
2024-10-15 12:02:18 +03:00
9eecbbab6e new method PIClientServer::Server::closeAll()
PISignals::releaseSignals()
2024-09-24 18:57:50 +03:00
3641e636d2 new PIClientServer::ClientBase::stopAndWait() method for blocking stop read.
PIClientServer::ClientBase::close() now non-blocking
2024-09-21 19:56:39 +03:00
4acab04895 PILog ready to use 2024-09-19 17:26:58 +03:00
aa963a4bda PIEthernet on error close disconnect 2024-09-17 16:50:22 +03:00
bdd18b614f PIEthernet more accuracy construct
PIThread windows fix
2024-09-17 16:11:18 +03:00
e186e0adff shorter thread names 2024-09-17 15:58:06 +03:00
f105f616f6 PIThread more accurate end, PIEthernet tcpserver client no reinit 2024-09-17 13:22:20 +03:00
andrey.bychkov
b99c51181d fix test 2024-09-17 12:31:03 +03:00
andrey.bychkov
bc6b584480 fix waitLoop 2024-09-17 11:28:34 +03:00
eb97de1413 close 2024-09-17 11:21:23 +03:00
97f1c25ff8 close 2024-09-17 11:15:50 +03:00
97aad47a21 some fixes 2024-09-16 23:32:01 +03:00
43bd1d8550 Merge remote-tracking branch 'remotes/origin/tests_client_server' into test 2024-09-16 19:58:26 +03:00
andrey.bychkov
3255199b3f Unit tests for PIClientServer 2024-09-16 19:54:44 +03:00
224412e20a PIDir::temporary fix 2024-09-16 16:24:11 +03:00
000ce2a54d PICout improvement:
* renamed private members for more clear code
 * registerExternalBufferID() method to obtain unique ID for withExternalBuffer()
 * PICoutManipulators::PICoutStdStream enum for select stream (stdout or stderr)
 * Constructors now accept optional stream
 * piCerr and piCerrObj macros

PIDir::temporary() moved to "mkdtemp"

PILog:
 * now 4 levels
 * you can set max level
 * Error writes to piCerr
2024-09-16 16:06:07 +03:00
andrey.bychkov
f992bf4cbb build fix 2024-09-16 10:43:22 +03:00
andrey.bychkov
96625bd93d minor clean 2024-09-16 10:11:31 +03:00
9d4357c066 PIVector2D =() fix 2024-09-15 16:50:15 +03:00
7a945f47b1 PILog works 2024-09-13 23:05:24 +03:00
9a352bfc83 add PISystemTime::toFrequency(), add PILog 2024-09-13 18:00:48 +03:00
aa2f117075 finalize module 2024-09-13 13:37:09 +03:00
bf5bb45771 decompose, add new main group "Application"
PICLI code brush
2024-09-13 13:31:31 +03:00
cdc966bd8c Merge pull request 'client_server' (#181) from client_server into master
Reviewed-on: #181
2024-09-13 12:12:10 +03:00
17b902ebcc add PIClientServer::Config, common configuration type for both sides, stream packer and encryption settings 2024-09-13 11:08:32 +03:00
996b7ea403 important:
* PIThread::~PIThread() now unregister itself from introspection, if terminates than show warning
 * PISystemMonitor now correctly stops
 * PIPeer now can correctly stopAndWait
 * PIPeer::destroy(), protected method for close all eths and threads
 * new PIINTROSPECTION_STOP macro
 * Introspection now can be correctly stopped by macro, more safety

ClientServer:
 * ClientBase::close() stop and disconnect channel
 * Server clients clean-up now event-based
 * No warnings on client destructor
2024-09-12 17:07:48 +03:00
da4b09be9e PIEthernet fix tcp-server close (properly delete all clients)
PIEthernet::stopThreadedListen() method
decompose client to 2 implementations - server-side and client-side
2024-09-11 21:41:55 +03:00
b24b5a1346 add encryption 2024-09-11 15:44:02 +03:00
0d94699206 first try, works 2024-09-11 10:18:45 +03:00
16a818c95e picloud hang fix try :`-( 2024-09-06 08:05:26 +03:00
a0454b809d change to private section 2024-08-28 17:21:11 +03:00
af8c096c7a PIStateMachine "addOnFinish" renamed to "setOnFinish" 2024-08-28 13:48:33 +03:00
14cf81aed0 remove void piLetobe(T * v) 2024-08-28 13:17:38 +03:00
c43b914fb3 PIMemoryBlock fix 2024-08-28 12:19:57 +03:00
f002f6cedd PIMemoryBlock fix 2024-08-28 12:19:37 +03:00
ce846eca51 fix deprecated message 2024-08-28 11:58:58 +03:00
e6c8714857 version 4.1.0
maybe fix hang on PIEthernet::interrupt()
replace piLetobe with piChangeEndian:
 * piChangeEndianBinary
 * piChangeBinary
 * piChangedBinary
PIDiagnostics::start now accept PISystemTime instead of number
add PITimer::start(PISystemTime, std::function<void()>) overload
2024-08-28 11:56:36 +03:00
33fc334077 PIStateMachine::postEvent() now thread-safe and can be recursive 2024-08-05 23:25:23 +03:00
6efc962923 in my opinion, PIStateMachine is ready to real work 2024-08-04 20:26:39 +03:00
7d02f710ea add PIPackedTCP 2024-08-02 14:43:42 +03:00
c8876807ed fix unidemponetial behaviour with PIP version 2024-07-30 17:21:30 +03:00
f43f834460 !! 2024-07-30 14:48:00 +03:00
ccf6b810b5 -librt is still need... 2024-07-30 14:41:54 +03:00
a438c4249d version fix 2024-07-30 14:26:07 +03:00
1c7fc39b6c version 4.0.0_alpha
in almost all methods removed timeouts in milliseconds, replaced to PISystemTime
PITimer rewrite, remove internal impl, now only thread implementation, API similar to PIThread
PITimer API no longer pass void*
PIPeer, PIConnection improved stability on reinit and exit
PISystemTime new methods
pisd now exit without hanging
2024-07-30 14:18:02 +03:00
f07c9cbce8 add timeout transition 2024-07-28 20:16:52 +03:00
abdba6d68b state machine, parallel seems to work, final state and info about active atomic states 2024-07-17 21:11:01 +03:00
3db26a762c first state machine code, exclusive already works
need to make final, parallel, timeouts
2024-07-17 14:16:25 +03:00
b35561f74e doc fix 2024-07-17 14:14:38 +03:00
f041d1435e PIIODevice::waitThreadedReadFinished now periodically (100 ms) call interrupt() 2024-07-10 18:36:29 +03:00
b781bd5148 PIBroadcast fix 2024-07-10 16:56:40 +03:00
a16e0b7659 substitution fix 2024-07-09 21:47:18 +03:00
0bafd3fa98 PIValueTree improvements: methods with path (recursive), forEachRecursive()
PIValueTreeConvertions::fromTextFile now can include other files and handle ${} substitutions
2024-07-09 21:44:30 +03:00
903b320629 version 3.21.0
add PISystemTime overload for thread/timer/io classes
2024-07-09 16:32:27 +03:00
9cd05996e7 version 3.20.0 2024-06-07 00:22:44 +03:00
15dc76c4a7 1 2024-06-06 22:06:40 +03:00
d46b5e008a try to fix cloud again 2024-06-01 22:27:39 +03:00
af4b718053 PIValueTree::contains fix for null entry 2024-05-22 15:15:32 +03:00
7eae1e127c PIBroadcast polishing 2024-05-14 21:01:53 +03:00
f97fed7daa string append more protection 2024-05-13 22:29:22 +03:00
d764171c82 Обновить libs/main/containers/pipair.h 2024-05-13 14:35:49 +03:00
d4a024ea75 remove harmful createPIPair() 2024-05-06 19:22:22 +03:00
491d89f117 version 3.19.0
PIMathVectorT subvector methods
PISystemTime::isNull()
PISystemTime::Frequency::isNull()
PISystemTime::toString()
PISystemTime::fromString()
PIVariant can handle strings with PISystemTime
PIDateTime::toSystemTime() now returns null time from invalid strings
2024-05-05 00:17:52 +03:00
a86e8f7b58 PIIOTextStream(PIString * string) now with mandatory Mode 2024-05-02 21:35:29 +03:00
d97798d063 version 3.18.1
fix pip_cmg - ignore static members
2024-04-30 15:23:26 +03:00
247759b364 version 3.18.0
PIMathMatrixT:: toType(), submatrix() and setSubmatrix()
2024-04-26 15:37:06 +03:00
a745f803b3 version 3.17.1
add PINonTriviallyCopyable struct
add PISerial check for error on Windows on every read()
2024-04-10 20:49:27 +03:00
1b67000887 PIPacketExtractor Timeout mode fix 2024-04-08 21:23:11 +03:00
04d3e31dbc PISet fix 2024-04-05 21:02:37 +03:00
9f29155d07 PISet fixes 2024-04-05 20:59:59 +03:00
021411defa PIConfig adopt for PIIOString changes 2024-04-05 20:41:07 +03:00
ee4d78d2e1 add PISet::const_iterator, now can iterate ranged-for PISet by T, not by PIPair<T, bool> 2024-04-05 17:13:18 +03:00
9283c88b4e version 3.17.0
finally properly works PIIOString inside PIIOStream
2024-04-05 15:34:38 +03:00
8d585439bb add PIChunkStream::getData(int id)
fix some COM on Windows
fix PIPacketExtractor
2024-04-04 20:50:44 +03:00
ebf2b08bb1 PIPacketExtractor fix 2024-04-04 12:34:00 +03:00
eb21c85170 version 3.16.1 2024-03-31 20:38:13 +03:00
fb68a9f9fe another segv on cloud 2024-03-31 20:31:35 +03:00
c7c3852747 cloud! finally fixed bug! 2024-03-25 22:40:29 +03:00
c18d0c918e 4 2024-03-25 21:45:59 +03:00
9c4fd41eef 3 2024-03-25 21:37:05 +03:00
9173dc936d 2 2024-03-25 21:34:30 +03:00
77c8681b43 1 2024-03-25 21:31:41 +03:00
2db9440a38 fix cloud ... :-/ 2024-03-25 21:24:29 +03:00
0d585cfebf cloud fix ... (( 2024-03-25 21:17:05 +03:00
02a9bfb76f another try fix 2024-03-22 22:29:14 +03:00
ad7385c21f more couts 2024-03-22 21:40:04 +03:00
dd6d91ac1d cloud fixes ... 2024-03-18 10:45:57 +03:00
576d9c79be Merge branch 'master' of https://git.shstk.ru/SHS/pip 2024-03-15 19:49:46 +03:00
3fa5d9d9df cloud inspecting ... 2024-03-15 19:49:37 +03:00
b14d30108a Optimization removeAll and removeWhere in PIVector and PIDeque (#180)
Reviewed-on: #180
Co-authored-by: Andrey Bychkov <andrey@signalmodelling.ru>
Co-committed-by: Andrey Bychkov <andrey@signalmodelling.ru>
2024-03-13 10:43:02 +03:00
2b738f6f43 more safety cloud_dispatcher 2024-03-10 21:22:05 +03:00
263fa18726 add warnings 2024-03-05 19:38:53 +03:00
f47bc411bc version 3.16.0
new PISystemTime::Frequency type
2024-03-05 17:55:25 +03:00
154fb7d9fd pip_vtt support special characters 2024-02-29 13:03:38 +03:00
9f09af9f27 doc to shstk.ru 2024-02-28 10:49:29 +03:00
960e4a7cce migrate to shstk.ru 2024-02-28 10:27:34 +03:00
50bff12364 map and cloud fix, add cloud debug 2024-02-22 17:10:38 +03:00
7297b9aee0 PICodeParser::parseFileContent 2024-01-25 23:58:50 +03:00
3652705784 usb 2024-01-17 18:39:53 +03:00
851f101470 usb 2024-01-17 18:38:40 +03:00
6b87536d8d usb fix 2024-01-17 18:32:06 +03:00
d299a1f386 support for multi ctor CONNECTL 2023-12-12 22:05:06 +03:00
c8350d2f0a doc 2023-12-09 07:25:48 +03:00
7efdacc979 main fix 2023-12-09 07:19:28 +03:00
c77afcc374 PICodeInfo compatible with old interface, safety access to PICODEINFO 2023-12-08 19:01:22 +03:00
b8fc44714c version 3.15.0 - improved pip_cmg and PICodeInfo storage
Important! changed API to access PICodeInfo storage
2023-12-08 16:14:18 +03:00
49a5ed6aa3 deploy_tool remove empty 2023-11-20 23:33:34 +03:00
76c76b48c5 OpenCL lib 2023-11-20 21:19:14 +03:00
03bd23a3b9 enable PIString2StdWString 2023-11-09 00:31:27 +03:00
61e6edb4c8 add PIOpenCL::Kernel::waitForFinish() 2023-09-25 14:28:15 +03:00
aa78e930be add toolTip attribute to PIValueTree 2023-09-13 10:33:12 +03:00
bb668dab29 ignore cross-compile dependencies 2023-09-07 13:11:26 +03:00
d1662d3535 PITextStream add long 2023-09-06 20:26:38 +03:00
12b136a2f4 version 3.14.1 2023-09-05 20:15:12 +03:00
aa69815a31 pip_cmg less code 2023-09-05 19:42:45 +03:00
3afa0ce0ab PIChunkStream::extract changed to PIBinaryStream 2023-08-30 17:08:11 +03:00
64a474c343 more safety 2023-08-30 12:29:06 +03:00
0907a3eb13 version 3.14.0
PIBinaryStream::wasReadError() method, remove incomplete read asserts
2023-08-30 12:18:04 +03:00
c86ec0ae82 normalizeAngleDeg methods 2023-08-14 12:37:32 +03:00
ac76e07d9d version 3.13.2 2023-07-14 22:14:02 +03:00
56aed70425 version 3.13.1 2023-07-14 10:51:01 +03:00
63321a4ce3 doc fix 2023-07-13 13:08:27 +03:00
66fb93ba88 change PIMap::at and add const to PIMap and PIBinaryLog 2023-07-13 12:32:45 +03:00
299a009d61 fix tests 2023-07-12 19:37:59 +03:00
4d395f4487 pivaluetreeconversions add file methods 2023-07-07 11:51:06 +03:00
2f82aaf97b missed include 2023-07-06 22:35:25 +03:00
13ececf370 linux fix 2023-07-06 21:57:41 +03:00
b19d50ba62 linux 2023-07-06 21:48:42 +03:00
b763f0e5cd version 3.13.0
Breaking changes in PIChar and PIString
2023-07-06 20:09:45 +03:00
27f6f5158d Merge pull request 'добавил const для части контейнеров и explicit для конструкторов' (#176) from const_explicit into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/176
2023-07-06 20:01:25 +03:00
61f1a34c14 PIString/PIChar explicit, support char16_t 2023-07-06 19:59:26 +03:00
8ad2503c5a pichar and pistring explicit test 2023-07-06 18:37:42 +03:00
1a96dc0cb9 PITimeMeasurer doc ru 2023-07-05 20:53:36 +03:00
de810b7bd6 auto-generated doc for PIValueTree 2023-07-04 22:50:25 +03:00
35aadb0e78 doc and brush 2023-07-04 13:08:37 +03:00
3a6b3a4064 добавил const для части контейнеров и explicit для конструкторов 2023-07-03 19:10:36 +03:00
9e78546b7e small fix 2023-07-02 14:12:48 +03:00
ccae1a7311 more literals, use some in PIP, small refactor PIThread::start (clang-format mistakes) 2023-07-02 14:02:10 +03:00
54d0ba1876 literals doc 2023-06-29 18:37:09 +03:00
d1193e7aa1 version 3.12.1
add piliterals.h
2023-06-29 18:20:24 +03:00
6c6437e980 typo fix 2023-06-21 17:20:07 +03:00
17e75c2951 expand ignored extensions for deploy_tool 2023-06-19 21:46:48 +03:00
c4766f8f5b piMin/piMax can accept any arguments count 2023-06-19 21:35:49 +03:00
1a214cff4e version 3.12.0
split pibase.h into 2 files
add PIScopeExitCall
2023-06-18 22:02:20 +03:00
dd56b1c142 deploy_tool - no objdump errors, Qml modules support, Windows custom Qt plugins and qml root directories 2023-06-14 23:30:48 +03:00
0ae63fa9ad Merge branch 'master' of https://git.shs.tools/SHS/pip 2023-05-24 22:13:35 +03:00
5e4c5b0d47 pichunkstream support full uint 2023-05-24 22:13:30 +03:00
58dcf7ba69 small fixes 2023-05-12 11:47:21 +03:00
1de4304e30 PIBinaryLog createIndexOnFly, loadIndex, saveIndex features
PIFile readAll and writeAll static methods
2023-05-11 21:44:31 +03:00
96e8ef2b23 .clang-format 2023-05-04 14:14:08 +03:00
dea29429bf PIBinaryLog support for uint ID 2023-05-03 22:12:56 +03:00
f5392f8b63 PIValueTree::readChildValue method
some child-oriented methods
allow to create JSON from single PIValueTree
2023-04-28 14:40:55 +03:00
3ab57eea88 PIProcess exit code for Windows 2023-04-25 17:15:00 +03:00
f503e85507 PIValueTree::childValue method 2023-04-24 19:03:36 +03:00
0f19719a98 fix CMake policy check 2023-04-23 23:15:55 +03:00
ee7251c17c PIDir::name() 2023-04-22 23:22:23 +03:00
2780dacb48 new piDeleteSafety() method 2023-04-13 20:40:14 +03:00
dea469d85e PIValueTree save issue 2023-04-10 13:16:59 +03:00
254649aa10 PIIOTextStream for strings fix 2023-04-07 19:43:56 +03:00
7badc531ce support PICodeParser "enum class" 2023-04-06 21:11:01 +03:00
6d3b7c8543 version 3.10.0
PIDir::CurrentDirOverrider and PIDir::absolute
2023-04-05 11:56:58 +03:00
4af5886649 some doc, deploy tool fix 2023-04-04 13:05:09 +03:00
38bcb6c482 picrypt.h doc 2023-03-28 17:43:30 +03:00
eb91ee1b35 deploy_tool now add wayland platform in addition to xcb 2023-03-26 18:16:14 +03:00
Бычков Андрей
2d1c86bc83 PIByteArray optimization - takeRange 2023-03-24 17:08:42 +03:00
d66f7efb3c fix include 2023-03-21 14:48:08 +03:00
20bdf3af61 version 2023-03-21 13:53:23 +03:00
49f5de26eb PIValueTree::applyValues now can be recursive 2023-03-21 14:55:55 +03:00
0cd1206f94 version 3.9.0, add PIEthernet::NoDelay parameter 2023-03-21 10:14:05 +03:00
df82102798 cmake fixes 2023-03-16 09:41:53 +03:00
650dadc347 new gtest 2023-03-16 09:34:34 +03:00
504fc5c896 small fixes 2023-03-14 17:41:12 +03:00
162f8e25fd pow10 error 2023-03-13 14:18:42 +03:00
e0900b6bd5 piDeleteAll fix 2023-02-11 15:56:14 +03:00
f3540d54b4 fix pichar 2023-02-10 12:39:32 +03:00
d743cc66d8 PIValueTree::applyValues 2023-02-07 23:24:43 +03:00
df4dcd7f32 PIGeoPosition as PIVariant support 2023-01-29 20:27:43 +03:00
3391d88460 version 3.8.2
PIObject::Connection::disconnect() now const
PIObject::deleted now public
2023-01-26 23:54:17 +03:00
5d75f1d298 PIValueTree::standardAttributes 2023-01-26 12:31:54 +03:00
73d482ebe2 PICloudClient interrupt fix 2023-01-10 12:10:35 +03:00
9ed66db515 version 3.8.0 2023-01-09 15:43:05 +03:00
c64a1beefa PISerial::readDevice 2023-01-09 15:39:46 +03:00
677ae06df8 PIIODevice::readForTime fix 2023-01-09 15:35:20 +03:00
5cc5369d2a missed include 2023-01-09 15:27:53 +03:00
5c16953d95 PIVariant, PIGPIO 2023-01-09 15:22:51 +03:00
f355cfc05e some PIFile functionality
PIBinaryLog::close fix
2022-12-26 14:09:05 +03:00
81cbf905ba PIValueTree add attributes 2022-12-20 16:10:38 +03:00
2732595efe CMakeLists.txt 2022-12-20 10:02:51 +03:00
2ac215c19e separate PIEthernet::Address to PINetworkAddress, typedef PIEthernet::Address to PINetworkAddress and mark as deprecated
PIValueTree new attributes for File and Dir
2022-12-19 14:29:18 +03:00
6c3f305562 improve pip_vtt - no-obsolete option, <location> support 2022-12-19 11:53:46 +03:00
fd82f5316c add pip_vtt util 2022-12-18 20:40:49 +03:00
a98176f513 PISerial Windows read fix 2022-12-18 14:23:19 +03:00
886eb06880 new attribute 2022-12-16 23:06:21 +03:00
581c7c937a .editorconfig 2022-12-16 16:45:07 +03:00
5836c64e5e .editorconfig 2022-12-16 16:41:20 +03:00
badcfac616 some PIValueTree changes, fix PIVariantTypes::Enum::fromString 2022-12-15 13:05:15 +03:00
c2b8a8d6da code format 2022-12-14 14:13:52 +03:00
430a41fefc before formatting 2022-12-14 13:56:19 +03:00
c74ba871cd pivariant, enum, tiny format 2022-12-13 21:44:06 +03:00
9d9357b0ca add .clang_format file 2022-12-12 12:40:24 +03:00
c4cb81a104 PIJSON::toJSON with optionally unicode masking
PIVariantTypes::Color::toName()
2022-12-08 13:21:11 +03:00
b609ce8027 version 3.7.0 2022-12-07 10:56:01 +03:00
0bd45ec49b friend with UNICODE macro on windows 2022-12-07 09:33:46 +03:00
3625627072 PIVariantTypes::Color::toString() now can return color name 2022-12-05 22:08:58 +03:00
8e744249de Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-12-05 19:16:56 +03:00
cf5284a244 color collection, now only CSS colors
PIVariantTypes::Color from/to string (with CSS names)
2022-12-05 19:16:48 +03:00
74c20c37b7 picloud_test build fix 2022-12-04 18:30:23 +03:00
b25ecf42fb PIValueTreeConversions text, options
PIVariant fixes
2022-12-04 18:27:54 +03:00
5bb9477b5b PIVariant string conversions, PIDateTime::fromString 2022-11-30 22:40:28 +03:00
a27353d42d PIValueTreeConversions start 2022-11-29 20:44:46 +03:00
1327e46f61 PIVariant and PIValueTree changes 2022-11-29 18:08:06 +03:00
a516acbd44 PIValueTree 2022-11-29 09:17:19 +03:00
d3d2b4281c PIP_ADD_COUNTER now almost unique across different cpp
add PIValueTree
2022-11-28 14:41:12 +03:00
ab0b6a7649 remove debug 2022-11-27 12:44:19 +03:00
6e13ee173e PIVariant::fromType() methods 2022-11-27 12:40:31 +03:00
a786c928e0 PIVariant custom casts works 2022-11-27 12:13:11 +03:00
f52fc5332c PIVariant add typeID, optimization, macros simplify and change custom logic to ID 2022-11-27 11:03:32 +03:00
dc6fbbf7ec folders 2022-11-25 21:35:39 +03:00
a2256a3872 PIString::simplified 2022-11-15 17:55:55 +03:00
d45996af28 "FFTW Create plan" remove 2022-11-14 21:29:01 +03:00
05dcbca894 PIBinaryStream patches 2022-11-14 12:31:20 +03:00
57ed40912d piDeleteAll and piDeleteAllAndClear 2022-11-13 22:55:10 +03:00
46751ab977 missing include 2022-11-12 13:38:07 +03:00
e9128771db version 3.6.0
another fixes in PIEthernet
remove PIThread::interrupt()
piwaitevent patches
2022-11-12 13:31:26 +03:00
Бычков Андрей
7bbffef237 version and remove debug 2022-11-11 16:26:11 +03:00
Бычков Андрей
cb59017ebb PICloud many important fixes 2022-11-11 16:18:05 +03:00
ec8fbcb112 cloud 2022-11-10 19:37:01 +03:00
4c909e692a Merge pull request 'thread' (#170) from thread into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/170
2022-11-10 19:02:42 +03:00
Бычков Андрей
cfc9ed131a Merge branch 'thread' of https://git.shs.tools/SHS/pip into thread 2022-11-10 19:01:52 +03:00
Бычков Андрей
39d81dd23b PICloudServer don't delete clients 2022-11-10 19:01:28 +03:00
56fd6b921e version 3.5.0 2022-11-10 16:16:57 +03:00
0fed454bb7 Merge pull request 'thread' (#169) from thread into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/169
2022-11-10 16:16:08 +03:00
cbac9f4253 PITimerImp_RT 2022-11-10 15:44:35 +03:00
Бычков Андрей
d46f1a137a PITimer remove wait in stop, waitForFinish 2022-11-10 15:26:19 +03:00
3d7e845213 Merge branch 'thread' of https://git.shs.tools/SHS/pip into thread 2022-11-10 15:03:59 +03:00
e9a7eaa276 fixes 2022-11-10 15:03:51 +03:00
Бычков Андрей
e6a5010023 remove debug picout from cloud 2022-11-10 14:25:57 +03:00
4994d0bf66 condvar fixes 2022-11-10 14:11:40 +03:00
Бычков Андрей
15a9d68a87 Merge branch 'thread' of https://git.shs.tools/SHS/pip into thread 2022-11-10 14:08:57 +03:00
Бычков Андрей
16c09ae6e9 PIEthernet atomic connected exchange 2022-11-10 14:08:42 +03:00
702d1642e0 PITimer thread imp changed from PIWaitEvent to PIConditionalVariable 2022-11-10 13:47:57 +03:00
d34374d4e0 missing 2022-11-10 12:29:49 +03:00
398d760ba9 PIObject::deleteLater important fix
PIWaitEvent::sleep() method
PITimer thread imp wait optimization, migrate to interruptable sleeps
2022-11-10 12:26:08 +03:00
Бычков Андрей
d9eac06749 pithread, pitimer stop, stopAndWait 2022-11-09 17:17:21 +03:00
Бычков Андрей
f9c1ef5ba4 Merge branch 'thread' of https://git.shs.tools/SHS/pip into thread 2022-11-09 17:04:28 +03:00
Бычков Андрей
8738043dce some PICloud and PIEthernet fixes 2022-11-09 17:04:13 +03:00
db5c4dcf3f PIThread::stopAndWait 2022-11-09 17:02:28 +03:00
d3dd3fb32b blocking PIEthernet write works 2022-11-08 17:34:06 +03:00
Бычков Андрей
21fa3baf4e убрал лишнее в PICloudServer 2022-11-08 16:37:10 +03:00
Бычков Андрей
b17510218b some fix for PICloudServer 2022-11-08 15:25:27 +03:00
Бычков Андрей
897f03f3d0 some fixes for picloud, but still not working correctly 2022-11-08 14:43:52 +03:00
Бычков Андрей
36ff427e0d Merge branch 'thread' of https://git.shs.tools/SHS/pip into thread 2022-11-08 10:53:43 +03:00
Бычков Андрей
2e1179e2fa Merge branch 'master' of https://git.shs.tools/SHS/pip into thread 2022-11-08 10:53:30 +03:00
fffaf0726d CAN adopted, Linux work 2022-11-07 18:07:26 +03:00
6da1ec5acf Merge branch 'thread' of https://git.shs.tools/SHS/pip into thread 2022-11-07 17:50:52 +03:00
16a8d37a8f Merge branch 'master' of https://git.shs.tools/SHS/pip into thread 2022-11-07 17:50:06 +03:00
Бычков Андрей
93a1bf4f6d some unsuccessfull fixes for picloud 2022-11-07 17:32:10 +03:00
Бычков Андрей
f08a07cab0 небольшая чистка и улучшение кода, попытка исправить picloud 2022-11-07 17:16:27 +03:00
8a5e72c723 migrate to async IO model
new PIIODevice::interrupt() virtual method
new PIWaitEvent private class
PIEthernet and PISerial basically tested on Windows and Linux
2022-11-05 23:43:07 +03:00
2163deb7ea PICodeParser entities visibility, check pip_cmg stream operators for public and global visibility 2022-11-01 14:54:53 +03:00
4219372e68 PIString::fromUTF8 BOM support 2022-11-01 14:29:07 +03:00
e48d0ebaab linux signal 2022-11-01 09:38:27 +03:00
591c92b4bb ready to test 2022-11-01 09:17:24 +03:00
6e81a419fb start move to interruption of blocking calls, PIThread and PIEthernet 2022-11-01 00:02:44 +03:00
ca403ca2c7 PIDiagnostics EPIC fix 2022-10-27 21:14:55 +03:00
e46cfdc4bd more precise using PIIODevice::reading_now flag, Warning! one should use it manually now
small enum fix for pip_cmg
2022-10-27 20:58:43 +03:00
609ff8e9c8 piserial should be fixed 2022-10-24 10:55:25 +03:00
ea0df21726 Merge pull request 'piethernet threaded connect fix, small brush of PIIODevice' (#168) from piiodevice_fix into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/168
2022-10-23 21:38:35 +03:00
3a5050b028 piethernet threaded connect fix, small brush of PIIODevice 2022-10-23 21:38:10 +03:00
2cf561767f Merge pull request 'piiodevice_fix' (#167) from piiodevice_fix into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/167
2022-10-23 19:33:41 +03:00
638f0e0181 PIIODevice remove init
picloud dispatcher fix
2022-10-23 19:22:36 +03:00
359c7816bc picloud 2022-10-23 18:48:28 +03:00
9438ab4e53 PIIODevice threaded read refactoring 2022-10-23 16:02:09 +03:00
e5777dde6c version 3.3.0 2022-10-01 10:53:09 +03:00
3c7e117661 PIJSON doc and << operator 2022-09-30 21:09:57 +03:00
0f48c206c3 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-09-30 20:28:03 +03:00
4a7f009cc6 doc 2022-09-30 20:27:58 +03:00
001812f3ce Merge pull request 'some code style' (#166) from json into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/166
2022-09-30 20:27:03 +03:00
Бычков Андрей
bf87f631f0 some code style 2022-09-30 13:58:43 +03:00
44876836c5 PIJSON improvements and doc reference 2022-09-28 18:08:19 +03:00
2d2f6b254b add PIJSON, yet without doc 2022-09-26 17:49:58 +03:00
858b54ce64 pistring::toFloat/Double/LDouble precise fixes 2022-09-19 15:20:24 +03:00
38840c5b7d version 3.2.0 2022-09-18 12:36:09 +03:00
499ee386a7 PIString::toFloat/Double/LDouble own fast implementation (. and , equivalent)
PICout ldouble support
PIEthernet small optimization
2022-09-17 17:53:58 +03:00
Бычков Андрей
eddef26b5e doc PIMap PIStack PIQueue done 2022-09-02 09:44:47 +03:00
Бычков Андрей
db3de9904a pimap some doc 2022-08-30 18:15:13 +03:00
Бычков Андрей
3511fee459 pimap some doc 2022-08-30 17:49:09 +03:00
Бычков Андрей
5a1a381a32 containers doc 2022-08-29 18:32:55 +03:00
Бычков Андрей
1bc9f5ed19 PIVector and PIDeque takeRange 2022-08-25 17:35:49 +03:00
Бычков Андрей
8370351ff3 add doc to previous commit 2022-08-24 17:33:00 +03:00
Бычков Андрей
952020a3e2 PIVector and PIDeque: split and splitBySize 2022-08-24 17:28:48 +03:00
Бычков Андрей
b35ec1f30a PIVector and PIDeque some code clean 2022-08-23 16:47:33 +03:00
443eeed38b Merge pull request 'PIDeque optimize and bugfix' (#165) from deque2 into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/165
2022-08-23 10:30:05 +03:00
d1abfe5213 Merge pull request 'PIVector some optimize code' (#164) from vector into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/164
2022-08-22 20:18:08 +03:00
Бычков Андрей
29e34bdd60 cmake generate right project tree 2022-08-22 18:44:18 +03:00
Бычков Андрей
4635e9ba4f insert optimize 2022-08-22 17:47:45 +03:00
Бычков Андрей
49e553c551 PIDeque optimize and bugfix 2022-08-22 15:59:25 +03:00
1abcf06bf6 PIVector some optimize code 2022-08-16 22:20:04 +03:00
2550f76376 return move-assignment vector optimization 2022-08-16 20:26:42 +03:00
24da7aa644 doc core reference done 2022-08-15 19:35:49 +03:00
494faf862b some doc 2022-08-15 11:43:27 +03:00
67561636e5 return move-assignment dequeue optimization 2022-08-12 23:53:22 +03:00
Бычков Андрей
00f7a24d54 new caontainers functions
atWhere()
lastAtWhere()
contains(v)
filter(), map(), reduce(), forEach() indexed and reverse variants
fix PIDeque reverse for
fix insert with move of complex type potential segfault
2022-08-12 18:14:55 +03:00
Бычков Андрей
f07f814b08 platformio_pre.py 2022-08-11 11:40:49 +03:00
fed2c5991d version 3.0.0_rc 2022-08-10 23:44:26 +03:00
ed888324b2 override 2022-08-10 23:34:11 +03:00
79efd9e15d clang fix 2022-08-10 23:23:23 +03:00
Бычков Андрей
1acd29e474 platformio_pre.py fix for new cmake macros 2022-08-10 16:37:28 +03:00
Бычков Андрей
cd7af5e9b7 remove pimap.cpp 2022-08-10 15:14:47 +03:00
Бычков Андрей
adef5b6781 PIMap some doc 2022-08-09 15:54:53 +03:00
Бычков Андрей
2e9acdb1ba убрал установку лишних инклюдов 2022-08-09 12:31:41 +03:00
f0fee0d78f mispell 2022-08-08 21:09:47 +03:00
Бычков Андрей
60f4db61eb Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-08-08 17:14:21 +03:00
Бычков Андрей
724a2dffcf picout and clean 2022-08-08 16:44:37 +03:00
616b384ad6 Merge pull request 'cmake refactoring' (#104) from cmake_refactor into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/104
2022-08-08 16:43:44 +03:00
8abc9777cc cmake refactoring 2022-08-08 15:41:01 +03:00
8551499a5e PICout refactoring, new SHSTKMacros 2022-08-07 22:07:26 +03:00
Бычков Андрей
1eaecb288f PIMapIterators refactoring
PIChunkStream some refactoring
2022-08-05 17:05:56 +03:00
Бычков Андрей
170a713357 PIMap new functions
PIByteArray checksum crc
some doc fixes
2022-08-04 20:20:08 +03:00
54cc6c55b2 pip_cmg and picodeinfo.h doc 2022-08-03 14:14:24 +03:00
e6aa3c34d4 Merge pull request 'added and fixed documentation for PIMath' (#101) from math-doc into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/101
2022-08-03 08:49:08 +03:00
bb40f69298 doc clean 2022-08-03 08:47:25 +03:00
af9a9e78b9 doc 2022-08-02 17:08:51 +03:00
af1264e42b doc fix 2022-08-02 08:25:34 +03:00
eb91fbfc45 doc stream 2022-08-01 21:23:21 +03:00
4ea5465637 PIString:: mid and cutMid does nothing if "start" < 0 2022-08-01 19:29:40 +03:00
ab7769dd5a map and set fix 2022-08-01 19:07:23 +03:00
b1e220e454 change PIIODevice read* and write* methods size to "ssize_t" 2022-08-01 18:52:30 +03:00
1b499530c5 add pisd deploy 2022-08-01 18:20:58 +03:00
b0d48caaad version 2.98.0
remove PIFile::readLine()
partially migrate PIConfig to text stream
add more "override"
2022-08-01 18:13:22 +03:00
Tamerlan Baziev
d6758a8562 исправление ошибок в документации 2022-08-01 12:29:42 +03:00
97734953dd PIString(int) constructors delete 2022-07-29 22:25:21 +03:00
bd98583116 PIString delete operator += int
PICout fix
2022-07-29 20:09:40 +03:00
Бычков Андрей
ddba8f401b PICout fix 2022-07-29 18:16:42 +03:00
Бычков Андрей
4725eb96d6 replace typedef function ptr by std::function
start PIMap refactoring
2022-07-29 15:49:36 +03:00
Бычков Андрей
38fd1b5dc4 PIPacketExtractor теперь работает 2022-07-28 17:02:33 +03:00
16c12a2756 Merge pull request 'Много исправлений и добавлений' (#100) from pip297 into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/100
2022-07-28 14:47:24 +03:00
Бычков Андрей
1b09ad5c27 binlog fixes
PIBinaryStream doc
remove makePIPair
rename bytesAvailable
2022-07-28 14:46:58 +03:00
Бычков Андрей
00d06f71ba version 2022-07-27 15:46:53 +03:00
Бычков Андрей
3873f0b03b PIIODevice::bytesAvailible()
fix pistringlist pibinarystream write
pibinarystream::binaryStreamSize()
PIByteArray pibinarystream read with more size fix
pistring pibinarystream read optimization
fix bug in PIIOBinaryStream read and write if failed
workaround in PIIOString::readDevice
PISPI readDevice bug Fixed
2022-07-27 15:43:04 +03:00
6ae6e9a540 remove test 2022-07-27 10:11:55 +03:00
Tamerlan Baziev
bbc83128b0 added and fixed documentation for PIMath
- added documentation for PIPoint, PILine;
- fixed documentation for PIMathMatrix.
2022-07-26 18:13:28 +03:00
Бычков Андрей
d13e68c206 threadedRead now const uchar *
pipacketextractor Header mode now more flexible
fix splitTime mode
more refactoring
add virtual override to functions
remove piforeach
replace 0 to nullptr
iterate over pimap via iterators
replace CONNECTU to CONNECT# with compile time check
2022-07-26 17:18:08 +03:00
a4882dc054 complex macros with ; 2022-07-25 11:18:09 +03:00
Бычков Андрей
a1b9b7e1d6 убрал лишние ; 2022-07-25 10:32:42 +03:00
Бычков Андрей
e1b89aeca8 PIByteArray begin end indexOf map reduce forEach
PIVector and PIDeque small fixes
2022-07-25 10:07:48 +03:00
242abaaf59 version 2.95.0
get rid of PIByteArray subclassing from PIDeque<uchar>
2022-07-22 16:40:09 +03:00
Бычков Андрей
0116387fe3 PIDeque fix ssize_t
fix uninitialized variables
fix PIDeque prepend with std::initializer_list
2022-07-22 16:31:40 +03:00
Бычков Андрей
f5953a0ba7 PIBinaryLog joinBinLogsSerial
correct timestamp wite with split
2022-07-22 15:24:07 +03:00
Бычков Андрей
7aa407264f Merge remote-tracking branch 'remotes/origin/stream_interface'
PIBinaryLog
2022-07-22 15:22:33 +03:00
Бычков Андрей
59c7896577 Merge branch 'pip2' 2022-07-22 11:18:03 +03:00
Бычков Андрей
a69de63db0 PISerial windows custom speed 2022-07-20 15:41:47 +03:00
e96b399da7 pip_cmg fix 2022-06-24 16:43:22 +03:00
33eefd7453 pip_cmg namespace fix 2022-06-24 14:46:55 +03:00
c7fffe1280 PIBinaryLog miss 2022-06-24 12:19:03 +03:00
1b04d7ecce version 2.93 ready to master
remove PIString << operators
2022-06-24 12:10:57 +03:00
b66272a68a version 2.92
pip_cmg
2022-06-09 17:59:04 +03:00
12c032392c pip_cmg namespaces fix 2022-05-20 15:23:01 +03:00
ffa25c18f0 pip_cmg include fix 2022-05-15 17:56:52 +03:00
f67e3030b9 move to PIIOTextStream 2022-05-13 13:24:09 +03:00
1028233553 version 2.91.0, PITextStream works 2022-05-13 11:26:01 +03:00
ef8ffcd02f DEPRECATED[M], createMemoryBlock(), text stream ... 2022-05-11 20:55:51 +03:00
0897a8369f macros rename 2022-05-11 16:49:33 +03:00
fa19ad1093 text stream ... 2022-05-11 12:39:36 +03:00
8c6b3613b6 code brush 2022-05-11 10:48:36 +03:00
a23eb341e2 pitextstream starts 2022-05-10 18:47:11 +03:00
b2bc385397 PIByteArray works on binary stream 2022-05-10 15:23:18 +03:00
0f9e592273 start moving to binarystream 2022-05-10 12:26:05 +03:00
cf4f58ed95 ready to integrate 2022-05-09 23:57:47 +03:00
0243f588bc before error detection 2022-05-09 22:35:53 +03:00
af77974e91 first try 2022-05-09 14:21:38 +03:00
a502182eba NO_UNUSED 2022-05-09 11:56:09 +03:00
d219baee27 path fix 2022-05-08 22:29:35 +03:00
0ea1e2c856 support for git download of CMake project (standalone PIP build) 2022-05-08 22:22:48 +03:00
3107949e6f doc, small fixes 2022-05-08 19:23:52 +03:00
460519c075 PISingleApplication fix and optimize 2022-05-08 16:35:01 +03:00
9347ed2e55 doc 2022-05-06 23:42:20 +03:00
5770adfd34 PIMap fix 2022-05-06 16:27:40 +03:00
9714d8ea42 PIMap {{K, T}, {K, T}, ...} constructor
doc ru
2022-05-06 12:45:08 +03:00
0b3ee4bb6a doc ru 2022-05-05 22:31:59 +03:00
d1f7065c8a PICout::writePIString -> PICout::write 2022-05-05 10:35:15 +03:00
6995c25613 PIIODevice fullPathPrefix returns PIConstChars 2022-05-04 16:33:05 +03:00
28ce6e8f3f version 2.39.0
PIString works with PIConstChars
picodeinfo optimizations
PIIODevice::availableClasses
2022-05-03 18:44:00 +03:00
8d5730f715 PIPluginLoader +1 error 2022-04-30 16:07:30 +03:00
2bbdbc3ac9 PIIODevice registration dramatically optimization 2022-04-30 11:21:57 +03:00
19e4eee222 PIConstChars API 2022-04-30 09:05:14 +03:00
4139d88103 PIConstChars PIMap supports 2022-04-30 00:07:58 +03:00
6881fd13b7 PIConstChars 2022-04-29 23:53:07 +03:00
Andrey
8c8553a6af PIObject Property const char * 2022-04-29 18:17:03 +03:00
97dd19f0c7 !!!!!!!!!!!!!!!!!! 2022-04-27 16:34:12 +03:00
Andrey
784c949b1a Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-27 15:49:37 +03:00
Andrey
7325e12e30 PIString doc 2022-04-27 15:49:30 +03:00
019ddbb80b TileInput fix 2022-04-27 13:35:27 +03:00
Andrey
6322b248a8 dtos fix 2022-04-27 13:27:58 +03:00
c1c47b4869 locale changes, piscreen 2022-04-27 12:41:38 +03:00
2f4e73ef13 console encoding patch 2022-04-26 22:49:31 +03:00
5ae1cfae87 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-26 21:02:07 +03:00
5d82caf889 Merge pull request 'PIString wo pideue parent' (#91) from pistring_unparent into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/91
2022-04-26 21:01:36 +03:00
d3028a3ce8 pistring remove indexOf* 2022-04-26 21:01:20 +03:00
eef4573a68 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-26 20:04:10 +03:00
48f3b62540 deploy_tool/main.cpp 2022-04-26 20:04:05 +03:00
Andrey
f7d6302572 fix 2022-04-26 17:20:07 +03:00
Andrey
7ad520a1c3 PIString optimization 2022-04-26 17:19:05 +03:00
Andrey
4bc12989ca Merge branch 'master' of https://git.shs.tools/SHS/pip into pistring_unparent 2022-04-26 16:59:36 +03:00
Andrey
186c71d973 linux mb test 2022-04-26 16:41:04 +03:00
Andrey
06c8e6af10 linux mb test 2022-04-26 16:30:26 +03:00
Andrey
69b9589e84 linux mb test 2022-04-26 16:03:37 +03:00
Andrey
5c767c5e3e linux mb test 2022-04-26 16:01:14 +03:00
Andrey
9cd0389a0b PIString wo pideue parent 2022-04-26 14:41:12 +03:00
Andrey
a7ffc85404 piminsleep bug and PIIODevice splitFullPath optimization 2022-04-26 14:09:59 +03:00
Andrey
2e9c3a1dbf PIString benchmarks 2022-04-26 11:53:28 +03:00
9f581335d3 version 2.37 2022-04-26 00:33:17 +03:00
e70e1c0203 pichar fix 2022-04-26 00:17:53 +03:00
cb179de856 linux PIString fix 2022-04-26 00:11:27 +03:00
0aaa5ba890 linux PIString fix 2022-04-25 23:58:38 +03:00
0cf7fb9f25 linux PIString fix 2022-04-25 23:58:06 +03:00
a304997177 linux PIString fix 2022-04-25 23:56:57 +03:00
d6ba51e4bc linux PIString fix 2022-04-25 23:44:30 +03:00
892edb7d5b linux PIString fix 2022-04-25 23:42:46 +03:00
c3cf0f3586 linux PIString fix 2022-04-25 23:41:43 +03:00
2dec17e871 linux PIString fix 2022-04-25 23:41:21 +03:00
88ffd602d6 linux PIString fix 2022-04-25 23:40:17 +03:00
a57e51bdf8 linux PIString fix 2022-04-25 23:39:33 +03:00
44c52c40f1 linux PIString fix 2022-04-25 23:38:09 +03:00
6ecd04b0d8 linux PIString fix 2022-04-25 23:37:06 +03:00
964823b332 linux PIString fix 2022-04-25 23:35:54 +03:00
ca8839f097 linux PIString fix 2022-04-25 23:34:16 +03:00
546ad6a744 linux PIString fix 2022-04-25 23:32:21 +03:00
bd9ad16074 linux PIString fix 2022-04-25 23:31:46 +03:00
23907c7043 fix appendFromChars 2022-04-25 23:06:49 +03:00
a6cea11911 PIString ICU 2022-04-25 22:54:46 +03:00
cea7a7c121 piChar mbrtowc 2022-04-25 22:15:58 +03:00
095ecd254f piChar mbrtowc 2022-04-25 22:14:42 +03:00
2246b8b5fd linux test 2022-04-25 22:01:50 +03:00
914ff5355d Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-25 21:55:14 +03:00
858269a46b linux test 2022-04-25 21:55:10 +03:00
5072d8c915 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-25 21:44:30 +03:00
5f8c04a78e containers minimum elements, windows memory leaks 2022-04-25 21:43:57 +03:00
41fb7cc40d linux fix 2022-04-25 21:32:35 +03:00
6a399c7d39 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-25 20:40:34 +03:00
90afc369f0 string brush 2022-04-25 15:29:27 +03:00
Andrey
765ef7368e PIString replace pibytearray by char * 2022-04-25 11:42:58 +03:00
03384d02a0 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-24 22:11:16 +03:00
cf48c9ebf7 string ascii 2022-04-24 19:15:51 +03:00
dd3d42944e Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-23 13:59:23 +03:00
c2e44dc3ba doc fix 2022-04-23 13:59:06 +03:00
c1c324a5a8 doc 2022-04-23 12:44:09 +03:00
7f93ba55b4 doc 2022-04-23 12:37:55 +03:00
fcd871c0fc doc 2022-04-23 12:32:17 +03:00
0c54709414 doc ru 2022-04-23 11:27:07 +03:00
7a458c5cbe doc ru 2022-04-23 00:44:52 +03:00
8da0469dbf Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-22 23:24:34 +03:00
38b75c85d7 doc fix 2022-04-22 23:24:28 +03:00
833d0333d7 doc fixes 2022-04-22 22:28:43 +03:00
e67a426ff2 doc fix 2022-04-22 21:48:35 +03:00
39e4d9a73c doc ru 2022-04-22 21:19:12 +03:00
Andrey
91216c4b17 PIPair doc 2022-04-22 19:20:50 +03:00
Andrey
416b142889 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-22 18:45:04 +03:00
Andrey
cb4df7dc42 fix PIVector and PIDeque typedefs 2022-04-22 18:44:58 +03:00
Andrey
99a4546775 ещё правки для PIVector и PIDeque iterator и убрал лишние строки 2022-04-22 17:54:08 +03:00
Andrey
8a9864a91c PIPair refactoring 2022-04-22 17:35:29 +03:00
6485d81025 piobject metasystem memory and performance optimization 2022-04-22 15:35:25 +03:00
Andrey
db54d0b052 mistake 2022-04-22 12:13:43 +03:00
Andrey
87105cff21 ещё правки документации для PIVector и PIDeque 2022-04-22 12:12:26 +03:00
Andrey
a489daa475 уменьшил количество строк 2022-04-22 11:51:19 +03:00
c476a06e8c containers doc brush 2022-04-21 22:58:24 +03:00
9deae168a6 thread doc ru 2022-04-21 22:26:49 +03:00
Andrey
93b881da1b PIDeque doc, fixes in PIVector and PIString 2022-04-21 18:25:44 +03:00
Andrey
8beaac5193 finish PIVector doc 2022-04-20 16:50:36 +03:00
Andrey
d4294e3d95 PIVector reshape... not works 2022-04-19 16:33:13 +03:00
Andrey
8c6db321cf PIDeque doc 2022-04-18 19:10:01 +03:00
Andrey
35e68bcd0e Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-18 18:16:38 +03:00
Andrey
f01ca5e5bf pivector doc 2022-04-18 18:16:26 +03:00
bef0ac1194 pip_cmg -H 2022-04-16 01:13:10 +03:00
9fa78a1dbf doc 2022-04-15 16:36:14 +03:00
4b32101de6 introspection major optimization 2022-04-15 01:31:22 +03:00
Andrey
6abec38856 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-14 18:00:39 +03:00
Andrey
d22af96bea PIDeque optimization 2022-04-14 18:00:33 +03:00
7b65a59a6e Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-14 17:48:22 +03:00
42e253adc7 PIIntrospection 2022-04-14 17:48:15 +03:00
Andrey
bb45a60d94 Iterators ssize_t 2022-04-14 17:43:55 +03:00
Andrey
fa93c8a486 PIVector doc, forEach refactory 2022-04-14 15:58:40 +03:00
77e0423375 fix pievaluator and PIDeque sort 2022-04-13 23:29:40 +03:00
c7e67b309e picout fix 2022-04-13 22:46:53 +03:00
Andrey
2ab2614ab4 PICout optimization 2022-04-13 17:59:24 +03:00
Andrey
5ed900c46c PIVector doc 2022-04-13 14:50:09 +03:00
Andrey
fb104a9f24 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-13 14:02:38 +03:00
Andrey
42bfe7c587 PIVector doc 2022-04-13 14:02:31 +03:00
4f2218619c version, debug printf 2022-04-13 12:31:11 +03:00
Andrey
e4e16764f3 PIP_DEBUG, PIVector sort and doc 2022-04-13 11:22:27 +03:00
00830958df doc ru, printf() before assert in containers 2022-04-12 23:17:05 +03:00
Andrey
486fdf3dcd PIVector doc 2022-04-12 10:43:07 +03:00
Andrey
7cd824f3ab PIVector doc 2022-04-11 17:57:23 +03:00
Andrey
60c9d60079 PIVector reverse_iterator sort 2022-04-07 18:17:23 +03:00
397d273802 support for std::sort in PIVector 2022-04-06 20:48:20 +03:00
a117844233 include fix 2022-04-06 20:22:00 +03:00
d5c27b1181 doc groups 2022-04-06 20:11:47 +03:00
c90d06871e PIVector iterator operators 2022-04-06 08:40:25 +03:00
fb282d405d string doc 2022-04-04 16:17:23 +03:00
Andrey
f83d08cf56 PIVector doc 2022-04-01 18:11:52 +03:00
Andrey
0194e3f6b6 PIVector doc 2022-03-31 17:49:18 +03:00
Andrey
1edd9e4c55 PIVector doc 2022-03-31 17:27:36 +03:00
Andrey
aa417be1d3 PIVector reverse, filter and reversed functions
PIVector lastIndexOf and lastIndexWhere correct behaviour
PIVector doc
picontainersmodule.h doc
2022-03-31 16:32:41 +03:00
Andrey
7ab16b641d PIVector doc 2022-03-31 13:28:18 +03:00
Andrey
42fd417e34 picontainers doc, PIVector doc 2022-03-30 17:32:34 +03:00
Andrey
c2ceb710c5 PIVector doc 2022-03-29 17:30:58 +03:00
Andrey
288062cfd6 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-03-29 12:39:49 +03:00
Andrey
9f1ae76d1e PIVector doc 2022-03-29 12:39:37 +03:00
7c927da979 Doxyfile.in 2022-03-29 11:59:54 +03:00
Andrey
7a9c3f72ca PIVector doc 2022-03-28 17:59:09 +03:00
35d340aaab doc ru 2022-03-26 21:47:57 +03:00
5d98a7dd3a README.md 2022-03-25 18:09:13 +03:00
5393225538 README.md 2022-03-25 18:08:31 +03:00
831f202536 README.md 2022-03-25 17:54:51 +03:00
81b749caa2 doc, pitime.h decomposition 2022-03-25 17:47:41 +03:00
a50953ae7c Merge pull request 'doxygen-ru' (#87) from doxygen-ru into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/87
2022-03-25 15:58:22 +03:00
08c5d15e6a doc ru 2022-03-25 15:57:40 +03:00
ff70bf6a0e Merge branch 'doxygen-ru' of https://git.shs.tools/SHS/pip into doxygen-ru 2022-03-25 15:45:26 +03:00
a315f7af25 doc pitime.h 2022-03-25 15:45:05 +03:00
Andrey
4c7df57e66 PIString and PIChar fixes 4 2022-03-25 15:10:29 +03:00
Andrey
7dee8f6313 PIString and PIChar fixes 3 2022-03-25 14:10:38 +03:00
Andrey
0ad6ca6602 PIString and PIChar fixes 2 2022-03-25 14:07:37 +03:00
Andrey
649850a1ba PIString and PIChar fixes 2022-03-25 13:49:32 +03:00
Andrey
8bb1af8d2a fix PIChar 2022-03-25 12:35:02 +03:00
7a0adf5e28 Merge pull request 'translation for russian starts' (#85) from doxygen-ru into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/85
2022-03-25 12:12:36 +03:00
Andrey
6241795b60 Merge branch 'master' of https://git.shs.tools/SHS/pip into doxygen-ru
# Conflicts:
#	libs/main/core/pivariant.cpp
#	libs/main/math/pigeometry.h
#	libs/main/math/pimathbase.h
2022-03-25 12:12:15 +03:00
Andrey
9d0451455a README.md ссылки на доку 2022-03-25 12:08:04 +03:00
peri4
9a8b9c7141 doc ru 2022-03-21 22:03:47 +03:00
866f71edb5 Merge pull request 'geometry_refact' (#86) from geometry_refact into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/86
2022-03-21 14:14:12 +03:00
Andrey
4bae04feec code style 2022-03-21 12:20:11 +03:00
Andrey
415160387b PILine 2022-03-21 10:49:41 +03:00
Andrey
3dd0d0b6cf PIRect complete 2022-03-21 10:35:34 +03:00
Andrey
2596b119ac start refactoring pigeometry.h 2022-03-18 18:06:40 +03:00
20e0771331 doc ru 2022-03-18 01:28:07 +03:00
7a26ae7292 doc ru 2022-03-17 18:13:02 +03:00
cc4e1f48aa doc ru 2022-03-17 00:57:15 +03:00
Andrey
6e6305d2ec start PIVector doc 2022-03-16 16:38:09 +03:00
Andrey
3e9cb2481c doc link to ru.cppreference.com for russian doc 2022-03-15 15:40:21 +03:00
Andrey
ea624f1223 picontainers.h doc 2022-03-15 15:34:45 +03:00
Andrey
e4aec3f95e Doxyfile.in upgrade 2022-03-15 15:10:59 +03:00
7d83c6fe19 PIByteArray doc 2022-03-14 23:19:46 +03:00
7ef4321a3d supports for doc language select with cmake 2022-03-14 21:53:30 +03:00
54b5372356 doxygen @ tags replaced to \ 2022-03-14 21:19:31 +03:00
Andrey
9bf1a11701 picontainers.h doxygen fixes, generating html/pip.cfg 2022-03-14 18:17:16 +03:00
Andrey
99280a40ef picontainers.h doxygen partial 2022-03-14 17:14:29 +03:00
Andrey
99061f6e24 utf-8 2022-03-14 12:46:13 +03:00
Andrey
2fd139b1e3 Merge branch 'master' of https://git.shs.tools/SHS/pip into doxygen-ru 2022-03-14 12:31:51 +03:00
ae29b4514c translation for russian starts 2022-03-14 12:11:46 +03:00
58de1ceafc Merge pull request 'micro' (#83) from micro into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/83
2022-03-14 12:10:32 +03:00
20e6d1be99 Merge branch 'master' into micro 2022-03-14 11:57:06 +03:00
2a877fbb6b pip_cmg supports for "simple-stream" PIMETA tag for structs and classes for simple de/serialization without PIChunkStream 2022-03-11 14:39:08 +03:00
2a6ebc9d8d piCompare change position 2022-02-14 19:12:41 +03:00
Andrey
c3c98b9d78 include fixes 2022-02-14 14:01:54 +03:00
Andrey
443e8b46a6 Merge branch 'master' of https://git.shs.tools/SHS/pip into micro 2022-02-11 12:00:49 +03:00
Andrey
fff2aa468a PIP_FORCE_NO_PIINTROSPECTION 2022-02-11 12:00:34 +03:00
1918e55a97 piCompare use piAbs 2022-02-08 00:33:12 +03:00
eb6d378de2 deploy tool unchained from "grep" and support qt6 2022-01-31 19:55:23 +03:00
b1b174ba64 missed include 2022-01-23 12:59:13 +03:00
Andrey
4921a3b0fd arduino PISystemTime::current 2022-01-21 17:09:21 +03:00
Andrey
8296e9a32b add FreeRTOS support for PIThread PIMutex PIConditionVariable 2022-01-21 14:15:42 +03:00
Andrey
7403ee67be gitignore 2022-01-20 16:54:20 +03:00
Andrey
cde2341c1f fix freertos includes 2022-01-20 16:46:04 +03:00
Andrey
542f180d9d add Freertos dependency 2022-01-17 18:39:57 +03:00
86130d7105 compiled for esp32 2022-01-15 14:54:36 +03:00
Andrey
c9e329d27d rename PIInit BuildOption 2022-01-14 18:51:37 +03:00
Andrey
d4c6c410da some fixes 2022-01-14 18:25:41 +03:00
Andrey
a7df53fbfe platformio_pre.py 2022-01-14 18:15:56 +03:00
Andrey
0504fa187e define PIP_MICRO
detect AVR_GCC
add library.json
2022-01-14 14:37:51 +03:00
1d9a39f792 piCompare 2022-01-10 17:10:41 +03:00
cbdaabee4a some build fixes 2022-01-07 01:58:38 +03:00
3c8ccf357b PIFile::openTemporary on Windows
PIPair from std::tuple
2021-12-24 14:41:18 +03:00
Andrey
92b20f6f46 PIByteArray getRange 2021-11-16 15:22:03 +03:00
04d7ed77d9 Merge pull request 'condvar_use' (#82) from condvar_use into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/82
2021-11-16 14:49:52 +03:00
a2a205cfd2 version 2.33.0
piMinSleep() method
2021-11-16 14:43:57 +03:00
d3b6597042 PIMap range-for decomposition declaration support 2021-11-01 23:29:42 +03:00
Andrey
48c885e12a PIThreadNotifier, rewrite PIObject::deleteLater()
tests for PIThreadNotifier and PIObject::deleteLater()
2021-10-29 18:20:48 +03:00
Andrey
6e5a5a6ade remove msleep, clean PIConditionVariable, rewrite pipipelinethread, etc... 2021-10-29 16:52:03 +03:00
21e03fc8cb flags 2021-10-27 10:53:27 +03:00
b85de0d704 work with PIFile::openTemporary() on Windows 2021-10-26 13:50:27 +03:00
peri4
f781cc3846 binary log improvements 2021-10-21 18:48:01 +03:00
peri4
1cb3d4ffe9 PIBinaryLog fix 2021-10-14 12:45:01 +03:00
peri4
9293706634 PISerial 14400 baudrate only for Windows 2021-10-08 22:11:47 +03:00
peri4
fde6bdf17f PISerial 14400 baudrate 2021-10-08 22:02:51 +03:00
Andrey
a1c1fd8339 Merge branch 'master' of https://git.shs.tools/SHS/pip 2021-10-08 15:16:19 +03:00
Andrey
01b39dc75f pip_cmg fix macros name 2021-10-08 15:16:08 +03:00
07ec32c969 tests 2021-10-05 20:31:00 +03:00
042366e19e Merge branch 'PIMathMatrixTests1-10' 2021-10-04 22:14:38 +03:00
948a90fcd9 option revert 2021-10-04 22:14:15 +03:00
c404688bbd more safety for PIObject::Connection::disconnect() 2021-10-04 21:57:34 +03:00
aa76a15f40 version 2.32.0
PIObject::Connection struct
2021-10-04 21:50:49 +03:00
Andrey
ca20785b53 revert piDisconnectAll 2021-10-04 15:07:14 +03:00
Andrey
13d0b2f960 remove piDisconnectAll 2021-10-04 15:05:58 +03:00
Andrey
46571ac39f piDisconnectAll private 2021-10-04 14:18:23 +03:00
36d770ea2e Merge pull request 'piobject_tests' (#80) from piobject_tests into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/80
2021-10-04 12:11:51 +03:00
Andrey
bc7d129a9e piobject/connect.cpp tests 2021-10-04 12:07:01 +03:00
8accc28804 test fix 2021-09-30 19:28:30 +03:00
Andrey
62e130f91b disconnect test failed 2021-09-30 18:41:01 +03:00
a009221092 pidisconnect now work with lambdas 2021-09-30 16:21:28 +03:00
dedc35b466 new class PIThreadPoolLoop 2021-09-24 16:03:20 +03:00
5e33587703 PISerial::setBreak linux fix 2021-09-17 21:27:24 +03:00
950f6830da old gcc pithread fix 2021-09-17 21:20:21 +03:00
Andrey
19a8ca84e6 PIByteArray checksumPlain invert flag
fix PISerial setBreak
2021-09-16 16:18:20 +03:00
Andrey
ece3fb1536 PISerial setBreak 2021-09-16 12:18:17 +03:00
0d119502a8 PIDeque functions same as PIVector
code brush
fix indexOf and entries with start<0
2021-09-09 18:01:57 +03:00
cc5951cfc3 PIVector getRange removeWhere 2021-09-09 17:38:28 +03:00
61d42e0ac5 PIVector: map, reduce
rename arguments in uniform style
2021-09-07 18:29:09 +03:00
127935086c PIVector: any, every, indexWhere, lastIndexWhere
start arg in indexOf, entries, lastIndexOf
and some code brush
2021-09-07 17:29:24 +03:00
76ed60edf3 code brush 2021-09-07 15:39:44 +03:00
3b0a1c70fe documentation fix 2021-09-03 17:12:46 +03:00
186e07e45d PICodeInfo::EnumInfo toPIVariantEnum 2021-09-03 16:19:57 +03:00
047cff7d6e version 2021-09-03 12:42:29 +03:00
305275e3ac PICodeParser namespaces fix 2021-09-03 11:39:26 +03:00
efb0d5f4f9 PICodeParser predefined PIP macros 2021-09-03 11:20:38 +03:00
991a074538 version 2.30
PIStreamPacker remove progresses
picloud various fixes
2021-09-01 23:48:13 +03:00
f82b6c12ee cloud_dispatcher patch 2021-09-01 22:43:40 +03:00
00edfa4ef0 cloud data send optimize 2021-09-01 17:48:58 +03:00
35a3ce6402 picloudtcp.cpp revert some mutex 2021-09-01 10:56:11 +03:00
be3ce454a0 picloud multithread fix 2021-08-31 19:40:22 +03:00
4c85206cfa version 2021-08-23 14:07:45 +03:00
5ecdcbe46e Merge pull request 'cloud_debug' (#78) from cloud_debug into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/78
2021-08-23 13:58:08 +03:00
c937d7251a it works 2021-08-23 13:56:21 +03:00
1cc46468c1 fail 2021-08-20 18:30:19 +03:00
5cc8ef1eb0 fail reconnect 2021-08-20 18:25:59 +03:00
99e135caa2 PICloudClient disconnect 2021-08-20 17:22:25 +03:00
9de7045d63 picloud revert to condvars and fix 2021-08-20 16:36:28 +03:00
0e65151e9f PIEthernet error 232
PICloud many fixes
PIBroadcast recursive fix
2021-08-20 10:55:47 +03:00
3c20728210 version 2021-08-19 18:29:05 +03:00
4c0530d89a picloud ping and fix big bugs 2021-08-19 18:13:05 +03:00
f5af8a1da9 disable autostart pibroadcast 2021-08-19 15:02:30 +03:00
44b9c37391 PICloudClient now soft stop thread when closed
last cmake changes
2021-08-16 22:30:56 +03:00
97b0b6fc0c picloud hash key 2021-08-12 22:05:02 +03:00
1a2e9afaef PIVector compare operators 2021-08-12 21:52:14 +03:00
39a3a23a24 PIByteArray compare operators 2021-08-12 21:41:22 +03:00
ee131921a0 add PIByteArray operator <, fix picloud 2021-08-12 20:22:43 +03:00
f8818c8537 picloud patch 2021-08-12 19:50:17 +03:00
b07242226e Tests1-10 2021-02-25 15:41:20 +03:00
468 changed files with 74848 additions and 37847 deletions

224
.clang-format Normal file
View File

@@ -0,0 +1,224 @@
---
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
...

6
.editorconfig Normal file
View File

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

4
.gitignore vendored
View File

@@ -2,4 +2,6 @@
/.svn
/doc/rtf
_unsused
CMakeLists.txt.user*
CMakeLists.txt.user*
/include
/release

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,22 +1,60 @@
cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
project(pip)
set(pip_MAJOR 2)
set(pip_MINOR 28)
set(pip_REVISION 1)
set(pip_SUFFIX )
set(pip_COMPANY SHS)
set(pip_DOMAIN org.SHS)
project(PIP)
set(PIP_MAJOR 4)
set(PIP_MINOR 4)
set(PIP_REVISION 1)
set(PIP_SUFFIX )
set(PIP_COMPANY SHS)
set(PIP_DOMAIN org.SHS)
set(GIT_CMAKE_DIR)
if (NOT DEFINED SHSTKPROJECT)
set(ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cmake-download/CMakeLists.txt"
"# This file was generated by PIP CMake, don`t edit it!
cmake_minimum_required(VERSION 2.8.2)
project(cmake-download NONE)
include(ExternalProject)
ExternalProject_Add(cmake
GIT_REPOSITORY https://git.shstk.ru/SHS/cmake.git
GIT_TAG \"origin/master\"
GIT_CONFIG \"advice.detachedHead=false\"
SOURCE_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cmake-src\"
BINARY_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cmake-build\"
INSTALL_COMMAND \"\"
TEST_COMMAND \"\"
)
")
execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cmake-download)
if(result)
message(FATAL_ERROR "CMake step for cmake failed: ${result}")
endif()
execute_process(COMMAND "${CMAKE_COMMAND}" --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cmake-download)
if(result)
message(FATAL_ERROR "Build step for cmake failed: ${result}")
endif()
install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" --build \"${CMAKE_CURRENT_BINARY_DIR}/cmake-build\" --target install)")
set(GIT_CMAKE_DIR "${CMAKE_CURRENT_BINARY_DIR}/cmake-src")
endif()
if ("x${CMAKE_MODULE_PATH}" STREQUAL "x")
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
endif()
if (NOT "x${GIT_CMAKE_DIR}" STREQUAL "x")
list(APPEND CMAKE_MODULE_PATH "${GIT_CMAKE_DIR}")
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
include(CheckFunctionExists)
include(PIPMacros)
include(SHSTKMacros)
shstk_begin_project(pip PIP)
shstk_begin_project(PIP)
set(PIP_VERSION "${PIP_VERSION}" CACHE STRING "")
set(_ICU_DEFAULT OFF)
if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE))
@@ -24,17 +62,29 @@ if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE
endif()
set(PIP_DLL_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "")
if (CMAKE_BUILD_TYPE MATCHES Debug)
set(PIP_BUILD_DEBUG ON)
else()
set(PIP_BUILD_DEBUG OFF)
endif()
# Options
option(ICU "ICU support for convert codepages" ${_ICU_DEFAULT})
option(STD_IOSTREAM "Building with std iostream operators support" OFF)
option(INTROSPECTION "Build with introspection" OFF)
option(TESTS "Build tests and perform their before install step" OFF)
option(TESTS "Build tests and perform their before install step" ${PIP_BUILD_DEBUG})
option(COVERAGE "Build project with coverage info" OFF)
set(PIP_UTILS 1)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_CXX_STANDARD 11)
shstk_is_parent_exists(_pe)
if (_pe)
set(BUILDING_pip 1 PARENT_SCOPE)
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}")
endif()
# Basic
set(PIP_MODULES)
@@ -47,7 +97,7 @@ set(PIP_UTILS_LIST)
set(PIP_TESTS_LIST)
set(PIP_EXPORTS)
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;cloud;lua")
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;client_server;cloud;lua;http_client;http_server")
foreach(_m ${PIP_SRC_MODULES})
set(PIP_MSG_${_m} "no")
endforeach()
@@ -59,7 +109,7 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
set(CRES)
file(GLOB_RECURSE CPPS "libs/${NAME}/*.cpp" "libs/${NAME}/*.c")
file(GLOB_RECURSE HS "libs/${NAME}/*.h")
file(GLOB_RECURSE PHS "libs/${NAME}/*_p.h")
file(GLOB_RECURSE PHS "libs/${NAME}/*_p.h" "libs/${NAME}/3rd/*.h")
file(GLOB_RECURSE RES "libs/${NAME}/*.conf")
if (NOT "x${PHS}" STREQUAL "x")
list(REMOVE_ITEM HS ${PHS})
@@ -68,9 +118,14 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
file(GLOB_RECURSE ASRC "${SOURCES}/*.cpp" "${SOURCES}/*.c")
list(APPEND CPPS ${ASRC})
endif()
#message("${NAME} HS = ${HS}")
list(APPEND HDRS ${HS})
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(_libs "${LIBS}")
if ("${NAME}" STREQUAL "main")
@@ -81,11 +136,11 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
string(TOUPPER "${_target}" DEF_NAME)
set(PIP_MSG_${NAME} "yes${MSG}")
import_version(${_target} pip)
set_deploy_property(${_target} ${pip_LIB_TYPE}
import_version(${_target} PIP)
set_deploy_property(${_target} ${PIP_LIB_TYPE}
LABEL "${LABEL}"
FULLNAME "${pip_DOMAIN}.${_target}"
COMPANY "${pip_COMPANY}"
FULLNAME "${PIP_DOMAIN}.${_target}"
COMPANY "${PIP_COMPANY}"
INFO "Platform-Independent Primitives")
make_rc(${_target} _RC)
@@ -102,7 +157,7 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
pip_resources(CRES "${RES}")
endif()
add_definitions(-D${DEF_NAME})
add_library(${_target} ${pip_LIB_TYPE} ${CPPS} ${CRES} ${_RC})
add_library(${_target} ${PIP_LIB_TYPE} ${CPPS} ${CRES} ${_RC} ${HS} ${PHS})
target_include_directories(${_target} PUBLIC ${PIP_INCLUDES})
if (NOT "x${RES}" STREQUAL "x")
add_dependencies(${_target} pip_rc)
@@ -134,10 +189,12 @@ if (NOT DEFINED PIP_CMG)
if (CMAKE_CROSSCOMPILING OR (DEFINED ANDROID_PLATFORM))
set(PIP_CMG "pip_cmg")
set(PIP_RC "pip_rc")
set(PIP_TR "pip_tr")
set(PIP_DEPLOY_TOOL "deploy_tool")
else()
set(PIP_CMG "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator/pip_cmg")
set(PIP_RC "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler/pip_rc")
set(PIP_TR "${CMAKE_CURRENT_BINARY_DIR}/utils/translator/pip_tr")
set(PIP_DEPLOY_TOOL "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool/deploy_tool")
endif()
endif()
@@ -197,26 +254,11 @@ if(PIP_MATH_YN)
add_definitions(-DPIP_MATH_YN)
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
if (CMAKE_BUILD_TYPE MATCHES Debug)
set(PIP_BUILD_TYPE "Debug")
if (PIP_BUILD_DEBUG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall")
add_definitions(-DPIP_DEBUG)
else()
set(PIP_BUILD_TYPE "Release")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall")
endif()
@@ -244,9 +286,14 @@ endif()
# Check if ICU used for PIString and PIChar
set(PIP_ICU "no")
if(ICU)
set(PIP_ICU "yes")
add_definitions(-DPIP_ICU)
list(APPEND LIBS_MAIN icuuc)
pip_find_lib(icuuc)
if (icuuc_FOUND)
set(PIP_ICU "yes")
add_definitions(-DPIP_ICU)
list(APPEND LIBS_MAIN icuuc)
else()
message(STATUS "Warning: ICU requested, but not found. Build without ICU")
endif()
endif()
@@ -270,42 +317,37 @@ list(APPEND HDRS ${_PIP_DEFS_FILE})
#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
if(APPLE)
add_definitions(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
endif()
if ((NOT DEFINED LIBPROJECT) AND (DEFINED ANDROID_PLATFORM))
if ((NOT DEFINED SHSTKPROJECT) AND (DEFINED ANDROID_PLATFORM))
include_directories(${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include)
#message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include")
#message("${ANDROID_NDK}/sysroot/usr/include")
endif()
if(NOT PIP_FREERTOS)
if(WIN32)
if(${C_COMPILER} STREQUAL "cl.exe")
if(WIN32)
if(${C_COMPILER} STREQUAL "cl.exe")
else()
list(APPEND LIBS_MAIN ws2_32 iphlpapi psapi cfgmgr32 setupapi)
endif()
else()
list(APPEND LIBS_MAIN ws2_32 iphlpapi psapi cfgmgr32 setupapi)
endif()
else()
list(APPEND LIBS_MAIN dl)
if(DEFINED ENV{QNX_HOST})
list(APPEND LIBS_MAIN socket)
else()
if (NOT DEFINED ANDROID_PLATFORM)
list(APPEND LIBS_MAIN pthread util)
list(APPEND LIBS_MAIN dl)
if(DEFINED ENV{QNX_HOST})
list(APPEND LIBS_MAIN socket)
else()
if (NOT DEFINED ANDROID_PLATFORM)
list(APPEND LIBS_MAIN pthread util)
if (NOT APPLE)
list(APPEND LIBS_MAIN rt)
endif()
endif()
endif()
endif()
endif()
endif()
set(PIP_LIBS)
if(PIP_FREERTOS)
set(PIP_LIBS ${LIBS_MAIN})
@@ -320,7 +362,7 @@ if(WIN32)
set(CMAKE_CXX_FLAGS "/O2 /Ob2 /Ot /W0")
endif()
else()
set(${CMAKE_CXX_FLAGS} "${CMAKE_CXX_FLAGS} -fPIC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
if(DEFINED ENV{QNX_HOST} OR PIP_FREERTOS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth-32")
endif()
@@ -332,6 +374,8 @@ pip_module(main "${LIBS_MAIN}" "PIP main library" "" "" "")
generate_export_header(pip)
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})
set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_${_m}_EXPORTS)
generate_export_header(pip BASE_NAME "pip_${_m}")
@@ -339,6 +383,17 @@ foreach(_m ${PIP_SRC_MODULES})
endforeach()
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 PIP_FREERTOS)
@@ -362,6 +417,7 @@ if (NOT CROSSTOOLS)
pip_find_lib(sodium)
if(sodium_FOUND)
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" "" "" "")
endif()
@@ -411,17 +467,16 @@ if (NOT CROSSTOOLS)
endif()
if (NOT "x${MINGW_INCLUDE}" STREQUAL "x")
list(APPEND CMAKE_INCLUDE_PATH "${MINGW_INCLUDE}")
endif()
find_package(OpenCL QUIET) #OpenCL_VERSION_STRING
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}")
if(APPLE)
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers")
endif()
pip_module(opencl "${_opencl_lib}" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})")
pip_module(opencl "OpenCL" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})")
endif()
@@ -443,15 +498,58 @@ if (NOT CROSSTOOLS)
endif()
list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge")
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
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)
add_executable(pip_test "main.cpp")
target_link_libraries(pip_test pip pip_cloud pip_lua)
if (NOT DEFINED ANDROID_PLATFORM)
if(microhttpd_FOUND AND curl_FOUND)
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()
else()
@@ -464,6 +562,43 @@ endif()
string(REPLACE ";" "," PIP_EXPORTS_STR "${PIP_EXPORTS}")
target_compile_definitions(pip PRIVATE "PICODE_DEFINES=\"${PIP_EXPORTS_STR}\"")
if(NOT PIP_FREERTOS)
# Auxiliary
if (NOT CROSSTOOLS)
add_subdirectory("utils/piterminal")
endif()
# Utils
add_subdirectory("utils/code_model_generator")
add_subdirectory("utils/resources_compiler")
add_subdirectory("utils/deploy_tool")
add_subdirectory("utils/qt_support")
add_subdirectory("utils/translator")
add_subdirectory("utils/value_tree_translator")
if(PIP_UTILS AND (NOT CROSSTOOLS))
add_subdirectory("utils/system_test")
add_subdirectory("utils/udp_file_transfer")
if(sodium_FOUND)
add_subdirectory("utils/system_daemon")
add_subdirectory("utils/crypt_tool")
add_subdirectory("utils/cloud_dispatcher")
endif()
endif()
endif()
# Translations
set(PIP_LANG)
if (NOT CROSSTOOLS)
# pip_translation(PIP_LANG lang/pip_ru.ts)
# add_custom_target(pip_lang SOURCES "${PIP_LANG}")
file(GLOB PIP_LANG "lang/*.btf")
endif()
# Install
# Check if system or local install will be used (to system install use "-DLIB=" argument of cmake)
if(NOT LOCAL)
@@ -471,6 +606,9 @@ if(NOT LOCAL)
if(MINGW)
if (NOT CROSSTOOLS)
install(FILES ${HDRS} DESTINATION ${MINGW_INCLUDE}/pip)
if(PIP_LANG)
install(FILES ${PIP_LANG} DESTINATION ${MINGW_INCLUDE}/../share/pip/lang)
endif()
if(HDR_DIRS)
install(DIRECTORY ${HDR_DIRS} DESTINATION ${MINGW_INCLUDE}/pip)
endif()
@@ -484,6 +622,7 @@ if(NOT LOCAL)
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator")
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler")
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool")
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/translator")
endif()
else()
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pip_export.h DESTINATION include)
@@ -491,6 +630,9 @@ if(NOT LOCAL)
else()
if (NOT CROSSTOOLS)
install(FILES ${HDRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip)
if(PIP_LANG)
install(FILES ${PIP_LANG} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pip/lang)
endif()
if(HDR_DIRS)
install(DIRECTORY ${HDR_DIRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip)
endif()
@@ -506,6 +648,9 @@ else()
install(TARGETS ${PIP_MODULES} DESTINATION lib)
endif()
install(FILES ${HDRS} DESTINATION include/pip)
if(PIP_LANG)
install(FILES ${PIP_LANG} DESTINATION share/pip/lang)
endif()
if(HDR_DIRS)
install(DIRECTORY ${HDR_DIRS} DESTINATION include/pip)
endif()
@@ -514,29 +659,6 @@ endif()
file(GLOB CMAKES "cmake/*.cmake" "cmake/*.in")
install(FILES ${CMAKES} DESTINATION ${CMAKE_ROOT}/Modules)
if(NOT PIP_FREERTOS)
# Auxiliary
if (NOT CROSSTOOLS)
add_subdirectory("utils/piterminal")
endif()
# Utils
add_subdirectory("utils/code_model_generator")
add_subdirectory("utils/resources_compiler")
add_subdirectory("utils/deploy_tool")
if(PIP_UTILS AND (NOT CROSSTOOLS))
add_subdirectory("utils/system_test")
add_subdirectory("utils/udp_file_transfer")
if(sodium_FOUND)
add_subdirectory("utils/system_daemon")
add_subdirectory("utils/crypt_tool")
add_subdirectory("utils/cloud_dispatcher")
endif()
endif()
endif()
shstk_is_parent_exists(_pe)
if (_pe)
@@ -550,25 +672,38 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
include(PIPDocumentation)
find_package(Doxygen)
if(DOXYGEN_FOUND)
set(DOXY_PROJECT_NUMBER "${pip_VERSION}")
set(DOXY_QHP_CUST_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_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"")
set(DOXY_EXCLUDE "\"${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd\"")
set(DOXY_DEFINES "${PIP_EXPORTS}")
foreach (_m "console" "usb" "compress" "crypt" "client_server" "cloud" "fftw" "opencl" "io_utils" "lua" "http_server" "http_client")
string(TOUPPER "${_m}" _mdef)
list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT")
endforeach()
set(DOXY_PROJECT_NUMBER "${PIP_VERSION}")
set(DOXY_QHP_CUST_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_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"")
set(DOXY_LOGO_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pip.png\"")
set(DOXY_EXCLUDE "\"${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd\"")
set(DOXY_DOMAIN "${PIP_DOMAIN}.${PROJECT_NAME}.doc")
if ("x${DOC_LANG}" STREQUAL "x")
set(DOXY_OUTPUT_LANGUAGE English)
set(DOXY_OUTPUT_DIR en)
else()
set(DOXY_OUTPUT_LANGUAGE ${DOC_LANG})
set(DOXY_OUTPUT_DIR ${DOC_DIR})
endif()
if(DOXYGEN_DOT_EXECUTABLE)
string(REPLACE "\\" "" _DOT_PATH "${DOXYGEN_DOT_PATH}")
string(REPLACE "\\" "/" _DOT_PATH "${DOXYGEN_DOT_PATH}")
set(DOXY_DOT_PATH "\"${_DOT_PATH}\"")
set(DOXY_MSCGEN_PATH "\"${_DOT_PATH}\"")
set(DOXY_DIA_PATH "\"${_DOT_PATH}\"")
endif()
set(DOXY_INPUT)
foreach(F ${PIP_MAIN_FOLDERS})
list(APPEND DOXY_INPUT "\"${F}\"")
endforeach(F)
string(REPLACE ";" " " DOXY_INPUT "\"${CMAKE_CURRENT_SOURCE_DIR}/libs\"")
string(REPLACE ";" " " DOXY_INCLUDE_PATH "${DOXY_INPUT}")
string(REPLACE ";" " " DOXY_DEFINES "${PIP_EXPORTS};DOXYGEN;PIOBJECT;PIOBJECT_SUBCLASS")
string(REPLACE ";" " " DOXY_INPUT "\"${CMAKE_CURRENT_SOURCE_DIR}/libs\";\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pages\"")
string(REPLACE ";" " " DOXY_INCLUDE_PATH "${PIP_INCLUDES}")
string(REPLACE ";" " " DOXY_DEFINES "${DOXY_DEFINES}")
add_documentation(doc doc/Doxyfile.in)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/html DESTINATION ../share/doc/pip COMPONENT doc EXCLUDE_FROM_ALL OPTIONAL)
endif()
@@ -594,10 +729,11 @@ macro(expand_to_length _out _str _len)
endmacro()
list(REMOVE_ITEM LIBS_STATUS ${PIP_MODULES})
list(REMOVE_DUPLICATES LIBS_STATUS)
message("----------PIP----------")
message(" Version: ${pip_VERSION} ")
message(" Linkage: ${pip_LIB_TYPE_MSG}")
message(" Type : ${pip_BUILD_TYPE}")
message(" Version: ${PIP_VERSION} ")
message(" Linkage: ${PIP_LIB_TYPE_MSG}")
message(" Type : ${CMAKE_BUILD_TYPE}")
if (NOT LOCAL)
message(" Install: \"${CMAKE_INSTALL_PREFIX}\"")
else()
@@ -609,7 +745,6 @@ message("")
message(" Options:")
message(" std::iostream: ${PIP_STD_IOSTREAM}")
message(" ICU strings : ${PIP_ICU}")
message(" Timer types : ${PIP_TIMERS}")
message(" Introspection: ${PIP_INTROSPECTION}")
message(" Coverage : ${PIP_COVERAGE}")
if(INTROSPECTION)

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
macro(ADD_DOCUMENTATION TARGET DOXYGEN_CONFIG_FILE)
if(DOXYGEN_FOUND)
configure_file("${PROJECT_SOURCE_DIR}/${DOXYGEN_CONFIG_FILE}" "${CMAKE_CURRENT_BINARY_DIR}/doxyfile-${TARGET}")
add_custom_target("genereate.${TARGET}" COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxyfile-${TARGET})
add_custom_target("genereate.${TARGET}" COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/doc/html" COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxyfile-${TARGET})
add_custom_target("${TARGET}" COMMAND ${CMAKE_COMMAND} -D COMPONENT=doc -P cmake_install.cmake)
add_dependencies("${TARGET}" "genereate.${TARGET}")
else(DOXYGEN_FOUND)

View File

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

View File

@@ -1,4 +1,4 @@
# Doxyfile 1.8.15
# Doxyfile 1.9.1
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -51,7 +51,7 @@ PROJECT_BRIEF = "Platform-Independent Primitives"
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
PROJECT_LOGO =
PROJECT_LOGO = ${DOXY_LOGO_PATH}
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
@@ -91,7 +91,7 @@ ALLOW_UNICODE_NAMES = NO
# Ukrainian and Vietnamese.
# The default value is: English.
OUTPUT_LANGUAGE = English
OUTPUT_LANGUAGE = ${DOXY_OUTPUT_LANGUAGE}
# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
# documentation generated by doxygen is written. Doxygen will use this
@@ -158,7 +158,7 @@ INLINE_INHERITED_MEMB = NO
# shortest path that makes the file name unique will be used
# The default value is: YES.
FULL_PATH_NAMES = YES
FULL_PATH_NAMES = NO
# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
# Stripping is only done if one of the specified strings matches the left-hand
@@ -197,10 +197,20 @@ SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
# such as
# /***************
# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
# Javadoc-style will behave just like regular comments and it will not be
# interpreted by doxygen.
# The default value is: NO.
JAVADOC_BANNER = NO
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
# requiring an explicit @brief command for a brief description.)
# requiring an explicit \brief command for a brief description.)
# The default value is: NO.
QT_AUTOBRIEF = NO
@@ -215,7 +225,15 @@ QT_AUTOBRIEF = NO
# not recognized any more.
# The default value is: NO.
MULTILINE_CPP_IS_BRIEF = NO
MULTILINE_CPP_IS_BRIEF = YES
# By default Python docstrings are displayed as preformatted text and doxygen's
# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
# doxygen's special commands can be used and the contents of the docstring
# documentation blocks is shown as doxygen documentation.
# The default value is: YES.
PYTHON_DOCSTRING = YES
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
# documentation from any documented member that it re-implements.
@@ -256,12 +274,6 @@ ALIASES = "handlers=\name Handlers" \
"events=\name Events" \
"ioparams=\name Configurable parameters"
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all
@@ -302,19 +314,22 @@ OPTIMIZE_OUTPUT_SLICE = NO
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,
# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
# tries to guess whether the code is fixed or free formatted code, this is the
# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat
# .inc files as Fortran files (default is PHP), and .f files as C (default is
# Fortran), use: inc=Fortran f=C.
# default for Fortran type files). For instance to make doxygen treat .inc files
# as Fortran files (default is PHP), and .f files as C (default is Fortran),
# use: inc=Fortran f=C.
#
# Note: For files without extension you can use no_extension as a placeholder.
#
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen.
# the files are not read by doxygen. When specifying no_extension you should add
# * to the FILE_PATTERNS.
#
# Note see also the list of default file extension mappings.
EXTENSION_MAPPING =
@@ -332,7 +347,7 @@ MARKDOWN_SUPPORT = YES
# to that level are automatically included in the table of contents, even if
# they do not have an id attribute.
# Note: This feature currently applies only to Markdown headings.
# Minimum value: 0, maximum value: 99, default value: 0.
# Minimum value: 0, maximum value: 99, default value: 5.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
TOC_INCLUDE_HEADINGS = 0
@@ -353,7 +368,7 @@ AUTOLINK_SUPPORT = YES
# diagrams that involve STL classes more complete and accurate.
# The default value is: NO.
BUILTIN_STL_SUPPORT = NO
BUILTIN_STL_SUPPORT = YES
# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
@@ -448,6 +463,19 @@ TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
# during processing. When set to 0 doxygen will based this on the number of
# cores available in the system. You can set it explicitly to a value larger
# than 0 to get more control over the balance between CPU load and processing
# speed. At this moment only the input processing can be done using multiple
# threads. Since this is still an experimental feature the default is set to 1,
# which efficively disables parallel processing. Please report any issues you
# encounter. Generating dot graphs in parallel is controlled by the
# DOT_NUM_THREADS setting.
# Minimum value: 0, maximum value: 32, default value: 1.
NUM_PROC_THREADS = 1
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
@@ -468,6 +496,12 @@ EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
# methods of a class will be included in the documentation.
# The default value is: NO.
EXTRACT_PRIV_VIRTUAL = YES
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
# The default value is: NO.
@@ -505,6 +539,13 @@ EXTRACT_LOCAL_METHODS = YES
EXTRACT_ANON_NSPACES = NO
# If this flag is set to YES, the name of an unnamed parameter in a declaration
# will be determined by the corresponding definition. By default unnamed
# parameters remain unnamed in the output.
# The default value is: YES.
RESOLVE_UNNAMED_PARAMS = YES
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
# undocumented members inside documented classes or files. If set to NO these
# members will be included in the various overviews, but no documentation
@@ -522,8 +563,8 @@ HIDE_UNDOC_MEMBERS = YES
HIDE_UNDOC_CLASSES = YES
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
# (class|struct|union) declarations. If set to NO, these declarations will be
# included in the documentation.
# declarations. If set to NO, these declarations will be included in the
# documentation.
# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = YES
@@ -542,11 +583,18 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
# able to match the capabilities of the underlying filesystem. In case the
# filesystem is case sensitive (i.e. it supports files in the same directory
# whose names only differ in casing), the option must be set to YES to properly
# deal with such files in case they appear in the input. For filesystems that
# are not case sensitive the option should be be set to NO to properly deal with
# output files written for symbols that only differ in casing, such as for two
# classes, one named CLASS and the other named Class, and to also support
# references to files without having to specify the exact matching casing. On
# Windows (including Cygwin) and MacOS, users should typically set this option
# to NO, whereas on Linux or other Unix flavors it should typically be set to
# YES.
# The default value is: system dependent.
CASE_SENSE_NAMES = NO
@@ -569,14 +617,14 @@ HIDE_COMPOUND_REFERENCE= NO
# the files that are included by a file in the documentation of that file.
# The default value is: YES.
SHOW_INCLUDE_FILES = NO
SHOW_INCLUDE_FILES = YES
# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
# grouped member an include statement to the documentation, telling the reader
# which file to include in order to use the member.
# The default value is: NO.
SHOW_GROUPED_MEMB_INC = NO
SHOW_GROUPED_MEMB_INC = YES
# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
# files with double quotes in the documentation rather than with sharp brackets.
@@ -785,7 +833,10 @@ WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered.
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
# at the end of the doxygen process doxygen will return with a non-zero status.
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
# The default value is: NO.
WARN_AS_ERROR = NO
@@ -821,8 +872,8 @@ INPUT = ${DOXY_INPUT}
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
# possible encodings.
# documentation (see:
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
@@ -835,46 +886,20 @@ INPUT_ENCODING = UTF-8
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen.
#
# Note the list of default checked file patterns might differ from the list of
# default file extension mappings.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl,
# *.ucf, *.qsf and *.ice.
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
FILE_PATTERNS = *.c \
*.cpp \
*.c++ \
*.d \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.idl \
*.odl \
*.cs \
*.php \
*.php3 \
*.inc \
*.m \
*.markdown \
*.md \
*.mm \
*.dox \
*.py \
*.f90 \
*.f \
*.for \
*.vhd \
*.vhdl
*.md
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
@@ -1087,16 +1112,22 @@ USE_HTAGS = NO
VERBATIM_HEADERS = NO
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
# cost of reduced performance. This can be particularly helpful with template
# rich C++ code for which doxygen's built-in parser lacks the necessary type
# information.
# clang parser (see:
# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
# performance. This can be particularly helpful with template rich C++ code for
# which doxygen's built-in parser lacks the necessary type information.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
# The default value is: NO.
CLANG_ASSISTED_PARSING = NO
# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to
# YES then doxygen will add the directory of each input to the include path.
# The default value is: YES.
CLANG_ADD_INC_PATHS = YES
# If clang assisted parsing is enabled you can provide the compiler with command
# line options that you would normally use when invoking the compiler. Note that
# the include paths will already be set by doxygen for the files and directories
@@ -1106,10 +1137,13 @@ CLANG_ASSISTED_PARSING = NO
CLANG_OPTIONS =
# If clang assisted parsing is enabled you can provide the clang parser with the
# path to the compilation database (see:
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files
# were built. This is equivalent to specifying the "-p" option to a clang tool,
# such as clang-check. These options will then be passed to the parser.
# path to the directory containing a file called compile_commands.json. This
# file is the compilation database (see:
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
# options used when the source files were built. This is equivalent to
# specifying the -p option to a clang tool, such as clang-check. These options
# will then be passed to the parser. Any options specified with CLANG_OPTIONS
# will be added as well.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
@@ -1126,13 +1160,6 @@ CLANG_DATABASE_PATH =
ALPHABETICAL_INDEX = YES
# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
# which the alphabetical index list will be split.
# Minimum value: 1, maximum value: 20, default value: 5.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all classes will
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
# can be used to specify a prefix (or a list of prefixes) that should be ignored
@@ -1156,7 +1183,7 @@ GENERATE_HTML = YES
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = html
HTML_OUTPUT = html/${DOXY_OUTPUT_DIR}
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).
@@ -1239,7 +1266,7 @@ HTML_EXTRA_FILES =
# Minimum value: 0, maximum value: 359, default value: 220.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_HUE = 246
HTML_COLORSTYLE_HUE = 221
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
# in the HTML output. For a value of 0 the output will use grayscales only. A
@@ -1247,7 +1274,7 @@ HTML_COLORSTYLE_HUE = 246
# Minimum value: 0, maximum value: 255, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_SAT = 79
HTML_COLORSTYLE_SAT = 100
# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
# luminance component of the colors in the HTML output. Values below 100
@@ -1271,9 +1298,9 @@ HTML_TIMESTAMP = YES
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
# documentation will contain a main index with vertical navigation menus that
# are dynamically created via Javascript. If disabled, the navigation index will
# are dynamically created via JavaScript. If disabled, the navigation index will
# consists of multiple levels of tabs that are statically embedded in every HTML
# page. Disable this option to support browsers that do not have Javascript,
# page. Disable this option to support browsers that do not have JavaScript,
# like the Qt help browser.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1299,14 +1326,15 @@ HTML_DYNAMIC_SECTIONS = NO
# Minimum value: 0, maximum value: 9999, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_INDEX_NUM_ENTRIES = 100
HTML_INDEX_NUM_ENTRIES = 1
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
# environment (see: https://developer.apple.com/xcode/), introduced with OSX
# 10.5 (Leopard). To create a documentation set, doxygen will generate a
# Makefile in the HTML output directory. Running make will produce the docset in
# that directory and running make install will install the docset in
# environment (see:
# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
# create a documentation set, doxygen will generate a Makefile in the HTML
# output directory. Running make will produce the docset in that directory and
# running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
# genXcode/_index.html for more information.
@@ -1329,7 +1357,7 @@ DOCSET_FEEDNAME = "Doxygen generated docs"
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_BUNDLE_ID = org.doxygen.Project
DOCSET_BUNDLE_ID = ${DOXY_DOMAIN}
# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
# the documentation publisher. This should be a reverse domain-name style
@@ -1337,19 +1365,19 @@ DOCSET_BUNDLE_ID = org.doxygen.Project
# The default value is: org.doxygen.Publisher.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_ID = ${DOXY_DOMAIN}
# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
# The default value is: Publisher.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_PUBLISHER_NAME = Publisher
DOCSET_PUBLISHER_NAME = PIP
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
# (see:
# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
@@ -1379,7 +1407,7 @@ CHM_FILE =
HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated
# (YES) or that it should be included in the master .chm file (NO).
# (YES) or that it should be included in the main .chm file (NO).
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1420,11 +1448,12 @@ GENERATE_QHP = YES
# the HTML output folder.
# This tag requires that the tag GENERATE_QHP is set to YES.
QCH_FILE = pip.qch
QCH_FILE = pip_${DOXY_OUTPUT_DIR}.qch
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
# (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1432,8 +1461,8 @@ QHP_NAMESPACE = PIP
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
# Folders (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
# folders).
# Folders (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1441,30 +1470,30 @@ QHP_VIRTUAL_FOLDER = PIP
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# Filters (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME = PIP
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# Filters (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS = ${DOXY_QHP_CUST_FILTER_ATTRS}
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
# http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS = ${DOXY_QHP_SECT_FILTER_ATTRS}
# The QHG_LOCATION tag can be used to specify the location of Qt's
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
# generated .qhp file.
# The QHG_LOCATION tag can be used to specify the location (absolute path
# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
# run qhelpgenerator on the generated .qhp file.
# This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION = qhelpgenerator
@@ -1487,7 +1516,7 @@ GENERATE_ECLIPSEHELP = NO
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
ECLIPSE_DOC_ID = org.doxygen.Project
ECLIPSE_DOC_ID = PIP
# If you want full control over the layout of the generated HTML pages it might
# be necessary to disable the index and replace it with your own. The
@@ -1515,7 +1544,7 @@ DISABLE_INDEX = NO
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = YES
GENERATE_TREEVIEW = NO
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation.
@@ -1541,6 +1570,17 @@ TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
# the HTML output. These images will generally look nicer at scaled resolutions.
# Possible values are: png (the default) and svg (looks nicer but requires the
# pdf2svg or inkscape tool).
# The default value is: png.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FORMULA_FORMAT = png
# Use this tag to change the font size of LaTeX formulas included as images in
# the HTML documentation. When you change the font size after a successful
# doxygen run you need to manually remove any form_*.png images from the HTML
@@ -1561,8 +1601,14 @@ FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
# to create new LaTeX commands to be used in formulas as building blocks. See
# the section "Including formulas" for details.
FORMULA_MACROFILE =
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# https://www.mathjax.org) which uses client side Javascript for the rendering
# https://www.mathjax.org) which uses client side JavaScript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
@@ -1574,7 +1620,7 @@ USE_MATHJAX = NO
# When MathJax is enabled you can set the default output format to be used for
# the MathJax output. See the MathJax site (see:
# http://docs.mathjax.org/en/latest/output.html) for more details.
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details.
# Possible values are: HTML-CSS (which is slower, but has the best
# compatibility), NativeMML (i.e. MathML) and SVG.
# The default value is: HTML-CSS.
@@ -1590,7 +1636,7 @@ MATHJAX_FORMAT = HTML-CSS
# Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of
# MathJax from https://www.mathjax.org before deployment.
# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
@@ -1604,7 +1650,8 @@ MATHJAX_EXTENSIONS =
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
# of code that will be used on startup of the MathJax code. See the MathJax site
# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
# (see:
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
# example see the documentation.
# This tag requires that the tag USE_MATHJAX is set to YES.
@@ -1629,10 +1676,10 @@ MATHJAX_CODEFILE =
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
SEARCHENGINE = NO
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using Javascript. There
# implemented using a web server instead of a web client using JavaScript. There
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
@@ -1651,7 +1698,8 @@ SERVER_BASED_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: https://xapian.org/).
# Xapian (see:
# https://xapian.org/).
#
# See the section "External Indexing and Searching" for details.
# The default value is: NO.
@@ -1664,8 +1712,9 @@ EXTERNAL_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: https://xapian.org/). See the section "External Indexing and
# Searching" for details.
# Xapian (see:
# https://xapian.org/). See the section "External Indexing and Searching" for
# details.
# This tag requires that the tag SEARCHENGINE is set to YES.
SEARCHENGINE_URL =
@@ -1736,13 +1785,14 @@ LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
# generate index for LaTeX.
# generate index for LaTeX. In case there is no backslash (\) as first character
# it will be automatically added in the LaTeX code.
# Note: This tag is used in the generated output file (.tex).
# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
# The default value is: \makeindex.
# The default value is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_MAKEINDEX_CMD = \makeindex
LATEX_MAKEINDEX_CMD = makeindex
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
@@ -1828,9 +1878,11 @@ LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
# the PDF file directly from the LaTeX files. Set this option to YES, to get a
# higher quality PDF documentation.
# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
# files. Set this option to YES, to get a higher quality PDF documentation.
#
# See also section LATEX_CMD_NAME for selecting the engine.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -2164,7 +2216,7 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED = ${DOXY_DEFINES}
PREDEFINED = DOXYGEN PIOBJECT PIOBJECT_SUBCLASS PIIODEVICE NO_COPY_CLASS ${DOXY_DEFINES}
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
@@ -2209,7 +2261,7 @@ TAGFILES =
# tag file that is based on the input files it reads. See section "Linking to
# external documentation" for more information about the usage of tag files.
GENERATE_TAGFILE = doc/pip.cfg
GENERATE_TAGFILE = doc/html/${DOXY_OUTPUT_DIR}/pip.cfg
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
# the class index. If set to NO, only the inherited external classes will be
@@ -2230,13 +2282,7 @@ EXTERNAL_GROUPS = YES
# be listed.
# The default value is: YES.
EXTERNAL_PAGES = YES
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of 'which perl').
# The default file (with absolute path) is: /usr/bin/perl.
PERL_PATH = /usr/bin/perl
EXTERNAL_PAGES = NO
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
@@ -2251,15 +2297,6 @@ PERL_PATH = /usr/bin/perl
CLASS_DIAGRAMS = YES
# You can define message sequence charts within doxygen comments using the \msc
# command. Doxygen will then run the mscgen tool (see:
# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH = ${DOXY_MSCGEN_PATH}
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
@@ -2357,10 +2394,32 @@ UML_LOOK = NO
# but if the number exceeds 15, the total amount of fields shown is limited to
# 10.
# Minimum value: 0, maximum value: 100, default value: 10.
# This tag requires that the tag HAVE_DOT is set to YES.
# This tag requires that the tag UML_LOOK is set to YES.
UML_LIMIT_NUM_FIELDS = 12
# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
# tag is set to YES, doxygen will add type and arguments for attributes and
# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
# will not generate fields with class member information in the UML graphs. The
# class diagrams will look similar to the default class diagrams but using UML
# notation for the relationships.
# Possible values are: NO, YES and NONE.
# The default value is: NO.
# This tag requires that the tag UML_LOOK is set to YES.
DOT_UML_DETAILS = NO
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
# to display on a single line. If the actual line length exceeds this threshold
# significantly it will wrapped across multiple lines. Some heuristics are apply
# to avoid ugly line breaks.
# Minimum value: 0, maximum value: 1000, default value: 17.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_WRAP_THRESHOLD = 17
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
# collaboration graphs will show the relations between templates and their
# instances.
@@ -2550,9 +2609,11 @@ DOT_MULTI_TARGETS = YES
GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
# files that are used to generate the various graphs.
#
# Note: This setting is not only used for dot files but also for msc and
# plantuml temporary files.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_CLEANUP = YES

View File

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

View File

@@ -1,25 +1,6 @@
#include "pip.h"
//! [main]
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;
}
These executions are similar:
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
//! [main]
void _() {

View File

@@ -4,14 +4,17 @@ void _() {
//! [foreach]
PIVector<int> vec;
vec << 1 << 2 << 3;
piForeach (int & i, vec)
cout << i << ", ";
// 1, 2, 3,
piForeach (int & i, vec)
i++;
piForeach (int & i, vec)
cout << i << ", ";
// 2, 3, 4,
piForeach (int & i, vec) piCout << i;
// 1
// 2
// 3
piForeach (int & i, vec) i++;
piForeach (int & i, vec) piCout << i;
// 2
// 3
// 4
//! [foreach]
//! [foreachC]
PIVector<int> vec;

View File

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

View File

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

View File

@@ -2,8 +2,5 @@
void _() {
//! [main]
mutex.lock();
// ... your code here
mutex.unlock();
//! [main]
}

View File

@@ -5,8 +5,8 @@ class ObjectA: public PIObject {
PIOBJECT(ObjectA)
public:
EVENT_HANDLER1(void, handlerA, const PIString & , str) {piCoutObj << "handler A:" << str;}
EVENT2(eventA2, int, i, float, f);
EVENT1(eventA1, const PIString & , str);
EVENT2(eventA2, int, i, float, f);
};
class ObjectB: public PIObject {
@@ -26,7 +26,11 @@ int main(int argc, char * argv[]) {
CONNECT1(void, PIString, &obj_b, eventB, &obj_a, handlerA);
obj_b.eventB("event to handler");
CONNECT1(void, PIString, &obj_a, eventA1, &obj_b, eventB);
CONNECTU(&obj_a, eventA1, &obj_b, eventB);
obj_a.eventA1("event to event");
obj_a.piDisconnect("eventA1");
CONNECTL(&obj_a, eventA1, ([](const PIString & str){piCout << str;}));
obj_a.eventA1("event to lambda");
};
//! [main]

View File

@@ -1,348 +0,0 @@
#include "pip.h"
void _() {
//! [PIString(char * )]
PIString s("string");
//! [PIString(char * )]
//! [PIString(wchar_t * )]
PIString s(L"string");
//! [PIString(wchar_t * )]
//! [PIString(char * , int)]
PIString s("string", 3); // s = "str"
//! [PIString(char * , int)]
//! [PIString(int, char)]
PIString s(5, 'p'); // s = "ppppp"
//! [PIString(int, char)]
//! [PIString(int, PIChar)]
PIString s(5, ""); // s = "№№№№№"
//! [PIString(int, PIChar)]
//! [PIString::char*]
PIString s("pip");
cout << (char*)s << endl; // pip
//! [PIString::char*]
//! [PIString::<<(PIString)]
PIString s("this"), s1(" is"), s2(" string");
s << s1 << s2; // s = "this is string"
//! [PIString::<<(PIString)]
//! [PIString::<<(PIChar)]
PIString s("stri");
s << PIChar('n') << PIChar('g'); // s = "string"
//! [PIString::<<(PIChar)]
//! [PIString::<<(char * )]
PIString s("this");
s << " is" << " string"; // s = "this is string"
//! [PIString::<<(char * )]
//! [PIString::<<(wchar_t * )]
PIString s;
s << L"№ -" << " number"; // s = "№ - number"
//! [PIString::<<(wchar_t * )]
//! [PIString::<<(int)]
PIString s("ten - ");
s << 10; // s = "ten - 10"
//! [PIString::<<(int)]
//! [PIString::mid]
PIString s("0123456789");
piCout << s.mid(-2, -1); // s = "0123456789"
piCout << s.mid(-2, 4); // s = "01"
piCout << s.mid(3, -1); // s = "3456789"
piCout << s.mid(3, 4); // s = "3456"
//! [PIString::mid]
//! [PIString::left]
PIString s("0123456789");
piCout << s.left(-1); // s = ""
piCout << s.left(1); // s = "0"
piCout << s.left(5); // s = "01234"
piCout << s.left(15); // s = "0123456789"
//! [PIString::left]
//! [PIString::right]
PIString s("0123456789");
piCout << s.right(-1); // s = ""
piCout << s.right(1); // s = "9"
piCout << s.right(5); // s = "56789"
piCout << s.right(15); // s = "0123456789"
//! [PIString::right]
//! [PIString::cutMid]
PIString s("0123456789");
s.cutMid(1, 3);
piCout << s; // s = "0456789"
s.cutMid(-1, 3);
piCout << s; // s = "56789"
s.cutMid(3, -1);
piCout << s; // s = "567"
//! [PIString::cutMid]
//! [PIString::cutLeft]
PIString s("0123456789");
s.cutLeft(1);
piCout << s; // s = "123456789"
s.cutLeft(3);
piCout << s; // s = "456789"
s.cutLeft(30);
piCout << s; // s = ""
//! [PIString::cutLeft]
//! [PIString::cutRight]
PIString s("0123456789");
s.cutRight(1);
piCout << s; // s = "012345678"
s.cutRight(3);
piCout << s; // s = "012345"
s.cutRight(30);
piCout << s; // s = ""
//! [PIString::cutRight]
//! [PIString::trim]
PIString s(" string ");
s.trim();
piCout << s; // s = "string"
//! [PIString::trim]
//! [PIString::trimmed]
PIString s(" string ");
piCout << s.trimmed(); // s = "string"
piCout << s; // s = " string "
//! [PIString::trimmed]
//! [PIString::replace_0]
PIString s("0123456789");
s.replace(2, 3, "_cut_");
piCout << s; // s = "01_cut_56789"
s.replace(0, 1, "one_");
piCout << s; // s = "one_1_cut_56789"
//! [PIString::replace_0]
//! [PIString::replaced_0]
PIString s("0123456789");
piCout << s.replaced(2, 3, "_cut_"); // s = "01_cut_56789"
piCout << s.replaced(0, 1, "one_"); // s = "one_123456789"
//! [PIString::replaced_0]
//! [PIString::replace_1]
PIString s("pip string");
bool ok;
s.replace("string", "conf", &ok);
piCout << s << ok; // s = "pip conf", true
s.replace("PIP", "PlInPr", &ok);
piCout << s << ok; // s = "pip conf", false
//! [PIString::replace_1]
//! [PIString::replaced_1]
PIString s("pip string");
bool ok;
piCout << s.replace("string", "conf", &ok); // s = "pip conf", true
piCout << s.replace("PIP", "PlInPr", &ok); // s = "pip string", false
//! [PIString::replaced_1]
//! [PIString::replaceAll]
PIString s("substrings");
s.replaceAll("s", "_");
piCout << s; // s = "_ub_tring_"
//! [PIString::replaceAll]
//! [PIString::repeat]
PIString s(" :-) ");
s.repeat(3);
piCout << s; // :-) :-) :-)
//! [PIString::repeat]
//! [PIString::repeated]
PIString s(" :-) ");
piCout << s.repeated(3); // :-) :-) :-)
piCout << s; // :-)
//! [PIString::repeated]
//! [PIString::insert_0]
PIString s("pp");
s.insert(1, "i");
piCout << s; // s = "pip"
//! [PIString::insert_0]
//! [PIString::insert_1]
PIString s("pp");
s.insert(1, 'i');
piCout << s; // s = "pip"
//! [PIString::insert_1]
//! [PIString::insert_2]
PIString s("stg");
s.insert(2, "rin");
piCout << s; // s = "string"
//! [PIString::insert_2]
//! [PIString::expandRightTo]
PIString s("str");
s.expandRightTo(2, "_");
piCout << s; // s = "str"
s.expandRightTo(6, "_");
piCout << s; // s = "str___"
//! [PIString::expandRightTo]
//! [PIString::expandLeftTo]
PIString s("str");
s.expandLeftTo(2, "_");
piCout << s; // s = "str"
s.expandLeftTo(6, "_");
piCout << s; // s = "___str"
//! [PIString::expandLeftTo]
//! [PIString::reverse]
PIString s("0123456789");
s.reverse();
piCout << s; // s = "9876543210"
//! [PIString::reverse]
//! [PIString::reversed]
PIString s("0123456789");
piCout << s.reversed(); // s = "9876543210"
piCout << s; // s = "0123456789"
//! [PIString::reversed]
//! [PIString::elided]
piCout << PIString("123456789ABCDEF").elided(8, PIString::ElideLeft); // ..ABCDEF
piCout << PIString("123456789ABCDEF").elided(8, PIString::ElideCenter); // 123..DEF
piCout << PIString("123456789ABCDEF").elided(8, PIString::ElideRight); // 123456..
piCout << PIString("123456789ABCDEF").elided(8, 0.25); // 12..CDEF
//! [PIString::elided]
//! [PIString::lengthAscii]
piCout << PIString("0123456789").lengthAscii(); // 10
piCout << PIString("№1").lengthAscii(); // 3
//! [PIString::lengthAscii]
//! [PIString::data]
piCout << PIString("0123456789").data(); // 0123456789
piCout << PIString("№1").data(); // №1
//! [PIString::data]
//! [PIString::split]
PIString s("1 2 3");
piCout << s.split(" "); // {"1", "2", "3"}
//! [PIString::split]
//! [PIString::find]
PIString s("012345012345");
piCout << s.find("-"); // -1
piCout << s.find("3"); // 3
piCout << s.find("3", 4); // 9
piCout << s.find("3", 10); // -1
//! [PIString::find]
//! [PIString::findLast]
PIString s("012345012345");
piCout << s.find("-"); // -1
piCout << s.find("3"); // 9
piCout << s.find("3", 4); // 9
piCout << s.find("3", 10); // -1
//! [PIString::findLast]
//! [PIString::findAny]
piCout << PIString("1.str").findAny(".,:"); // 1
piCout << PIString("1,str").findAny(".,:"); // 1
piCout << PIString("1:str").findAny(".,:"); // 1
//! [PIString::findAny]
//! [PIString::findAnyLast]
piCout << PIString("str.0").findAny(".,:"); // 3
piCout << PIString("str,0").findAny(".,:"); // 3
piCout << PIString("str:0").findAny(".,:"); // 3
//! [PIString::findAnyLast]
//! [PIString::findWord]
PIString s("this is <PIP>");
piCout << s.find("this"); // 0
piCout << s.find("is"); // 5
piCout << s.find("PIP", 4); // -1
piCout << s.find("<PIP>", 10); // 8
//! [PIString::findWord]
//! [PIString::findCWord]
PIString s("this::is <PIP>");
piCout << s.find("this"); // 0
piCout << s.find("is"); // 6
piCout << s.find("PIP", 4); // 10
piCout << s.find("<PIP>", 10); // 9
//! [PIString::findCWord]
//! [PIString::toNumber]
piCout << PIString("123").toInt(); // 123
piCout << PIString("123").toInt(16); // 291
piCout << PIString("0x123").toInt(); // 291
piCout << PIString("1001").toInt(2); // 9
//! [PIString::toNumber]
//! [PIString::toFloat]
piCout << PIString("123").toFloat(); // 123
piCout << PIString("1.2E+2").toFloat(); // 120
piCout << PIString("0.01").toFloat(); // 0.01
//! [PIString::toFloat]
//! [PIString::setNumber]
PIString s;
s.setNumber(123);
piCout << s; // 123
s.setNumber(123, 16);
piCout << s; // 7B
//! [PIString::setNumber]
//! [PIString::setFloat]
PIString s;
s.setNumber(12.3);
piCout << s; // 12.3
//! [PIString::setFloat]
//! [PIString::setReadableSize]
PIString s;
s.setReadableSize(512);
piCout << s; // 512 B
s.setReadableSize(5120);
piCout << s; // 5.0 kB
s.setReadableSize(512000);
piCout << s; // 500.0 kB
s.setReadableSize(5120000);
piCout << s; // 4.8 MB
s.setReadableSize(512000000);
piCout << s; // 488.2 MB
s.setReadableSize(51200000000);
piCout << s; // 47.6 GB
//! [PIString::setReadableSize]
//! [PIString::fromNumber]
piCout << PIString::fromNumber(123); // 123
piCout << PIString::fromNumber(123, 16); // 7B
//! [PIString::fromNumber]
//! [PIString::fromFloat]
piCout << PIString::fromNumber(12.3); // 12.3
//! [PIString::fromFloat]
//! [PIString::readableSize]
piCout << PIString::readableSize(512); // 512 B
piCout << PIString::readableSize(5120); // 5.0 kB
piCout << PIString::readableSize(512000); // 500.0 kB
piCout << PIString::readableSize(5120000); // 4.8 MB
piCout << PIString::readableSize(512000000); // 488.2 MB
piCout << PIString::readableSize(51200000000); // 47.6 GB
//! [PIString::readableSize]
//! [PIString::takeSymbol]
PIString s("\t ! word");
piCout << s.takeSymbol(); // "!"
piCout << s.takeSymbol(); // "w"
piCout << s.takeSymbol(); // "o"
piCout << s; // "rd"
//! [PIString::takeSymbol]
//! [PIString::takeWord]
PIString s("some words\nnew line ");
piCout << s.takeWord(); // "some"
piCout << s.takeWord(); // "words"
piCout << s.takeWord(); // "new"
piCout << s; // " line "
//! [PIString::takeWord]
//! [PIString::takeLine]
PIString s("some words\nnew line \n\nend");
piCout << s.takeLine(); // "some words"
piCout << s.takeLine(); // "new line "
piCout << s.takeLine(); // ""
piCout << s; // "end"
//! [PIString::takeLine]
//! [PIString::takeNumber]
PIString s(" 0xFF -99 1.2E+5f 1000L");
piCout << s.takeNumber(); // "0xFF"
piCout << s.takeNumber(); // "-99"
piCout << s.takeNumber(); // "1.2E+5f"
piCout << s.takeNumber(); // "1000L"
piCout << s; // ""
//! [PIString::takeNumber]
//! [PIString::takeRange]
PIString s(" {figures{inside}}");
piCout << s.takeRange('{', '}'); // "figures{inside}"
piCout << s; // ""
s = "\"text\\\"shielded\" next";
piCout << s.takeRange('"', '"'); // "text\"shielded"
piCout << s; // " next"
//! [PIString::takeRange]
//! [PIStringList::join]
PIStringList sl("1", "2");
sl << "3";
piCout << sl.join(" < "); // 1 < 2 < 3
//! [PIStringList::join]
//! [PIStringList::removeStrings]
PIStringList sl("1", "2");
sl << "1" << "2" << "3";
piCout << sl; // {"1", "2", "1", "2", "3"}
piCout << sl.removeStrings("1"); // {"2", "2", "3"}
//! [PIStringList::removeStrings]
//! [PIStringList::removeDuplicates]
PIStringList sl("1", "2");
sl << "1" << "2" << "3";
piCout << sl; // {"1", "2", "1", "2", "3"}
piCout << sl.removeDuplicates(); // {"1", "2", "3"}
//! [PIStringList::removeDuplicates]
};

View File

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

BIN
doc/images/pirect.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

297
doc/pages/code_model.md Normal file
View File

@@ -0,0 +1,297 @@
\~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

125
doc/pages/iostream.md Normal file
View File

@@ -0,0 +1,125 @@
\~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. Рекомендуется делать эту проверку после чтения
данных для корректной обработки ошибки.

44
doc/pages/main.md Normal file
View File

@@ -0,0 +1,44 @@
\~english \mainpage What is PIP
\~russian \mainpage Что такое PIP
\~english
PIP - Platform-Independent Primitives - is crossplatform library for C++ developers.
This library can help developers write non-GUI projects much more quickly, efficiently
and customizable than on pure C++.
Application written on PIP works the same on any system. One can read and write
any data types, serialize any types to device channels between any systems.
Many common data types, system primitives and devices implemented in this library.
PIP also tightly integrates with [CMake](https://cmake.org/) build system, providing handly search
main library, additional modules of PIP and several utilites. With
CMake with PIP one can easily generate and use code metainformation or
serialize custom types with it versions back-compatability.
Summary one can find at \ref summary page.
Basic using of PIP described at \ref using_basic page.
\~russian
PIP - Platform-Independent Primitives - кроссплатформенная библиотека для разработчиков на C++.
Эта библиотека поможет разработчику написать неграфическое приложение быстрее, эффективнее
и более гибко, чем на чистом C++.
Приложения, написанные на PIP, работают одинаково на многих системах. Можно читать и писать
любые типы данных, сериализовать любые типы в каналы устройств между любыми системами.
Многие типы данных, системные сущности и устройства реализованы в библиотеке.
PIP также тесно интегрируется с системой сборки [CMake](https://cmake.org/), предоставляя удобный поиск
главной библиотеки, модулей PIP и некоторых утилит. Используя CMake вместе с PIP
можно генерировать и использовать метаинформация о коде или сериализовать
свои типы данных с обратной совместимостью их версий.
Сводку можно найти на странице \ref summary.
Базовое использование PIP описано на странице \ref using_basic.

124
doc/pages/summary.md Normal file
View File

@@ -0,0 +1,124 @@
\~english \page summary Functionality summary
\~russian \page summary Сводка функциональности
\~english
* Direct output to console (\a PICout)
* Containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
* Byte array (\a PIByteArray)
* Serialization (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON)
* String (\a PIConstChars, \a PIString, \a PIStringList)
* Base object (events and handlers) (\a PIObject)
* Multithreading
* thread (\a PIThread)
* blocking (\a PIMutex, \a PISpinlock, \a PIConditionVariable, \a PISemaphore, \a PIReadWriteLock)
* executor (\a PIThreadPoolExecutor, \a PIThreadPoolLoop)
* blocking dequeue (\a PIBlockingDequeue)
* timer (\a PITimer)
* Tiling console (with widgets) (\a PIScreen)
* simple text rows
* scroll bar
* list
* button
* buttons group
* check box
* progress bar
* PICout output
* text input
* I/O devices
* base class (\a PIIODevice)
* file (\a PIFile)
* serial port (\a PISerial)
* ethernet (\a PIEthernet)
* USB (\a PIUSB)
* packets extractor (\a PIPacketExtractor)
* binary log (\a PIBinaryLog)
* complex I/O point (\a PIConnection)
* peering net node (\a PIPeer)
* connection quality diagnotic (\a PIDiagnostics)
* Run-time libraries
* external process (\a PIProcess)
* external library (\a PILibrary)
* plugin (\a PIPluginLoader)
* Mathematics
* complex numbers
* vectors (\a PIMathVector, \a PIMathVectorT)
* matrices (\a PIMathMatrix, \a PIMathMatrixT)
* quaternion (\a PIQuaternion)
* 2D geometry (\a PIPoint, \a PILine, \a PIRect)
* statistic (\a PIStatistic)
* CRC checksum (\a PICRC)
* Fourier transform (\a PIFFTW, \a PIFFT)
* expression evaluator (\a PIEvaluator)
* Application-level
* command-line arguments parser (\a PICLI)
* system resources monitoring (\a PISystemMonitor)
* single-instance application control (\a PISingleApplication)
* high-level log (\a PILog)
* translation support (\a PITranslator)
* State machine ([By stantard](https://www.w3.org/TR/scxml/)) (\a PIStateMachine)
* High-level TCP client-server
* server (\a PIClientServer::Server, \a PIClientServer::ServerClient)
* client (\a PIClientServer::Client)
* Crypt support (\a PICrypt, \a PIAuth)
\~russian
* Общение с консолью (\a PICout)
* Контейнеры (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
* Байтовый массив (\a PIByteArray)
* Сериализация (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON)
* Строка (\a PIConstChars, \a PIString, \a PIStringList)
* Базовый объект (события и обработчики) (\a PIObject)
* Многопоточность
* поток (\a PIThread)
* блокировки (\a PIMutex, \a PISpinlock, \a PIConditionVariable, \a PISemaphore, \a PIReadWriteLock)
* исполнитель (\a PIThreadPoolExecutor, \a PIThreadPoolLoop)
* блокирующая очередь (\a PIBlockingDequeue)
* таймер (\a PITimer)
* Тайлинговая консоль (с виджетами) (\a PIScreen)
* простой вывод строк
* скроллбар
* лист
* кнопка
* группа кнопок
* галочка
* прогрессбар
* вывод PICout
* текстовый ввод
* Устройства ввода/вывода
* базовый класс (\a PIIODevice)
* файл (\a PIFile)
* последовательный порт (\a PISerial)
* ethernet (\a PIEthernet)
* USB (\a PIUSB)
* packets extractor (\a PIPacketExtractor)
* бинарный логфайл (\a PIBinaryLog)
* сложное составное устройство (\a PIConnection)
* пиринговая сеть (\a PIPeer)
* диагностика качества связи (\a PIDiagnostics)
* Поддержка библиотек времени выполнения
* внешний процесс (\a PIProcess)
* внешняя библиотека (\a PILibrary)
* плагин (\a PIPluginLoader)
* Математика
* комплексные числа
* вектора (\a PIMathVector, \a PIMathVectorT)
* матрицы (\a PIMathMatrix, \a PIMathMatrixT)
* кватернион (\a PIQuaternion)
* 2D геометрия (\a PIPoint, \a PILine, \a PIRect)
* статистика (\a PIStatistic)
* CRC контрольная сумма (\a PICRC)
* преобразования Фурье (\a PIFFTW, \a PIFFT)
* вычислитель выражений (\a PIEvaluator)
* Уровень приложения
* парсер аргументов командной строки (\a PICLI)
* мониторинг ресурсов системы (\a PISystemMonitor)
* контроль одного экземпляра приложения (\a PISingleApplication)
* высокоуровневый лог (\a PILog)
* поддержка перевода (\a PITranslator)
* Машина состояний ([По стандарту](https://www.w3.org/TR/scxml/)) (\a PIStateMachine)
* Высокоуровневый TCP клиент-сервер
* сервер (\a PIClientServer::Server, \a PIClientServer::ServerClient)
* клиент (\a PIClientServer::Client)
* Поддержка шифрования (\a PICrypt, \a PIAuth)

128
doc/pages/using_basic.md Normal file
View File

@@ -0,0 +1,128 @@
\~english \page using_basic Getting started
\~russian \page using_basic Простые начала
\~english
Many novice programmers are solved many common task with system integrity: output to console,
keyboard buttons press detecting, working with serial ports, ethernet or files, and many other.
These tasks can solve this library, and code, based only on PIP will be compile and work
similar on many systems: Windows, any Linux, Red Hat, FreeBSD, MacOS X and QNX.
Typical application on PIP looks like this: \n
\~russian
Многие начинающие программисты решают общие задачи взаимодействия с операционной системой:
вывод в консоль, определение нажатия клавиш, работа с последовательными портами, сетью или файлами,
и многое другое. Эти задачи решены в библиотеке, и код, основанный на PIP будет компилироваться
и работать одинаково на многих системах: Windows, любой Linux, Red Hat, FreeBSD, MacOS X и QNX.
Типовое приложение на PIP выглядит примерно так: \n
\code{.cpp}
#include <pip.h>
// declare key press handler
void key_event(char key, void * );
PIConsole console(false, key_event); // don`t start now, key handler is "key_event"
// some vars
int i = 2, j = 3;
// implicit key press handler
void key_event(char key, void * ) {
switch (key) {
case '-':
i--;
break;
case '+':
i++;
break;
case '(':
j--;
break;
case ')':
j++;
break;
};
};
class MainClass: public PITimer {
PIOBJECT(MainClass)
public:
MainClass() {}
protected:
void tick(int delimiter) {
piCout << "timer tick";
// timer tick
}
};
MainClass main_class;
int main(int argc, char * argv[]) {
// enabling auto-detection of exit button press, by default 'Q' (shift+q)
console.enableExitCapture();
// if we want to parse command-line arguments
PICLI cli(argc, argv);
cli.addArgument("console"); // "-c" or "--console"
cli.addArgument("debug"); // "-d" or "--debug"
// enabling or disabling global debug flag
piDebug = cli.hasArgument("debug");
// configure console
console.addTab("first tab", '1');
console.addString("PIP console", 1, PIConsole::Bold);
console.addVariable("int var (i)", &i, 1);
console.addVariable("int green var (j)", &j, 1, PIConsole::Green);
console.addString("'-' - i--", 2);
console.addString("'+' - i++", 2);
console.addString("'(' - j--", 2);
console.addString("')' - j++", 2);
console.addTab("second tab", '2');
console.addString("col 1", 1);
console.addString("col 2", 2);
console.addString("col 3", 3);
console.setTab("first tab");
// start output to console if "console" argument exists
if (cli.hasArgument("console"))
console.start();
// start main class, e.g. 40 Hz
main_class.start(25.);
// wait for 'Q' press, independently if console is started or not
console.waitForFinish();
return 0;
};
\endcode
\~english
This code demonstrates simple interactive configurable program, which can be started with console
display or not, and with debug or not. \b MainClass is central class that also can be inherited from
\a PIThread and reimplement \a run() function.
\n Many PIP classes has events and event handlers, which can be connected one to another.
Details you can see at \a PIObject reference page (\ref PIObject_sec0).
\n To configure your program from file use \a PIConfig.
\n If you want more information see \ref using_advanced
\~russian
Этот код демонстрирует простую конфигурируемую программу, которая может быть запущена с
This code demonstrates simple interactive configurable program, which can be started with console
display or not, and with debug or not. \b MainClass is central class that also can be inherited from
\a PIThread and reimplement \a run() function.
\n Many PIP classes has events and event handlers, which can be connected one to another.
Details you can see at \a PIObject reference page (\ref PIObject_sec0).
\n To configure your program from file use \a PIConfig.

BIN
doc/pip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

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

1
lang/compile.bat Normal file
View File

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

BIN
lang/pip_ru.btf Normal file

Binary file not shown.

531
lang/pip_ru.ts Normal file
View File

@@ -0,0 +1,531 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru">
<context>
<name>PICLI</name>
<message>
<location filename="../libs/main/application/picli.cpp" line="120"/>
<source>Arguments overflow, &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>

1
lang/update.bat Normal file
View File

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

29
library.json Normal file
View File

@@ -0,0 +1,29 @@
{
"name": "PIP",
"keywords": "pip",
"description": "Platform-Independent Primitives",
"repository":
{
"type": "git",
"url": "https://git.shs.tools/SHS/pip.git"
},
"frameworks": "*",
"platforms": "*",
"dependencies": {
"mike-matera/ArduinoSTL": "^1.3.2",
"linlin-study/FreeRTOS-Kernel": ">=10.0.0"
},
"build":
{
"srcFilter": [
"+<libs/main/core/*.cpp>",
"+<libs/main/containers/*.cpp>",
"+<libs/main/math/*.cpp>",
"+<libs/main/thread/*.cpp>",
"+<libs/main/io_uutils/*.cpp>",
"+<libs/main/geo/*.cpp>"
],
"extraScript": "platformio_pre.py",
"flags": "-DPIP_FREERTOS"
}
}

View File

@@ -0,0 +1,53 @@
/*
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

@@ -0,0 +1,117 @@
/*
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

@@ -0,0 +1,143 @@
/*
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,8 +1,8 @@
#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);
}

View File

@@ -1,151 +1,192 @@
/*
PIP - Platform Independent Primitives
PICloud Client
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 "picloudclient.h"
#include "picloudtcp.h"
PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode) : PIIODevice(path, mode), PICloudBase() {
tcp.setRole(PICloud::TCP::Client);
setName("cloud_client");
is_connected = false;
CONNECTL(&eth, connected, [this](){tcp.sendStart();});
CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
CONNECTL(&eth, disconnected, [this](bool){
piCoutObj << "disconnected";
opened_ = false;
is_connected = false;
cond_connect.notifyOne();
cond_buff.notifyOne();
piMSleep(100);
});
}
PICloudClient::~PICloudClient() {
eth.close();
if (is_connected) {
is_connected = false;
disconnected();
cond_buff.notifyOne();
cond_connect.notifyOne();
}
close();
stop();
}
void PICloudClient::setServerName(const PIString & server_name) {
setName("cloud_client__" + server_name);
tcp.setServerName(server_name);
}
void PICloudClient::setKeepConnection(bool on) {
eth.setParameter(PIEthernet::KeepConnection, on);
}
bool PICloudClient::openDevice() {
// piCout << "PICloudClient open device" << path();
bool op = eth.connect(PIEthernet::Address::resolve(path()), false);
if (op) {
mutex_buff.lock();
eth.startThreadedRead();
bool conn_ok = cond_connect.waitFor(mutex_buff, (int)eth.readTimeout(), [this](){return isConnected();});
piCoutObj << "conn_ok" << conn_ok;
mutex_buff.unlock();
if (!conn_ok) {
eth.stop();
eth.close();
piMSleep(100);
}
return isConnected();
} else {
eth.close();
return false;
}
}
bool PICloudClient::closeDevice() {
if (is_connected) {
is_connected = false;
disconnected();
cond_buff.notifyOne();
cond_connect.notifyOne();
}
eth.stop();
if (eth.isOpened()) eth.close();
return true;
}
int PICloudClient::readDevice(void * read_to, int max_size) {
// piCoutObj << "readDevice";
if (!is_connected) return -1;
mutex_buff.lock();
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty();});
int sz = piMini(max_size, buff.size());
memcpy(read_to, buff.data(), sz);
buff.remove(0, sz);
mutex_buff.unlock();
return sz;
}
int PICloudClient::writeDevice(const void * data, int size) {
// piCoutObj << "writeDevice";
return tcp.sendData(PIByteArray(data, size));
}
void PICloudClient::_readed(PIByteArray & ba) {
mutex_buff.lock();
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
if (hdr.second == tcp.role()) {
switch (hdr.first) {
case PICloud::TCP::Connect:
if (tcp.parseConnect(ba) == 1) {
is_connected = true;
connected();
cond_connect.notifyOne();
}
break;
case PICloud::TCP::Disconnect:
is_connected = false;
eth.stop();
eth.close();
disconnected();
break;
case PICloud::TCP::Data:
if (is_connected) {
buff.append(ba);
cond_buff.notifyOne();
}
break;
default:
break;
}
//piCoutObj << "readed" << ba.toHex();
}
mutex_buff.unlock();
while (buff.size_s() > threadedReadBufferSize()) piMSleep(100);
}
/*
PIP - Platform Independent Primitives
PICloud Client
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 "picloudclient.h"
#include "picloudtcp.h"
#include "pitranslator.h"
PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() {
tcp.setRole(PICloud::TCP::Client);
setThreadedReadBufferSize(eth.threadedReadBufferSize());
setName("cloud_client");
is_connected = false;
is_deleted = false;
// setReopenEnabled(false);
CONNECTL(&eth, connected, [this]() {
opened_ = true;
tcp.sendStart();
});
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed);
CONNECTL(&eth, disconnected, [this](bool) {
if (is_deleted) return;
bool need_disconn = is_connected;
// piCoutObj << "eth disconnected";
eth.stop();
opened_ = false;
internalDisconnect();
if (need_disconn) disconnected();
// piCoutObj << "eth disconnected done";
});
}
PICloudClient::~PICloudClient() {
// piCoutObj << "~PICloudClient() ..." << this;
is_deleted = true;
stopAndWait();
close();
internalDisconnect();
// piCoutObj << "~PICloudClient() done" << this;
}
void PICloudClient::setServerName(const PIString & server_name) {
setName("cloud_client__" + server_name);
tcp.setServerName(server_name);
}
void PICloudClient::setKeepConnection(bool on) {
eth.setParameter(PIEthernet::KeepConnection, on);
}
void PICloudClient::interrupt() {
cond_buff.notifyOne();
cond_connect.notifyOne();
eth.interrupt();
}
bool PICloudClient::openDevice() {
// piCoutObj << "open";// << path();
bool op = eth.connect(PINetworkAddress::resolve(path()), false);
if (op) {
mutex_connect.lock();
eth.startThreadedRead();
// piCoutObj << "connecting...";
bool conn_ok = cond_connect.waitFor(mutex_connect, eth.readTimeout());
// piCoutObj << "conn_ok" << conn_ok << is_connected;
mutex_connect.unlock();
if (!conn_ok) {
mutex_connect.lock();
eth.stopAndWait();
eth.close();
mutex_connect.unlock();
}
return is_connected;
} else {
// eth.close();
return false;
}
}
bool PICloudClient::closeDevice() {
// PIThread::stop();
if (is_connected) {
internalDisconnect();
}
eth.stopAndWait();
eth.close();
return true;
}
ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) {
if (is_deleted || max_size <= 0) return -1;
// piCoutObj << "readDevice ...";
if (!is_connected && eth.isClosed()) openDevice();
ssize_t sz = -1;
mutex_buff.lock();
if (is_connected) {
if (buff.isEmpty()) {
sz = 0;
} else {
sz = piMin<ssize_t>(max_size, buff.size_s());
memcpy(read_to, buff.data(), sz);
buff.remove(0, sz);
}
if (sz == 0) cond_buff.wait(mutex_buff);
}
mutex_buff.unlock();
if (!is_connected) opened_ = false;
// piCoutObj << "readDevice done" << sz;
return sz;
}
ssize_t PICloudClient::writeDevice(const void * data, ssize_t size) {
if (is_deleted || !is_connected) return -1;
// piCoutObj << "writeDevice" << size;
return tcp.sendData(PIByteArray(data, size));
}
void PICloudClient::internalDisconnect() {
// piCoutObj << "internalDisconnect";
is_connected = false;
cond_buff.notifyOne();
cond_connect.notifyOne();
streampacker.clear();
buff.clear();
}
void PICloudClient::_readed(PIByteArray & ba) {
if (is_deleted) return;
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
// piCoutObj << "_readed" << ba.size() << hdr.first << hdr.second;
if (hdr.second == tcp.role()) {
switch (hdr.first) {
case PICloud::TCP::Connect:
if (tcp.parseConnect(ba) == 1) {
mutex_connect.lock();
is_connected = true;
mutex_connect.unlock();
cond_connect.notifyOne();
connected();
}
break;
case PICloud::TCP::Disconnect:
eth.stop();
opened_ = false;
eth.close();
break;
case PICloud::TCP::Data:
if (is_connected) {
mutex_buff.lock();
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,225 +1,301 @@
/*
PIP - Platform Independent Primitives
PICloud Server
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 "picloudserver.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);
tcp.setServerName(server_name);
setName("cloud_server__" + server_name);
CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
CONNECTL(&eth, connected, [this](){tcp.sendStart();});
CONNECTL(&eth, disconnected, [this](bool){
piCoutObj << "disconnected";
opened_ = false;
piMSleep(100);
});
}
PICloudServer::~PICloudServer() {
stop();
close();
}
void PICloudServer::setServerName(const PIString & server_name) {
setName("cloud_server__" + server_name);
tcp.setServerName(server_name);
}
PIVector<PICloudServer::Client *> PICloudServer::clients() const {
PIMutexLocker _ml(clients_mutex);
return clients_;
}
bool PICloudServer::openDevice() {
piCout << "PICloudServer open device" << path();
bool op = eth.connect(PIEthernet::Address::resolve(path()), false);
if (op) {
eth.startThreadedRead();
return true;
}
eth.close();
return false;
}
bool PICloudServer::closeDevice() {
eth.stop();
clients_mutex.lock();
for (auto c : clients_) {
c->close();
c->stop();
}
clients_mutex.unlock();
eth.close();
for (auto c : clients_)
delete c;
return true;
}
int PICloudServer::readDevice(void * read_to, int max_size) {
//piCoutObj << "readDevice";
piMSleep(eth.readTimeout());
return -1;
}
int PICloudServer::writeDevice(const void * data, int max_size) {
//piCoutObj << "writeDevice";
return -1;
}
void PICloudServer::clientDisconnect(uint client_id) {
tcp.sendDisconnected(client_id);
}
int PICloudServer::sendData(const PIByteArray & data, uint client_id) {
return tcp.sendData(data, client_id);
}
PICloudServer::Client::Client(PICloudServer * srv, uint id) : server(srv), client_id(id) {
setMode(PIIODevice::ReadWrite);
setReopenEnabled(false);
is_connected = true;
}
PICloudServer::Client::~Client() {
if (is_connected) {
is_connected = false;
cond_buff.notifyOne();
}
close();
stop();
}
bool PICloudServer::Client::openDevice() {
return is_connected;
}
bool PICloudServer::Client::closeDevice() {
if (is_connected) {
server->clientDisconnect(client_id);
is_connected = false;
cond_buff.notifyOne();
}
return true;
}
int PICloudServer::Client::readDevice(void * read_to, int max_size) {
if (!is_connected) return -1;
mutex_buff.lock();
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty();});
int sz = piMini(max_size, buff.size());
memcpy(read_to, buff.data(), sz);
buff.remove(0, sz);
mutex_buff.unlock();
return sz;
}
int PICloudServer::Client::writeDevice(const void * data, int size) {
return server->sendData(PIByteArray(data, size), client_id);
}
void PICloudServer::Client::pushBuffer(const PIByteArray & ba) {
if (!is_connected) return;
mutex_buff.lock();
buff.append(ba);
cond_buff.notifyOne();
mutex_buff.unlock();
while (buff.size_s() > threadedReadBufferSize()) piMSleep(100);
}
void PICloudServer::_readed(PIByteArray & ba) {
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) {
tcp.sendDisconnected(id);
} else {
piCoutObj << "new Client" << id;
Client * c = new Client(this, id);
CONNECTU(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 << "remove Client" << id;
clients_mutex.lock();
Client * oc = index_clients.value(id, nullptr);
clients_mutex.unlock();
if (oc) {
oc->is_connected = false;
oc->close();
}
} 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.toHex();
if (oc && !d.second.isEmpty()) oc->pushBuffer(d.second);
} break;
default: break;
}
}
}
void PICloudServer::clientDeleted(PIObject * o) {
PICloudServer::Client * c = (PICloudServer::Client*)o;
clients_mutex.lock();
clients_.removeOne(c);
auto it = index_clients.makeIterator();
while (it.hasNext()) {
it.next();
if (it.value() == c) {
index_clients.remove(it.key());
break;
}
}
clients_mutex.unlock();
}
/*
PIP - Platform Independent Primitives
PICloud Server
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 "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);
tcp.setServerName(server_name);
setName("cloud_server__" + server_name);
is_deleted = false;
eth.setReopenEnabled(false);
setThreadedReadBufferSize(eth.threadedReadBufferSize());
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed);
CONNECTL(&eth, connected, [this]() {
open_mutex.lock();
opened_ = true;
cvar.notifyOne();
open_mutex.unlock();
piCoutObj << "connected";
tcp.sendStart();
});
CONNECTL(&eth, disconnected, [this](bool) {
if (is_deleted) return;
piCoutObj << "disconnected";
clients_mutex.lock();
for (auto c: clients_) {
c->is_connected = false;
c->close();
}
removed_clients_.append(clients_);
clients_.clear();
index_clients.clear();
clients_mutex.unlock();
open_mutex.lock();
opened_ = false;
cvar.notifyOne();
open_mutex.unlock();
ping_timer.stop();
});
ping_timer.setSlot([this]() {
if (eth.isConnected()) tcp.sendPing();
});
}
PICloudServer::~PICloudServer() {
// piCoutObj << "~PICloudServer ..." << this;
is_deleted = true;
stop();
close();
waitThreadedReadFinished();
// piCout << "wait";
while (removed_clients_.isNotEmpty()) {
Client * c = removed_clients_.take_back();
delete c;
}
// piCoutObj << "~PICloudServer done" << this;
}
void PICloudServer::setServerName(const PIString & server_name) {
setName("cloud_server__" + server_name);
tcp.setServerName(server_name);
}
PIVector<PICloudServer::Client *> PICloudServer::clients() const {
PIMutexLocker _ml(clients_mutex);
return clients_;
}
bool PICloudServer::openDevice() {
piCoutObj << "open device" << path();
if (is_deleted) return false;
bool op = eth.connect(PINetworkAddress::resolve(path()), false);
if (op) {
eth.startThreadedRead();
ping_timer.start(5_s);
return true;
} else {
ping_timer.stop();
eth.close();
return false;
}
}
bool PICloudServer::closeDevice() {
// piCoutObj << "closeDevice" << this;
eth.stopAndWait();
ping_timer.stop();
eth.close();
cvar.notifyOne();
clients_mutex.lock();
for (auto c: clients_) {
c->is_connected = false;
c->close();
}
removed_clients_.append(clients_);
clients_.clear();
index_clients.clear();
clients_mutex.unlock();
return true;
}
ssize_t PICloudServer::readDevice(void * read_to, ssize_t max_size) {
if (is_deleted) return -1;
// piCoutObj << "readDevice";
open_mutex.lock();
if (isOpened()) cvar.wait(open_mutex);
open_mutex.unlock();
// piCoutObj << "opened_ = " << opened_;
// else piMSleep(eth.readTimeout());
return -1;
}
ssize_t PICloudServer::writeDevice(const void * data, ssize_t max_size) {
// piCoutObj << "writeDevice";
return -1;
}
void PICloudServer::interrupt() {
eth.interrupt();
cvar.notifyOne();
}
void PICloudServer::clientDisconnect(uint client_id) {
tcp.sendDisconnected(client_id);
}
int PICloudServer::sendData(const PIByteArray & data, uint client_id) {
if (!opened_) return -1;
return tcp.sendData(data, client_id);
}
PICloudServer::Client::Client(PICloudServer * srv, uint id): server(srv), client_id(id) {
setMode(PIIODevice::ReadWrite);
setReopenEnabled(false);
setThreadedReadBufferSize(server->threadedReadBufferSize());
is_connected = true;
}
PICloudServer::Client::~Client() {
// piCoutObj << "~PICloudServer::Client..." << this;
close();
stopAndWait(10_s);
// piCoutObj << "~PICloudServer::Client done" << this;
}
bool PICloudServer::Client::openDevice() {
return is_connected;
}
bool PICloudServer::Client::closeDevice() {
// piCoutObj << "closeDevice" << this;
if (is_connected) {
server->clientDisconnect(client_id);
is_connected = false;
}
cond_buff.notifyOne();
return true;
}
ssize_t PICloudServer::Client::readDevice(void * read_to, ssize_t max_size) {
if (!is_connected) return -1;
ssize_t sz = -1;
mutex_buff.lock();
if (is_connected) {
if (buff.isEmpty()) {
sz = 0;
} else {
sz = piMini(max_size, buff.size());
memcpy(read_to, buff.data(), sz);
buff.remove(0, sz);
}
if (sz == 0) cond_buff.wait(mutex_buff);
}
mutex_buff.unlock();
return sz;
}
ssize_t PICloudServer::Client::writeDevice(const void * data, ssize_t size) {
if (!is_connected) return -1;
return server->sendData(PIByteArray(data, size), client_id);
}
void PICloudServer::Client::interrupt() {
cond_buff.notifyOne();
}
void PICloudServer::Client::pushBuffer(const PIByteArray & ba) {
if (!is_connected) return;
mutex_buff.lock();
if (buff.size_s() > threadedReadBufferSize()) {
piCoutObj << "Error: buffer overflow, drop %1 bytes"_tr("PICloud").arg(ba.size());
mutex_buff.unlock();
return;
}
buff.append(ba);
cond_buff.notifyOne();
mutex_buff.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,163 +1,185 @@
/*
PIP - Platform Independent Primitives
PICloud TCP transport
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 "picloudtcp.h"
#include "picrypt.h"
#include "pichunkstream.h"
#include "piethernet.h"
#include "pistreampacker.h"
const char hash_def_key[] = "_picrypt_";
PICloud::TCP::Header::Header() {
version = Version_2;
}
PICloud::TCP::TCP(PIStreamPacker * s) : streampacker(s) {
}
void PICloud::TCP::setRole(PICloud::TCP::Role r) {
header.role = r;
}
void PICloud::TCP::setServerName(const PIString & server_name_) {
server_name = server_name_;
suuid = PICrypt::hash(server_name_);
}
PIString PICloud::TCP::serverName() const {
return server_name;
}
void PICloud::TCP::sendStart() {
//piCout << "sendStart";
if (suuid.size() != PICrypt::sizeHash()) {
piCout << "PICloud ERROR, server not set, invoke setServerName first";
return;
}
header.type = PICloud::TCP::Connect;
PIByteArray ba;
ba << header;
ba.append(suuid);
streampacker->send(ba);
}
void PICloud::TCP::sendConnected(uint client_id) {
header.type = PICloud::TCP::Connect;
PIByteArray ba;
ba << header << client_id;
streampacker->send(ba);
}
void PICloud::TCP::sendDisconnected(uint client_id) {
header.type = PICloud::TCP::Disconnect;
PIByteArray ba;
ba << header << client_id;
streampacker->send(ba);
}
int PICloud::TCP::sendData(const PIByteArray & data) {
header.type = PICloud::TCP::Data;
PIByteArray ba;
ba << header;
ba.append(data);
// piCout << "sendData" << ba.toHex();
streampacker->send(ba);
return data.size_s();
}
int PICloud::TCP::sendData(const PIByteArray & data, uint client_id) {
header.type = PICloud::TCP::Data;
PIByteArray ba;
ba << header << client_id;
ba.append(data);
streampacker->send(ba);
return data.size_s();
}
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteArray & ba) {
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> ret;
ret.first = InvalidType;
ret.second = InvalidRole;
if (ba.size() < sizeof(Header)) return ret;
PICloud::TCP::Header hdr;
ba >> hdr;
if (hdr.version != header.version) {
piCout << "[PICloud]" << "invalid PICloud::TCP version!";
return ret;
}
ret.first = (Type)hdr.type;
ret.second = (Role)hdr.role;
return ret;
}
PIByteArray PICloud::TCP::parseData(PIByteArray & ba) {
if (header.role == Client) {
return ba;
}
return PIByteArray();
}
PIPair<uint, PIByteArray> PICloud::TCP::parseDataServer(PIByteArray & ba) {
PIPair<uint, PIByteArray> ret;
ret.first = 0;
if (header.role == Server) {
ba >> ret.first;
ret.second = ba;
}
return ret;
}
PIByteArray PICloud::TCP::parseConnect_d(PIByteArray & ba) {
if (ba.size() != PICrypt::sizeHash()) {
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::parseDisconnect(PIByteArray & ba) {
uint ret;
ba >> ret;
return ret;
}
/*
PIP - Platform Independent Primitives
PICloud TCP transport
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 "picloudtcp.h"
#include "pichunkstream.h"
#include "picrypt.h"
#include "piethernet.h"
#include "pistreampacker.h"
#include "pitranslator.h"
const char hash_cloud_key[] = "_picloud_";
PICloud::TCP::Header::Header() {
version = Version_2;
}
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::setServerName(const PIString & server_name_) {
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;
}
void PICloud::TCP::sendStart() {
// piCout << "sendStart";
if (suuid.size() != PICrypt::sizeHash()) {
piCout << "PICloud ERROR, server not set, invoke setServerName first";
return;
}
header.type = PICloud::TCP::Connect;
PIByteArray ba;
ba << header;
ba.append(suuid);
// mutex_send.lock();
streampacker->send(ba);
// mutex_send.unlock();
}
void PICloud::TCP::sendConnected(uint client_id) {
header.type = PICloud::TCP::Connect;
PIByteArray ba;
ba << header << client_id;
// mutex_send.lock();
streampacker->send(ba);
// mutex_send.unlock();
}
void PICloud::TCP::sendDisconnected(uint client_id) {
header.type = PICloud::TCP::Disconnect;
PIByteArray ba;
ba << header << client_id;
// mutex_send.lock();
streampacker->send(ba);
// mutex_send.unlock();
}
int PICloud::TCP::sendData(const PIByteArray & data) {
header.type = PICloud::TCP::Data;
PIByteArray ba;
ba << header;
ba.append(data);
// piCout << "[PICloud::TCP] sendData" << ba.toHex();
mutex_send.lock();
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;
ba << header << client_id;
ba.append(data);
mutex_send.lock();
streampacker->send(ba);
mutex_send.unlock();
return data.size_s();
}
void PICloud::TCP::sendPing() {
header.type = PICloud::TCP::Ping;
PIByteArray ba;
ba << header;
ba.append(suuid);
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;
ret.second = InvalidRole;
if (ba.size() < sizeof(Header)) return ret;
PICloud::TCP::Header hdr;
ba >> hdr;
if (hdr.version != header.version) {
piCout << "[PICloud]"
<< "Invalid PICloud::TCP version!"_tr("PICloud");
return ret;
}
ret.first = (Type)hdr.type;
ret.second = (Role)hdr.role;
return ret;
}
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) {
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();
} else {
return ba;
}
}
uint PICloud::TCP::parseConnect(PIByteArray & ba) {
uint ret = 0;
ba >> ret;
return ret;
}
uint PICloud::TCP::parseDisconnect(PIByteArray & ba) {
uint ret = 0;
ba >> ret;
return ret;
}

View File

@@ -1,76 +1,83 @@
/*
PIP - Platform Independent Primitives
Compress class using zlib
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 "picompress.h"
#ifdef PIP_COMPRESS
# ifdef FREERTOS
# include "esp32/rom/miniz.h"
# define compress2 mz_compress2
# define Z_OK MZ_OK
# define uncompress mz_uncompress
# else
# include <zlib.h>
# endif
#endif
PIByteArray piCompress(const PIByteArray & ba, int level) {
#ifdef PIP_COMPRESS
PIByteArray zba;
zba.resize(ba.size() + 128);
int ret = 0;
ulong sz = zba.size();
ret = compress2(zba.data(), &sz, ba.data(), ba.size(), level);
if (ret != Z_OK) {
piCout << "[PICompress]" << "Error: invalid input or not enought memory";
return ba;
}
zba.resize(sz);
zba << ullong(ba.size());
return zba;
#else
piCout << "[PICompress]" << "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
#endif
return ba;
}
PIByteArray piDecompress(const PIByteArray & zba) {
#ifdef PIP_COMPRESS
ullong sz;
if (zba.size() < sizeof(ullong)) {
piCout << "[PICompress]" << "Error: invalid input";
return zba;
}
PIByteArray ba(zba.data(zba.size() - sizeof(ullong)), sizeof(ullong));
ba >> sz;
ba.resize(sz);
int ret = 0;
ulong s = sz;
ret = uncompress(ba.data(), &s, zba.data(), zba.size());
if (ret != Z_OK) {
piCout << "[PICompress]" << "Error: invalid input or not enought memory";
return zba;
}
return ba;
#else
piCout << "[PICompress]" << "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
#endif
return zba;
}
/*
PIP - Platform Independent Primitives
Compress class using zlib
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 "picompress.h"
#include "pitranslator.h"
#ifdef PIP_COMPRESS
# ifdef ESP_PLATFORM
# include "esp32/rom/miniz.h"
# define compress2 mz_compress2
# define Z_OK MZ_OK
# define uncompress mz_uncompress
# else
# include <zlib.h>
# endif
#endif
PIByteArray piCompress(const PIByteArray & ba, int level) {
#ifdef PIP_COMPRESS
PIByteArray zba;
zba.resize(ba.size() + 128);
int ret = 0;
ulong sz = zba.size();
ret = compress2(zba.data(), &sz, ba.data(), ba.size(), level);
if (ret != Z_OK) {
piCout << "[PICompress]"
<< "Error: invalid input or not enought memory"_tr("PICompress");
return ba;
}
zba.resize(sz);
zba << ullong(ba.size());
return zba;
#else
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 = 0;
if (zba.size() < sizeof(ullong)) {
piCout << "[PICompress]"
<< "Error: invalid input"_tr("PICompress");
return zba;
}
PIByteArray ba(zba.data(zba.size() - sizeof(ullong)), sizeof(ullong));
ba >> sz;
ba.resize(sz);
int ret = 0;
ulong s = sz;
ret = uncompress(ba.data(), &s, zba.data(), zba.size());
if (ret != Z_OK) {
piCout << "[PICompress]"
<< "Error: invalid input or not enought memory"_tr("PICompress");
return zba;
}
return ba;
#else
piCout << "[PICompress]"
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library"_tr("PICompress");
#endif
return zba;
}

View File

@@ -1,31 +1,34 @@
/*
PIP - Platform Independent Primitives
Console output/input
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Console output/input
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 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.
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/>.
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 "piscreen.h"
#include "piincludes_p.h"
#include "piliterals_time.h"
#ifndef WINDOWS
# include <sys/ioctl.h>
# include <fcntl.h>
# include <sys/ioctl.h>
# include <termios.h>
#else
# include <wincon.h>
# include <wingdi.h>
# ifndef COMMON_LVB_UNDERSCORE
# define COMMON_LVB_UNDERSCORE 0x8000
# define COMMON_LVB_UNDERSCORE 0x8000
# endif
#endif
@@ -50,29 +53,6 @@ PRIVATE_DEFINITION_END(PIScreen::SystemConsole)
PIScreen::SystemConsole::SystemConsole() {
width = height = pwidth = pheight = 0;
mouse_x = mouse_y = -1;
int w, h;
#ifdef WINDOWS
PRIVATE->ulcoord.X = 0;
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
PRIVATE->dattr = PRIVATE->sbi.wAttributes;
w = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
h = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top;
GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode);
GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
#else
# ifdef FREERTOS
w = 80;
h = 24;
# else
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
w = ws.ws_col;
h = ws.ws_row;
# endif
#endif
resize(w, h);
}
@@ -85,6 +65,29 @@ PIScreen::SystemConsole::~SystemConsole() {
void PIScreen::SystemConsole::begin() {
int w, h;
#ifdef WINDOWS
PRIVATE->ulcoord.X = 0;
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
PRIVATE->dattr = PRIVATE->sbi.wAttributes;
w = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
h = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top;
GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode);
GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
#else
# ifdef MICRO_PIP
w = 80;
h = 24;
# else
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
w = ws.ws_col;
h = ws.ws_row;
# endif
#endif
resize(w, h);
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT);
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
@@ -92,6 +95,7 @@ void PIScreen::SystemConsole::begin() {
PRIVATE->bc.Y = 0;
#endif
clear();
clearScreen();
hideCursor();
}
@@ -108,16 +112,13 @@ void PIScreen::SystemConsole::end() {
void PIScreen::SystemConsole::prepare() {
int w, h;
int w = 80, h = 24;
#ifdef WINDOWS
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi);
w = PRIVATE->csbi.srWindow.Right - PRIVATE->csbi.srWindow.Left + 1;
h = PRIVATE->csbi.srWindow.Bottom - PRIVATE->csbi.srWindow.Top + 1;
#else
# ifdef FREERTOS
w = 80;
h = 24;
# else
# ifndef MICRO_PIP
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
w = ws.ws_col;
@@ -136,15 +137,15 @@ void PIScreen::SystemConsole::clear() {
void PIScreen::SystemConsole::resize(int w, int h) {
if (w == pwidth && h == pheight) return;
width = piMaxi(w, 0);
height = piMaxi(h, 0);
pwidth = width;
width = piMaxi(w, 0);
height = piMaxi(h, 0);
pwidth = width;
pheight = height;
cells.resize(height);
pcells.resize(height);
for (int i = 0; i < height; ++i) {
cells[i].resize(width);
pcells[i].resize(width, Cell(0));
pcells[i].resize(width, Cell(PIChar()));
}
#ifdef WINDOWS
PRIVATE->sbi.srWindow = PRIVATE->csbi.srWindow;
@@ -159,7 +160,7 @@ void PIScreen::SystemConsole::resize(int w, int h) {
void PIScreen::SystemConsole::print() {
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
PRIVATE->srect = PRIVATE->sbi.srWindow;
@@ -187,10 +188,10 @@ void PIScreen::SystemConsole::print() {
int k = j * dw + i;
Cell & c(cells[j + dy0][i + dx0]);
PRIVATE->chars[k].Char.UnicodeChar = 0;
PRIVATE->chars[k].Char.AsciiChar = c.symbol.toConsole1Byte();
PRIVATE->chars[k].Attributes = attributes(c);
PRIVATE->chars[k].Char.AsciiChar = c.symbol.toConsole1Byte();
PRIVATE->chars[k].Attributes = attributes(c);
}
//piCout << "draw" << dw << dh;
// piCout << "draw" << dw << dh;
PRIVATE->bs.X = dw;
PRIVATE->bs.Y = dh;
PRIVATE->srect.Left += dx0;
@@ -221,14 +222,15 @@ void PIScreen::SystemConsole::print() {
} else {
if (!s.isEmpty()) {
moveTo(si, sj);
printf("%s", s.data());
PICout::stdoutPIString(s);
s.clear();
}
}
}
if (!s.isEmpty()) {
moveTo(si, sj);
printf("%s", s.data());
PICout::stdoutPIString(s);
// printf("%s", s.data());
s.clear();
}
}
@@ -240,33 +242,37 @@ void PIScreen::SystemConsole::print() {
#ifdef WINDOWS
#define FOREGROUND_MASK (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
#define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
# define FOREGROUND_MASK (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
# define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) {
WORD attr = PRIVATE->dattr;
if (c.format.flags & Bold) attr |= FOREGROUND_INTENSITY;
else attr &= ~FOREGROUND_INTENSITY;
if (c.format.flags & Underline) attr |= COMMON_LVB_UNDERSCORE;
else attr &= ~COMMON_LVB_UNDERSCORE;
if (c.format.flags & Bold)
attr |= FOREGROUND_INTENSITY;
else
attr &= ~FOREGROUND_INTENSITY;
if (c.format.flags & Underline)
attr |= COMMON_LVB_UNDERSCORE;
else
attr &= ~COMMON_LVB_UNDERSCORE;
switch (c.format.color_char) {
case Black: attr = (attr & ~FOREGROUND_MASK); break;
case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break;
case Green: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN; break;
case Blue: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_BLUE; break;
case Cyan: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
case Black: attr = (attr & ~FOREGROUND_MASK); break;
case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break;
case Green: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN; break;
case Blue: attr = (attr & ~FOREGROUND_MASK) | 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 Yellow: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_GREEN; break;
case White: attr = attr | FOREGROUND_MASK; break;
case Yellow: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_GREEN; break;
case White: attr = attr | FOREGROUND_MASK; break;
}
switch (c.format.color_back) {
case Black: attr = (attr & ~BACKGROUND_MASK); break;
case Red: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED; break;
case Green: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN; break;
case Blue: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_BLUE; break;
case Cyan: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
case Black: attr = (attr & ~BACKGROUND_MASK); break;
case Red: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED; break;
case Green: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN; break;
case Blue: attr = (attr & ~BACKGROUND_MASK) | 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 Yellow: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_GREEN; break;
case White: attr = attr | BACKGROUND_MASK; break;
case Yellow: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_GREEN; break;
case White: attr = attr | BACKGROUND_MASK; break;
}
if ((c.format.flags & Inverse) == Inverse) {
uchar f = attr & 0xFF;
@@ -276,8 +282,8 @@ ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) {
}
return attr;
}
#undef FOREGROUND_MASK
#undef BACKGROUND_MASK
# undef FOREGROUND_MASK
# undef BACKGROUND_MASK
void PIScreen::SystemConsole::getWinCurCoord() {
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi);
@@ -292,37 +298,38 @@ void PIScreen::SystemConsole::clearLine() {
void PIScreen::SystemConsole::newLine() {
getWinCurCoord();
PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++;
PRIVATE->ccoord.X = 0;
PRIVATE->ccoord.Y++;
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
}
#else // WINDOWS
#else // WINDOWS
PIString PIScreen::SystemConsole::formatString(const PIScreenTypes::Cell & c) {
PIString ts("\e[0");
PIString ts = PIStringAscii("\e[0");
switch (c.format.color_char) {
case Black: ts += ";30"; break;
case Red: ts += ";31"; break;
case Green: ts += ";32"; break;
case Blue: ts += ";34"; break;
case Cyan: ts += ";36"; break;
case Magenta: ts += ";35"; break;
case Yellow: ts += ";33"; break;
case White: ts += ";37"; break;
case Black: ts += PIStringAscii(";30"); break;
case Red: ts += PIStringAscii(";31"); break;
case Green: ts += PIStringAscii(";32"); break;
case Blue: ts += PIStringAscii(";34"); break;
case Cyan: ts += PIStringAscii(";36"); break;
case Magenta: ts += PIStringAscii(";35"); break;
case Yellow: ts += PIStringAscii(";33"); break;
case White: ts += PIStringAscii(";37"); break;
}
switch (c.format.color_back) {
case Black: ts += ";40"; break;
case Red: ts += ";41"; break;
case Green: ts += ";42"; break;
case Blue: ts += ";44"; break;
case Cyan: ts += ";46"; break;
case Magenta: ts += ";45"; break;
case Yellow: ts += ";43"; break;
case White: ts += ";47"; break;
case Black: ts += PIStringAscii(";40"); break;
case Red: ts += PIStringAscii(";41"); break;
case Green: ts += PIStringAscii(";42"); break;
case Blue: ts += PIStringAscii(";44"); break;
case Cyan: ts += PIStringAscii(";46"); break;
case Magenta: ts += PIStringAscii(";45"); break;
case Yellow: ts += PIStringAscii(";43"); break;
case White: ts += PIStringAscii(";47"); break;
}
if ((c.format.flags & Bold) == Bold) ts += ";1";
if ((c.format.flags & Underline) == Underline) ts += ";4";
if ((c.format.flags & Blink) == Blink) ts += ";5";
if ((c.format.flags & Inverse) == Inverse) ts += ";7";
return ts + "m";
if ((c.format.flags & Bold) == Bold) ts += PIStringAscii(";1");
if ((c.format.flags & Underline) == Underline) ts += PIStringAscii(";4");
if ((c.format.flags & Blink) == Blink) ts += PIStringAscii(";5");
if ((c.format.flags & Inverse) == Inverse) ts += PIStringAscii(";7");
return ts + 'm';
}
#endif // WINDOWS
@@ -358,8 +365,16 @@ void PIScreen::SystemConsole::clearScreen() {
void PIScreen::SystemConsole::clearScreenLower() {
#ifdef WINDOWS
getWinCurCoord();
FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, 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);
FillConsoleOutputAttribute(PRIVATE->hOut,
PRIVATE->dattr,
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
printf("\e[0m\e[J");
#endif
@@ -384,34 +399,33 @@ void PIScreen::SystemConsole::showCursor() {
}
// PIScreen
PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawer_(console.cells), root("rootTile") {
setName("screen");
setPriority(piLow);
needLockRun(true);
mouse_ = false;
ret_func = slot;
tile_focus = tile_dialog = 0;
root.screen = this;
listener = new PIKbdListener(key_eventS, this, startNow);
CONNECTU(listener, mouseEvent, this, mouse_event);
CONNECTU(listener, wheelEvent, this, wheel_event);
mouse_ = false;
ret_func = slot;
tile_focus = tile_dialog = nullptr;
root.screen = this;
listener = new PIKbdListener(key_eventS, this, startNow);
CONNECT1(void, PIKbdListener::MouseEvent, listener, mouseEvent, this, mouse_event);
CONNECT1(void, PIKbdListener::WheelEvent, listener, wheelEvent, this, wheel_event);
if (startNow) start();
}
PIScreen::~PIScreen() {
if (isRunning())
stop();
PIThread::waitForFinish(10);
listener->waitForFinish(10);
if (isRunning()) stop();
PIThread::waitForFinish(100_ms);
listener->waitForFinish(100_ms);
delete listener;
}
void PIScreen::setMouseEnabled(bool on) {
mouse_ = on;
mouse_ = on;
console.mouse_x = console.mouse_y = -1;
}
@@ -423,14 +437,12 @@ void PIScreen::key_event(PIKbdListener::KeyEvent key) {
return;
*/
PIScreenTile * rtile = rootTile();
if (tile_dialog)
rtile = tile_dialog;
if (tile_dialog) rtile = tile_dialog;
bool used = nextFocus(rtile, key);
if (used) return;
if (!used && tile_focus) {
if (tile_focus->visible) {
if (tile_focus->keyEvent(key))
return;
if (tile_focus->keyEvent(key)) return;
}
}
if (ret_func != 0) ret_func(key, data_);
@@ -438,14 +450,14 @@ void PIScreen::key_event(PIKbdListener::KeyEvent key) {
}
PIVector<PIScreenTile * > PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) {
PIVector<PIScreenTile * > ret;
PIVector<PIScreenTile *> PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) {
PIVector<PIScreenTile *> ret;
if (!mouse_ || !e) return ret;
console.mouse_x = e->x;
console.mouse_y = e->y;
PIVector<PIScreenTile * > tl = tilesUnderMouse(e->x, e->y);
bool ff = false;
piForeachR (PIScreenTile * t, tl) {
console.mouse_x = e->x;
console.mouse_y = e->y;
PIVector<PIScreenTile *> tl = tilesUnderMouse(e->x, e->y);
bool ff = false;
piForeachR(PIScreenTile * t, tl) {
if (!ff) {
if (t->focus_flags[FocusOnMouse] && (e->action == PIKbdListener::MouseButtonPress)) {
t->setFocus();
@@ -456,20 +468,19 @@ PIVector<PIScreenTile * > PIScreen::prepareMouse(PIKbdListener::MouseEvent * e)
ff = true;
}
}
}
return tl;
}
PIVector<PIScreenTile * > PIScreen::tilesUnderMouse(int x, int y) {
PIVector<PIScreenTile * > ret;
PIVector<PIScreenTile *> PIScreen::tilesUnderMouse(int x, int y) {
PIVector<PIScreenTile *> ret;
if (x < 0 || x >= console.width || y < 0 || y >= console.height) return ret;
PIScreenTile * ct = tile_dialog ? tile_dialog : rootTile();
bool f = true;
bool f = true;
while (ct) {
if (!f) ret << ct;
f = false;
f = false;
ct = ct->childUnderMouse(x, y);
}
return ret;
@@ -477,27 +488,25 @@ PIVector<PIScreenTile * > PIScreen::tilesUnderMouse(int x, int y) {
void PIScreen::mouse_event(PIKbdListener::MouseEvent me) {
PIVector<PIScreenTile * > tl = prepareMouse(&me);
PIVector<PIScreenTile *> tl = prepareMouse(&me);
if (tl.isEmpty()) return;
piForeachR (PIScreenTile * t, tl)
piForeachR(PIScreenTile * t, tl)
if (t->mouseEvent(me)) break;
}
void PIScreen::wheel_event(PIKbdListener::WheelEvent we) {
PIVector<PIScreenTile * > tl = prepareMouse(&we);
PIVector<PIScreenTile *> tl = prepareMouse(&we);
if (tl.isEmpty()) return;
piForeachR (PIScreenTile * t, tl)
piForeachR(PIScreenTile * t, tl)
if (t->wheelEvent(we)) break;
}
bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
PIVector<PIScreenTile*> vtl = rt->children(true), ftl;
piForeach (PIScreenTile * t, vtl) {
if (t->focus_flags[CanHasFocus])
ftl << t;
PIVector<PIScreenTile *> vtl = rt->children(true), ftl;
for (PIScreenTile * t: vtl) {
if (t->focus_flags[CanHasFocus]) ftl << t;
}
int ind = -1;
for (int i = 0; i < ftl.size_s(); ++i)
@@ -505,18 +514,15 @@ bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
ind = i;
break;
}
if (ind < 0)
tile_focus = 0;
if (ind < 0) tile_focus = 0;
if (ftl.isEmpty())
tile_focus = 0;
else {
if (tile_focus)
if (!tile_focus->visible)
tile_focus = 0;
if (!tile_focus->visible) tile_focus = 0;
int next = tile_focus ? 0 : 1;
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 (key.key == PIKbdListener::LeftArrow) next = -1;
if (key.key == PIKbdListener::RightArrow) next = 1;
@@ -526,16 +532,16 @@ bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
if (key.key == PIKbdListener::DownArrow) next = 1;
}
}
//piCout << ftl.size() << ind << next;
// piCout << ftl.size() << ind << next;
if (next != 0) {
PIVector<PIScreenTile*> tl = rt->children();
piForeach (PIScreenTile * t, tl)
PIVector<PIScreenTile *> tl = rt->children();
for (PIScreenTile * t: tl)
t->has_focus = false;
if (!ftl.isEmpty()) {
ind += next;
if (ind >= ftl.size_s()) ind = 0;
if (ind < 0) ind = ftl.size_s() - 1;
tile_focus = ftl[ind];
tile_focus = ftl[ind];
tile_focus->has_focus = true;
}
return true;
@@ -551,22 +557,19 @@ void PIScreen::tileEventInternal(PIScreenTile * t, TileEvent e) {
void PIScreen::tileRemovedInternal(PIScreenTile * t) {
if (tile_dialog == t)
tile_dialog = 0;
if (tile_dialog == t) tile_dialog = 0;
}
void PIScreen::tileSetFocusInternal(PIScreenTile * t) {
PIScreenTile * rt = rootTile();
if (tile_dialog)
rt = tile_dialog;
PIVector<PIScreenTile*> tl = rt->children(), ftl;
piForeach (PIScreenTile * i, tl)
if (tile_dialog) rt = tile_dialog;
PIVector<PIScreenTile *> tl = rt->children(), ftl;
for (PIScreenTile * i: tl)
i->has_focus = false;
tile_focus = t;
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;
}
@@ -588,8 +591,14 @@ void PIScreen::waitForFinish() {
}
void PIScreen::start(bool wait) {
PIThread::start(25_Hz);
if (wait) waitForFinish();
}
void PIScreen::stop(bool clear) {
PIThread::stop(true);
PIThread::stopAndWait();
if (clear) console.clearScreen();
#ifndef WINDOWS
fflush(0);
@@ -613,16 +622,21 @@ void PIScreen::run() {
if (tile_dialog) {
int sw(0), sh(0);
tile_dialog->sizeHint(sw, sh);
sw = piClampi(sw, tile_dialog->minimumWidth, tile_dialog->maximumWidth);
sh = piClampi(sh, tile_dialog->minimumHeight, tile_dialog->maximumHeight);
tile_dialog->x_ = (console.width - sw) / 2;
tile_dialog->y_ = (console.height - sh) / 2;
tile_dialog->width_ = sw;
sw = piClampi(sw, tile_dialog->minimumWidth, tile_dialog->maximumWidth);
sh = piClampi(sh, tile_dialog->minimumHeight, tile_dialog->maximumHeight);
tile_dialog->x_ = (console.width - sw) / 2;
tile_dialog->y_ = (console.height - sh) / 2;
tile_dialog->width_ = sw;
tile_dialog->height_ = sh;
tile_dialog->layout();
int dx = tile_dialog->x_ - 1, dy = tile_dialog->y_ - 1, dw = tile_dialog->width_, dh = tile_dialog->height_;
drawer_.drawFrame(dx, dy, 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);
drawer_.drawFrame(dx,
dy,
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_);
}
console.print();
@@ -636,10 +650,8 @@ void PIScreen::end() {
PIScreenTile * PIScreen::tileByName(const PIString & name) {
PIVector<PIScreenTile*> tl(tiles());
piForeach (PIScreenTile * t, tl)
if (t->name() == name)
return t;
PIVector<PIScreenTile *> tl(tiles());
for (PIScreenTile * t: tl)
if (t->name() == name) return t;
return 0;
}

View File

@@ -1,20 +1,20 @@
/*
PIP - Platform Independent Primitives
Tile for PIScreen with PIConsole API
Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
Tile for PIScreen with PIConsole API
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 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.
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/>.
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 "piscreenconsole.h"
@@ -22,21 +22,14 @@
using namespace PIScreenTypes;
TileVars::TileVars(const PIString &n) : PIScreenTile(n) {
TileVars::TileVars(const PIString & n): PIScreenTile(n) {
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
Console output/input
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Console output/input
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 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.
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/>.
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 "piscreendrawer.h"
@@ -25,68 +25,68 @@
using namespace PIScreenTypes;
PIScreenDrawer::PIScreenDrawer(PIVector<PIVector<Cell> > & c): cells(c) {
PIScreenDrawer::PIScreenDrawer(PIVector<PIVector<Cell>> & c): cells(c) {
arts_[LineVertical] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('|');
PIChar('|');
#endif
arts_[LineHorizontal] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('-');
PIChar('-');
#endif
arts_[Cross] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('+');
PIChar('+');
#endif
arts_[CornerTopLeft] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('+');
PIChar('+');
#endif
arts_[CornerTopRight] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('+');
PIChar('+');
#endif
arts_[CornerBottomLeft] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('+');
PIChar('+');
#endif
arts_[CornerBottomRight] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('+');
PIChar('+');
#endif
arts_[Unchecked] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('O');
PIChar('O');
#endif
arts_[Checked] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('0');
PIChar('0');
#endif
}
@@ -98,45 +98,43 @@ void PIScreenDrawer::clear() {
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;
cells[y][x].symbol = c;
cells[y][x].symbol = c;
cells[y][x].format.color_char = col_char;
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) {
if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char);
Cell cc;
cc.symbol = c;
cc.symbol = c;
cc.format.color_char = col_char;
cc.format.color_back = col_back;
cc.format.flags = flags_char;
cc.format.flags = flags_char;
int x = 0, y = 0;
if (piAbsi(x1 - x0) >= piAbsi(y1 - y0)) {
float dy = (y1 - y0) / float(piAbsi(x1 - x0)), cy = y0;
int dx = x0 < x1 ? 1 : -1;
for (int i = x0; i != x1; i += dx) {
x = i; y = piRound(cy);
if (x >= 0 && x < width && y >= 0 && y < height)
cells[y][x] = cc;
x = i;
y = piRound(cy);
if (x >= 0 && x < width && y >= 0 && y < height) cells[y][x] = cc;
cy += dy;
}
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 {
float dx = (x1 - x0) / float(piAbsi(y1 - y0)), cx = x0;
int dy = y0 < y1 ? 1 : -1;
for (int i = y0; i != y1; i += dy) {
x = piRound(cx); y = i;
if (x >= 0 && x < width && y >= 0 && y < height)
cells[y][x] = cc;
x = piRound(cx);
y = i;
if (x >= 0 && x < width && y >= 0 && y < height) cells[y][x] = cc;
cx += dx;
}
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;
}
}
@@ -144,32 +142,29 @@ 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) {
if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char);
Cell cc;
cc.symbol = c;
cc.symbol = c;
cc.format.color_char = col_char;
cc.format.color_back = col_back;
cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1;
int xs[2] = {x0, x1};
int ys[2] = {y0, y1};
cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1;
int xs[2] = {x0, x1};
int ys[2] = {y0, y1};
for (int k = 0; k < 2; ++k) {
int j = ys[k];
if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]);
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];
if (j >= 0 && j < width) {
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;
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;
}
@@ -178,35 +173,37 @@ void PIScreenDrawer::drawFrame(int x0, int y0, int x1, int y1, Color col_char, C
Cell cc;
cc.format.color_char = col_char;
cc.format.color_back = col_back;
cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1;
int xs[2] = {x0, x1};
int ys[2] = {y0, y1};
cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1;
int xs[2] = {x0, x1};
int ys[2] = {y0, y1};
for (int k = 0; k < 2; ++k) {
int j = ys[k];
if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]);
cc.symbol = artChar(LineHorizontal);
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];
if (j >= 0 && j < width) {
cc.symbol = artChar(LineVertical);
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; cc.symbol = artChar(CornerTopLeft);
int i = x0, j = y0;
cc.symbol = artChar(CornerTopLeft);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
i = x1, j = y0; cc.symbol = artChar(CornerTopRight);
i = x1, j = y0;
cc.symbol = artChar(CornerTopRight);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
i = x0, j = y1; cc.symbol = artChar(CornerBottomLeft);
i = x0, j = y1;
cc.symbol = artChar(CornerBottomLeft);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
i = x1, j = y1; cc.symbol = artChar(CornerBottomRight);
i = x1, j = y1;
cc.symbol = artChar(CornerBottomRight);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
}
@@ -214,23 +211,22 @@ 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) {
if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char);
Cell cc;
cc.symbol = c;
cc.symbol = c;
cc.format.color_char = col_char;
cc.format.color_back = col_back;
cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1;
cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1;
for (int j = y0; j != y1; j += dy)
if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]);
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 (y0 > y1) piSwap(y0, y1);
int w = x1 - x0;
@@ -241,14 +237,13 @@ void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<
PIVector<Cell> & cv(cells[y0 + j]);
PIVector<Cell> & contv(content[j]);
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)
cells[i].fill(Cell());
}
@@ -260,12 +255,12 @@ void PIScreenDrawer::drawText(int x, int y, const PIString & s, Color col_char,
Cell cc;
cc.format.color_char = col_char;
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) {
int j = i + x;
if (j >= 0 && j < width) {
cc.symbol = s[i];
cv[j] = cc;
cv[j] = cc;
}
}
}

View File

@@ -1,23 +1,24 @@
/*
PIP - Platform Independent Primitives
Basic PIScreen tile
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Basic PIScreen tile
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 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.
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/>.
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 "piscreentile.h"
#include "piscreendrawer.h"
@@ -25,24 +26,23 @@ using namespace PIScreenTypes;
PIScreenTile::PIScreenTile(const PIString & n, Direction d, SizePolicy p): PIObject(n) {
direction = d;
size_policy = p;
focus_flags = 0;
screen = 0;
direction = d;
size_policy = p;
focus_flags = 0;
screen = 0;
minimumWidth = minimumHeight = x_ = y_ = width_ = height_ = pw = ph = 0;
maximumWidth = maximumHeight = 65535;
marginLeft = marginRight = marginTop = marginBottom = spacing = 0;
parent = 0;
back_symbol = ' ';
visible = true;
has_focus = false;
parent = 0;
back_symbol = ' ';
visible = true;
has_focus = false;
}
PIScreenTile::~PIScreenTile() {
//piCout << this << "~";
if (screen)
screen->tileRemovedInternal(this);
// piCout << this << "~";
if (screen) screen->tileRemovedInternal(this);
setScreen(0);
deleteChildren();
if (!parent) return;
@@ -76,20 +76,18 @@ void PIScreenTile::removeTile(PIScreenTile * t) {
}
PIVector<PIScreenTile * > PIScreenTile::children(bool only_visible) {
PIVector<PIScreenTile * > ret;
piForeach (PIScreenTile * t, tiles)
if (t->visible || !only_visible)
ret << t << t->children(only_visible);
PIVector<PIScreenTile *> PIScreenTile::children(bool only_visible) {
PIVector<PIScreenTile *> ret;
for (auto * t: tiles)
if (t->visible || !only_visible) ret << t << t->children(only_visible);
return ret;
}
PIScreenTile * PIScreenTile::childUnderMouse(int x, int y) {
piForeach (PIScreenTile * t, tiles) {
for (auto * t: tiles) {
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;
}
}
@@ -105,13 +103,13 @@ void PIScreenTile::raiseEvent(TileEvent e) {
void PIScreenTile::setScreen(PIScreenBase * s) {
screen = s;
piForeach (PIScreenTile * t, tiles)
for (auto * t: tiles)
t->setScreen(s);
}
void PIScreenTile::deleteChildren() {
piForeach (PIScreenTile * t, tiles) {
for (auto * t: tiles) {
t->parent = 0;
delete t;
}
@@ -129,9 +127,16 @@ void PIScreenTile::drawEventInternal(PIScreenDrawer * d) {
if (!visible) {
return;
}
d->fillRect(x_, y_, x_ + width_, y_ + height_, back_symbol, (Color)back_format.color_char, (Color)back_format.color_back, back_format.flags);
d->fillRect(x_,
y_,
x_ + width_,
y_ + height_,
back_symbol,
(Color)back_format.color_char,
(Color)back_format.color_back,
back_format.flags);
drawEvent(d);
piForeach (PIScreenTile * t, tiles)
for (auto * t: tiles)
t->drawEventInternal(d);
}
@@ -141,18 +146,22 @@ void PIScreenTile::sizeHint(int & w, int & h) const {
h = 0;
if (tiles.isEmpty()) return;
int sl = spacing * (tiles.size_s() - 1);
if (direction == Horizontal) w += sl;
else h += sl;
piForeachC (PIScreenTile * t, tiles) {
if (direction == Horizontal)
w += sl;
else
h += sl;
for (const auto * t: tiles) {
if (!t->visible) continue;
int cw(0), ch(0);
t->sizeHint(cw, ch);
cw = piClampi(cw, t->minimumWidth, t->maximumWidth);
ch = piClampi(ch, t->minimumHeight, t->maximumHeight);
if (direction == Horizontal) {
w += cw; h = piMaxi(h, ch);
w += cw;
h = piMaxi(h, ch);
} else {
h += ch; w = piMaxi(w, cw);
h += ch;
w = piMaxi(w, cw);
}
}
w += marginLeft + marginRight;
@@ -163,7 +172,7 @@ void PIScreenTile::sizeHint(int & w, int & h) const {
void PIScreenTile::layout() {
if (tiles.isEmpty() || !visible) return;
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);
ts -= spacing * (tiles.size_s() - 1);
PIVector<int> hints(tiles.size_s());
@@ -180,7 +189,7 @@ void PIScreenTile::layout() {
cs = (direction == Horizontal) ? cw : ch;
as += cs;
}
hints[i] = cs;
hints[i] = cs;
asizes[i] = 0.f;
}
if (as <= ts) {
@@ -188,10 +197,10 @@ void PIScreenTile::layout() {
SizePolicy pol = Fixed;
if (ecnt > 0) {
acnt = ecnt;
pol = Expanding;
pol = Expanding;
} else if (pcnt > 0) {
acnt = pcnt;
pol = Preferred;
pol = Preferred;
}
if (acnt > 0) {
float add_a = float(ts - as), add_s = add_a / acnt, add_da(0.);
@@ -210,8 +219,7 @@ void PIScreenTile::layout() {
for (int j = 0; j < tiles.size_s(); ++j) {
if (i == 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;
}
}
}
@@ -233,16 +241,15 @@ void PIScreenTile::layout() {
t->x_ = cx;
t->y_ = cy;
if (direction == Horizontal) {
t->width_ = hints[i];
t->width_ = hints[i];
t->height_ = ts2;
cx += hints[i] + spacing;
} else {
t->width_ = ts2;
t->width_ = ts2;
t->height_ = hints[i];
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->ph = t->height_;
t->layout();

View File

@@ -1,23 +1,24 @@
/*
PIP - Platform Independent Primitives
Various tiles for PIScreen
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Various tiles for PIScreen
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 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.
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/>.
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 "piscreentiles.h"
#include "piscreendrawer.h"
@@ -37,7 +38,7 @@ TileSimple::TileSimple(const TileSimple::Row & r): PIScreenTile() {
void TileSimple::sizeHint(int & w, int & h) const {
w = h = 0;
piForeachC (Row & r, content)
for (const auto & r: content)
w = piMaxi(w, r.first.size_s());
h = content.size_s();
}
@@ -57,13 +58,13 @@ void TileSimple::drawEvent(PIScreenDrawer * d) {
}
// TileScrollBar
TileScrollBar::TileScrollBar(const PIString & n) {
direction = Vertical;
thickness = 1;
minimum_ = value_ = 0;
maximum_ = 100;
maximum_ = 100;
}
@@ -122,15 +123,15 @@ bool TileScrollBar::mouseEvent(PIKbdListener::MouseEvent me) {
}
// TileList
TileList::TileList(const PIString & n, SelectionMode sm): PIScreenTile(n) {
alignment = Left;
alignment = Left;
focus_flags = CanHasFocus | NextByArrowsHorizontal | NextByTab | FocusOnMouseOrWheel;
lhei = offset = cur = 0;
mouse_sel = false;
selection_mode = sm;
scroll = new TileScrollBar();
mouse_sel = false;
selection_mode = sm;
scroll = new TileScrollBar();
scroll->size_policy = Ignore;
addTile(scroll);
}
@@ -138,26 +139,26 @@ TileList::TileList(const PIString & n, SelectionMode sm): PIScreenTile(n) {
void TileList::sizeHint(int & w, int & h) const {
w = h = 0;
piForeachC (Row & r, content)
for (const auto & r: content)
w = piMaxi(w, r.first.size_s());
h = 3;
}
void TileList::resizeEvent(int w, int h) {
scroll->x_ = x_ + width_ - 1;
scroll->y_ = y_;
scroll->width_ = 1;
scroll->x_ = x_ + width_ - 1;
scroll->y_ = y_;
scroll->width_ = 1;
scroll->height_ = height_;
}
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());
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);
//piCout << is << ie << offset << lhei << content.size_s();
// piCout << is << ie << offset << lhei << content.size_s();
for (int i = is; i < ie; ++i) {
Row & r(content[i]);
bool sel = i == cur && has_focus;
@@ -172,7 +173,7 @@ void TileList::drawEvent(PIScreenDrawer * d) {
case Right: rx = x_ + width_ - 1 - r.first.size_s(); break;
};
CharFlags cf = r.second.flags;
Color cc = (Color)r.second.color_char;
Color cc = (Color)r.second.color_char;
if (selected[i]) {
cf |= Bold;
cc = Yellow;
@@ -188,9 +189,7 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
lhei = height_ - 2;
int oo(0), osp = piMini(3, lhei / 4);
switch (key.key) {
case PIKbdListener::PageUp:
cur -= lhei / 2;
oo -= lhei / 2;
case PIKbdListener::PageUp: cur -= lhei / 2; oo -= lhei / 2;
case PIKbdListener::UpArrow:
cur--;
oo--;
@@ -207,7 +206,8 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
switch (selection_mode) {
case NoSelection: return false;
case SingleSelection:
if (selected.isEmpty()) selected << cur;
if (selected.isEmpty())
selected << cur;
else {
bool add = !selected[cur];
selected.clear();
@@ -216,8 +216,10 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
raiseEvent(TileEvent(SelectionChanged));
return true;
case MultiSelection:
if (selected[cur]) selected.remove(cur);
else selected << cur;
if (selected[cur])
selected.remove(cur);
else
selected << cur;
raiseEvent(TileEvent(SelectionChanged));
break;
}
@@ -238,17 +240,14 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
if (offset >= content.size_s() - lhei) offset = content.size_s() - lhei;
if (offset < 0) offset = 0;
return true;
case PIKbdListener::Home:
cur = offset = 0;
return true;
case PIKbdListener::Home: cur = offset = 0; return true;
case PIKbdListener::End:
cur = content.size_s() - 1;
cur = content.size_s() - 1;
offset = content.size_s() - lhei;
if (offset < 0) offset = 0;
return true;
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;
case '*':
if (selection_mode == TileList::MultiSelection) {
@@ -278,12 +277,8 @@ bool TileList::mouseEvent(PIKbdListener::MouseEvent me) {
if (mp < 0 || mp >= content.size_s()) return true;
cur = mp;
switch (me.action) {
case PIKbdListener::MouseButtonPress:
mouse_sel = !selected.contains(cur);
break;
case PIKbdListener::MouseButtonDblClick:
keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return));
return true;
case PIKbdListener::MouseButtonPress: mouse_sel = !selected.contains(cur); break;
case PIKbdListener::MouseButtonDblClick: keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return)); return true;
default: break;
}
if (me.buttons[PIKbdListener::MouseRight]) {
@@ -294,8 +289,10 @@ bool TileList::mouseEvent(PIKbdListener::MouseEvent me) {
raiseEvent(TileEvent(SelectionChanged));
break;
case MultiSelection:
if (mouse_sel) selected << cur;
else selected.remove(cur);
if (mouse_sel)
selected << cur;
else
selected.remove(cur);
raiseEvent(TileEvent(SelectionChanged));
break;
default: break;
@@ -311,7 +308,7 @@ bool TileList::wheelEvent(PIKbdListener::WheelEvent we) {
}
// TileButton
TileButton::TileButton(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse;
@@ -327,7 +324,7 @@ void TileButton::sizeHint(int & w, int & h) const {
void TileButton::drawEvent(PIScreenDrawer * d) {
Color cb = has_focus ? Blue : Cyan;
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->drawText(x_, y_, "[", ct, Transparent, ff);
d->drawText(x_ + (width_ - text.size_s()) / 2, y_, text, ct, Transparent, ff);
@@ -351,25 +348,25 @@ bool TileButton::mouseEvent(PIKbdListener::MouseEvent me) {
}
// TileButtons
TileButtons::TileButtons(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | FocusOnMouse;
direction = Horizontal;
alignment = PIScreenTypes::Center;
cur = 0;
direction = Horizontal;
alignment = PIScreenTypes::Center;
cur = 0;
}
void TileButtons::sizeHint(int & w, int & h) const {
w = h = 0;
if (direction == Horizontal) {
piForeachC (Button & b, content)
for (const auto & b: content)
w += b.first.size_s() + 4;
w += piMaxi(0, content.size_s() - 1) * 2;
h += 1;
} else {
piForeachC (Button & b, content)
for (const auto & b: content)
w = piMaxi(w, b.first.size_s() + 4);
h += content.size_s();
h += piMaxi(0, content.size_s() - 1);
@@ -387,12 +384,11 @@ void TileButtons::drawEvent(PIScreenDrawer * d) {
case PIScreenTypes::Right: dx = width_ - shw; break;
default: break;
}
if (direction == PIScreenTypes::Horizontal)
cx += dx;
if (direction == PIScreenTypes::Horizontal) cx += dx;
for (int i = 0; i < content.size_s(); ++i) {
Color cb = Cyan;
Color ct = Black;
int ff = 0;
int ff = 0;
if (i == cur && has_focus) {
cb = Blue;
ct = White;
@@ -430,9 +426,7 @@ bool TileButtons::keyEvent(PIKbdListener::KeyEvent key) {
if (cur >= content.size_s()) cur = content.size_s() - 1;
return true;
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);
}
@@ -441,8 +435,7 @@ bool TileButtons::keyEvent(PIKbdListener::KeyEvent key) {
bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) {
if (me.action == PIKbdListener::MouseMove || me.action == PIKbdListener::MouseButtonPress) {
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;
break;
}
@@ -454,11 +447,11 @@ bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) {
}
// TileCheck
TileCheck::TileCheck(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse;
toggled = false;
toggled = false;
}
@@ -471,7 +464,7 @@ void TileCheck::sizeHint(int & w, int & h) const {
void TileCheck::drawEvent(PIScreenDrawer * d) {
Color cb = has_focus ? Blue : Cyan;
Color ct = has_focus ? White : Black;
int ff = has_focus ? Bold : 0;
int ff = has_focus ? Bold : 0;
PIString cs("[ ]");
if (toggled) cs[1] = '*';
d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb);
@@ -499,12 +492,12 @@ bool TileCheck::mouseEvent(PIKbdListener::MouseEvent me) {
}
// TileProgress
TileProgress::TileProgress(const PIString & n): PIScreenTile(n) {
maximum = 100.;
value = 0.;
suffix = " %";
value = 0.;
suffix = " %";
}
@@ -515,7 +508,7 @@ void TileProgress::sizeHint(int & w, int & h) const {
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;
int w = piRoundd(v / 100. * width_), sx = (width_ - s.size_s()) / 2;
d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, Cyan);
@@ -532,28 +525,26 @@ void TileProgress::drawEvent(PIScreenDrawer * d) {
}
// TilePICout
TilePICout::TilePICout(const PIString & n): TileList(n) {
max_lines = 1024;
max_lines = 1024;
selection_mode = TileList::SingleSelection;
PICout::setOutputDevices(PICout::Buffer);
PICout::setBufferActive(true);
}
void TilePICout::drawEvent(PIScreenDrawer * d) {
PIString out = PICout::buffer(true);
PIString out = PICout::getBufferAndClear();
if (!out.isEmpty()) {
PIStringList l = out.split("\n");
bool scroll = (cur == content.size_s() - 1) || !has_focus;
piForeachC (PIString & s, l)
bool scroll = (cur == content.size_s() - 1) || !has_focus;
for (const auto & s: l)
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) {
offset = piMaxi(0, content.size_s() - lhei);
cur = content.size_s() - 1;
cur = content.size_s() - 1;
}
}
TileList::drawEvent(d);
@@ -570,16 +561,16 @@ bool TilePICout::keyEvent(PIKbdListener::KeyEvent key) {
}
// TileInput
TileInput::TileInput(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | FocusOnMouse;
focus_flags = CanHasFocus | NextByTab | FocusOnMouse;
back_format.color_back = White;
format.color_char = Black;
format.color_back = White;
max_length = 1024;
format.color_char = Black;
format.color_back = White;
max_length = 1024;
cur = offset = 0;
inv = false;
inv = false;
}
@@ -592,10 +583,8 @@ void TileInput::sizeHint(int & w, int & h) const {
void TileInput::drawEvent(PIScreenDrawer * d) {
PIString ps = text.mid(offset, width_ - 2);
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 (text.size_s() - offset >= width_ - 2)
d->drawText(x_ + width_ - 1, y_, ">", Green, Black, Bold);
if (offset > 0) 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;
Color cb = (Color)format.color_char, cc = (Color)format.color_back;
if (tm_blink.elapsed_m() >= 650) {
@@ -642,14 +631,13 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
reserCursor();
return true;
case PIKbdListener::End:
cur = text.size_s();
cur = text.size_s();
offset = text.size_s() - lwid;
if (offset < 0) offset = 0;
reserCursor();
return true;
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);
cur--;
if (cur > text.size_s()) cur = text.size_s();
@@ -659,8 +647,7 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
reserCursor();
return true;
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);
if (cur < 0) cur = 0;
if (cur > text.size_s()) cur = text.size_s();
@@ -686,16 +673,9 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
case PIKbdListener::F9:
case PIKbdListener::F10:
case PIKbdListener::F11:
case PIKbdListener::F12:
break;
case PIKbdListener::F12: break;
default:
PIChar tc
#ifdef WINDOWS
= PIChar(key.key);
#else
= PIChar::fromUTF8((char *)&(key.key));
#endif
text.insert(cur, tc);
text.insert(cur, PIChar((ushort)key.key));
cur++;
oo++;
if (cur - offset >= lwid - osp) offset += oo;

View File

@@ -1,57 +1,61 @@
/*
PIP - Platform Independent Primitives
Virtual terminal
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Virtual terminal
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 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.
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/>.
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 "piincludes_p.h"
#include "piterminal.h"
#include "piincludes_p.h"
#include "piliterals_time.h"
#include "pisharedmemory.h"
#ifndef FREERTOS
#ifdef WINDOWS
# include <windows.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>
#ifndef MICRO_PIP
# ifdef WINDOWS
# include <wincon.h>
# include <windows.h>
# include <wingdi.h>
# include <winuser.h>
# else
# ifdef MAC_OS
# include <util.h>
# else
# include <pty.h>
# endif
# include "piprocess.h"
# include <csignal>
# include <fcntl.h>
# include <sys/ioctl.h>
# 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
# 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
# define PIPE_BUFFER_SIZE 1024
# ifdef WINDOWS
# define PIPE_BUFFER_SIZE 1024
enum PITerminalAuxMessageType {
mtKey = 1,
mtResize,
@@ -64,22 +68,22 @@ struct PITerminalAuxData {
int size_y;
int cells_size;
};
#else
# define BUFFER_SIZE 4096
# else
# define BUFFER_SIZE 4096
enum DECType {
CKM = 1
};
#endif
# endif
PRIVATE_DEFINITION_START(PITerminal)
#ifdef WINDOWS
# ifdef WINDOWS
PISharedMemory * shm;
HANDLE hConBuf;
STARTUPINFOA si;
PROCESS_INFORMATION pi;
HANDLE pipe;
#else
# else
PIString shell;
PIByteArray read_buf, tmp_buf;
PIScreenTypes::CellFormat cur_format, line_format;
@@ -91,21 +95,21 @@ PRIVATE_DEFINITION_START(PITerminal)
PIString esc_seq;
bool is_esc_seq, last_read;
PIMap<int, bool> DEC;
PIVector<PIVector<PIScreenTypes::Cell> > cells_save;
#endif
PIVector<PIVector<PIScreenTypes::Cell>> cells_save;
# endif
PRIVATE_DEFINITION_END(PITerminal)
#ifdef WINDOWS
# ifdef WINDOWS
int writePipe(HANDLE pipe, const PIByteArray & ba) {
DWORD wrote[2];
int sz = ba.size_s();
WriteFile(pipe, &sz, 4, &(wrote[0]), 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]);
}
#endif
# endif
PITerminal::PITerminal(): PIThread() {
@@ -113,42 +117,41 @@ PITerminal::PITerminal(): PIThread() {
initPrivate();
cursor_blink = false;
cursor_x = cursor_y = 0;
dsize_x = 80;
dsize_y = 24;
#ifdef WINDOWS
dsize_x = 80;
dsize_y = 24;
# ifdef WINDOWS
PRIVATE->shm = 0;
#endif
# endif
}
PITerminal::~PITerminal() {
if (isRunning())
stop();
PIThread::waitForFinish(10);
if (isRunning()) stop();
PIThread::waitForFinish(1_s);
destroy();
#ifdef WINDOWS
# ifdef WINDOWS
if (PRIVATE->shm) delete PRIVATE->shm;
#endif
# endif
}
void PITerminal::write(const PIByteArray & d) {
#ifdef WINDOWS
# ifdef WINDOWS
PIByteArray msg;
PIVector<PIKbdListener::KeyEvent> ke;
for (int i = 0; i < d.size_s(); ++i)
ke << PIKbdListener::KeyEvent(d[i]);
msg << int(mtKey) << ke;
writePipe(PRIVATE->pipe, msg);
#else
# ifdef HAS_FORKPTY
# else
# ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return;
//ssize_t wrote = 0;
//wrote =
// ssize_t wrote = 0;
// wrote =
::write(PRIVATE->fd, d.data(), d.size_s());
//piCout << "wrote" << wrote << d;
// piCout << "wrote" << wrote << d;
# endif
# endif
#endif
cursor_tm.reset();
cursor_blink = true;
}
@@ -156,15 +159,16 @@ void PITerminal::write(const PIByteArray & d) {
void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m) {
PIByteArray ba;
#ifdef WINDOWS
# ifdef WINDOWS
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::Space: ba << uchar(' '); break;
case PIKbdListener::Space: ba << uchar(' '); break;
default: break;
}
//piCout << "write" << ba.size();
if (!ba.isEmpty()) write(ba);
// piCout << "write" << ba.size();
if (!ba.isEmpty())
write(ba);
else {
PIByteArray msg;
PIVector<PIKbdListener::KeyEvent> ke;
@@ -172,19 +176,20 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
msg << int(mtKey) << ke;
writePipe(PRIVATE->pipe, msg);
}
#else
int term = PRIVATE->term_type;
# else
int term = PRIVATE->term_type;
int flags = 0;
switch (k) {
case PIKbdListener::Tab: ba << uchar('\t'); break;
case PIKbdListener::Return: ba << uchar('\n'); break;
case PIKbdListener::Esc: ba << uchar('\e'); break;
case PIKbdListener::Space: ba << uchar(' '); break;
case PIKbdListener::Backspace: ba << uchar(0x7f); break;
case PIKbdListener::UpArrow:
case PIKbdListener::DownArrow:
case PIKbdListener::RightArrow:
case PIKbdListener::LeftArrow: if (PRIVATE->DEC.value(CKM, false)) flags = 1;
case PIKbdListener::Tab: ba << uchar('\t'); break;
case PIKbdListener::Return: ba << uchar('\n'); break;
case PIKbdListener::Esc: ba << uchar('\e'); break;
case PIKbdListener::Space: ba << uchar(' '); break;
case PIKbdListener::Backspace: ba << uchar(0x7f); break;
case PIKbdListener::UpArrow:
case PIKbdListener::DownArrow:
case PIKbdListener::RightArrow:
case PIKbdListener::LeftArrow:
if (PRIVATE->DEC.value(CKM, false)) flags = 1;
/*case PIKbdListener::Home: //break;
case PIKbdListener::End: //break;
case PIKbdListener::PageUp: //ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break;
@@ -205,55 +210,55 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
case PIKbdListener::F12: //break;
*/
default: {
//piCout << flags;
//int mod = 0;
// piCout << flags;
// int mod = 0;
if (m[PIKbdListener::Shift]) m |= 1;
if (m[PIKbdListener::Alt]) m |= 2;
if (m[PIKbdListener::Ctrl]) m |= 4;
for (int i = 0; ; ++i) {
if (m[PIKbdListener::Alt]) m |= 2;
if (m[PIKbdListener::Ctrl]) m |= 4;
for (int i = 0;; ++i) {
const PIKbdListener::EscSeq & e(PIKbdListener::esc_seq[i]);
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.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();
write(d);
break;
}
}
}
} break;
} break;
}
//piCout << "write" << ba.size();
// piCout << "write" << ba.size();
if (!ba.isEmpty()) write(ba);
#endif
# endif
cursor_tm.reset();
cursor_blink = true;
}
void PITerminal::write(PIKbdListener::KeyEvent ke) {
if (isSpecialKey(ke.key)) write((PIKbdListener::SpecialKey)ke.key, ke.modifiers);
if (isSpecialKey(ke.key))
write((PIKbdListener::SpecialKey)ke.key, ke.modifiers);
else {
PIByteArray ba;
#ifdef WINDOWS
ba << uchar(PIChar(ke.key).toConsole1Byte());
#else
ba = PIString(PIChar(ke.key)).toUTF8();
#endif
# ifdef WINDOWS
ba << uchar(PIChar((ushort)ke.key).toConsole1Byte());
# else
ba = PIString(PIChar((ushort)ke.key)).toUTF8();
# endif
write(ba);
}
}
PIVector<PIVector<PIScreenTypes::Cell> > PITerminal::content() {
PIVector<PIVector<PIScreenTypes::Cell>> PITerminal::content() {
readConsole();
PIVector<PIVector<PIScreenTypes::Cell> > ret = cells;
PIVector<PIVector<PIScreenTypes::Cell>> ret = cells;
if (cursor_blink && cursor_visible)
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;
}
@@ -294,56 +299,56 @@ bool PITerminal::isSpecialKey(int k) {
void PITerminal::initPrivate() {
#ifdef WINDOWS
PRIVATE->hConBuf = INVALID_HANDLE_VALUE;
PRIVATE->pipe = INVALID_HANDLE_VALUE;
# ifdef WINDOWS
PRIVATE->hConBuf = INVALID_HANDLE_VALUE;
PRIVATE->pipe = INVALID_HANDLE_VALUE;
PRIVATE->pi.hProcess = 0;
#else
# else
PRIVATE->shell = "/bin/bash";
PRIVATE->read_buf.reserve(BUFFER_SIZE);
PRIVATE->read_buf.fill(0);
PRIVATE->fd = PRIVATE->cur_x = PRIVATE->cur_y = 0;
PRIVATE->save_cur_x = PRIVATE->save_cur_y = 0;
PRIVATE->pid = 0;
PRIVATE->term_type = 0;
PRIVATE->is_esc_seq = false;
PRIVATE->last_read = true;
PRIVATE->pid = 0;
PRIVATE->term_type = 0;
PRIVATE->is_esc_seq = false;
PRIVATE->last_read = true;
PRIVATE->esc_seq.clear();
PRIVATE->cur_format = PIScreenTypes::CellFormat();
#endif
# endif
cursor_blink = cursor_visible = true;
size_x = size_y = 0;
}
void PITerminal::readConsole() {
#ifdef WINDOWS
# ifdef WINDOWS
if (!PRIVATE->shm) return;
PITerminalAuxData data;
PRIVATE->shm->read(&data, sizeof(data));
if (data.cells_size <= 4) return;
cursor_x = data.cursor_x;
cursor_y = data.cursor_y;
size_x = data.size_x;
size_y = data.size_y;
size_x = data.size_x;
size_y = data.size_y;
PIByteArray ba;
ba.resize(data.cells_size);
PRIVATE->shm->read(ba.data(), ba.size_s(), sizeof(data));
ba >> cells;
#endif
//piCout << cursor_x << cursor_y;
# endif
// piCout << cursor_x << cursor_y;
}
void PITerminal::getCursor(int & x, int & y) {
#ifdef WINDOWS
# ifdef WINDOWS
if (!PRIVATE->shm) return;
int sz = 0;
PRIVATE->shm->read(&sz, 4);
#else
x = PRIVATE->cur_x;
y = PRIVATE->cur_y;
#endif
# else
x = PRIVATE->cur_x;
y = PRIVATE->cur_y;
# endif
}
@@ -369,16 +374,16 @@ void PITerminal::run() {
cursor_tm.reset();
cursor_blink = !cursor_blink;
}
#ifndef WINDOWS
# ifdef HAS_FORKPTY
# ifndef WINDOWS
# ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return;
PRIVATE->tmp_buf.resize(BUFFER_SIZE);
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) {
PRIVATE->last_read = true;
//piCoutObj << "readed" << readed << PIString(PRIVATE->tmp_buf.resized(readed)).replaceAll("\e", "\\e");
//piCoutObj << "readed" << readed << (PRIVATE->tmp_buf.resized(readed));
// piCoutObj << "readed" << readed << PIString(PRIVATE->tmp_buf.resized(readed)).replaceAll("\e", "\\e");
// piCoutObj << "readed" << readed << (PRIVATE->tmp_buf.resized(readed));
PRIVATE->read_buf.append(PRIVATE->tmp_buf.resized(readed));
for (;;) {
int ind = -1;
@@ -394,28 +399,27 @@ void PITerminal::run() {
}
bool parse = PRIVATE->read_buf.size_s() >= BUFFER_SIZE;
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) {
parseInput(PIString(PRIVATE->read_buf));
parseInput(PIString::fromUTF8(PRIVATE->read_buf));
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()) {
parseInput(PIString(PRIVATE->read_buf));
parseInput(PIString::fromUTF8(PRIVATE->read_buf));
PRIVATE->read_buf.clear();
}
PRIVATE->last_read = false;
# endif
# endif
#endif
}
#ifndef WINDOWS
# ifndef WINDOWS
void PITerminal::parseInput(const PIString & s) {
//piCoutObj << s.replaceAll("\e", "\\e");
//printf("%s", s.data());
// piCoutObj << s.replaceAll("\e", "\\e");
// printf("%s", s.data());
for (int i = 0; i < s.size_s(); ++i) {
if (s[i].unicode16Code() == 0) break;
if (PRIVATE->is_esc_seq) {
@@ -428,7 +432,7 @@ void PITerminal::parseInput(const PIString & s) {
if (isCompleteEscSeq(PRIVATE->esc_seq)) {
PRIVATE->is_esc_seq = false;
applyEscSeq(PRIVATE->esc_seq);
//piCoutObj << PRIVATE->esc_seq;
// piCoutObj << PRIVATE->esc_seq;
}
}
} else {
@@ -443,14 +447,15 @@ void PITerminal::parseInput(const PIString & s) {
}
if (s[i] == '\r') continue;
if (s[i] == '\n') {
//piCoutObj << "new line";
for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format;
// piCoutObj << "new line";
for (int i = PRIVATE->cur_x; i < size_x; ++i)
cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format;
PRIVATE->line_format = PRIVATE->cur_format;
PRIVATE->cur_x = 0;
PRIVATE->cur_x = 0;
moveCursor(0, 1);
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].format = PRIVATE->cur_format;
moveCursor(1, 0);
@@ -474,10 +479,10 @@ bool PITerminal::isCompleteEscSeq(const PIString & es) {
void PITerminal::applyEscSeq(PIString es) {
piCoutObj << es;
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);
if (es[1] == '?' && es.size_s() >= 2) {
char a = es.takeRight(1)[0].toAscii();
char a = es.takeRight(1)[0].toAscii();
bool val = false;
if (a == 'l') val = false;
if (a == 'h') val = true;
@@ -497,7 +502,8 @@ void PITerminal::applyEscSeq(PIString es) {
case 1047:
if (val) {
PRIVATE->cells_save = cells;
for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell);
for (int i = 0; i < size_y; ++i)
cells[i].fill(def_cell);
} else {
cells = PRIVATE->cells_save;
}
@@ -512,7 +518,7 @@ void PITerminal::applyEscSeq(PIString es) {
return;
}
PIStringList args = es.split(";");
piForeachC (PIString & a, args) {
for (const auto & a: args) {
int av = a.toInt();
switch (av) {
case 0: PRIVATE->cur_format = PIScreenTypes::CellFormat(); break;
@@ -523,8 +529,14 @@ void PITerminal::applyEscSeq(PIString es) {
default: {
bool col = false, target = false;
int cid = av % 10;
if (av >= 30 && av <= 37) {col = true; target = false;}
if (av >= 40 && av <= 47) {col = true; target = true;}
if (av >= 30 && av <= 37) {
col = true;
target = false;
}
if (av >= 40 && av <= 47) {
col = true;
target = true;
}
if (col) {
int cfl = 0;
switch (cid) {
@@ -543,13 +555,13 @@ void PITerminal::applyEscSeq(PIString es) {
PRIVATE->cur_format.color_char = cfl;
break;
}
} break;
} break;
}
}
/*if ((PRIVATE->cur_format.flags & PIScreenTypes::Inverse) == PIScreenTypes::Inverse) {
uchar t = PRIVATE->cur_format.color_char;
PRIVATE->cur_format.color_char = PRIVATE->cur_format.color_back;
PRIVATE->cur_format.color_back = t;
uchar t = PRIVATE->cur_format.color_char;
PRIVATE->cur_format.color_char = PRIVATE->cur_format.color_back;
PRIVATE->cur_format.color_back = t;
}*/
}
if (es.back() == 'r') {
@@ -578,33 +590,37 @@ void PITerminal::applyEscSeq(PIString es) {
int x(0), y(0);
if (!args[0].isEmpty()) y = args[0].toInt() - 1;
if (!args[1].isEmpty()) x = args[1].toInt() - 1;
//piCoutObj << x << y;
PRIVATE->cur_x = piClamp(x, 0, size_x - 1);
PRIVATE->cur_y = piClamp(y, 0, size_y - 1);
// piCoutObj << x << y;
PRIVATE->cur_x = piClamp(x, 0, size_x - 1);
PRIVATE->cur_y = piClamp(y, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'A') { // cursor up
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'B') { // cursor down
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'C' || es.back() == 'a') { // cursor forward, next column
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1);
int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'D') { // cursor back
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1);
int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'G' || es.back() == '`') { // goto column
@@ -615,66 +631,92 @@ void PITerminal::applyEscSeq(PIString es) {
}
if (es.back() == 'd') { // goto line
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1);
int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'E' || es.back() == 'e') { // next line
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'F') { // previous line
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'L') { // insert lines
es.cutLeft(1).cutRight(1);
int v = es.toInt(); 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 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;
int v = es.toInt();
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 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
es.cutLeft(1).cutRight(1);
int v = es.toInt(); 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];
int v = es.toInt();
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 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) cells[j][i] = def_cell;
for (int i = 0; i < PRIVATE->cur_x; ++i)
cells[j][i] = def_cell;
}
if (es.back() == 'P') { // delete characters
es.cutLeft(1).cutRight(1);
int v = es.toInt(); 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 = size_x - v; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
int v = es.toInt();
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 = size_x - v; i < size_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
}
if (es.back() == '@') { // delete characters
es.cutLeft(1).cutRight(1);
int v = es.toInt(); 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 = PRIVATE->cur_x; i < PRIVATE->cur_x + v; ++i) cells[PRIVATE->cur_y][i] = def_cell;
int v = es.toInt();
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 = PRIVATE->cur_x; i < PRIVATE->cur_x + v; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
}
if (es.back() == 'J') { // erase data
es.cutLeft(1).cutRight(1);
int v = es.toInt();
switch (v) {
case 0:
for (int i = PRIVATE->cur_x; i < size_x; ++i) 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_x; i < size_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
for (int i = PRIVATE->cur_y + 1; i < size_y; ++i)
cells[i].fill(def_cell);
break;
case 1:
for (int i = 0; i <= PRIVATE->cur_x; ++i) 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_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
for (int i = 0; i < PRIVATE->cur_y; ++i)
cells[i].fill(def_cell);
break;
case 2:
for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell);
//PRIVATE->cur_x = PRIVATE->cur_y = 0;
for (int i = 0; i < size_y; ++i)
cells[i].fill(def_cell);
// PRIVATE->cur_x = PRIVATE->cur_y = 0;
break;
}
}
@@ -683,14 +725,14 @@ void PITerminal::applyEscSeq(PIString es) {
int v = es.toInt();
switch (v) {
case 0:
for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
for (int i = PRIVATE->cur_x; i < size_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
break;
case 1:
for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
break;
case 2:
cells[PRIVATE->cur_y].fill(def_cell);
for (int i = 0; i <= PRIVATE->cur_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
break;
case 2: cells[PRIVATE->cur_y].fill(def_cell); break;
}
}
}
@@ -704,12 +746,12 @@ void PITerminal::moveCursor(int dx, int dy) {
if (PRIVATE->cur_y < 0) PRIVATE->cur_y = 0;
if (PRIVATE->cur_x >= size_x) {
PRIVATE->line_format = PRIVATE->cur_format;
PRIVATE->cur_x = 0;
PRIVATE->cur_x = 0;
PRIVATE->cur_y++;
}
if (PRIVATE->cur_y >= size_y) {
int scroll = piMini(PRIVATE->cur_y - size_y + 1, size_y - 1);
//piCout << "scroll" << size_x << size_y << size_y - scroll - 1;
int scroll = piMini(PRIVATE->cur_y - size_y + 1, size_y - 1);
// piCout << "scroll" << size_x << size_y << size_y - scroll - 1;
PRIVATE->cur_y = size_y - 1;
for (int y = 0; y < size_y - scroll; ++y)
cells[y] = cells[y + scroll];
@@ -720,58 +762,76 @@ void PITerminal::moveCursor(int dx, int dy) {
int PITerminal::termType(const PIString & t) {
if (t == "xterm") return PIKbdListener::vt_xterm;
else if (t == "linux") return PIKbdListener::vt_linux;
if (t == "xterm")
return PIKbdListener::vt_xterm;
else if (t == "linux")
return PIKbdListener::vt_linux;
return PIKbdListener::vt_none;
}
#endif
# endif
bool PITerminal::initialize() {
destroy();
#ifdef WINDOWS
# ifdef WINDOWS
/*SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = true;
sa.lpSecurityDescriptor = 0;
if (!CreatePipe(&(PRIVATE->pipe_in[0]), &(PRIVATE->pipe_in[1]), &sa, 0)) {
piCoutObj << "CreatePipe error," << errorString();
initPrivate();
return false;
piCoutObj << "CreatePipe error," << errorString();
initPrivate();
return false;
}
PRIVATE->hConBuf = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, &sa, CONSOLE_TEXTMODE_BUFFER, 0);
if (PRIVATE->hConBuf == INVALID_HANDLE_VALUE) {
piCoutObj << "CreateConsoleScreenBuffer error," << errorString();
destroy();
return false;
piCoutObj << "CreateConsoleScreenBuffer error," << errorString();
destroy();
return false;
}*/
//CreatePipe(&(PRIVATE->pipe_out[0]), &(PRIVATE->pipe_out[1]), &sa, 0);
//SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0);
//SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0);
//GetStartupInfoA(&PRIVATE->si);
// CreatePipe(&(PRIVATE->pipe_out[0]), &(PRIVATE->pipe_out[1]), &sa, 0);
// SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0);
// SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0);
// GetStartupInfoA(&PRIVATE->si);
memset(&PRIVATE->si, 0, sizeof(PRIVATE->si));
PRIVATE->si.cb = sizeof(STARTUPINFO);
//PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES;
// PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES;
PRIVATE->si.dwFlags |= STARTF_USESHOWWINDOW;
PRIVATE->si.dwFlags |= STARTF_USECOUNTCHARS;
//PRIVATE->si.hStdInput = PRIVATE->pipe;
//PRIVATE->si.hStdOutput = PRIVATE->hConBuf;
//PRIVATE->si.hStdError = PRIVATE->hConBuf;
PRIVATE->si.wShowWindow = SW_HIDE;
// PRIVATE->si.hStdInput = PRIVATE->pipe;
// PRIVATE->si.hStdOutput = PRIVATE->hConBuf;
// PRIVATE->si.hStdError = PRIVATE->hConBuf;
PRIVATE->si.wShowWindow = SW_HIDE;
PRIVATE->si.dwXCountChars = 80;
PRIVATE->si.dwYCountChars = 24;
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 cmd = "piterminal \"" + shmh + "\" \"" + pname + "\"";
if(!CreateProcessA(0, (LPSTR)cmd.dataAscii(), 0, 0, false, CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, 0, 0, &PRIVATE->si, &PRIVATE->pi)) {
PIString cmd = "piterminal \"" + shmh + "\" \"" + pname + "\"";
if (!CreateProcessA(0,
(LPSTR)cmd.dataAscii(),
0,
0,
false,
CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
0,
0,
&PRIVATE->si,
&PRIVATE->pi)) {
piCoutObj << "CreateProcess error," << errorString();
destroy();
return false;
}
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);
PRIVATE->pipe = CreateNamedPipeA((LPSTR)pname.dataAscii(),
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) {
piCoutObj << "CreateNamedPipe error," << errorString();
destroy();
@@ -791,31 +851,33 @@ bool PITerminal::initialize() {
return false;
}
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);
resize(dsize_x, dsize_y);
#else
# ifdef HAS_FORKPTY
char pty[256]; memset(pty, 0, 256);
# else
# ifdef HAS_FORKPTY
char pty[256];
memset(pty, 0, 256);
winsize ws;
ws.ws_col = dsize_x;
ws.ws_row = dsize_y;
ws.ws_col = dsize_x;
ws.ws_row = dsize_y;
PIStringList env = PIProcess::currentEnvironment();
piForeachC (PIString & e, env)
for (const auto & e: env)
if (e.startsWith("TERM=")) {
PRIVATE->term_type = termType(e.mid(5).trim().toLowerCase());
//piCout << PRIVATE->term_type;
// piCout << PRIVATE->term_type;
break;
}
pid_t fr = forkpty(&(PRIVATE->fd), pty, 0, &ws);
//piCoutObj << fr << PRIVATE->fd << pty;
// piCoutObj << fr << PRIVATE->fd << pty;
if (fr == 0) {
char ** argv = new char*[2];
argv[0] = new char[PRIVATE->shell.lengthAscii() + 1];
memcpy(argv[0], PRIVATE->shell.dataAscii(), PRIVATE->shell.lengthAscii());
argv[0][PRIVATE->shell.lengthAscii()] = 0;
argv[1] = 0;
execvp(PRIVATE->shell.dataAscii(), argv);
char ** argv = new char *[2];
PIByteArray shell = PRIVATE->shell.toByteArray();
argv[0] = new char[shell.size() + 1];
memcpy(argv[0], shell.data(), shell.size());
argv[0][shell.size()] = 0;
argv[1] = 0;
execvp(argv[0], argv);
delete[] argv[0];
delete[] argv;
exit(0);
@@ -827,79 +889,77 @@ bool PITerminal::initialize() {
}
PRIVATE->pid = fr;
fcntl(PRIVATE->fd, F_SETFL, O_NONBLOCK);
/*
tcgetattr(PRIVATE->fd, &PRIVATE->desc);
PRIVATE->desc.c_oflag = PRIVATE->desc.c_lflag = PRIVATE->desc.c_cflag = 0;
PRIVATE->desc.c_iflag = IGNBRK;
PRIVATE->desc.c_cflag = CLOCAL | HUPCL;
PRIVATE->desc.c_cflag |= (CSIZE & CS8);
PRIVATE->desc.c_cflag |= CREAD;
PRIVATE->desc.c_cc[VMIN] = 1;
PRIVATE->desc.c_cc[VTIME] = 1;
/*
tcgetattr(PRIVATE->fd, &PRIVATE->desc);
PRIVATE->desc.c_oflag = PRIVATE->desc.c_lflag = PRIVATE->desc.c_cflag = 0;
PRIVATE->desc.c_iflag = IGNBRK;
PRIVATE->desc.c_cflag = CLOCAL | HUPCL;
PRIVATE->desc.c_cflag |= (CSIZE & CS8);
PRIVATE->desc.c_cflag |= CREAD;
PRIVATE->desc.c_cc[VMIN] = 1;
PRIVATE->desc.c_cc[VTIME] = 1;
cfsetispeed(&PRIVATE->desc, B38400);
cfsetospeed(&PRIVATE->desc, B38400);
cfsetispeed(&PRIVATE->desc, B38400);
cfsetospeed(&PRIVATE->desc, B38400);
if (tcsetattr(PRIVATE->fd, TCSANOW, &PRIVATE->desc) < 0) {
piCoutObj << "Can`t set attributes for \"" << pty << "\"";
destroy();
return false;
}
*/
if (tcsetattr(PRIVATE->fd, TCSANOW, &PRIVATE->desc) < 0) {
piCoutObj << "Can`t set attributes for \"" << pty << "\"";
destroy();
return false;
}
*/
size_x = dsize_x;
size_y = dsize_y;
resize(size_x, size_y);
}
# endif
# endif
#endif
cursor_blink = false;
cursor_tm.reset();
start(40);
start(25_Hz);
return true;
}
void PITerminal::destroy() {
//piCout << "destroy ...";
// piCout << "destroy ...";
stop();
waitForFinish(1000);
#ifdef WINDOWS
waitForFinish(1_s);
# ifdef WINDOWS
if (PRIVATE->pi.hProcess) {
//piCout << "term";
//TerminateProcess(PRIVATE->pi.hProcess, 0);
// piCout << "term";
// TerminateProcess(PRIVATE->pi.hProcess, 0);
GenerateConsoleCtrlEvent(CTRL_C_EVENT, PRIVATE->pi.dwProcessId);
CloseHandle(PRIVATE->pi.hProcess);
}
if (PRIVATE->pipe != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->pipe);
if (PRIVATE->hConBuf != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->hConBuf);
//piCout << "destroy" << size_y;
#else
# ifdef HAS_FORKPTY
if (PRIVATE->pid != 0)
kill(PRIVATE->pid, SIGKILL);
if (PRIVATE->fd != 0)
::close(PRIVATE->fd);
// piCout << "destroy" << size_y;
# else
# ifdef HAS_FORKPTY
if (PRIVATE->pid != 0) kill(PRIVATE->pid, SIGKILL);
if (PRIVATE->fd != 0) ::close(PRIVATE->fd);
# endif
# endif
#endif
initPrivate();
}
bool PITerminal::resize(int cols, int rows) {
bool ret = true;
dsize_x = cols;
dsize_y = rows;
#ifdef WINDOWS
dsize_x = cols;
dsize_y = rows;
# ifdef WINDOWS
if (PRIVATE->pipe == INVALID_HANDLE_VALUE) return false;
PIByteArray msg;
msg << int(mtResize) << dsize_x << dsize_y;
writePipe(PRIVATE->pipe, msg);
#else
# ifdef HAS_FORKPTY
# else
# ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return false;
size_x = dsize_x;
size_y = dsize_y;
//piCout << "resize" << PRIVATE->fd << size_x << size_y;
// piCout << "resize" << PRIVATE->fd << size_x << size_y;
winsize ws;
ws.ws_col = cols;
ws.ws_row = rows;
@@ -909,12 +969,12 @@ bool PITerminal::resize(int cols, int rows) {
PRIVATE->cells_save.resize(size_y);
for (int i = 0; i < size_y; ++i)
PRIVATE->cells_save[i].resize(size_x);
# endif
# endif
#endif
cells.resize(size_y);
for (int i = 0; i < size_y; ++i)
cells[i].resize(size_x);
return ret;
}
#endif // FREERTOS
#endif // MICRO_PIP

View File

@@ -1,297 +1,297 @@
/*
PIP - Platform Independent Primitives
PIP Authentication API
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 "piauth.h"
#define PIAUTH_NOISE_MAX_SIZE 256
PIAuth::PIAuth(const PIByteArray & sign) : PIObject() {
setName("Client");
role = Client;
state = NotConnected;
sign_sk = sign;
sign_pk = crypt.extractSignPublicKey(sign);
}
void PIAuth::setServerPassword(const PIString & ps) {
pass_hash = crypt.passwordHash(ps, PIString("PIAuth").toByteArray());
}
void PIAuth::stop() {
role = Client;
state = NotConnected;
auth_sign.clear();
box_sk.clear();
box_pk.clear();
my_pk.clear();
}
void PIAuth::startClient() {
role = Client;
state = AuthProbe;
}
PIByteArray PIAuth::startServer() {
setName("Server");
role = Server;
state = AuthProbe;
PIByteArray ba;
crypt.generateKeypair(my_pk, box_sk);
PIByteArray noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE+128);
ba << (int)state << custom_info << sign_pk << my_pk << noise;
PIByteArray sign = crypt.signMessage(ba, sign_sk);
ba << sign;
return ba;
}
PIAuth::State PIAuth::receive(PIByteArray & ba) {
if (ba.size() < sizeof(int)) return disconnect(ba, "invalid data size");
State rstate;
int s;
ba >> s;
rstate = (State)s;
// if (state != rstate) return disconect(ba);
//client side
if (role == Client) {
if (state == AuthProbe && rstate == AuthProbe) {
if (ba.size() < sizeof(int)*5) return disconnect(ba, "invalid data size");
PIByteArray rinfo;
PIByteArray rsign;
PIByteArray rsign_pk;
PIByteArray noise;
ba >> rinfo >> rsign_pk >> box_pk >> noise >> rsign;
if (rsign_pk.isEmpty() || box_pk.isEmpty() || rsign.isEmpty()) return disconnect(ba, "invalid key size");
PIByteArray tba;
tba << (int)rstate << rinfo << rsign_pk << box_pk << noise;
if (!crypt.verifySign(tba, rsign, rsign_pk)) return disconnect(ba, "Incorrect sign");
bool auth = false;
if (isAuthorizedKey(rsign_pk)) {
auth = true;
} else {
authorize(rinfo, &auth);
if (auth) auth_pkeys << rsign_pk;
}
if (!auth) return disconnect(ba, "Unauthorised");
ba.clear();
auth_sign = rsign_pk;
crypt.generateKeypair(my_pk, box_sk);
tba.clear();
tba << sign_pk << my_pk << box_pk;
PIByteArray sign = crypt.signMessage(tba, sign_sk);
tba << sign;
tba = crypt.crypt(tba, box_pk, box_sk);
state = AuthReply;
noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
ba << (int)state << tba << my_pk << noise;
sign = crypt.signMessage(ba, sign_sk);
ba << sign;
return state;
}
if (state == AuthReply && rstate == PassRequest) {
PIByteArray ctba, tba;
PIByteArray noise;
PIByteArray rsign, rsign_pk;
ba >> ctba >> rsign;
bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear();
ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
ctba.clear();
tba >> rsign_pk >> noise >> ctba;
if (rsign_pk != auth_sign || ctba != my_pk) return disconnect(ba, "Invalid public key");
PIString ps;
PIByteArray ph;
passwordRequest(&ps);
if (ps.isEmpty()) return disconnect(ba, "Canceled by user");
ph = crypt.passwordHash(ps, PIString("PIAuth").toByteArray());
ps.fill(PIChar(0));
tba.clear();
tba << ph << auth_sign << sign_pk;
tba = crypt.crypt(tba, box_pk, box_sk);
ba.clear();
state = PassRequest;
ba << (int)state << tba;
rsign = crypt.signMessage(ba, sign_sk);
ba << rsign;
return state;
}
if ((state == AuthReply && rstate == KeyExchange) || (state == PassRequest && rstate == KeyExchange)) {
PIByteArray tba, ctba;
PIByteArray rsign;
ba >> ctba >> rsign;
bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear();
ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
tba >> secret_key;
if (secret_key.size() != crypt.sizeKey()) return disconnect(ba, "Invalid key");
ba.clear();
state = Connected;
connected(PIString());
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state;
}
if (state == Connected && rstate == Connected) {
ba.clear();
state = Connected;
connected(PIString());
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state;
}
}
// server side
if (role == Server) {
if (state == AuthProbe && rstate == AuthReply) {
if (ba.size() < sizeof(int)*4) return disconnect(ba, "invalid data size");
PIByteArray ctba, tba;
PIByteArray noise;
PIByteArray rsign1, rsign2;
PIByteArray rsign_pk;
PIByteArray pk, mpk;
ba >> ctba >> pk >> noise >> rsign1;
bool ok = false;
tba = crypt.decrypt(ctba, pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
if (tba.size() < sizeof(int)*3) return disconnect(tba, "invalid data size");
tba >> rsign_pk >> box_pk >> mpk >> rsign2;
if (pk != box_pk || mpk != my_pk) return disconnect(ba, "Invalid public key");
ba.clear();
ba << (int)rstate << ctba << box_pk << noise;
if (!crypt.verifySign(ba, rsign1, rsign_pk)) return disconnect(ba, "Incorrect sign");
ba.clear();
ba << rsign_pk << box_pk << my_pk;
if (!crypt.verifySign(ba, rsign2, rsign_pk)) return disconnect(ba, "Incorrect sign");
auth_sign = rsign_pk;
if (isAuthorizedKey(rsign_pk)) {
state = KeyExchange;
ba = createSKMessage();
return state;
} else {
ba.clear();
tba.clear();
state = PassRequest;
noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
tba << sign_pk << noise << box_pk;
tba = crypt.crypt(tba, box_pk, box_sk);
ba << (int)state << tba;
rsign1 = crypt.signMessage(ba, sign_sk);
ba << rsign1;
return state;
}
}
if (state == PassRequest && rstate == PassRequest) {
PIByteArray tba, ctba;
PIByteArray rsign_pk, rsign, mpk;
ba >> ctba >> rsign;
bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear();
ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
ctba.clear();
tba >> ctba >> mpk >> rsign_pk;
if (rsign_pk != auth_sign || mpk != sign_pk) return disconnect(ba, "Invalid public key");
bool auth = (ctba == pass_hash);
if (ctba.isEmpty() || pass_hash.isEmpty()) auth = false;
passwordCheck(auth);
if (!auth) {
// piSleep(1);
return disconnect(ba, "Invalid password");
}
state = KeyExchange;
ba = createSKMessage();
return state;
}
if ((state == KeyExchange && rstate == Connected) || (state == Connected && rstate == Connected)) {
ba.clear();
PIByteArray rinfo;
ba >> rinfo;
bool ok = false;
rinfo = crypt.decrypt(rinfo, secret_key, &ok);
if (!ok) return disconnect(ba, "Error while exchange keys");
state = Connected;
connected(rinfo);
ba << (int)state << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state;
}
}
return disconnect(ba, "invalid state " + PIString::fromNumber((int)state));
}
PIByteArray PIAuth::getSecretKey() {
if (state == Connected) return secret_key;
return PIByteArray();
}
PIByteArray PIAuth::generateSign(const PIByteArray & seed) {
PIByteArray pk, sk;
PICrypt::generateSignKeys(pk, sk, seed);
return sk;
}
PIAuth::State PIAuth::disconnect(PIByteArray & ba, const PIString & error) {
if (!error.isEmpty()) piCoutObj << error;
auth_sign.clear();
box_sk.clear();
box_pk.clear();
my_pk.clear();
secret_key.clear();
ba.clear();
state = NotConnected;
disconnected(error);
return state;
}
bool PIAuth::isAuthorizedKey(const PIByteArray & pkey) {
for (int i=0; i<auth_pkeys.size_s(); ++i) {
if (pkey == auth_pkeys[i]) return true;
}
return false;
}
PIByteArray PIAuth::createSKMessage() {
secret_key = crypt.generateKey();
PIByteArray tba;
PIByteArray noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
tba << secret_key << noise;
tba = crypt.crypt(tba, box_pk, box_sk);
PIByteArray ret;
ret << (int)state << tba;
PIByteArray sign = crypt.signMessage(ret, sign_sk);
ret << sign;
return ret;
}
/*
PIP - Platform Independent Primitives
PIP Authentication API
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 "piauth.h"
#define PIAUTH_NOISE_MAX_SIZE 256
PIAuth::PIAuth(const PIByteArray & sign): PIObject() {
setName("Client");
role = Client;
state = NotConnected;
sign_sk = sign;
sign_pk = crypt.extractSignPublicKey(sign);
}
void PIAuth::setServerPassword(const PIString & ps) {
pass_hash = crypt.passwordHash(ps, PIString("PIAuth").toByteArray());
}
void PIAuth::stop() {
role = Client;
state = NotConnected;
auth_sign.clear();
box_sk.clear();
box_pk.clear();
my_pk.clear();
}
void PIAuth::startClient() {
role = Client;
state = AuthProbe;
}
PIByteArray PIAuth::startServer() {
setName("Server");
role = Server;
state = AuthProbe;
PIByteArray ba;
crypt.generateKeypair(my_pk, box_sk);
PIByteArray noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE + 128);
ba << (int)state << custom_info << sign_pk << my_pk << noise;
PIByteArray sign = crypt.signMessage(ba, sign_sk);
ba << sign;
return ba;
}
PIAuth::State PIAuth::receive(PIByteArray & ba) {
if (ba.size() < sizeof(int)) return disconnect(ba, "invalid data size");
State rstate;
int s;
ba >> s;
rstate = (State)s;
// if (state != rstate) return disconect(ba);
// client side
if (role == Client) {
if (state == AuthProbe && rstate == AuthProbe) {
if (ba.size() < sizeof(int) * 5) return disconnect(ba, "invalid data size");
PIByteArray rinfo;
PIByteArray rsign;
PIByteArray rsign_pk;
PIByteArray noise;
ba >> rinfo >> rsign_pk >> box_pk >> noise >> rsign;
if (rsign_pk.isEmpty() || box_pk.isEmpty() || rsign.isEmpty()) return disconnect(ba, "invalid key size");
PIByteArray tba;
tba << (int)rstate << rinfo << rsign_pk << box_pk << noise;
if (!crypt.verifySign(tba, rsign, rsign_pk)) return disconnect(ba, "Incorrect sign");
bool auth = false;
if (isAuthorizedKey(rsign_pk)) {
auth = true;
} else {
authorize(rinfo, &auth);
if (auth) auth_pkeys << rsign_pk;
}
if (!auth) return disconnect(ba, "Unauthorised");
ba.clear();
auth_sign = rsign_pk;
crypt.generateKeypair(my_pk, box_sk);
tba.clear();
tba << sign_pk << my_pk << box_pk;
PIByteArray sign = crypt.signMessage(tba, sign_sk);
tba << sign;
tba = crypt.crypt(tba, box_pk, box_sk);
state = AuthReply;
noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
ba << (int)state << tba << my_pk << noise;
sign = crypt.signMessage(ba, sign_sk);
ba << sign;
return state;
}
if (state == AuthReply && rstate == PassRequest) {
PIByteArray ctba, tba;
PIByteArray noise;
PIByteArray rsign, rsign_pk;
ba >> ctba >> rsign;
bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear();
ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
ctba.clear();
tba >> rsign_pk >> noise >> ctba;
if (rsign_pk != auth_sign || ctba != my_pk) return disconnect(ba, "Invalid public key");
PIString ps;
PIByteArray ph;
passwordRequest(&ps);
if (ps.isEmpty()) return disconnect(ba, "Canceled by user");
ph = crypt.passwordHash(ps, PIString("PIAuth").toByteArray());
ps.fill(PIChar());
tba.clear();
tba << ph << auth_sign << sign_pk;
tba = crypt.crypt(tba, box_pk, box_sk);
ba.clear();
state = PassRequest;
ba << (int)state << tba;
rsign = crypt.signMessage(ba, sign_sk);
ba << rsign;
return state;
}
if ((state == AuthReply && rstate == KeyExchange) || (state == PassRequest && rstate == KeyExchange)) {
PIByteArray tba, ctba;
PIByteArray rsign;
ba >> ctba >> rsign;
bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear();
ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
tba >> secret_key;
if (secret_key.size() != crypt.sizeKey()) return disconnect(ba, "Invalid key");
ba.clear();
state = Connected;
connected(PIString());
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
return state;
}
if (state == Connected && rstate == Connected) {
ba.clear();
state = Connected;
connected(PIString());
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
return state;
}
}
// server side
if (role == Server) {
if (state == AuthProbe && rstate == AuthReply) {
if (ba.size() < sizeof(int) * 4) return disconnect(ba, "invalid data size");
PIByteArray ctba, tba;
PIByteArray noise;
PIByteArray rsign1, rsign2;
PIByteArray rsign_pk;
PIByteArray pk, mpk;
ba >> ctba >> pk >> noise >> rsign1;
bool ok = false;
tba = crypt.decrypt(ctba, pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
if (tba.size() < sizeof(int) * 3) return disconnect(tba, "invalid data size");
tba >> rsign_pk >> box_pk >> mpk >> rsign2;
if (pk != box_pk || mpk != my_pk) return disconnect(ba, "Invalid public key");
ba.clear();
ba << (int)rstate << ctba << box_pk << noise;
if (!crypt.verifySign(ba, rsign1, rsign_pk)) return disconnect(ba, "Incorrect sign");
ba.clear();
ba << rsign_pk << box_pk << my_pk;
if (!crypt.verifySign(ba, rsign2, rsign_pk)) return disconnect(ba, "Incorrect sign");
auth_sign = rsign_pk;
if (isAuthorizedKey(rsign_pk)) {
state = KeyExchange;
ba = createSKMessage();
return state;
} else {
ba.clear();
tba.clear();
state = PassRequest;
noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
tba << sign_pk << noise << box_pk;
tba = crypt.crypt(tba, box_pk, box_sk);
ba << (int)state << tba;
rsign1 = crypt.signMessage(ba, sign_sk);
ba << rsign1;
return state;
}
}
if (state == PassRequest && rstate == PassRequest) {
PIByteArray tba, ctba;
PIByteArray rsign_pk, rsign, mpk;
ba >> ctba >> rsign;
bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear();
ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
ctba.clear();
tba >> ctba >> mpk >> rsign_pk;
if (rsign_pk != auth_sign || mpk != sign_pk) return disconnect(ba, "Invalid public key");
bool auth = (ctba == pass_hash);
if (ctba.isEmpty() || pass_hash.isEmpty()) auth = false;
passwordCheck(auth);
if (!auth) {
// piSleep(1);
return disconnect(ba, "Invalid password");
}
state = KeyExchange;
ba = createSKMessage();
return state;
}
if ((state == KeyExchange && rstate == Connected) || (state == Connected && rstate == Connected)) {
ba.clear();
PIByteArray rinfo;
ba >> rinfo;
bool ok = false;
rinfo = crypt.decrypt(rinfo, secret_key, &ok);
if (!ok) return disconnect(ba, "Error while exchange keys");
state = Connected;
connected(PIString::fromUTF8(rinfo));
ba << (int)state << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
return state;
}
}
return disconnect(ba, "invalid state " + PIString::fromNumber((int)state));
}
PIByteArray PIAuth::getSecretKey() {
if (state == Connected) return secret_key;
return PIByteArray();
}
PIByteArray PIAuth::generateSign(const PIByteArray & seed) {
PIByteArray pk, sk;
PICrypt::generateSignKeys(pk, sk, seed);
return sk;
}
PIAuth::State PIAuth::disconnect(PIByteArray & ba, const PIString & error) {
if (!error.isEmpty()) piCoutObj << error;
auth_sign.clear();
box_sk.clear();
box_pk.clear();
my_pk.clear();
secret_key.clear();
ba.clear();
state = NotConnected;
disconnected(error);
return state;
}
bool PIAuth::isAuthorizedKey(const PIByteArray & pkey) {
for (int i = 0; i < auth_pkeys.size_s(); ++i) {
if (pkey == auth_pkeys[i]) return true;
}
return false;
}
PIByteArray PIAuth::createSKMessage() {
secret_key = crypt.generateKey();
PIByteArray tba;
PIByteArray noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
tba << secret_key << noise;
tba = crypt.crypt(tba, box_pk, box_sk);
PIByteArray ret;
ret << (int)state << tba;
PIByteArray sign = crypt.signMessage(ret, sign_sk);
ret << sign;
return ret;
}

View File

@@ -1,435 +1,376 @@
/*
PIP - Platform Independent Primitives
Cryptographic class using lib Sodium
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 "picrypt.h"
#ifdef PIP_CRYPT
# include <sodium.h>
#endif
#define PICRYPT_DISABLED_WARNING piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and rebuild pip";
const char hash_def_key[] = "_picrypt_\0\0\0\0\0\0\0";
const int hash_def_key_size = 9;
PICrypt::PICrypt() {
#ifdef PIP_CRYPT
if (!init()) piCout << "[PICrypt]" << "Error while initialize sodium!";
nonce_.resize(crypto_secretbox_NONCEBYTES);
key_.resize(crypto_secretbox_KEYBYTES);
randombytes_buf(key_.data(), key_.size());
randombytes_buf(nonce_.data(), nonce_.size());
#else
PICRYPT_DISABLED_WARNING
#endif
}
bool PICrypt::setKey(const PIByteArray & _key) {
if (_key.size() != key_.size()) return false;
key_ = _key;
return true;
}
PIByteArray PICrypt::setKey(const PIString & secret) {
PIByteArray hash;
#ifdef PIP_CRYPT
hash.resize(crypto_generichash_BYTES);
PIByteArray s(secret.data(), secret.size());
crypto_generichash(hash.data(), hash.size(), s.data(), s.size(), (const uchar*)hash_def_key, hash_def_key_size);
hash.resize(key_.size());
setKey(hash);
#endif
return hash;
}
PIByteArray PICrypt::crypt(const PIByteArray & data) {
PIByteArray ret;
#ifdef PIP_CRYPT
ret.resize(data.size() + crypto_secretbox_MACBYTES);
randombytes_buf(nonce_.data(), nonce_.size());
crypto_secretbox_easy(ret.data(), data.data(), data.size(), nonce_.data(), key_.data());
ret.append(nonce_);
#endif
return ret;
}
PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (key.size() != crypto_secretbox_KEYBYTES)
key.resize(crypto_secretbox_KEYBYTES, ' ');
//return PIByteArray();
if (!init()) return ret;
PIByteArray n;
ret.resize(data.size() + crypto_secretbox_MACBYTES);
n.resize(crypto_secretbox_NONCEBYTES);
randombytes_buf(n.data(), n.size());
crypto_secretbox_easy(ret.data(), data.data(), data.size(), n.data(), key.data());
ret.append(n);
#else
PICRYPT_DISABLED_WARNING
#endif
return ret;
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool *ok) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (crypt_data.size() < nonce_.size() + crypto_secretbox_MACBYTES) {
if (ok) *ok = false;
return PIByteArray();
}
ret.resize(crypt_data.size() - nonce_.size() - crypto_secretbox_MACBYTES);
memcpy(nonce_.data(), crypt_data.data(crypt_data.size() - nonce_.size()), nonce_.size());
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - nonce_.size(), nonce_.data(), key_.data()) != 0) {
if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_";
return PIByteArray();
}
#endif
if (ok) *ok = true;
return ret;
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bool *ok) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (key.size() != crypto_secretbox_KEYBYTES)
key.resize(crypto_secretbox_KEYBYTES, ' ');
/*if (ok) *ok = false;
return PIByteArray();
}*/
if (crypt_data.size() < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES) {
if (ok) *ok = false;
return PIByteArray();
}
if (!init()) 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_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), key.data()) != 0) {
if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_";
return PIByteArray();
} else if (ok) *ok = true;
#else
PICRYPT_DISABLED_WARNING
#endif
return ret;
}
PIByteArray PICrypt::hash(const PIString & secret) {
PIByteArray hash;
#ifdef PIP_CRYPT
if (!init()) return hash;
hash.resize(crypto_generichash_BYTES);
PIByteArray s(secret.data(), secret.size());
crypto_generichash(hash.data(), hash.size(), s.data(), s.size(),(const uchar*)hash_def_key, hash_def_key_size);
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
PIByteArray PICrypt::hash(const PIByteArray & data) {
PIByteArray hash;
#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);
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
size_t PICrypt::sizeHash() {
#ifdef PIP_CRYPT
return crypto_generichash_BYTES;
#else
PICRYPT_DISABLED_WARNING
#endif
return 0;
}
ullong PICrypt::shorthash(const PIString& s, PIByteArray key) {
ullong hash = 0;
#ifdef PIP_CRYPT
if (crypto_shorthash_BYTES != sizeof(hash)) piCout << "[PICrypt]" << "internal error: bad hash size";
if (!init()) return hash;
if (key.size() != crypto_shorthash_KEYBYTES) {
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());
crypto_shorthash((uchar *)&hash, in.data(), in.size(), key.data());
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
PIByteArray PICrypt::generateKey() {
PIByteArray hash;
#ifdef PIP_CRYPT
if (!init()) return hash;
hash.resize(crypto_secretbox_KEYBYTES);
randombytes_buf(hash.data(), hash.size());
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
PIByteArray PICrypt::generateRandomBuff(int size) {
PIByteArray hash;
#ifdef PIP_CRYPT
if (!init() || size <= 0) return hash;
hash.resize(size);
randombytes_buf(hash.data(), hash.size());
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
size_t PICrypt::sizeKey() {
#ifdef PIP_CRYPT
return crypto_secretbox_KEYBYTES;
#else
PICRYPT_DISABLED_WARNING
#endif
return 0;
}
size_t PICrypt::sizeCrypt() {
#ifdef PIP_CRYPT
return crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES;
#else
PICRYPT_DISABLED_WARNING
#endif
return 0;
}
void PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key) {
#ifdef PIP_CRYPT
if (!init()) return;
public_key.resize(crypto_sign_PUBLICKEYBYTES);
secret_key.resize(crypto_sign_SECRETKEYBYTES);
crypto_sign_keypair(public_key.data(), secret_key.data());
#else
PICRYPT_DISABLED_WARNING
#endif
}
void PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) {
#ifdef PIP_CRYPT
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());
#else
PICRYPT_DISABLED_WARNING
#endif
}
PIByteArray PICrypt::extractSignPublicKey(const PIByteArray & secret_key) {
PIByteArray pk;
#ifdef PIP_CRYPT
if (!init() || secret_key.size() != crypto_sign_SECRETKEYBYTES) return pk;
pk.resize(crypto_sign_PUBLICKEYBYTES);
crypto_sign_ed25519_sk_to_pk(pk.data(), secret_key.data());
#else
PICRYPT_DISABLED_WARNING
#endif
return pk;
}
PIByteArray PICrypt::signMessage(const PIByteArray & data, PIByteArray secret_key) {
PIByteArray sign;
#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());
#else
PICRYPT_DISABLED_WARNING
#endif
return sign;
}
bool PICrypt::verifySign(const PIByteArray & data, const PIByteArray & signature, PIByteArray public_key) {
#ifdef PIP_CRYPT
if (!init()) return false;
return (crypto_sign_verify_detached(signature.data(), data.data(), data.size(), public_key.data()) == 0);
#else
PICRYPT_DISABLED_WARNING
#endif
return false;
}
void PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key) {
#ifdef PIP_CRYPT
if (!init()) return;
public_key.resize(crypto_box_PUBLICKEYBYTES);
secret_key.resize(crypto_box_SECRETKEYBYTES);
crypto_box_keypair(public_key.data(), secret_key.data());
#else
PICRYPT_DISABLED_WARNING
#endif
}
void PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) {
#ifdef PIP_CRYPT
if (!init()) return;
public_key.resize(crypto_box_PUBLICKEYBYTES);
secret_key.resize(crypto_box_SECRETKEYBYTES);
crypto_box_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data());
#else
PICRYPT_DISABLED_WARNING
#endif
}
PIByteArray PICrypt::crypt(const PIByteArray & data, const PIByteArray & public_key, const PIByteArray & secret_key) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (!init()) return ret;
if (public_key.size() != crypto_box_PUBLICKEYBYTES)
return ret;
if (secret_key.size() != crypto_box_SECRETKEYBYTES)
return ret;
PIByteArray n;
ret.resize(data.size() + crypto_box_MACBYTES);
n.resize(crypto_box_NONCEBYTES);
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();
ret.append(n);
#else
PICRYPT_DISABLED_WARNING
#endif
return ret;
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray & public_key, const PIByteArray & secret_key, bool * ok) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (!init()) return ret;
if (public_key.size() != crypto_box_PUBLICKEYBYTES) {
if (ok) *ok = false;
return ret;
}
if (secret_key.size() != crypto_box_SECRETKEYBYTES) {
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;
}
/*
PIP - Platform Independent Primitives
Cryptographic class using lib Sodium
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 "picrypt.h"
#include "pitranslator.h"
#include <sodium.h>
namespace {
constexpr char hash_def_key[] = "_picrypt_\0\0\0\0\0\0\0";
constexpr int hash_def_key_size = 9;
} // namespace
PICrypt::PICrypt() {
if (!init()) {
piCout << "[PICrypt]"
<< "Error while initialize sodium!"_tr("PICrypt");
}
nonce_.resize(crypto_secretbox_NONCEBYTES);
key_.resize(crypto_secretbox_KEYBYTES);
randombytes_buf(key_.data(), key_.size());
randombytes_buf(nonce_.data(), nonce_.size());
}
PICrypt::~PICrypt() {
key_.fill(0);
nonce_.fill(0);
}
bool PICrypt::setKey(const PIByteArray & _key) {
if (_key.size() != key_.size()) return false;
key_ = _key;
return true;
}
bool PICrypt::setKey(const PIString & secret) {;
key_ = hash(secret);
return key_.isNotEmpty();
}
PIByteArray PICrypt::crypt(const PIByteArray & data) {
PIByteArray ret;
ret.resize(data.size() + crypto_secretbox_MACBYTES);
randombytes_buf(nonce_.data(), nonce_.size());
if (crypto_secretbox_easy(ret.data(), data.data(), data.size(), nonce_.data(), key_.data()) != 0) {
ret.clear();
} else {
ret.append(nonce_);
}
return ret;
}
PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) {
if (!init()) {
key.fill(0);
return PIByteArray();
}
if (key.size() != crypto_secretbox_KEYBYTES) key.resize(crypto_secretbox_KEYBYTES, ' ');
PIByteArray n;
n.resize(crypto_secretbox_NONCEBYTES);
PIByteArray ret;
ret.resize(data.size() + crypto_secretbox_MACBYTES);
randombytes_buf(n.data(), n.size());
if (crypto_secretbox_easy(ret.data(), data.data(), data.size(), n.data(), key.data()) != 0) {
ret.clear();
} else {
ret.append(n);
}
key.fill(0);
return ret;
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool * ok) {
if (crypt_data.size() < nonce_.size() + crypto_secretbox_MACBYTES) {
if (ok) *ok = false;
return PIByteArray();
}
const ullong data_size = crypt_data.size() - nonce_.size();
PIByteArray ret;
ret.resize(data_size - crypto_secretbox_MACBYTES);
memcpy(nonce_.data(), crypt_data.data(data_size), nonce_.size());
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), data_size, nonce_.data(), key_.data()) != 0) {
// Bad key
if (ok) *ok = false;
ret.clear();
} else if (ok) {
*ok = true;
}
return ret;
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bool * ok) {
if (!init()) {
key.fill(0);
return PIByteArray();
}
if (crypt_data.size() < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES) {
if (ok) *ok = false;
key.fill(0);
return PIByteArray();
}
if (key.size() != crypto_secretbox_KEYBYTES) key.resize(crypto_secretbox_KEYBYTES, ' ');
PIByteArray n;
n.resize(crypto_secretbox_NONCEBYTES);
const ullong data_size = crypt_data.size() - n.size();
PIByteArray ret;
ret.resize(data_size - crypto_secretbox_MACBYTES);
memcpy(n.data(), crypt_data.data(data_size), n.size());
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), data_size, n.data(), key.data()) != 0) {
// Bad key
if (ok) *ok = false;
ret.clear();
} else if (ok) {
*ok = true;
}
key.fill(0);
return ret;
}
PIByteArray PICrypt::hash(PIString secret) {
if (!init()) return {};
PIByteArray s = secret.toUTF8();
PIByteArray h = hash(s);
memset(const_cast<char *>(secret.data()), 0, s.size());
secret.fill('\0');
s.fill(0);
return h;
}
PIByteArray PICrypt::hash(const PIByteArray & data) {
if (!init()) return {};
PIByteArray h;
h.resize(crypto_generichash_BYTES);
crypto_generichash(h.data(), h.size(), data.data(), data.size(), (const uchar *)hash_def_key, hash_def_key_size);
return h;
}
PIByteArray PICrypt::hash(const PIByteArray & data, const unsigned char * key, size_t keylen) {
PIByteArray hash;
if (!init()) return hash;
hash.resize(crypto_generichash_BYTES);
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), key, keylen);
return hash;
}
size_t PICrypt::sizeHash() {
return crypto_generichash_BYTES;
}
ullong PICrypt::shorthash(const PIString & s, PIByteArray key) {
ullong hash = 0;
if (!init()) {
key.fill(0);
return hash;
}
if (crypto_shorthash_BYTES != sizeof(hash))
piCout << "[PICrypt]"
<< "internal error: bad hash size"_tr("PICrypt");
if (key.size() != crypto_shorthash_KEYBYTES) {
piCout << "[PICrypt]"
<< "invalid key size %1, should be %2, filled with zeros"_tr("PICrypt").arg(key.size()).arg(crypto_shorthash_KEYBYTES);
key.resize(crypto_shorthash_KEYBYTES, 0);
}
PIByteArray in(s.data(), s.size());
crypto_shorthash((uchar *)&hash, in.data(), in.size(), key.data());
key.fill(0);
return hash;
}
PIByteArray PICrypt::generateKey() {
return generateRandomBuff(sizeKey());
}
PIByteArray PICrypt::generateRandomBuff(int size) {
PIByteArray hash;
if (!init() || size <= 0) return hash;
hash.resize(size);
randombytes_buf(hash.data(), hash.size());
return hash;
}
size_t PICrypt::sizeKey() {
return crypto_secretbox_KEYBYTES;
}
size_t PICrypt::sizeCrypt() {
return crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES;
}
bool PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key) {
if (!init()) return false;
public_key.resize(crypto_sign_PUBLICKEYBYTES);
secret_key.resize(crypto_sign_SECRETKEYBYTES);
return crypto_sign_keypair(public_key.data(), secret_key.data()) == 0;
}
bool PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) {
if (!init() || seed.isEmpty()) return false;
public_key.resize(crypto_sign_PUBLICKEYBYTES);
secret_key.resize(crypto_sign_SECRETKEYBYTES);
return crypto_sign_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data()) == 0;
}
PIByteArray PICrypt::extractSignPublicKey(const PIByteArray & secret_key) {
PIByteArray pk;
if (!init() || secret_key.size() != crypto_sign_SECRETKEYBYTES) return pk;
pk.resize(crypto_sign_PUBLICKEYBYTES);
if (crypto_sign_ed25519_sk_to_pk(pk.data(), secret_key.data()) != 0) {
pk.clear();
}
return pk;
}
PIByteArray PICrypt::signMessage(const PIByteArray & data, const PIByteArray & secret_key) {
PIByteArray sign;
if (!init()) return sign;
sign.resize(crypto_sign_BYTES);
if (crypto_sign_detached(sign.data(), 0, data.data(), data.size(), secret_key.data()) != 0) {
sign.clear();
}
return sign;
}
bool PICrypt::verifySign(const PIByteArray & data, const PIByteArray & signature, const PIByteArray & public_key) {
if (!init()) return false;
return (crypto_sign_verify_detached(signature.data(), data.data(), data.size(), public_key.data()) == 0);
return false;
}
bool PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key) {
if (!init()) return false;
public_key.resize(crypto_box_PUBLICKEYBYTES);
secret_key.resize(crypto_box_SECRETKEYBYTES);
return crypto_box_keypair(public_key.data(), secret_key.data()) == 0;
}
bool PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) {
if (!init()) return false;
public_key.resize(crypto_box_PUBLICKEYBYTES);
secret_key.resize(crypto_box_SECRETKEYBYTES);
return crypto_box_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data()) == 0;
}
PIByteArray PICrypt::crypt(const PIByteArray & data, const PIByteArray & public_key, const PIByteArray & secret_key) {
if (!init()) return PIByteArray();
if (public_key.size() != crypto_box_PUBLICKEYBYTES) return PIByteArray();
if (secret_key.size() != crypto_box_SECRETKEYBYTES) return PIByteArray();
PIByteArray n;
n.resize(crypto_box_NONCEBYTES);
PIByteArray ret;
ret.resize(data.size() + crypto_box_MACBYTES);
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();
}
ret.append(n);
return ret;
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray & public_key, const PIByteArray & secret_key, bool * ok) {
if (!init()) {
if (ok) *ok = false;
return PIByteArray();
}
if (public_key.size() != crypto_box_PUBLICKEYBYTES) {
if (ok) *ok = false;
return PIByteArray();
}
if (secret_key.size() != crypto_box_SECRETKEYBYTES) {
if (ok) *ok = false;
return PIByteArray();
}
if (crypt_data.size() < crypto_box_NONCEBYTES + crypto_box_MACBYTES) {
if (ok) *ok = false;
return PIByteArray();
}
PIByteArray n;
n.resize(crypto_secretbox_NONCEBYTES);
const ullong data_size = crypt_data.size() - n.size();
PIByteArray ret;
ret.resize(data_size - crypto_secretbox_MACBYTES);
memcpy(n.data(), crypt_data.data(data_size), n.size());
if (crypto_box_open_easy(ret.data(), crypt_data.data(), data_size, n.data(), public_key.data(), secret_key.data()) != 0) {
// Bad key
if (ok) *ok = false;
ret.clear();
} else if (ok) {
*ok = true;
}
return ret;
}
PIByteArray PICrypt::passwordHash(PIString password, const PIByteArray & seed) {
#ifdef crypto_pwhash_ALG_ARGON2I13
PIByteArray pass = password.toUTF8();
PIByteArray n = hash(seed);
PIByteArray ph;
ph.resize(crypto_box_SEEDBYTES);
n.resize(crypto_pwhash_SALTBYTES);
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);
pass.fill(0);
memset(const_cast<char *>(password.data()), 0, pass.size());
password.fill('\0');
if (r != 0) return PIByteArray();
return ph;
#else
piCout << "[PICrypt] Error, ALG_ARGON2I13 not availible!";
return PIByteArray();
#endif
}
PIString PICrypt::version() {
return SODIUM_VERSION_STRING;
}
bool PICrypt::init() {
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;
}

View File

@@ -1,34 +1,48 @@
/*
PIP - Platform Independent Primitives
Class for FFT, IFFT and Hilbert transformations
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 "pifft.h"
#include "pifft_p.h"
#define _PIFFTW_CPP(type) \
_PIFFTW_P_##type##_::_PIFFTW_P_##type##_() {impl = new PIFFTW_Private<type>();;} \
_PIFFTW_P_##type##_::~_PIFFTW_P_##type##_() {delete (PIFFTW_Private<type>*)impl;} \
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);} \
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)
/*
PIP - Platform Independent Primitives
Class for FFT, IFFT and Hilbert transformations
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 "pifft.h"
#include "pifft_p.h"
#define _PIFFTW_CPP(type) \
_PIFFTW_P_##type##_::_PIFFTW_P_##type##_() { \
impl = new PIFFTW_Private<type>(); \
; \
} \
_PIFFTW_P_##type##_::~_PIFFTW_P_##type##_() { \
delete (PIFFTW_Private<type> *)impl; \
} \
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); \
} \
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,180 +1,248 @@
/*! @file pifft_p.h
* @brief Class for FFT, IFFT and Hilbert transformations
*/
/*
PIP - Platform Independent Primitives
Private header for fftw3
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/>.
*/
#ifndef PIFFT_P_H
#define PIFFT_P_H
#include "pivector.h"
#include "picout.h"
#if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq)
# include "fftw3.h"
#else
# define FFTW_FORWARD 0
# define FFTW_BACKWARD 0
# define FFTW_ESTIMATE 0
# define FFTW_MEASURE 0
#endif
template <typename T>
class PIFFTW_Private
{
public:
explicit PIFFTW_Private() {
plan = 0;
//#ifndef PIP_FFTW
// piCout << "[PIFFTW]" << "Warning: PIFFTW is disabled, to enable install libfftw3-dev library and build pip with -DFFTW=1";
//#endif
p_makeThreadSafe();
}
~PIFFTW_Private() {p_destroyPlan(plan);}
const PIVector<complex<T> > & calcFFT(const PIVector<complex<T> > & in) {
if (prepare != PlanParams(in.size(), fo_complex)) {
p_out.resize(in.size());
piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_complex);
}
p_executePlan_c2c(plan, in.data(), p_out.data());
return p_out;
}
const PIVector<complex<T> > & calcFFT(const PIVector<T> & in) {
if (prepare != PlanParams(in.size(), fo_real)) {
p_out.resize(in.size());
piCout << "[PIFFTW]" << "creating plan";
p_createPlan_r2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_real);
}
p_executePlan_r2c(plan, in.data(), p_out.data());
return p_out;
}
const PIVector<complex<T> > & calcFFTinverse(const PIVector<complex<T> > & in) {
if (prepare != PlanParams(in.size(), fo_inverse)) {
p_out.resize(in.size());
piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_inverse);
}
p_executePlan_c2c(plan, in.data(), p_out.data());
return p_out;
}
enum FFT_Operation {fo_real, fo_complex, fo_inverse};
void preparePlan(int size, int op) {
p_inr.clear();
p_in.clear();
p_out.clear();
switch ((FFT_Operation)op) {
case fo_real:
p_inr.resize(size);
p_out.resize(size);
p_createPlan_r2c_1d(plan, size, p_inr.data(), p_out.data(), FFTW_MEASURE | FFTW_UNALIGNED);
break;
case fo_complex:
p_in.resize(size);
p_out.resize(size);
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_FORWARD, FFTW_MEASURE | FFTW_UNALIGNED);
break;
case fo_inverse:
p_in.resize(size);
p_out.resize(size);
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_BACKWARD, FFTW_MEASURE | FFTW_UNALIGNED);
break;
default:
size = 0;
break;
}
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_executePlan(void * plan) {}
inline void p_executePlan_c2c(void * plan, const void * in, void * out) {}
inline void p_executePlan_r2c(void * plan, const void * in, void * out) {}
inline void p_destroyPlan(void *& plan) {}
inline void p_makeThreadSafe() {}
struct PlanParams {
PlanParams() {size = 0; op = fo_complex;}
PlanParams(int size_, FFT_Operation op_) {size = size_; op = op_;}
bool isValid() {return size > 0;}
bool operator ==(const PlanParams & v) const {return (v.size == size) && (v.op == op);}
bool operator !=(const PlanParams & v) const {return !(*this == v);}
int size;
FFT_Operation op;
};
PIVector<complex<T> > p_in;
PIVector<T> p_inr;
PIVector<complex<T> > p_out;
void * plan;
PlanParams prepare;
};
#ifdef PIP_FFTWf
template<> inline void PIFFTW_Private<float>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
plan = fftwf_plan_dft_1d(size, (fftwf_complex *)in, (fftwf_complex *)out, dir, flags);}
template<> inline void PIFFTW_Private<float>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
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);}
template<> inline void PIFFTW_Private<float>::p_destroyPlan(void *& plan) {if (plan) fftwf_destroy_plan((fftwf_plan)plan); plan = 0;}
# ifdef PIP_FFTWf_THREADSAFE
template<> inline void PIFFTW_Private<float>::p_makeThreadSafe() {fftwf_make_planner_thread_safe();}
# endif
#endif // PIP_FFTWf
#ifdef PIP_FFTW
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<> 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
/*! \file pifft_p.h
* \brief Class for FFT, IFFT and Hilbert transformations
*/
/*
PIP - Platform Independent Primitives
Private header for fftw3
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/>.
*/
#ifndef PIFFT_P_H
#define PIFFT_P_H
#include "picout.h"
#include "pimathcomplex.h"
#include "pivector.h"
#if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq)
# include "fftw3.h"
#else
# define FFTW_FORWARD 0
# define FFTW_BACKWARD 0
# define FFTW_ESTIMATE 0
# define FFTW_MEASURE 0
#endif
template<typename T>
class PIFFTW_Private {
public:
explicit PIFFTW_Private() {
plan = 0;
// #ifndef PIP_FFTW
// piCout << "[PIFFTW]" << "Warning: PIFFTW is disabled, to enable install libfftw3-dev library and build pip with -DFFTW=1";
// #endif
p_makeThreadSafe();
}
~PIFFTW_Private() { p_destroyPlan(plan); }
const PIVector<complex<T>> & calcFFT(const PIVector<complex<T>> & in) {
if (prepare != PlanParams(in.size(), fo_complex)) {
p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_complex);
}
p_executePlan_c2c(plan, in.data(), p_out.data());
return p_out;
}
const PIVector<complex<T>> & calcFFT(const PIVector<T> & in) {
if (prepare != PlanParams(in.size(), fo_real)) {
p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan";
p_createPlan_r2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_real);
}
p_executePlan_r2c(plan, in.data(), p_out.data());
return p_out;
}
const PIVector<complex<T>> & calcFFTinverse(const PIVector<complex<T>> & in) {
if (prepare != PlanParams(in.size(), fo_inverse)) {
p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_inverse);
}
p_executePlan_c2c(plan, in.data(), p_out.data());
return p_out;
}
enum FFT_Operation {
fo_real,
fo_complex,
fo_inverse
};
void preparePlan(int size, int op) {
p_inr.clear();
p_in.clear();
p_out.clear();
switch ((FFT_Operation)op) {
case fo_real:
p_inr.resize(size);
p_out.resize(size);
p_createPlan_r2c_1d(plan, size, p_inr.data(), p_out.data(), FFTW_MEASURE | FFTW_UNALIGNED);
break;
case fo_complex:
p_in.resize(size);
p_out.resize(size);
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_FORWARD, FFTW_MEASURE | FFTW_UNALIGNED);
break;
case fo_inverse:
p_in.resize(size);
p_out.resize(size);
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_BACKWARD, FFTW_MEASURE | FFTW_UNALIGNED);
break;
default: size = 0; break;
}
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_executePlan(void * plan) {}
inline void p_executePlan_c2c(void * plan, const void * in, void * out) {}
inline void p_executePlan_r2c(void * plan, const void * in, void * out) {}
inline void p_destroyPlan(void *& plan) {}
inline void p_makeThreadSafe() {}
struct PlanParams {
PlanParams() {
size = 0;
op = fo_complex;
}
PlanParams(int size_, FFT_Operation op_) {
size = size_;
op = op_;
}
bool isValid() { return size > 0; }
bool operator==(const PlanParams & v) const { return (v.size == size) && (v.op == op); }
bool operator!=(const PlanParams & v) const { return !(*this == v); }
int size;
FFT_Operation op;
};
PIVector<complex<T>> p_in;
PIVector<T> p_inr;
PIVector<complex<T>> p_out;
void * plan;
PlanParams prepare;
};
#ifdef PIP_FFTWf
template<>
inline void PIFFTW_Private<float>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
plan = fftwf_plan_dft_1d(size, (fftwf_complex *)in, (fftwf_complex *)out, dir, flags);
}
template<>
inline void PIFFTW_Private<float>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
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);
}
template<>
inline void PIFFTW_Private<float>::p_destroyPlan(void *& plan) {
if (plan) fftwf_destroy_plan((fftwf_plan)plan);
plan = 0;
}
# ifdef PIP_FFTWf_THREADSAFE
template<>
inline void PIFFTW_Private<float>::p_makeThreadSafe() {
fftwf_make_planner_thread_safe();
}
# endif
#endif // PIP_FFTWf
#ifdef PIP_FFTW
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<>
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

@@ -0,0 +1,77 @@
#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

@@ -0,0 +1,31 @@
#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

@@ -0,0 +1,237 @@
#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

@@ -0,0 +1,367 @@
#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];
memset(buffer, 0, 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;
memset(&sa_addr, 0, sizeof(sa_addr));
sa_addr.sin_port = htons(addr.port());
sa_addr.sin_addr.s_addr = addr.ip();
sa_addr.sin_family = AF_INET;
PIVector<MHD_OptionItem> options;
options.append({MHD_OPTION_EXTERNAL_LOGGER, (intptr_t)log_callback, this});
options.append({MHD_OPTION_NOTIFY_COMPLETED, (intptr_t)request_completed, nullptr});
options.append({MHD_OPTION_CONNECTION_LIMIT, opts.value(Option::ConnectionLimit).toInt(), nullptr});
options.append({MHD_OPTION_CONNECTION_TIMEOUT, piRound(opts.value(Option::ConnectionTimeout).toSystemTime().toSeconds()), nullptr});
options.append({MHD_OPTION_SOCK_ADDR, 0, &sa_addr});
if (opts.value(Option::HTTPSEnabled).toBool()) {
options.append({MHD_OPTION_HTTPS_MEM_KEY, 0, mem_key.data()});
options.append({MHD_OPTION_HTTPS_MEM_CERT, 0, mem_cert.data()});
options.append({MHD_OPTION_HTTPS_KEY_PASSWORD, 0, key_pass.data()});
}
options.append({MHD_OPTION_END, 0, nullptr});
PRIVATE->daemon = MHD_start_daemon(flags,
addr.port(),
nullptr,
nullptr,
(MHD_AccessHandlerCallback)answer_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

@@ -0,0 +1,90 @@
#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,268 +1,270 @@
/*
PIP - Platform Independent Primitives
Broadcast for all interfaces, including loopback
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 "pibroadcast.h"
/** \class PIBroadcast
* @brief Broadcast for all interfaces, including loopback
*
* \section PIBroadcast_synopsis Synopsis
* %PIBroadcast used as multichannel IO device. It can use
* multicast, broadcast and loopback ethernet channels to
* send/receive packets. \a send() function send packet to
* all initialized ethernets. \a receiveEvent() raised on
* packet received by any ethernet. All multi/broadcast
* 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 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
* \a reinit() if it necessary.
*
*/
#define MULTICAST_TTL 4
PIBroadcast::PIBroadcast(bool send_only): PIThread(), PIEthUtilBase() {
_channels = All;
eth_lo = 0;
mcast_address.set("232.13.3.14", 14100);
lo_port = 14200;
lo_pcnt = 5;
_started = false;
_send_only = send_only;
_reinit = true;
//initMcast(PIEthernet::allAddresses());
PIThread::start(3000);
}
PIBroadcast::~PIBroadcast() {
PIThread::stop();
mcast_mutex.unlock();
destroyAll();
}
void PIBroadcast::setChannels(PIBroadcast::Channels ch) {
PIMutexLocker ml(mcast_mutex);
_channels = ch;
_reinit = true;
}
void PIBroadcast::setMulticastGroup(const PIString & mg) {
PIMutexLocker ml(mcast_mutex);
mcast_address.setIP(mg);
_reinit = true;
}
void PIBroadcast::setMulticastPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
mcast_address.setPort(port);
_reinit = true;
}
void PIBroadcast::setMulticastAddress(const PIEthernet::Address & addr) {
PIMutexLocker ml(mcast_mutex);
mcast_address = addr;
_reinit = true;
}
void PIBroadcast::setBroadcastPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
bcast_port = port;
_reinit = true;
}
void PIBroadcast::setLoopbackPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
lo_port = port;
_reinit = true;
}
void PIBroadcast::setLoopbackPortsCount(int count) {
PIMutexLocker ml(mcast_mutex);
lo_pcnt = count;
_reinit = true;
}
void PIBroadcast::destroyAll() {
piForeach (PIEthernet * e, eth_mcast) {
e->stopThreadedRead();
delete e;
}
eth_mcast.clear();
if (eth_lo) {
eth_lo->stopThreadedRead();
delete eth_lo;
eth_lo = 0;
}
}
void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
PIMutexLocker ml(mcast_mutex);
destroyAll();
_reinit = false;
prev_al = al;
al.removeAll(PIEthernet::Address("127.0.0.1"));
al << mcast_address;
eth_mcast.clear();
PIEthernet::InterfaceList ifaces = PIEthernet::interfaces();
piForeachC (PIEthernet::Address & a, al) {
PIEthernet * ce = 0;
//piCout << "mcast try" << a;
if (_channels[Multicast]) {
ce = new PIEthernet();
ce->setDebug(false);
ce->setName("PIMulticast_" + a.toString());
ce->setParameters(0);
ce->setSendAddress(mcast_address);
ce->setMulticastTTL(MULTICAST_TTL);
if (!_send_only) {
ce->setReadAddress(a.ipString(), mcast_address.port());
ce->joinMulticastGroup(mcast_address.ipString());
//piCout << "mcast " << ce->readAddress() << ce->sendAddress();
if (ce->open()) {
eth_mcast << ce;
CONNECTU(ce, threadedReadEvent, this, mcastRead);
} else {
delete ce;
}
} else {
eth_mcast << ce;
}
}
if (_channels[Broadcast]) {
ce = new PIEthernet();
ce->setDebug(false);
ce->setName("PIMulticast_" + a.toString());
ce->setParameters(PIEthernet::Broadcast);
const PIEthernet::Interface * cint = ifaces.getByAddress(a.ipString());
PIEthernet::Address nm((cint == 0) ? "255.255.255.0" : cint->netmask);
ce->setSendAddress(PIEthernet::getBroadcast(a, nm).ipString(), bcast_port);
if (!_send_only) {
ce->setReadAddress(PIEthernet::Address(a.ip(), bcast_port));
//piCout << "bcast " << ce->readAddress() << ce->sendAddress();
if (ce->open()) {
eth_mcast << ce;
CONNECTU(ce, threadedReadEvent, this, mcastRead);
} else {
delete ce;
}
} else {
eth_mcast << ce;
}
}
}
if (_channels[Loopback]) {
eth_lo = new PIEthernet();
eth_lo->setDebug(false);
eth_lo->setName("PIMulticast_loopback");
if (!_send_only) {
eth_lo->setParameter(PIEthernet::ReuseAddress, false);
CONNECTU(eth_lo, threadedReadEvent, this, mcastRead);
for (int i = 0; i < lo_pcnt; ++i) {
eth_lo->setReadAddress("127.0.0.1", lo_port + i);
if (eth_lo->open()) {
//piCout << "bind local to" << (lo_port + i);
break;
}
}
}
}
}
void PIBroadcast::send(const PIByteArray & data) {
PIByteArray cd = cryptData(data);
if (cd.isEmpty()) return;
PIMutexLocker ml(mcast_mutex);
piForeach (PIEthernet * e, eth_mcast)
e->send(cd);
if (eth_lo) {
for (int i = 0; i < lo_pcnt; ++i) {
eth_lo->send("127.0.0.1", lo_port + i, cd);
}
}
}
void PIBroadcast::startRead() {
if (_send_only) return;
PIMutexLocker ml(mcast_mutex);
piForeach (PIEthernet * e, eth_mcast)
e->startThreadedRead();
if (eth_lo)
eth_lo->startThreadedRead();
_started = true;
}
void PIBroadcast::stopRead() {
PIMutexLocker ml(mcast_mutex);
piForeach (PIEthernet * e, eth_mcast)
e->stopThreadedRead();
if (eth_lo)
eth_lo->stopThreadedRead();
_started = false;
}
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);
receiveEvent(cd);
}
void PIBroadcast::run() {
PIVector<PIEthernet::Address> al = PIEthernet::allAddresses();
mcast_mutex.lock();
bool r = _reinit, ac = (al != prev_al);
mcast_mutex.unlock();
if (ac || r)
reinit();
if (ac)
addressesChanged();
}
/*
PIP - Platform Independent Primitives
Broadcast for all interfaces, including loopback
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 "pibroadcast.h"
#include "piliterals_time.h"
/** \class PIBroadcast
* \brief Broadcast for all interfaces, including loopback
*
* \section PIBroadcast_synopsis Synopsis
* %PIBroadcast used as multichannel IO device. It can use
* multicast, broadcast and loopback ethernet channels to
* send/receive packets. \a send() function send packet to
* all initialized ethernets. \a receiveEvent() raised on
* packet received by any ethernet. All multi/broadcast
* 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 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
* \a reinit() if it necessary.
*
*/
#define MULTICAST_TTL 4
PIBroadcast::PIBroadcast(bool send_only): PIThread(), PIEthUtilBase() {
_channels = All;
eth_lo = 0;
mcast_address.set("232.13.3.14", 14100);
lo_port = 14200;
lo_pcnt = 5;
_started = false;
_send_only = send_only;
_reinit = true;
}
PIBroadcast::~PIBroadcast() {
PIThread::stopAndWait();
// mcast_mutex.unlock();
destroyAll();
}
void PIBroadcast::setChannels(PIBroadcast::Channels ch) {
PIMutexLocker ml(mcast_mutex);
_channels = ch;
_reinit = true;
}
void PIBroadcast::setMulticastGroup(const PIString & mg) {
PIMutexLocker ml(mcast_mutex);
mcast_address.setIP(mg);
_reinit = true;
}
void PIBroadcast::setMulticastPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
mcast_address.setPort(port);
_reinit = true;
}
void PIBroadcast::setMulticastAddress(const PINetworkAddress & addr) {
PIMutexLocker ml(mcast_mutex);
mcast_address = addr;
_reinit = true;
}
void PIBroadcast::setBroadcastPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
bcast_port = port;
_reinit = true;
}
void PIBroadcast::setLoopbackPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
lo_port = port;
_reinit = true;
}
void PIBroadcast::setLoopbackPortsCount(int count) {
PIMutexLocker ml(mcast_mutex);
lo_pcnt = count;
_reinit = true;
}
void PIBroadcast::destroyAll() {
for (auto * e: eth_mcast) {
e->stopAndWait();
piDeleteSafety(e);
}
eth_mcast.clear();
if (eth_lo) {
eth_lo->stopAndWait();
piDeleteSafety(eth_lo);
}
}
void PIBroadcast::initAll(PIVector<PINetworkAddress> al) {
PIMutexLocker ml(mcast_mutex);
destroyAll();
_reinit = false;
prev_al = al;
al.removeAll(PINetworkAddress("127.0.0.1"));
al << mcast_address;
eth_mcast.clear();
PIEthernet::InterfaceList ifaces = PIEthernet::interfaces();
for (const auto & a: al) {
PIEthernet * ce = 0;
// piCout << "mcast try" << a;
if (_channels[Multicast]) {
ce = new PIEthernet();
ce->setDebug(false);
ce->setName("PIMulticast_" + a.toString());
ce->setParameters(0);
ce->setSendAddress(mcast_address);
ce->setMulticastTTL(MULTICAST_TTL);
if (!_send_only) {
ce->setReadAddress(a.ipString(), mcast_address.port());
ce->joinMulticastGroup(mcast_address.ipString());
// piCout << "mcast " << ce->readAddress() << ce->sendAddress();
if (ce->open()) {
eth_mcast << ce;
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mcastRead);
} else {
delete ce;
}
} else {
eth_mcast << ce;
}
}
if (_channels[Broadcast]) {
ce = new PIEthernet();
ce->setDebug(false);
ce->setName("PIMulticast_" + a.toString());
ce->setParameters(PIEthernet::Broadcast);
const PIEthernet::Interface * cint = ifaces.getByAddress(a.ipString());
PINetworkAddress nm((cint == 0) ? "255.255.255.0" : cint->netmask);
ce->setSendAddress(PIEthernet::getBroadcast(a, nm).ipString(), bcast_port);
if (!_send_only) {
ce->setReadAddress(PINetworkAddress(a.ip(), bcast_port));
// piCout << "bcast " << ce->readAddress() << ce->sendAddress();
if (ce->open()) {
eth_mcast << ce;
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mcastRead);
} else {
delete ce;
}
} else {
eth_mcast << ce;
}
}
}
if (_channels[Loopback]) {
eth_lo = new PIEthernet();
eth_lo->setDebug(false);
eth_lo->setName("PIMulticast_loopback");
if (!_send_only) {
eth_lo->setParameter(PIEthernet::ReuseAddress, false);
CONNECT2(void, const uchar *, ssize_t, eth_lo, threadedReadEvent, this, mcastRead);
for (int i = 0; i < lo_pcnt; ++i) {
eth_lo->setReadAddress("127.0.0.1", lo_port + i);
if (eth_lo->open()) {
// piCout << "bind local to" << (lo_port + i);
break;
}
}
}
}
}
void PIBroadcast::send(const PIByteArray & data) {
/*if (!isRunning()) {
reinit();
PIThread::start(3000);
}*/
PIByteArray cd = cryptData(data);
if (cd.isEmpty()) return;
PIMutexLocker ml(mcast_mutex);
for (auto * e: eth_mcast)
e->send(cd);
if (eth_lo) {
for (int i = 0; i < lo_pcnt; ++i) {
eth_lo->send("127.0.0.1", lo_port + i, cd);
}
}
}
void PIBroadcast::startRead() {
if (!isRunning()) {
_started = false;
reinit();
PIThread::start(3_s);
}
if (_send_only) return;
PIMutexLocker ml(mcast_mutex);
for (auto * e: eth_mcast)
e->startThreadedRead();
if (eth_lo) eth_lo->startThreadedRead();
_started = true;
}
void PIBroadcast::stopRead() {
if (isRunning()) stopAndWait();
PIMutexLocker ml(mcast_mutex);
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::mcastRead(const uchar * data, ssize_t size) {
PIByteArray cd = decryptData(PIByteArray(data, size));
if (cd.isEmpty()) return;
received(cd);
receiveEvent(cd);
}
void PIBroadcast::run() {
PIVector<PINetworkAddress> al = PIEthernet::allAddresses();
mcast_mutex.lock();
bool r = _reinit, ac = (al != prev_al);
mcast_mutex.unlock();
if (ac || r) reinit();
if (ac) addressesChanged();
}

View File

@@ -1,121 +1,131 @@
/*
PIP - Platform Independent Primitives
Base class for ethernet utils
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 "piethutilbase.h"
#ifdef PIP_CRYPT
# include "picrypt.h"
#endif
/** \class PIEthUtilBase
* @brief Base class for ethernet utils
*
* \section PIEthUtilBase_synopsis Synopsis
* %PIEthUtilBase provides crypt layer for derived classes:
* \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.
*
* You can separetely enable it and set ready-to-use
* key by \a setCryptEnabled() and \a setCryptKey(). Or you can
* 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.
*
* 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() {
}
void PIEthUtilBase::setCryptEnabled(bool on) {
_crypt = on;
}
void PIEthUtilBase::cryptEnable() {
setCryptEnabled(true);
}
void PIEthUtilBase::cryptDisable() {
setCryptEnabled(false);
}
bool PIEthUtilBase::isCryptEnabled() const {
return _crypt;
}
void PIEthUtilBase::setCryptKey(const PIByteArray & k) {
_key = k;
setCryptEnabled(true);
}
void PIEthUtilBase::createCryptKey(const PIString & k) {
#ifdef PIP_CRYPT
_key = PICrypt::hash("sodium_bug");
_key = PICrypt::hash(k);
#else
piCout << "[PIEthUtilBase] PICrypt wasn`t built!";
#endif
_crypt = true;
}
PIByteArray PIEthUtilBase::cryptKey() const {
return _key;
}
PIByteArray PIEthUtilBase::cryptData(const PIByteArray & data) {
if (!_crypt) return data;
return
#ifdef PIP_CRYPT
PICrypt::crypt(data, _key);
#else
PIByteArray();
#endif
}
PIByteArray PIEthUtilBase::decryptData(const PIByteArray & data) {
if (!_crypt) return data;
#ifdef PIP_CRYPT
bool ok = false;
PIByteArray ret = PICrypt::decrypt(data, _key, &ok);
if (!ok) return PIByteArray();
return ret;
#else
return PIByteArray();
#endif
}
/*
PIP - Platform Independent Primitives
Base class for ethernet utils
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 "piethutilbase.h"
#include "pitranslator.h"
#ifdef PIP_CRYPT
# include "picrypt.h"
#endif
/** \class PIEthUtilBase
* \brief Base class for ethernet utils
*
* \section PIEthUtilBase_synopsis Synopsis
* %PIEthUtilBase provides crypt layer for derived classes:
* \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.
*
* You can separetely enable it and set ready-to-use
* key by \a setCryptEnabled() and \a setCryptKey(). Or you can
* 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.
*
* 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() {}
void PIEthUtilBase::setCryptEnabled(bool on) {
_crypt = on;
}
void PIEthUtilBase::cryptEnable() {
setCryptEnabled(true);
}
void PIEthUtilBase::cryptDisable() {
setCryptEnabled(false);
}
bool PIEthUtilBase::isCryptEnabled() const {
return _crypt;
}
void PIEthUtilBase::setCryptKey(const PIByteArray & k) {
_key = k;
setCryptEnabled(true);
}
void PIEthUtilBase::createCryptKey(const PIString & k) {
#ifdef PIP_CRYPT
_key = PICrypt::hash("sodium_bug");
_key = PICrypt::hash(k);
#else
piCout << "[PIEthUtilBase]"
<< "PICrypt wasn`t built!"_tr("PIEthUtilBase");
#endif
_crypt = true;
}
PIByteArray PIEthUtilBase::cryptKey() const {
return _key;
}
PIByteArray PIEthUtilBase::cryptData(const PIByteArray & data) {
if (!_crypt) return data;
return
#ifdef PIP_CRYPT
PICrypt::crypt(data, _key);
#else
PIByteArray();
#endif
}
PIByteArray PIEthUtilBase::decryptData(const PIByteArray & data) {
if (!_crypt) return data;
#ifdef PIP_CRYPT
bool ok = false;
PIByteArray ret = PICrypt::decrypt(data, _key, &ok);
if (!ok) return PIByteArray();
return ret;
#else
return PIByteArray();
#endif
}
size_t PIEthUtilBase::cryptSizeAddition() {
#ifdef PIP_CRYPT
return PICrypt::sizeCrypt();
#else
return 0;
#endif
}

View File

@@ -0,0 +1,199 @@
/*
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,256 +1,176 @@
/*
PIP - Platform Independent Primitives
Simple packet wrap aroud any PIIODevice
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/>.
*/
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnonnull"
#endif
#include "pistreampacker.h"
#include "piiodevice.h"
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
/** \class PIStreamPacker
* @brief Simple packet wrap aroud any PIIODevice
*
* \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()
* event raised several times.
*
* When your device receive some data, call \a received() function.
* \a packetReceiveEvent() event will be raised when packet will be
* collected.
*
* Use \a assignDevice() to connect device to this %PIStreamPacker.
*
*/
PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() {
crypt_frag = crypt_size = false;
aggressive_optimization = true;
packet_size = -1;
size_crypted_size = sizeof(int);
crypt_frag_size = 1024*1024;
max_packet_size = 1400;
packet_sign = 0xAFBE;
assignDevice(dev);
}
void PIStreamPacker::setCryptSizeEnabled(bool on) {
crypt_size = on;
if (crypt_size) {
PIByteArray ba; ba << int(0);
size_crypted_size = cryptData(ba).size_s();
} else
size_crypted_size = sizeof(int);
}
void PIStreamPacker::send(const PIByteArray & data) {
if (data.isEmpty()) return;
PIByteArray cd;
if (crypt_frag) {
int fcnt = (data.size_s() - 1) / crypt_frag_size + 1, fst = 0;
//piCout << "crypt_frag send" << fcnt << "frags";
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;
cd << cryptData(frag);
}
} else {
cd = cryptData(data);
}
//piCout << "crypt" << data.size() << "->" << cd.size() << key().size();
PIByteArray hdr, part;
hdr << packet_sign;
if (crypt_size) {
PIByteArray crsz; crsz << int(cd.size_s());
hdr.append(cryptData(crsz));
} else
hdr << int(cd.size_s());
cd.insert(0, hdr);
int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
if (pcnt > 1) {
prog_s_mutex.lock();
prog_s.active = true;
prog_s.bytes_all = data.size_s();
prog_s.bytes_current = 0;
prog_s.progress = 0.;
prog_s_mutex.unlock();
}
for (int i = 0; i < pcnt; ++i) {
if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst);
else part = PIByteArray(cd.data(pst), max_packet_size);
//piCout << "send" << part.size();
sendRequest(part);
pst += max_packet_size;
if (pcnt > 1) {
prog_s_mutex.lock();
prog_s.bytes_current += part.size_s();
prog_s.progress = (double)prog_s.bytes_current / prog_s.bytes_all;
prog_s_mutex.unlock();
}
}
if (pcnt > 1) {
prog_s_mutex.lock();
prog_s.active = false;
prog_s_mutex.unlock();
}
}
void PIStreamPacker::received(uchar * readed, int size) {
received(PIByteArray(readed, size));
}
void PIStreamPacker::received(const PIByteArray & data) {
stream.append(data);
//piCout << "rec" << data.size();
while (!stream.isEmpty()) {
int hdr_size = sizeof(packet_sign) + size_crypted_size;
if (packet_size < 0) {
if (stream.size_s() < hdr_size) return;
ushort sign(0);
memcpy(&sign, stream.data(), 2);
if (sign != packet_sign) {
if (aggressive_optimization) stream.clear();
else stream.pop_front();
continue;
}
int sz = -1;
if (crypt_size) {
PIByteArray crsz((uint)size_crypted_size);
memcpy(crsz.data(), stream.data(2), size_crypted_size);
crsz = decryptData(crsz);
if (crsz.size() < sizeof(sz)) {
if (aggressive_optimization) stream.clear();
else stream.pop_front();
continue;
}
crsz >> sz;
} else {
memcpy(&sz, stream.data(2), size_crypted_size);
}
if (sz < 0) {
if (aggressive_optimization) stream.clear();
else stream.pop_front();
continue;
}
stream.remove(0, hdr_size);
packet.clear();
packet_size = sz;
if (packet_size == 0)
packet_size = -1;
else {
prog_r_mutex.lock();
prog_r.active = true;
prog_r.bytes_all = packet_size;
prog_r.bytes_current = 0;
prog_r.progress = 0.;
prog_r_mutex.unlock();
}
continue;
} else {
int ps = piMini(stream.size_s(), packet_size - packet.size_s());
packet.append(stream.data(), ps);
prog_r_mutex.lock();
prog_r.bytes_current = packet.size_s();
prog_r.progress = (double)prog_r.bytes_current / piMaxi(1, prog_r.bytes_all);
prog_r_mutex.unlock();
stream.remove(0, ps);
if (packet.size_s() == packet_size) {
PIByteArray cd;
if (crypt_frag) {
//piCout << "decrypt frags ..." << packet_size;
while (packet.size_s() >= 4) {
//piCout << "decrypt frags take data ...";
PIByteArray frag;
//piCout << "decrypt frags take data done" << frag.size_s();
packet >> frag;
if (frag.isEmpty()) {
//piCout << "decrypt frags corrupt, break";
cd.clear();
break;
}
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;
prog_r_mutex.lock();
prog_r.active = false;
prog_r_mutex.unlock();
}
}
}
}
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);
}
PIStreamPacker::Progress PIStreamPacker::progressSend() const {
PIStreamPacker::Progress ret;
prog_s_mutex.lock();
ret = prog_s;
prog_s_mutex.unlock();
return ret;
}
PIStreamPacker::Progress PIStreamPacker::progressReceive() const {
PIStreamPacker::Progress ret;
prog_r_mutex.lock();
ret = prog_r;
prog_r_mutex.unlock();
return ret;
}
PIStreamPacker::Progress::Progress() {
active = false;
bytes_all = bytes_current = 0;
progress = 0.;
}
/*
PIP - Platform Independent Primitives
Simple packet wrap aroud any PIIODevice
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/>.
*/
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnonnull"
#endif
#include "pistreampacker.h"
#include "piiodevice.h"
#include "pitranslator.h"
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
/** \class PIStreamPacker
* \brief Simple packet wrap aroud any PIIODevice
*
* \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()
* event raised several times.
*
* When your device receive some data, call \a received() function.
* \a packetReceiveEvent() event will be raised when packet will be
* collected.
*
* Use \a assignDevice() to connect device to this %PIStreamPacker.
*
*/
PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() {
packet_size = -1;
if (dev) assignDevice(dev);
}
void PIStreamPacker::clear() {
packet.clear();
packet_size = -1;
stream.clear();
}
void PIStreamPacker::send(const PIByteArray & data) {
if (data.isEmpty()) return;
PIByteArray cd = cryptData(data);
// piCout << "crypt" << data.size() << "->" << cd.size() << key().size();
PIByteArray hdr, part;
hdr << packet_sign;
if (crypt_size) {
PIByteArray crsz;
crsz << int(cd.size_s());
hdr.append(cryptData(crsz));
} else
hdr << int(cd.size_s());
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)
part = PIByteArray(cd.data(pst), cd.size_s() - pst);
else
part = PIByteArray(cd.data(pst), max_packet_size);
// piCout << "send" << part.size();
sendRequest(part);
pst += max_packet_size;
}
}
void PIStreamPacker::received(const uchar * readed, ssize_t size) {
if (size <= 0) return;
received(PIByteArray(readed, size));
}
void PIStreamPacker::received(const PIByteArray & data) {
stream.append(data);
// piCout << "rec" << data.size();
while (!stream.isEmpty()) {
int hdr_size = sizeof(packet_sign) + sizeCryptedSize();
if (packet_size < 0) {
if (stream.size_s() < hdr_size) return;
ushort sign(0);
memcpy(&sign, stream.data(), 2);
if (sign != packet_sign) {
if (aggressive_optimization)
stream.clear();
else
stream.pop_front();
continue;
}
int sz = -1;
if (crypt_size) {
PIByteArray crsz(sizeCryptedSize());
memcpy(crsz.data(), stream.data(2), crsz.size());
crsz = decryptData(crsz);
if (crsz.size() < sizeof(sz)) {
if (aggressive_optimization)
stream.clear();
else
stream.pop_front();
continue;
}
crsz >> sz;
} else {
memcpy(&sz, stream.data(2), sizeCryptedSize());
}
if (sz < 0) {
if (aggressive_optimization)
stream.clear();
else
stream.pop_front();
continue;
}
stream.remove(0, hdr_size);
packet.clear();
packet_size = sz;
if (packet_size == 0)
packet_size = -1;
else
startPacketReceive(packet_size);
continue;
} else {
int ps = piMini(stream.size_s(), packet_size - packet.size_s());
packet.append(stream.data(), ps);
stream.remove(0, ps);
if (packet.size_s() == packet_size) {
PIByteArray cd = decryptData(packet);
// piCout << "decrypt" << packet.size() << "->" << cd.size() << key().size();
if (!cd.isEmpty()) {
endPacketReceive();
packetReceived(cd);
packetReceiveEvent(cd);
}
packet.clear();
packet_size = -1;
}
}
}
}
void PIStreamPacker::assignDevice(PIIODevice * dev) {
if (!dev) {
piCoutObj << "Error! device is NULL";
return;
}
if (!dev->infoFlags()[PIIODevice::Reliable]) {
piCoutObj << "Warning! Not recommended to use with non-reliable device"_tr("PIStreamPacker") << dev;
}
CONNECT2(void, const uchar *, ssize_t, dev, threadedReadEvent, this, received);
CONNECT1(void, PIByteArray, this, sendRequest, dev, write);
}
uint PIStreamPacker::sizeCryptedSize() {
return sizeof(int) + (crypt_size ? cryptSizeAddition() : 0);
}

View File

@@ -1,20 +1,20 @@
/*
PIP - Platform Independent Primitives
PILuaProgram
Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
PILuaProgram
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 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.
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/>.
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 "piluaprogram.h"
@@ -50,4 +50,3 @@ luabridge::LuaRef PILuaProgram::getGlobal(const PIString & name) {
luabridge::Namespace PILuaProgram::getGlobalNamespace() {
return luabridge::getGlobalNamespace(PRIVATE->lua_state);
}

View File

@@ -0,0 +1,60 @@
/*
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

@@ -0,0 +1,256 @@
/*
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

@@ -0,0 +1,136 @@
/*! \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

@@ -0,0 +1,247 @@
/*
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

@@ -0,0 +1,181 @@
/*! \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

@@ -0,0 +1,152 @@
/*
PIP - Platform Independent Primitives
Single application
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 "pisingleapplication.h"
#include "piliterals_bytes.h"
#include "piliterals_time.h"
#include "pisharedmemory.h"
#include "pitime.h"
//! \class PISingleApplication pisingleapplication.h
//! \~\details
//! \~english
//!
//!
//! \~russian
//! Этот класс позволяет отслеживать повторный запуск приложения
//! и передавать сообщение первому запущеному.
//!
//! Видят друг друга %PISingleApplication с одинаковыми "app_name",
//! задаваемым в конструкторе.
//!
//! Если проверка \a isFirst() успешна, значит этот экземпляр
//! запущен первым, и можно соединиться к событию \a messageReceived().
//!
//! Если проверка провалена, значит этот экземпляр не первый,
//! и можно послать ему сообщение с помощью \a sendMessage(),
//! а затем выйти.
//!
//! \~\code
//! int main(int argc, char * argv[]) {
//! PISingleApplication sapp("myapp");
//! if (sapp.isFirst()) {
//! piCout << "I`m first, wait for another";
//! CONNECTL(&sapp, messageReceived, [](PIByteArray msg){
//! piCout << "Msg from another:" << PIString(msg);
//! });
//! } else {
//! piCout << "I`m not first, send and exit";
//! sapp.sendMessage(PIString("Hello!").toByteArray());
//! return 0;
//! }
//! WAIT_FOREVER
//! return 0;
//! }
//! \endcode
//!
#define SHM_SIZE 32_KiB
PISingleApplication::PISingleApplication(const PIString & app_name): PIThread() {
first = true;
started = false;
sacnt = 0;
shm = new PISharedMemory("sa_" + app_name, SHM_SIZE);
start(10_Hz);
}
PISingleApplication::~PISingleApplication() {
stop();
if (!waitForFinish(5_s)) terminate();
delete shm;
}
bool PISingleApplication::isFirst() const {
waitFirst();
return first;
}
void PISingleApplication::sendMessage(const PIByteArray & m) {
waitFirst();
PIByteArray ba;
int lm[3] = {0, 0, 0};
for (;;) {
shm->read(lm, 12);
if (lm[2] == 0) break;
piMSleep(10);
}
ba << sacnt << sacnt << int(1) << m;
shm->write(ba);
}
void PISingleApplication::begin() {
int cnt[2] = {0, 0};
int tcnt = 0;
shm->read(cnt, 8);
for (int i = 0; i < 5; ++i) {
tcnt = cnt[0];
shm->read(cnt, 8);
if (cnt[0] == cnt[1] && cnt[0] != tcnt) {
first = false;
break;
}
piMSleep(100);
}
// piCoutObj << "started" << first << shm->size();
readed.reserve(shm->size());
started = true;
}
void PISingleApplication::run() {
if (!first) return;
++sacnt;
int st_[2] = {sacnt, sacnt};
shm->write(st_, 8);
// piCoutObj << "write" << sacnt;
int ri[3] = {0, 0, 0};
const int hdr_sz = sizeof(int) * 3;
shm->read(ri, hdr_sz);
if (ri[2] != 0 && ri[0] == ri[1]) {
readed.resize(shm->size() - hdr_sz);
shm->read(readed.data(), readed.size(), hdr_sz);
PIByteArray msg;
readed >> msg;
if (msg.isNotEmpty()) {
messageReceived(msg);
// piCoutObj << "message" << msg;
}
int wi[3] = {sacnt, sacnt, 0};
shm->write(wi, 12);
}
}
void PISingleApplication::waitFirst() const {
while (!started)
piMSleep(50);
}

View File

@@ -0,0 +1,86 @@
/*! \file pisingleapplication.h
* \ingroup Application
* \~\brief
* \~english Single-instance application control
* \~russian Контроль одного экземпляра приложения
*/
/*
PIP - Platform Independent Primitives
Single application
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 PISINGLEAPPLICATION_H
#define PISINGLEAPPLICATION_H
#include "pithread.h"
class PISharedMemory;
//! \ingroup Application
//! \~\brief
//! \~english Single-instance application control.
//! \~russian Контроль одного экземпляра приложения.
class PIP_EXPORT PISingleApplication: public PIThread {
PIOBJECT_SUBCLASS(PISingleApplication, PIThread);
public:
//! \~english Construct %PISingleApplication with name "app_name"
//! \~russian Создает %PISingleApplication с именем "app_name"
PISingleApplication(const PIString & app_name = PIString());
~PISingleApplication();
//! \~english Returns if this application instance is launched first
//! \~russian Возвращает первым ли был запущен этот экземпляр приложения
bool isFirst() const;
EVENT_HANDLER1(void, sendMessage, const PIByteArray &, m);
EVENT1(messageReceived, PIByteArray, m);
//! \handlers
//! \{
//! \fn void sendMessage(const PIByteArray & m)
//! \brief
//! \~english Send message "m" to first launched application
//! \~russian Посылает сообщение "m" первому запущеному приложению
//! \}
//! \events
//! \{
//! \fn void messageReceived(PIByteArray m)
//! \brief
//! \~english Raise on first launched application receive message from another
//! \~russian Вызывается первым запущеным приложением по приему сообщения от других
//! \}
private:
void begin() override;
void run() override;
void waitFirst() const;
PISharedMemory * shm;
PITimeMeasurer ftm;
PIByteArray readed;
bool first, started;
int sacnt;
};
#endif // PISINGLEAPPLICATION_H

View File

@@ -1,501 +1,459 @@
/*
PIP - Platform Independent Primitives
Process resource monitor
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 "piincludes_p.h"
#include "pisystemmonitor.h"
#include "pisysteminfo.h"
#include "piprocess.h"
#include "pidir.h"
#include "pitime_win.h"
#ifdef WINDOWS
# include <psapi.h>
# include <tlhelp32.h>
#endif
#ifdef MAC_OS
struct kqueue_id_t;
# include <libproc.h>
# include <sys/proc_info.h>
#endif
#ifdef ESP_PLATFORM
# include "esp_heap_caps.h"
#endif
PISystemMonitor::ProcessStatsFixed::ProcessStatsFixed() {
ID = parent_ID = group_ID = session_ID = priority = threads = 0;
physical_memsize = resident_memsize = share_memsize = virtual_memsize = data_memsize = 0;
cpu_load_user = cpu_load_system = 0.f;
}
void PISystemMonitor::ProcessStats::makeStrings() {
physical_memsize_readable.setReadableSize(physical_memsize);
resident_memsize_readable.setReadableSize(resident_memsize);
share_memsize_readable.setReadableSize(share_memsize);
virtual_memsize_readable.setReadableSize(virtual_memsize);
data_memsize_readable.setReadableSize(data_memsize);
}
PISystemMonitor::ThreadStatsFixed::ThreadStatsFixed() {
id = 0;
cpu_load_kernel = cpu_load_user = -1.f;
}
#ifndef FREERTOS
PRIVATE_DEFINITION_START(PISystemMonitor)
#ifndef WINDOWS
# ifdef MAC_OS
PISystemTime
# else
llong
# endif
cpu_u_cur, cpu_u_prev, cpu_s_cur, cpu_s_prev;
PIString proc_dir;
PIFile file, filem;
#else
HANDLE hProc;
PROCESS_MEMORY_COUNTERS mem_cnt;
PISystemTime tm_kernel, tm_user;
PITimeMeasurer tm;
#endif
PRIVATE_DEFINITION_END(PISystemMonitor)
#endif
PISystemMonitor::PISystemMonitor(): PIThread() {
pID_ = cycle = 0;
cpu_count = PISystemInfo::instance()->processorsCount;
#ifndef FREERTOS
#ifndef WINDOWS
# ifdef QNX
page_size = 4096;
# else
page_size = getpagesize();
# endif
#else
PRIVATE->hProc = 0;
PRIVATE->mem_cnt.cb = sizeof(PRIVATE->mem_cnt);
#endif
#endif
setName("system_monitor");
}
PISystemMonitor::~PISystemMonitor() {
stop();
}
#ifndef FREERTOS
bool PISystemMonitor::startOnProcess(int pID, int interval_ms) {
stop();
pID_ = pID;
Pool::instance()->add(this);
cycle = -1;
#ifndef WINDOWS
# ifndef MAC_OS
PRIVATE->proc_dir = PIStringAscii("/proc/") + PIString::fromNumber(pID_) + PIStringAscii("/");
PRIVATE->file. open(PRIVATE->proc_dir + "stat", PIIODevice::ReadOnly);
PRIVATE->filem.open(PRIVATE->proc_dir + "statm", PIIODevice::ReadOnly);
if (!PRIVATE->file.isOpened()) {
piCoutObj << "Can`t find process with ID = " << pID_ << "!";
return false;
}
# endif
#else
PRIVATE->hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pID_);
if (PRIVATE->hProc == 0) {
piCoutObj << "Can`t open process with ID = " << pID_ << "," << errorString();
return false;
}
PRIVATE->tm.reset();
#endif
return start(interval_ms);
}
#endif
bool PISystemMonitor::startOnSelf(int interval_ms) {
#ifndef FREERTOS
bool ret = startOnProcess(PIProcess::currentPID(), interval_ms);
cycle = -1;
#else
bool ret = start(interval_ms);
#endif
return ret;
}
PIVector<PISystemMonitor::ThreadStats> PISystemMonitor::threadsStatistic() const {
mutex_.lock();
PIVector<PISystemMonitor::ThreadStats> ret = cur_ts;
mutex_.unlock();
return ret;
}
void PISystemMonitor::setStatistic(const PISystemMonitor::ProcessStats & s) {
PIMutexLocker _ml(stat_mutex);
stat = s;
stat.makeStrings();
}
void PISystemMonitor::stop() {
PIThread::stop();
#ifdef WINDOWS
if (PRIVATE->hProc != 0) {
CloseHandle(PRIVATE->hProc);
PRIVATE->hProc = 0;
}
#endif
Pool::instance()->remove(this);
}
PISystemMonitor::ProcessStats PISystemMonitor::statistic() const {
PIMutexLocker _ml(stat_mutex);
return stat;
}
#ifdef MAC_OS
PISystemTime uint64toST(uint64_t v) {
return PISystemTime(((uint*)&(v))[1], ((uint*)&(v))[0]);
}
#endif
void PISystemMonitor::run() {
cur_tm.clear();
tbid.clear();
__PIThreadCollection * pitc = __PIThreadCollection::instance();
pitc->lock();
PIVector<PIThread * > tv = pitc->threads();
piForeach (PIThread * t, tv)
if (t->isPIObject())
tbid[t->tid()] = t->name();
pitc->unlock();
//piCout << tbid.keys().toType<uint>();
ProcessStats tstat;
tstat.ID = pID_;
#ifdef FREERTOS
piForeach (PIThread * t, tv)
if (t->isPIObject())
gatherThread(t->tid());
#else
#ifndef WINDOWS
tbid[pID_] = "main";
# ifdef MAC_OS
rusage_info_current ru;
proc_pid_rusage(pID_, RUSAGE_INFO_CURRENT, (rusage_info_t*)&ru);
//piCout << PISystemTime(((uint*)&(ru.ri_user_time))[1], ((uint*)&(ru.ri_user_time))[0]);
if (cycle < 0) {
PRIVATE->cpu_u_prev = PRIVATE->cpu_u_cur = uint64toST(ru.ri_user_time);
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur = uint64toST(ru.ri_system_time);
}
PRIVATE->cpu_u_prev = PRIVATE->cpu_u_cur;
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur;
PRIVATE->cpu_u_cur = uint64toST(ru.ri_user_time);
PRIVATE->cpu_s_cur = uint64toST(ru.ri_system_time);
tstat.cpu_load_system = 100.f * (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev).toMilliseconds() / delay_;
tstat.cpu_load_user = 100.f * (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_;
cycle = 0;
//piCout << (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_;
# else
PRIVATE->file.seekToBegin();
PIString str(PRIVATE->file.readAll(true));
int si = str.find('(') + 1, fi = 0, cc = 1;
for (int i = si; i < str.size_s(); ++i) {
if (str[i] == '(') cc++;
if (str[i] == ')') cc--;
if (cc <= 0) {
fi = i;
break;
}
}
tstat.exec_name = str.mid(si, fi - si);
str.cutMid(si - 1, fi - si + 3);
PIStringList sl = str.split(" ");
if (sl.size_s() < 19) return;
tstat.ID = sl[0].toInt();
tstat.state = sl[1];
tstat.parent_ID = sl[2].toInt();
tstat.group_ID = sl[3].toInt();
tstat.session_ID = sl[4].toInt();
if (cycle < 0) {
PRIVATE->cpu_u_prev = PRIVATE->cpu_u_cur = sl[12].toLLong();
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur = sl[13].toLLong();
}
PRIVATE->cpu_u_prev = PRIVATE->cpu_u_cur;
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur;
PRIVATE->cpu_u_cur = sl[12].toLLong();
PRIVATE->cpu_s_cur = sl[13].toLLong();
tstat.cpu_load_system = (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev) / (delay_ / 1000.);
tstat.cpu_load_user = (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev) / (delay_ / 1000.);
tstat.cpu_load_system /= cpu_count;
tstat.cpu_load_user /= cpu_count;
cycle = 0;
tstat.priority = sl[16].toInt();
tstat.threads = sl[18].toInt();
//piCout << "\n";
//piCout << sl[0] << sl[12] << sl[13];
PRIVATE->filem.seekToBegin();
str = PRIVATE->filem.readAll(true);
sl = str.split(" ");
if (sl.size_s() < 6) return;
tstat.virtual_memsize = sl[0].toLong() * page_size;
tstat.resident_memsize = sl[1].toLong() * page_size;
tstat.share_memsize = sl[2].toLong() * page_size;
tstat.data_memsize = sl[5].toLong() * page_size;
tstat.physical_memsize = tstat.resident_memsize - tstat.share_memsize;
PIVector<PIFile::FileInfo> tld = PIDir(PRIVATE->proc_dir + "task").entries();
piForeachC (PIFile::FileInfo & i, tld) {
if (i.flags[PIFile::FileInfo::Dot] || i.flags[PIFile::FileInfo::DotDot])
continue;
gatherThread(i.name().toInt());
}
# endif
#else
if (GetProcessMemoryInfo(PRIVATE->hProc, &PRIVATE->mem_cnt, sizeof(PRIVATE->mem_cnt)) != 0) {
tstat.physical_memsize = PRIVATE->mem_cnt.WorkingSetSize;
}
tstat.priority = GetPriorityClass(PRIVATE->hProc);
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, pID_);
int thcnt = 0;
if (snap != 0) {
THREADENTRY32 thread;
thread.dwSize = sizeof(THREADENTRY32);
if (Thread32First(snap, &thread) == TRUE) {
if (thread.th32OwnerProcessID == DWORD(pID_)) {
++thcnt;
gatherThread(thread.th32ThreadID);
}
while (Thread32Next(snap, &thread) == TRUE) {
if (thread.th32OwnerProcessID == DWORD(pID_)) {
++thcnt;
gatherThread(thread.th32ThreadID);
}
//piCout << thread.th32ThreadID;
}
}
tstat.threads = thcnt;
CloseHandle(snap);
}
FILETIME ft0, ft1, ft_kernel, ft_user;
double el_s = PRIVATE->tm.elapsed_s() * cpu_count / 100.;
if (GetProcessTimes(PRIVATE->hProc, &ft0, &ft1, &ft_kernel, &ft_user) != 0) {
PISystemTime tm_kernel_c = FILETIME2PISystemTime(ft_kernel);
PISystemTime tm_user_c = FILETIME2PISystemTime(ft_user);
if (cycle < 0) {
PRIVATE->tm_kernel = tm_kernel_c;
PRIVATE->tm_user = tm_user_c;
}
cycle = 0;
if (el_s <= 0.) {
tstat.cpu_load_system = 0.f;
tstat.cpu_load_user = 0.f;
} else {
tstat.cpu_load_system = (tm_kernel_c - PRIVATE->tm_kernel).toSeconds() / el_s;
tstat.cpu_load_user = (tm_user_c - PRIVATE->tm_user).toSeconds() / el_s;
}
PRIVATE->tm_kernel = tm_kernel_c;
PRIVATE->tm_user = tm_user_c;
} else {
tstat.cpu_load_system = 0.f;
tstat.cpu_load_user = 0.f;
}
PRIVATE->tm.reset();
#endif
#endif
tstat.cpu_load_system = piClampf(tstat.cpu_load_system, 0.f, 100.f);
tstat.cpu_load_user = piClampf(tstat.cpu_load_user , 0.f, 100.f);
auto i = cur_tm.makeIterator();
while (i.next()) {
if (!last_tm.contains(i.key())) continue;
ThreadStats & ts_new(i.valueRef());
ThreadStats & ts_old(last_tm[i.key()]);
ts_new.cpu_load_kernel = calcThreadUsage(ts_new.kernel_time, ts_old.kernel_time);
ts_new.cpu_load_user = calcThreadUsage(ts_new.user_time, ts_old.user_time);
//piCout << ts_new.cpu_load_user;
}
last_tm = cur_tm;
mutex_.lock();
cur_ts = cur_tm.values();
mutex_.unlock();
tstat.ram_total = totalRAM();
tstat.ram_used = usedRAM();
tstat.ram_free = freeRAM();
stat_mutex.lock();
stat = tstat;
stat.makeStrings();
stat_mutex.unlock();
}
void PISystemMonitor::gatherThread(llong id) {
PISystemMonitor::ThreadStats ts;
ts.id = id;
#ifdef FREERTOS
ts.name = tbid.value(id, "<PIThread>");
#else
ts.name = tbid.value(id, "<non-PIThread>");
# ifndef WINDOWS
PIFile f(PRIVATE->proc_dir + "task/" + PIString::fromNumber(id) + "/stat");
//piCout << f.path();
if (!f.open(PIIODevice::ReadOnly))
return;
PIString str = f.readAll(true);
int si = str.find('(') + 1, fi = 0, cc = 1;
for (int i = si; i < str.size_s(); ++i) {
if (str[i] == '(') cc++;
if (str[i] == ')') cc--;
if (cc <= 0) {
fi = i;
break;
}
}
str.cutMid(si - 1, fi - si + 3);
PIStringList sl = str.split(" ");
if (sl.size_s() < 14) return;
//piCout << sl[0] << sl[12] << sl[13];
ts.user_time = PISystemTime::fromMilliseconds(sl[12].toInt() * 10.);
ts.kernel_time = PISystemTime::fromMilliseconds(sl[13].toInt() * 10.);
# else
PISystemTime ct = PISystemTime::current();
FILETIME times[4];
HANDLE thdl = OpenThread(THREAD_QUERY_INFORMATION, FALSE, DWORD(id));
if (thdl == NULL) {
piCout << "[PISystemMonitor] gatherThread(" << id << "):: OpenThread() error:" << errorString();
return;
}
if (GetThreadTimes(thdl, &(times[0]), &(times[1]), &(times[2]), &(times[3])) == 0) {
piCout << "[PISystemMonitor] gatherThread(" << id << "):: GetThreadTimes() error:" << errorString();
return;
}
CloseHandle(thdl);
ts.created = FILETIME2PIDateTime(times[0]);
ts.work_time = ct - ts.created.toSystemTime();
ts.kernel_time = FILETIME2PISystemTime(times[2]);
ts.user_time = FILETIME2PISystemTime(times[3]);
# endif
#endif
cur_tm[id] = ts;
}
float PISystemMonitor::calcThreadUsage(PISystemTime & t_new, PISystemTime & t_old) {
if (delay_ <= 0) return -1.;
return piClampf(100. * ((t_new - t_old).toMilliseconds() / delay_), 0.f, 100.f);
}
ullong PISystemMonitor::totalRAM() {
#ifdef ESP_PLATFORM
multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t));
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_allocated_bytes + heap_info.total_free_bytes;
#endif
return 0;
}
ullong PISystemMonitor::freeRAM() {
#ifdef ESP_PLATFORM
multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t));
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_free_bytes;
#endif
return 0;
}
ullong PISystemMonitor::usedRAM() {
#ifdef ESP_PLATFORM
multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t));
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_allocated_bytes;
#endif
return 0;
}
PISystemMonitor::Pool * PISystemMonitor::Pool::instance() {
static Pool ret;
return &ret;
}
PISystemMonitor * PISystemMonitor::Pool::getByPID(int pID) {
PIMutexLocker _ml(mutex);
return sysmons.value(pID, 0);
}
void PISystemMonitor::Pool::add(PISystemMonitor * sm) {
PIMutexLocker _ml(mutex);
sysmons[sm->pID()] = sm;
}
void PISystemMonitor::Pool::remove(PISystemMonitor * sm) {
PIMutexLocker _ml(mutex);
sysmons.remove(sm->pID());
}
PIByteArray & operator <<(PIByteArray & s, const PISystemMonitor::ProcessStats & v) {
s << PIByteArray::RawData(&v, sizeof(PISystemMonitor::ProcessStatsFixed))
<< v.exec_name << v.state;
return s;
}
PIByteArray & operator >>(PIByteArray & s, PISystemMonitor::ProcessStats & v) {
s >> PIByteArray::RawData(&v, sizeof(PISystemMonitor::ProcessStatsFixed))
>> v.exec_name >> v.state;
v.makeStrings();
return s;
}
PIByteArray & operator <<(PIByteArray & s, const PISystemMonitor::ThreadStats & v) {
s << PIByteArray::RawData(&v, sizeof(PISystemMonitor::ThreadStatsFixed))
<< v.name;
return s;
}
PIByteArray & operator >>(PIByteArray & s, PISystemMonitor::ThreadStats & v) {
s >> PIByteArray::RawData(&v, sizeof(PISystemMonitor::ThreadStatsFixed))
>> v.name;
return s;
}
/*
PIP - Platform Independent Primitives
Process resource monitor
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 "pisystemmonitor.h"
#include "pidir.h"
#include "piliterals_string.h"
#include "piprocess.h"
#include "pisysteminfo.h"
#include "pitime_win.h"
#include "pitranslator.h"
#include <unistd.h>
#ifdef WINDOWS
# include <psapi.h>
# include <tlhelp32.h>
#endif
#ifdef MAC_OS
struct kqueue_id_t;
# include <libproc.h>
# include <sys/proc_info.h>
#endif
#ifdef ESP_PLATFORM
# include "esp_heap_caps.h"
#endif
void PISystemMonitor::ProcessStats::makeStrings() {
physical_memsize_readable.setReadableSize(physical_memsize);
resident_memsize_readable.setReadableSize(resident_memsize);
share_memsize_readable.setReadableSize(share_memsize);
virtual_memsize_readable.setReadableSize(virtual_memsize);
data_memsize_readable.setReadableSize(data_memsize);
}
#ifndef MICRO_PIP
PRIVATE_DEFINITION_START(PISystemMonitor)
# ifndef WINDOWS
# ifdef MAC_OS
PISystemTime
# else
llong
# endif
cpu_u_cur,
cpu_u_prev, cpu_s_cur, cpu_s_prev;
PIString proc_dir;
PIFile file, filem;
# else
HANDLE hProc;
PROCESS_MEMORY_COUNTERS mem_cnt;
PISystemTime tm_kernel, tm_user;
PITimeMeasurer tm;
# endif
PRIVATE_DEFINITION_END(PISystemMonitor)
#endif
PISystemMonitor::PISystemMonitor(): PIThread() {
pID_ = cycle = 0;
cpu_count = PISystemInfo::instance()->processorsCount;
#ifndef MICRO_PIP
# ifndef WINDOWS
# ifdef QNX
page_size = 4096;
# else
page_size = getpagesize();
# endif
# else
PRIVATE->hProc = 0;
PRIVATE->mem_cnt.cb = sizeof(PRIVATE->mem_cnt);
# endif
#endif
setName("system_monitor"_a);
}
PISystemMonitor::~PISystemMonitor() {
stop();
}
#ifndef MICRO_PIP
bool PISystemMonitor::startOnProcess(int pID, PISystemTime interval) {
stop();
pID_ = pID;
Pool::instance()->add(this);
cycle = -1;
# ifndef WINDOWS
# ifndef MAC_OS
PRIVATE->proc_dir = PIStringAscii("/proc/") + PIString::fromNumber(pID_) + PIStringAscii("/");
PRIVATE->file.open(PRIVATE->proc_dir + "stat", PIIODevice::ReadOnly);
PRIVATE->filem.open(PRIVATE->proc_dir + "statm", PIIODevice::ReadOnly);
if (!PRIVATE->file.isOpened()) {
piCoutObj << "Can`t find process with ID = %1!"_tr("PISystemMonitor").arg(pID_);
return false;
}
# endif
# else
PRIVATE->hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pID_);
if (PRIVATE->hProc == 0) {
piCoutObj << "Can`t open process with ID = %1, %2!"_tr("PISystemMonitor").arg(pID_).arg(errorString());
return false;
}
PRIVATE->tm.reset();
# endif
return start(interval);
}
#endif
bool PISystemMonitor::startOnSelf(PISystemTime interval) {
#ifndef MICRO_PIP
bool ret = startOnProcess(PIProcess::currentPID(), interval);
cycle = -1;
#else
bool ret = start(interval);
#endif
return ret;
}
PIVector<PISystemMonitor::ThreadStats> PISystemMonitor::threadsStatistic() const {
lock();
PIVector<PISystemMonitor::ThreadStats> ret = cur_ts;
unlock();
return ret;
}
void PISystemMonitor::setStatistic(const PISystemMonitor::ProcessStats & s) {
PIMutexLocker _ml(stat_mutex);
stat = s;
stat.makeStrings();
}
void PISystemMonitor::stop() {
PIThread::stopAndWait();
#ifdef WINDOWS
if (PRIVATE->hProc != 0) {
CloseHandle(PRIVATE->hProc);
PRIVATE->hProc = 0;
}
#endif
Pool::instance()->remove(this);
}
PISystemMonitor::ProcessStats PISystemMonitor::statistic() const {
PIMutexLocker _ml(stat_mutex);
return stat;
}
#ifdef MAC_OS
PISystemTime uint64toST(uint64_t v) {
return PISystemTime(((uint *)&(v))[1], ((uint *)&(v))[0]);
}
#endif
void PISystemMonitor::run() {
cur_tm.clear();
tbid.clear();
__PIThreadCollection * pitc = __PIThreadCollection::instance();
pitc->lock();
PIVector<PIThread *> tv = pitc->threads();
for (auto * t: tv)
if (t->isPIObject()) tbid[t->tid()] = t->name();
pitc->unlock();
// piCout << tbid.keys().toType<uint>();
ProcessStats tstat;
tstat.ID = pID_;
#ifdef MICRO_PIP
for (auto * t: tv)
if (t->isPIObject()) gatherThread(t->tid());
#else
# ifndef WINDOWS
double delay_ms = delay_.toMilliseconds();
tbid[pID_] = "main";
# ifdef MAC_OS
rusage_info_current ru;
proc_pid_rusage(pID_, RUSAGE_INFO_CURRENT, (rusage_info_t *)&ru);
// piCout << PISystemTime(((uint*)&(ru.ri_user_time))[1], ((uint*)&(ru.ri_user_time))[0]);
if (cycle < 0) {
PRIVATE->cpu_u_prev = PRIVATE->cpu_u_cur = uint64toST(ru.ri_user_time);
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur = uint64toST(ru.ri_system_time);
}
PRIVATE->cpu_u_prev = PRIVATE->cpu_u_cur;
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur;
PRIVATE->cpu_u_cur = uint64toST(ru.ri_user_time);
PRIVATE->cpu_s_cur = uint64toST(ru.ri_system_time);
tstat.cpu_load_system = 100.f * (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev).toMilliseconds() / delay_ms;
tstat.cpu_load_user = 100.f * (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_ms;
cycle = 0;
// piCout << (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_ms;
# else
PRIVATE->file.seekToBegin();
PIString str = PIString::fromAscii(PRIVATE->file.readAll(true));
int si = str.find('(') + 1, fi = 0, cc = 1;
for (int i = si; i < str.size_s(); ++i) {
if (str[i] == '(') cc++;
if (str[i] == ')') cc--;
if (cc <= 0) {
fi = i;
break;
}
}
tstat.exec_name = str.mid(si, fi - si);
str.cutMid(si - 1, fi - si + 3);
PIStringList sl = str.split(" ");
if (sl.size_s() < 19) return;
tstat.ID = sl[0].toInt();
tstat.state = sl[1];
tstat.parent_ID = sl[2].toInt();
tstat.group_ID = sl[3].toInt();
tstat.session_ID = sl[4].toInt();
if (cycle < 0) {
PRIVATE->cpu_u_prev = PRIVATE->cpu_u_cur = sl[12].toLLong();
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur = sl[13].toLLong();
}
PRIVATE->cpu_u_prev = PRIVATE->cpu_u_cur;
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur;
PRIVATE->cpu_u_cur = sl[12].toLLong();
PRIVATE->cpu_s_cur = sl[13].toLLong();
tstat.cpu_load_system = (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev) / (delay_ms / 1000.);
tstat.cpu_load_user = (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev) / (delay_ms / 1000.);
tstat.cpu_load_system /= cpu_count;
tstat.cpu_load_user /= cpu_count;
cycle = 0;
tstat.priority = sl[16].toInt();
tstat.threads = sl[18].toInt();
// piCout << "\n";
// piCout << sl[0] << sl[12] << sl[13];
PRIVATE->filem.seekToBegin();
str = PIString::fromAscii(PRIVATE->filem.readAll(true));
sl = str.split(" ");
if (sl.size_s() < 6) return;
tstat.virtual_memsize = sl[0].toLong() * page_size;
tstat.resident_memsize = sl[1].toLong() * page_size;
tstat.share_memsize = sl[2].toLong() * page_size;
tstat.data_memsize = sl[5].toLong() * page_size;
tstat.physical_memsize = tstat.resident_memsize - tstat.share_memsize;
PIVector<PIFile::FileInfo> tld = PIDir(PRIVATE->proc_dir + "task").entries();
for (const auto & i: tld) {
if (i.flags[PIFile::FileInfo::Dot] || i.flags[PIFile::FileInfo::DotDot]) continue;
gatherThread(i.name().toInt());
}
# endif
# else
if (GetProcessMemoryInfo(PRIVATE->hProc, &PRIVATE->mem_cnt, sizeof(PRIVATE->mem_cnt)) != 0) {
tstat.physical_memsize = PRIVATE->mem_cnt.WorkingSetSize;
}
tstat.priority = GetPriorityClass(PRIVATE->hProc);
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, pID_);
int thcnt = 0;
if (snap != 0) {
THREADENTRY32 thread;
thread.dwSize = sizeof(THREADENTRY32);
if (Thread32First(snap, &thread) == TRUE) {
if (thread.th32OwnerProcessID == DWORD(pID_)) {
++thcnt;
gatherThread(thread.th32ThreadID);
}
while (Thread32Next(snap, &thread) == TRUE) {
if (thread.th32OwnerProcessID == DWORD(pID_)) {
++thcnt;
gatherThread(thread.th32ThreadID);
}
// piCout << thread.th32ThreadID;
}
}
tstat.threads = thcnt;
CloseHandle(snap);
}
FILETIME ft0, ft1, ft_kernel, ft_user;
double el_s = PRIVATE->tm.elapsed_s() * cpu_count / 100.;
if (GetProcessTimes(PRIVATE->hProc, &ft0, &ft1, &ft_kernel, &ft_user) != 0) {
PISystemTime tm_kernel_c = FILETIME2PISystemTime(ft_kernel);
PISystemTime tm_user_c = FILETIME2PISystemTime(ft_user);
if (cycle < 0) {
PRIVATE->tm_kernel = tm_kernel_c;
PRIVATE->tm_user = tm_user_c;
}
cycle = 0;
if (el_s <= 0.) {
tstat.cpu_load_system = 0.f;
tstat.cpu_load_user = 0.f;
} else {
tstat.cpu_load_system = (tm_kernel_c - PRIVATE->tm_kernel).toSeconds() / el_s;
tstat.cpu_load_user = (tm_user_c - PRIVATE->tm_user).toSeconds() / el_s;
}
PRIVATE->tm_kernel = tm_kernel_c;
PRIVATE->tm_user = tm_user_c;
} else {
tstat.cpu_load_system = 0.f;
tstat.cpu_load_user = 0.f;
}
PRIVATE->tm.reset();
# endif
#endif
tstat.cpu_load_system = piClampf(tstat.cpu_load_system, 0.f, 100.f);
tstat.cpu_load_user = piClampf(tstat.cpu_load_user, 0.f, 100.f);
auto i = cur_tm.makeIterator();
while (i.next()) {
if (!last_tm.contains(i.key())) continue;
ThreadStats & ts_new(i.value());
ThreadStats & ts_old(last_tm[i.key()]);
ts_new.cpu_load_kernel = calcThreadUsage(ts_new.kernel_time, ts_old.kernel_time);
ts_new.cpu_load_user = calcThreadUsage(ts_new.user_time, ts_old.user_time);
// piCout << ts_new.cpu_load_user;
}
last_tm = cur_tm;
lock();
cur_ts = cur_tm.values();
unlock();
tstat.ram_total = totalRAM();
tstat.ram_used = usedRAM();
tstat.ram_free = freeRAM();
stat_mutex.lock();
stat = tstat;
stat.makeStrings();
stat_mutex.unlock();
}
void PISystemMonitor::gatherThread(llong id) {
PISystemMonitor::ThreadStats ts;
if (id == 0) return;
ts.id = id;
#ifdef MICRO_PIP
ts.name = tbid.value(id, "<PIThread>");
#else
ts.name = tbid.value(id, "<non-PIThread>");
# ifndef WINDOWS
PIFile f(PRIVATE->proc_dir + "task/" + PIString::fromNumber(id) + "/stat");
// piCout << f.path();
if (!f.open(PIIODevice::ReadOnly)) return;
PIString str = PIString::fromAscii(f.readAll(true));
int si = str.find('(') + 1, fi = 0, cc = 1;
for (int i = si; i < str.size_s(); ++i) {
if (str[i] == '(') cc++;
if (str[i] == ')') cc--;
if (cc <= 0) {
fi = i;
break;
}
}
str.cutMid(si - 1, fi - si + 3);
PIStringList sl = str.split(" ");
if (sl.size_s() < 14) return;
// piCout << sl[0] << sl[12] << sl[13];
ts.user_time = PISystemTime::fromMilliseconds(sl[12].toInt() * 10.);
ts.kernel_time = PISystemTime::fromMilliseconds(sl[13].toInt() * 10.);
# else
PISystemTime ct = PISystemTime::current();
FILETIME times[4];
HANDLE thdl = OpenThread(THREAD_QUERY_INFORMATION, FALSE, DWORD(id));
if (!thdl) {
piCoutObj << "GatherThread(" << id << "):: OpenThread() error:" << errorString();
return;
}
if (GetThreadTimes(thdl, &(times[0]), &(times[1]), &(times[2]), &(times[3])) == 0) {
CloseHandle(thdl);
piCoutObj << "GatherThread(" << id << "):: GetThreadTimes() error:" << errorString();
return;
}
CloseHandle(thdl);
ts.created = FILETIME2PIDateTime(times[0]);
ts.work_time = ct - ts.created.toSystemTime();
ts.kernel_time = FILETIME2PISystemTime(times[2]);
ts.user_time = FILETIME2PISystemTime(times[3]);
# endif
#endif
cur_tm[id] = ts;
}
float PISystemMonitor::calcThreadUsage(PISystemTime & t_new, PISystemTime & t_old) {
if (delay_.isNull()) return -1.;
return piClampf(100. * ((t_new - t_old).toMilliseconds() / delay_.toMilliseconds()), 0.f, 100.f);
}
ullong PISystemMonitor::totalRAM() {
#ifdef ESP_PLATFORM
multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t));
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_allocated_bytes + heap_info.total_free_bytes;
#endif
return 0;
}
ullong PISystemMonitor::freeRAM() {
#ifdef ESP_PLATFORM
multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t));
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_free_bytes;
#endif
return 0;
}
ullong PISystemMonitor::usedRAM() {
#ifdef ESP_PLATFORM
multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t));
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_allocated_bytes;
#endif
return 0;
}
PISystemMonitor::Pool * PISystemMonitor::Pool::instance() {
static Pool ret;
return &ret;
}
PISystemMonitor * PISystemMonitor::Pool::getByPID(int pID) {
PIMutexLocker _ml(mutex);
return sysmons.value(pID, 0);
}
void PISystemMonitor::Pool::add(PISystemMonitor * sm) {
PIMutexLocker _ml(mutex);
sysmons[sm->pID()] = sm;
}
void PISystemMonitor::Pool::remove(PISystemMonitor * sm) {
PIMutexLocker _ml(mutex);
sysmons.remove(sm->pID());
}

View File

@@ -0,0 +1,323 @@
/*! \file pisystemmonitor.h
* \ingroup Application
* \~\brief
* \~english System resources monitoring
* \~russian Мониторинг ресурсов системы
*/
/*
PIP - Platform Independent Primitives
Process resource monitor
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 PISYSTEMMONITOR_H
#define PISYSTEMMONITOR_H
#include "pifile.h"
#include "pithread.h"
//! \ingroup Application
//! \~\brief
//! \~english Process monitoring.
//! \~russian Мониторинг процесса.
class PIP_EXPORT PISystemMonitor: public PIThread {
PIOBJECT_SUBCLASS(PISystemMonitor, PIThread);
friend class PIIntrospectionServer;
public:
//! \~english Constructs unassigned %PISystemMonitor
//! \~russian Создает непривязанный %PISystemMonitor
PISystemMonitor();
~PISystemMonitor();
#pragma pack(push, 1)
//! \ingroup Application
//! \~\brief
//! \~english Process statistics (fixed-size fields).
//! \~russian Статистика процесса (фиксированные поля).
struct PIP_EXPORT ProcessStatsFixed {
//! \~english PID
//! \~russian PID
int ID = 0;
//! \~english Parent PID
//! \~russian PID родителя
int parent_ID = 0;
//! \~english Group ID
//! \~russian ID группы
int group_ID = 0;
//! \~english Session ID
//! \~russian ID сессии
int session_ID = 0;
//! \~english Priority
//! \~russian Приоритет
int priority = 0;
//! \~english Threads count
//! \~russian Количество потоков
int threads = 0;
//! \~english Physical memory in bytes
//! \~russian Физическая память в байтах
ullong physical_memsize = 0;
//! \~english Resident memory in bytes
//! \~russian Резидентная память в байтах
ullong resident_memsize = 0;
//! \~english Share memory in bytes
//! \~russian Разделяемая память в байтах
ullong share_memsize = 0;
//! \~english Virtual memory in bytes
//! \~russian Виртуальная память в байтах
ullong virtual_memsize = 0;
//! \~english Data memory in bytes
//! \~russian Память данных в байтах
ullong data_memsize = 0;
//! \~english
//! \~russian
ullong ram_total = 0;
//! \~english
//! \~russian
ullong ram_free = 0;
//! \~english
//! \~russian
ullong ram_used = 0;
//! \~english CPU load in kernel space
//! \~russian Загрузка CPU в пространстве ядра
float cpu_load_system = 0.f;
//! \~english CPU load in user space
//! \~russian Загрузка CPU в пространстве пользователя
float cpu_load_user = 0.f;
};
//! \ingroup Application
//! \~\brief
//! \~english Thread statistics (fixed-size fields).
//! \~russian Статистика потока (фиксированные поля).
struct PIP_EXPORT ThreadStatsFixed {
//! \~english TID
//! \~russian TID
llong id = 0;
//! \~english Overall live time
//! \~russian Полное время жизни
PISystemTime work_time;
//! \~english Busy time in kernel space
//! \~russian Время работы в пространстве ядра
PISystemTime kernel_time;
//! \~english Busy time in user space
//! \~russian Время работы в пространстве пользователя
PISystemTime user_time;
//! \~english CPU load in kernel space
//! \~russian Загрузка CPU в пространстве ядра
float cpu_load_kernel = -1.f;
//! \~english CPU load in user space
//! \~russian Загрузка CPU в пространстве пользователя
float cpu_load_user = -1.f;
//! \~english Date and time of creation
//! \~russian Дата и время создания
PIDateTime created;
};
#pragma pack(pop)
//! \ingroup Application
//! \~\brief
//! \~english Process statistics.
//! \~russian Статистика процесса.
struct PIP_EXPORT ProcessStats: ProcessStatsFixed {
//! \~english Fill human-readable fields
//! \~russian Заполнить читаемые поля
void makeStrings();
//! \~english Execution command
//! \~russian Команда запуска
PIString exec_name;
//! \~english State
//! \~russian Состояние
PIString state;
//! \~english Human-readable physical memory
//! \~russian Физическая память в читаемом виде
PIString physical_memsize_readable;
//! \~english Human-readable resident memory
//! \~russian Резидентная память в читаемом виде
PIString resident_memsize_readable;
//! \~english Human-readable share memory
//! \~russian Разделяемая память в читаемом виде
PIString share_memsize_readable;
//! \~english Human-readable virtual memory
//! \~russian Виртуальная память в читаемом виде
PIString virtual_memsize_readable;
//! \~english Human-readable data memory
//! \~russian Память данных в читаемом виде
PIString data_memsize_readable;
};
//! \ingroup Application
//! \~\brief
//! \~english Thread statistics.
//! \~russian Статистика потока.
struct PIP_EXPORT ThreadStats: ThreadStatsFixed {
//! \~english Name
//! \~russian Имя
PIString name;
};
#ifndef MICRO_PIP
//! \~english Starts monitoring of process with PID "pID" and update interval "interval_ms" milliseconds
//! \~russian Начинает мониторинг процесса с PID "pID" и интервалом обновления "interval_ms" миллисекунд
bool startOnProcess(int pID, PISystemTime interval = PISystemTime::fromSeconds(1.));
#endif
//! \~english Starts monitoring of application process with update interval "interval_ms" milliseconds
//! \~russian Начинает мониторинг процесса приложения с интервалом обновления "interval_ms" миллисекунд
bool startOnSelf(PISystemTime interval = PISystemTime::fromSeconds(1.));
//! \~english Stop monitoring
//! \~russian Останавливает мониторинг
void stop();
//! \~english Returns monitoring process PID
//! \~russian Возвращает PID наблюдаемого процесса
int pID() const { return pID_; }
//! \~english Returns monitoring process statistics
//! \~russian Возвращает статистику наблюдаемого процесса
ProcessStats statistic() const;
//! \~english Returns monitoring process threads statistics
//! \~russian Возвращает статистику потоков наблюдаемого процесса
PIVector<ThreadStats> threadsStatistic() const;
void setStatistic(const ProcessStats & s);
//! \~english
//! \~russian
static ullong totalRAM();
//! \~english
//! \~russian
static ullong freeRAM();
//! \~english
//! \~russian
static ullong usedRAM();
private:
void run() override;
void gatherThread(llong id);
float calcThreadUsage(PISystemTime & t_new, PISystemTime & t_old);
ProcessStats stat;
PIVector<ThreadStats> cur_ts;
PIMap<llong, ThreadStats> last_tm, cur_tm;
PIMap<llong, PIString> tbid;
mutable PIMutex stat_mutex;
int pID_, page_size, cpu_count, cycle;
#ifndef MICRO_PIP
PRIVATE_DECLARATION(PIP_EXPORT)
#endif
class PIP_EXPORT Pool {
friend class PISystemMonitor;
public:
static Pool * instance();
PISystemMonitor * getByPID(int pID);
private:
void add(PISystemMonitor * sm);
void remove(PISystemMonitor * sm);
PIMap<int, PISystemMonitor *> sysmons;
PIMutex mutex;
};
};
//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
inline PICout operator<<(PICout s, const PISystemMonitor::ThreadStats & v) {
s.saveAndSetControls(0);
s << "ThreadInfo(\"" << v.name << "\", created " << v.created << ", work " << v.work_time.toMilliseconds() << " ms"
<< ", kernel " << v.kernel_time.toMilliseconds() << " ms"
<< ", user " << v.user_time.toMilliseconds() << " ms"
<< ")\n";
s.restoreControls();
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Store operator.
//! \~russian Оператор сохранения.
BINARY_STREAM_WRITE(PISystemMonitor::ProcessStats) {
s << PIMemoryBlock(&v, sizeof(PISystemMonitor::ProcessStatsFixed)) << v.exec_name << v.state;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Restore operator.
//! \~russian Оператор извлечения.
BINARY_STREAM_READ(PISystemMonitor::ProcessStats) {
s >> PIMemoryBlock(&v, sizeof(PISystemMonitor::ProcessStatsFixed)) >> v.exec_name >> v.state;
v.makeStrings();
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Store operator.
//! \~russian Оператор сохранения.
BINARY_STREAM_WRITE(PISystemMonitor::ThreadStats) {
s << PIMemoryBlock(&v, sizeof(PISystemMonitor::ThreadStatsFixed)) << v.name;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Restore operator.
//! \~russian Оператор извлечения.
BINARY_STREAM_READ(PISystemMonitor::ThreadStats) {
s >> PIMemoryBlock(&v, sizeof(PISystemMonitor::ThreadStatsFixed)) >> v.name;
return s;
}
#endif // PISYSTEMMONITOR_H

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,69 @@
/*! \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

@@ -0,0 +1,88 @@
/*! \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

@@ -0,0 +1,79 @@
/*! \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

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

View File

@@ -1,23 +1,26 @@
/*! @file picloudbase.h
* @brief PICloud Base - Base class for PICloudClient and PICloud Server
*/
/*! \file picloudbase.h
* \ingroup Cloud
* \~\brief
* \~english Base class for PICloudClient and PICloudServer
* \~russian Базовый класс для PICloudClient и PICloudServer
*/
/*
PIP - Platform Independent Primitives
PICloud Base - Base class for PICloudClient and PICloud Server
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
PICloud Base - Base class for PICloudClient and PICloud Server
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 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.
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/>.
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 PICLOUDBASE_H
@@ -28,8 +31,7 @@
#include "pistreampacker.h"
class PIP_CLOUD_EXPORT PICloudBase
{
class PIP_CLOUD_EXPORT PICloudBase {
public:
PICloudBase();

View File

@@ -1,23 +1,26 @@
/*! @file picloudclient.h
* @brief PICloud Client
*/
/*! \file picloudclient.h
* \ingroup Cloud
* \~\brief
* \~english PICloud Client
* \~russian Клиент PICloud
*/
/*
PIP - Platform Independent Primitives
PICloud Client
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
PICloud Client
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 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.
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/>.
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 PICLOUDCLIENT_H
@@ -27,37 +30,44 @@
#include "piconditionvar.h"
//! @brief PICloudClient
//! \brief PICloudClient
class PIP_CLOUD_EXPORT PICloudClient
: public PIIODevice
, public PICloudBase {
PIIODEVICE(PICloudClient, "");
class PIP_CLOUD_EXPORT PICloudClient: public PIIODevice, public PICloudBase
{
PIIODEVICE(PICloudClient)
public:
explicit PICloudClient(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
virtual ~PICloudClient();
void setServerName(const PIString & server_name);
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(disconnected)
EVENT(connected);
EVENT(disconnected);
protected:
bool openDevice();
bool closeDevice();
int readDevice(void * read_to, int max_size);
int writeDevice(const void * data, int size);
DeviceInfoFlags deviceInfoFlags() const {return PIIODevice::Reliable;}
bool openDevice() override;
bool closeDevice() override;
ssize_t readDevice(void * read_to, ssize_t max_size) override;
ssize_t writeDevice(const void * data, ssize_t size) override;
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
private:
EVENT_HANDLER1(void, _readed, PIByteArray &, data);
void internalDisconnect();
PIByteArray buff;
PIMutex mutex_buff;
PIMutex mutex_connect;
PIConditionVariable cond_buff;
PIConditionVariable cond_connect;
std::atomic_bool is_connected;
std::atomic_bool is_deleted;
};
#endif // PICLOUDCLIENT_H

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