Compare commits
442 Commits
pimap
...
8e96750046
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e96750046 | |||
| d01baffb0b | |||
| 82cda42e75 | |||
| 5755d172cd | |||
| 0dd47f50a0 | |||
| 60d2a83df5 | |||
| 7757ac10ec | |||
| f334a6603f | |||
| 15548de79c | |||
| 49713ddc57 | |||
| 0973379f53 | |||
| a3004491d6 | |||
| 199a272eb8 | |||
| 855d1ca1b5 | |||
| 64025e0399 | |||
| 6e5556969d | |||
| b50eeaef46 | |||
| ffc471359a | |||
| 79007e7b4e | |||
| 9e08b6ffc5 | |||
| 9b8a1583c2 | |||
| cae264a77b | |||
| 4f934fef35 | |||
| 3a159b0553 | |||
| 0c973f0216 | |||
| 65d3168eb5 | |||
| 12114b3e77 | |||
| 6f6b717354 | |||
| 58b3fa64bc | |||
| 1acaf24df9 | |||
| c2c9822169 | |||
| dff4f2b3a0 | |||
| bf9ad65ff0 | |||
| 53ec75bf0c | |||
| f5270d75eb | |||
| 4aa596b179 | |||
| 002f21fc9e | |||
| 9ab46e4afc | |||
| caa7880cc4 | |||
| 24112498ce | |||
| c9a5ddd89f | |||
| 3483edbd76 | |||
| fe82c12d5b | |||
| d90c3f0991 | |||
| f6b9131f4a | |||
| c67f7a2b64 | |||
| 047d38ea59 | |||
| 3d07795515 | |||
| ee137b2820 | |||
| cdde340efe | |||
| ee34e8a72e | |||
| 0840d807a0 | |||
| 4655d72554 | |||
| 5b066cbc27 | |||
| 2247473959 | |||
| 57f8c1313e | |||
| 73ed51e3d4 | |||
| 1106cde3e4 | |||
| b43158d3a8 | |||
| 9a928f6feb | |||
| df75efe881 | |||
| 9f1d23ad8e | |||
| 7cd2f7a310 | |||
| 315966504e | |||
| 7209eec012 | |||
| 992f59904a | |||
| 9dbd7210cb | |||
| ac8efc9f88 | |||
| 92a0a9356c | |||
| 28f3471036 | |||
| d3d7235338 | |||
| 92a87a0c64 | |||
| cd7e053fc5 | |||
| 9eecbbab6e | |||
| 3641e636d2 | |||
| 4acab04895 | |||
| aa963a4bda | |||
| bdd18b614f | |||
| e186e0adff | |||
| f105f616f6 | |||
|
|
b99c51181d | ||
|
|
bc6b584480 | ||
| eb97de1413 | |||
| 97f1c25ff8 | |||
| 97aad47a21 | |||
| 43bd1d8550 | |||
|
|
3255199b3f | ||
| 224412e20a | |||
| 000ce2a54d | |||
|
|
f992bf4cbb | ||
|
|
96625bd93d | ||
| 9d4357c066 | |||
| 7a945f47b1 | |||
| 9a352bfc83 | |||
| aa2f117075 | |||
| bf5bb45771 | |||
| cdc966bd8c | |||
| 17b902ebcc | |||
| 996b7ea403 | |||
| da4b09be9e | |||
| b24b5a1346 | |||
| 0d94699206 | |||
| 16a818c95e | |||
| a0454b809d | |||
| af8c096c7a | |||
| 14cf81aed0 | |||
| c43b914fb3 | |||
| f002f6cedd | |||
| ce846eca51 | |||
| e6c8714857 | |||
| 33fc334077 | |||
| 6efc962923 | |||
| 7d02f710ea | |||
| c8876807ed | |||
| f43f834460 | |||
| ccf6b810b5 | |||
| a438c4249d | |||
| 1c7fc39b6c | |||
| f07c9cbce8 | |||
| abdba6d68b | |||
| 3db26a762c | |||
| b35561f74e | |||
| f041d1435e | |||
| b781bd5148 | |||
| a16e0b7659 | |||
| 0bafd3fa98 | |||
| 903b320629 | |||
| 9cd05996e7 | |||
| 15dc76c4a7 | |||
| d46b5e008a | |||
| af4b718053 | |||
| 7eae1e127c | |||
| f97fed7daa | |||
| d764171c82 | |||
| d4a024ea75 | |||
| 491d89f117 | |||
| a86e8f7b58 | |||
| d97798d063 | |||
| 247759b364 | |||
| a745f803b3 | |||
| 1b67000887 | |||
| 04d3e31dbc | |||
| 9f29155d07 | |||
| 021411defa | |||
| ee4d78d2e1 | |||
| 9283c88b4e | |||
| 8d585439bb | |||
| ebf2b08bb1 | |||
| eb21c85170 | |||
| fb68a9f9fe | |||
| c7c3852747 | |||
| c18d0c918e | |||
| 9c4fd41eef | |||
| 9173dc936d | |||
| 77c8681b43 | |||
| 2db9440a38 | |||
| 0d585cfebf | |||
| 02a9bfb76f | |||
| ad7385c21f | |||
| dd6d91ac1d | |||
| 576d9c79be | |||
| 3fa5d9d9df | |||
| b14d30108a | |||
| 2b738f6f43 | |||
| 263fa18726 | |||
| f47bc411bc | |||
| 154fb7d9fd | |||
| 9f09af9f27 | |||
| 960e4a7cce | |||
| 50bff12364 | |||
| 7297b9aee0 | |||
| 3652705784 | |||
| 851f101470 | |||
| 6b87536d8d | |||
| d299a1f386 | |||
| c8350d2f0a | |||
| 7efdacc979 | |||
| c77afcc374 | |||
| b8fc44714c | |||
| 49a5ed6aa3 | |||
| 76c76b48c5 | |||
| 03bd23a3b9 | |||
| 61e6edb4c8 | |||
| aa78e930be | |||
| bb668dab29 | |||
| d1662d3535 | |||
| 12b136a2f4 | |||
| aa69815a31 | |||
| 3afa0ce0ab | |||
| 64a474c343 | |||
| 0907a3eb13 | |||
| c86ec0ae82 | |||
| ac76e07d9d | |||
| 56aed70425 | |||
| 63321a4ce3 | |||
| 66fb93ba88 | |||
| 299a009d61 | |||
| 4d395f4487 | |||
| 2f82aaf97b | |||
| 13ececf370 | |||
| b19d50ba62 | |||
| b763f0e5cd | |||
| 27f6f5158d | |||
| 61f1a34c14 | |||
| 8ad2503c5a | |||
| 1a96dc0cb9 | |||
| de810b7bd6 | |||
| 35aadb0e78 | |||
| 3a6b3a4064 | |||
| 9e78546b7e | |||
| ccae1a7311 | |||
| 54d0ba1876 | |||
| d1193e7aa1 | |||
| 6c6437e980 | |||
| 17e75c2951 | |||
| c4766f8f5b | |||
| 1a214cff4e | |||
| dd56b1c142 | |||
| 0ae63fa9ad | |||
| 5e4c5b0d47 | |||
| 58dcf7ba69 | |||
| 1de4304e30 | |||
| 96e8ef2b23 | |||
| dea29429bf | |||
| f5392f8b63 | |||
| 3ab57eea88 | |||
| f503e85507 | |||
| 0f19719a98 | |||
| ee7251c17c | |||
| 2780dacb48 | |||
| dea469d85e | |||
| 254649aa10 | |||
| 7badc531ce | |||
| 6d3b7c8543 | |||
| 4af5886649 | |||
| 38bcb6c482 | |||
| eb91ee1b35 | |||
|
|
2d1c86bc83 | ||
|
d66f7efb3c
|
|||
|
20bdf3af61
|
|||
| 49f5de26eb | |||
| 0cd1206f94 | |||
|
df82102798
|
|||
|
650dadc347
|
|||
| 504fc5c896 | |||
| 162f8e25fd | |||
|
e0900b6bd5
|
|||
|
f3540d54b4
|
|||
| d743cc66d8 | |||
| df4dcd7f32 | |||
| 3391d88460 | |||
| 5d75f1d298 | |||
| 73d482ebe2 | |||
| 9ed66db515 | |||
| c64a1beefa | |||
| 677ae06df8 | |||
| 5cc5369d2a | |||
| 5c16953d95 | |||
| f355cfc05e | |||
| 81cbf905ba | |||
| 2732595efe | |||
| 2ac215c19e | |||
| 6c3f305562 | |||
| fd82f5316c | |||
| a98176f513 | |||
| 886eb06880 | |||
| 581c7c937a | |||
| 5836c64e5e | |||
| badcfac616 | |||
| c2b8a8d6da | |||
| 430a41fefc | |||
| c74ba871cd | |||
| 9d9357b0ca | |||
| c4cb81a104 | |||
| b609ce8027 | |||
| 0bd45ec49b | |||
| 3625627072 | |||
| 8e744249de | |||
| cf5284a244 | |||
| 74c20c37b7 | |||
| b25ecf42fb | |||
| 5bb9477b5b | |||
| a27353d42d | |||
| 1327e46f61 | |||
| a516acbd44 | |||
| d3d2b4281c | |||
| ab0b6a7649 | |||
| 6e13ee173e | |||
| a786c928e0 | |||
| f52fc5332c | |||
| dc6fbbf7ec | |||
| a2256a3872 | |||
| d45996af28 | |||
| 05dcbca894 | |||
| 57ed40912d | |||
| 46751ab977 | |||
| e9128771db | |||
|
|
7bbffef237 | ||
|
|
cb59017ebb | ||
| ec8fbcb112 | |||
| 4c909e692a | |||
|
|
cfc9ed131a | ||
|
|
39d81dd23b | ||
| 56fd6b921e | |||
| 0fed454bb7 | |||
| cbac9f4253 | |||
|
|
d46f1a137a | ||
| 3d7e845213 | |||
| e9a7eaa276 | |||
|
|
e6a5010023 | ||
| 4994d0bf66 | |||
|
|
15a9d68a87 | ||
|
|
16c09ae6e9 | ||
| 702d1642e0 | |||
| d34374d4e0 | |||
| 398d760ba9 | |||
|
|
d9eac06749 | ||
|
|
f9c1ef5ba4 | ||
|
|
8738043dce | ||
| db5c4dcf3f | |||
| d3dd3fb32b | |||
|
|
21fa3baf4e | ||
|
|
b17510218b | ||
|
|
897f03f3d0 | ||
|
|
36ff427e0d | ||
|
|
2e1179e2fa | ||
| fffaf0726d | |||
| 6da1ec5acf | |||
| 16a8d37a8f | |||
|
|
93a1bf4f6d | ||
|
|
f08a07cab0 | ||
| 8a5e72c723 | |||
| 2163deb7ea | |||
| 4219372e68 | |||
| e48d0ebaab | |||
| 591c92b4bb | |||
| 6e81a419fb | |||
| ca403ca2c7 | |||
| e46cfdc4bd | |||
| 609ff8e9c8 | |||
| ea0df21726 | |||
| 3a5050b028 | |||
| 2cf561767f | |||
| 638f0e0181 | |||
| 359c7816bc | |||
| 9438ab4e53 | |||
| e5777dde6c | |||
| 3c7e117661 | |||
| 0f48c206c3 | |||
| 4a7f009cc6 | |||
| 001812f3ce | |||
|
|
bf87f631f0 | ||
| 44876836c5 | |||
| 2d2f6b254b | |||
| 858b54ce64 | |||
| 38840c5b7d | |||
| 499ee386a7 | |||
|
|
eddef26b5e | ||
|
|
db3de9904a | ||
|
|
3511fee459 | ||
|
|
5a1a381a32 | ||
|
|
1bc9f5ed19 | ||
|
|
8370351ff3 | ||
|
|
952020a3e2 | ||
|
|
b35ec1f30a | ||
| 443eeed38b | |||
| d1abfe5213 | |||
|
|
29e34bdd60 | ||
|
|
4635e9ba4f | ||
|
|
49e553c551 | ||
| 1abcf06bf6 | |||
| 2550f76376 | |||
| 24da7aa644 | |||
| 494faf862b | |||
| 67561636e5 | |||
|
|
00f7a24d54 | ||
|
|
f07f814b08 | ||
| fed2c5991d | |||
| ed888324b2 | |||
| 79efd9e15d | |||
|
|
1acd29e474 | ||
|
|
cd7af5e9b7 | ||
|
|
adef5b6781 | ||
|
|
2e9acdb1ba | ||
| f0fee0d78f | |||
|
|
60f4db61eb | ||
|
|
724a2dffcf | ||
| 616b384ad6 | |||
| 8abc9777cc | |||
| 8551499a5e | |||
|
|
1eaecb288f | ||
|
|
170a713357 | ||
| 54cc6c55b2 | |||
| e6aa3c34d4 | |||
| bb40f69298 | |||
| af9a9e78b9 | |||
| af1264e42b | |||
| eb91fbfc45 | |||
| 4ea5465637 | |||
| ab7769dd5a | |||
| b1e220e454 | |||
| 1b499530c5 | |||
| b0d48caaad | |||
|
|
d6758a8562 | ||
| 97734953dd | |||
| bd98583116 | |||
|
|
ddba8f401b | ||
|
|
4725eb96d6 | ||
|
|
38fd1b5dc4 | ||
| 16c12a2756 | |||
|
|
1b09ad5c27 | ||
|
|
00d06f71ba | ||
|
|
3873f0b03b | ||
| 6ae6e9a540 | |||
|
|
bbc83128b0 | ||
|
|
d13e68c206 | ||
| a4882dc054 | |||
|
|
a1b9b7e1d6 | ||
|
|
e1b89aeca8 | ||
| 242abaaf59 | |||
|
|
0116387fe3 | ||
|
|
f5953a0ba7 | ||
|
|
7aa407264f | ||
|
|
59c7896577 | ||
|
|
a69de63db0 | ||
| e96b399da7 | |||
| 33eefd7453 | |||
| c7fffe1280 | |||
| 1b04d7ecce | |||
| b66272a68a | |||
| f67e3030b9 | |||
| 1028233553 | |||
| ef8ffcd02f | |||
| 0897a8369f | |||
| fa19ad1093 | |||
| 8c6b3613b6 | |||
| a23eb341e2 | |||
| b2bc385397 | |||
| 0f9e592273 | |||
| cf4f58ed95 | |||
| 0243f588bc | |||
| af77974e91 |
224
.clang-format
Normal file
224
.clang-format
Normal 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
6
.editorconfig
Normal file
@@ -0,0 +1,6 @@
|
||||
root = true
|
||||
|
||||
[*.{h,c,cpp}]
|
||||
charset = utf-8
|
||||
indent_style = tab
|
||||
tab_width = 4
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,4 +3,5 @@
|
||||
/doc/rtf
|
||||
_unsused
|
||||
CMakeLists.txt.user*
|
||||
/include
|
||||
/include
|
||||
/release
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lapi_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lcode_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lctype_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define ldebug_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define ldo_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define ldump_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lfunc_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lgc_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define llex_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lmem_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lobject_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lopcodes_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lparser_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lstate_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lstring_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define ltable_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define ltm_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lundump_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lvm_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lzio_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
468
CMakeLists.txt
468
CMakeLists.txt
@@ -1,12 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
|
||||
project(pip)
|
||||
set(pip_MAJOR 2)
|
||||
set(pip_MINOR 39)
|
||||
set(pip_REVISION 0)
|
||||
set(pip_SUFFIX )
|
||||
set(pip_COMPANY SHS)
|
||||
set(pip_DOMAIN org.SHS)
|
||||
project(PIP)
|
||||
set(PIP_MAJOR 4)
|
||||
set(PIP_MINOR 7)
|
||||
set(PIP_REVISION 0)
|
||||
set(PIP_SUFFIX )
|
||||
set(PIP_COMPANY SHS)
|
||||
set(PIP_DOMAIN org.SHS)
|
||||
|
||||
set(GIT_CMAKE_DIR)
|
||||
if (NOT DEFINED SHSTKPROJECT)
|
||||
@@ -17,7 +17,7 @@ cmake_minimum_required(VERSION 2.8.2)
|
||||
project(cmake-download NONE)
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(cmake
|
||||
GIT_REPOSITORY https://git.shs.tools/SHS/cmake.git
|
||||
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\"
|
||||
@@ -53,7 +53,8 @@ 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))
|
||||
@@ -61,7 +62,6 @@ if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE
|
||||
endif()
|
||||
set(PIP_DLL_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "")
|
||||
|
||||
|
||||
# Options
|
||||
option(ICU "ICU support for convert codepages" ${_ICU_DEFAULT})
|
||||
option(STD_IOSTREAM "Building with std iostream operators support" OFF)
|
||||
@@ -72,6 +72,13 @@ 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)
|
||||
@@ -84,9 +91,11 @@ 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")
|
||||
string(TOUPPER "${_m}" _mu)
|
||||
option(PIP_BUILD_${_mu} "Build \"${_m}\" module" ON)
|
||||
endforeach()
|
||||
|
||||
macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
|
||||
@@ -96,7 +105,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})
|
||||
@@ -105,9 +114,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")
|
||||
@@ -118,11 +132,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)
|
||||
|
||||
@@ -139,7 +153,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)
|
||||
@@ -171,10 +185,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()
|
||||
@@ -234,26 +250,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()
|
||||
|
||||
@@ -281,9 +282,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()
|
||||
|
||||
|
||||
@@ -307,15 +313,6 @@ 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)
|
||||
@@ -326,23 +323,27 @@ if ((NOT DEFINED SHSTKPROJECT) AND (DEFINED ANDROID_PLATFORM))
|
||||
#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})
|
||||
@@ -369,6 +370,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}")
|
||||
@@ -376,131 +379,253 @@ 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)
|
||||
|
||||
if (PIP_BUILD_CONSOLE)
|
||||
pip_module(console "" "PIP console support" "" "" "")
|
||||
endif()
|
||||
|
||||
pip_module(console "" "PIP console support" "" "" "")
|
||||
|
||||
|
||||
pip_find_lib(usb)
|
||||
if(usb_FOUND)
|
||||
pip_module(usb "usb" "PIP usb support" "" "" "")
|
||||
if (PIP_BUILD_USB)
|
||||
pip_find_lib(usb)
|
||||
if(usb_FOUND)
|
||||
pip_module(usb "usb" "PIP usb support" "" "" "")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
pip_find_lib(zlib NAMES z zlib)
|
||||
if(zlib_FOUND)
|
||||
pip_module(compress "zlib" "PIP compression support" "" "" "")
|
||||
if (PIP_BUILD_COMPRESS)
|
||||
pip_find_lib(zlib NAMES z zlib)
|
||||
if(zlib_FOUND)
|
||||
pip_module(compress "zlib" "PIP compression support" "" "" "")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
pip_find_lib(sodium)
|
||||
if(sodium_FOUND)
|
||||
pip_module(crypt "sodium" "PIP crypt support" "" "" "")
|
||||
pip_module(cloud "pip_io_utils" "PIP cloud support" "" "" "")
|
||||
if (PIP_BUILD_CRYPT)
|
||||
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()
|
||||
endif()
|
||||
|
||||
|
||||
# Check if PIP support fftw3 for PIFFT using in math module
|
||||
set(FFTW_LIB_NAME fftw3)
|
||||
set(FFTW_LIB_SUFFIXES "" "f" "l" "q")
|
||||
set(FFTW_LIB_SUFFIXES2 "" "-3")
|
||||
set(FFTW_LIBS)
|
||||
set(FFTW_ABS_LIBS)
|
||||
set(CMAKE_REQUIRED_INCLUDES fftw3.h)
|
||||
foreach(FFTW_S_ IN LISTS FFTW_LIB_SUFFIXES)
|
||||
set(FFTW_BREAK false)
|
||||
foreach(FFTW_S2_ IN LISTS FFTW_LIB_SUFFIXES2)
|
||||
if(NOT FFTW_BREAK)
|
||||
set(FFTW_CLN "${FFTW_LIB_NAME}${FFTW_S_}${FFTW_S2_}")
|
||||
set(FFTW_CLNT "${FFTW_LIB_NAME}${FFTW_S_}_threads${FFTW_S2_}")
|
||||
find_library(${FFTW_CLN}_LIBRARIES ${FFTW_CLN})
|
||||
find_library(${FFTW_CLNT}_LIBRARIES ${FFTW_CLNT})
|
||||
set(${FFTW_CLN}_FOUND FALSE)
|
||||
set(${FFTW_CLNT}_FOUND FALSE)
|
||||
if(${FFTW_CLN}_LIBRARIES)
|
||||
set(${FFTW_CLN}_FOUND TRUE)
|
||||
list(APPEND FFTW_LIBS "${FFTW_CLN}")
|
||||
list(APPEND FFTW_ABS_LIBS "${${FFTW_CLN}_LIBRARIES}")
|
||||
set(${FFTW_CLN}_CTS "${FFTW_CLN}")
|
||||
if(${FFTW_CLNT}_FLIBRARIES)
|
||||
set(${FFTW_CLNT}_FOUND TRUE)
|
||||
list(APPEND FFTW_LIBS "${FFTW_CLNT}")
|
||||
list(APPEND FFTW_ABS_LIBS "${${FFTW_CLNT}_LIBRARIES}")
|
||||
list(APPEND ${FFTW_CLN}_CTS "${FFTW_CLNT}")
|
||||
if (PIP_BUILD_FFTW)
|
||||
# Check if PIP support fftw3 for PIFFT using in math module
|
||||
set(FFTW_LIB_NAME fftw3)
|
||||
set(FFTW_LIB_SUFFIXES "" "f" "l" "q")
|
||||
set(FFTW_LIB_SUFFIXES2 "" "-3")
|
||||
set(FFTW_LIBS)
|
||||
set(FFTW_ABS_LIBS)
|
||||
set(CMAKE_REQUIRED_INCLUDES fftw3.h)
|
||||
foreach(FFTW_S_ IN LISTS FFTW_LIB_SUFFIXES)
|
||||
set(FFTW_BREAK false)
|
||||
foreach(FFTW_S2_ IN LISTS FFTW_LIB_SUFFIXES2)
|
||||
if(NOT FFTW_BREAK)
|
||||
set(FFTW_CLN "${FFTW_LIB_NAME}${FFTW_S_}${FFTW_S2_}")
|
||||
set(FFTW_CLNT "${FFTW_LIB_NAME}${FFTW_S_}_threads${FFTW_S2_}")
|
||||
find_library(${FFTW_CLN}_LIBRARIES ${FFTW_CLN})
|
||||
find_library(${FFTW_CLNT}_LIBRARIES ${FFTW_CLNT})
|
||||
set(${FFTW_CLN}_FOUND FALSE)
|
||||
set(${FFTW_CLNT}_FOUND FALSE)
|
||||
if(${FFTW_CLN}_LIBRARIES)
|
||||
set(${FFTW_CLN}_FOUND TRUE)
|
||||
list(APPEND FFTW_LIBS "${FFTW_CLN}")
|
||||
list(APPEND FFTW_ABS_LIBS "${${FFTW_CLN}_LIBRARIES}")
|
||||
set(${FFTW_CLN}_CTS "${FFTW_CLN}")
|
||||
if(${FFTW_CLNT}_FLIBRARIES)
|
||||
set(${FFTW_CLNT}_FOUND TRUE)
|
||||
list(APPEND FFTW_LIBS "${FFTW_CLNT}")
|
||||
list(APPEND FFTW_ABS_LIBS "${${FFTW_CLNT}_LIBRARIES}")
|
||||
list(APPEND ${FFTW_CLN}_CTS "${FFTW_CLNT}")
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${${FFTW_CLN}_CTS})
|
||||
CHECK_FUNCTION_EXISTS(fftw${FFTW_S_}_make_planner_thread_safe ${FFTW_CLN}_TSFE)
|
||||
add_definitions(-DPIP_FFTW${FFTW_S_})
|
||||
if(${FFTW_CLN}_TSFE)
|
||||
add_definitions(-DPIP_FFTW${FFTW_S_}_THREADSAFE)
|
||||
else()
|
||||
message(STATUS "Warning: PIFFTW${FFTW_S_}::preparePlan was not threadsafe")
|
||||
endif()
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${${FFTW_CLN}_CTS})
|
||||
CHECK_FUNCTION_EXISTS(fftw${FFTW_S_}_make_planner_thread_safe ${FFTW_CLN}_TSFE)
|
||||
add_definitions(-DPIP_FFTW${FFTW_S_})
|
||||
if(${FFTW_CLN}_TSFE)
|
||||
add_definitions(-DPIP_FFTW${FFTW_S_}_THREADSAFE)
|
||||
else()
|
||||
message(STATUS "Warning: PIFFTW${FFTW_S_}::preparePlan was not threadsafe")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
if(FFTW_LIBS)
|
||||
pip_module(fftw "${FFTW_LIBS}" "PIP FFTW support" "" "" "")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if (PIP_BUILD_OPENCL)
|
||||
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_inc "${OpenCL_INCLUDE_DIRS}")
|
||||
if(APPLE)
|
||||
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers")
|
||||
endif()
|
||||
pip_module(opencl "OpenCL" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if (PIP_BUILD_IO_UTILS)
|
||||
if(sodium_FOUND)
|
||||
pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
|
||||
else()
|
||||
pip_module(io_utils "" "PIP I/O support" "" "" "")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if (PIP_BUILD_LUA)
|
||||
# Lua module
|
||||
set(_lua_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/3rd/lua")
|
||||
set(_lua_bri_dir "${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd")
|
||||
set(_lua_src_hdr "${_lua_src_dir}/lua.hpp" "${_lua_src_dir}/lua.h" "${_lua_src_dir}/luaconf.h" "${_lua_src_dir}/lualib.h")
|
||||
pip_module(lua "" "PIP Lua support" "${_lua_src_dir};${_lua_bri_dir}" "${_lua_src_dir}" " (internal)")
|
||||
target_include_directories(pip_lua PUBLIC "${_lua_src_dir}" "${_lua_bri_dir}")
|
||||
if (WIN32)
|
||||
target_compile_definitions(pip_lua PRIVATE LUA_BUILD_AS_DLL LUA_CORE)
|
||||
endif()
|
||||
list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge")
|
||||
list(APPEND HDRS ${_lua_src_hdr})
|
||||
endif()
|
||||
|
||||
|
||||
if (PIP_BUILD_HTTP_SERVER)
|
||||
# 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()
|
||||
endforeach()
|
||||
endforeach()
|
||||
if(FFTW_LIBS)
|
||||
pip_module(fftw "${FFTW_LIBS}" "PIP FFTW support" "" "" "")
|
||||
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)
|
||||
#list(APPEND microhttpd_LIBRARIES "${_microhttpd_add_libs}")
|
||||
pip_module(http_server "${_microhttpd_add_libs}" "PIP HTTP server" "" "" "")
|
||||
endif()
|
||||
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}")
|
||||
if(APPLE)
|
||||
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers")
|
||||
endif()
|
||||
|
||||
|
||||
if (PIP_BUILD_HTTP_CLIENT)
|
||||
# libcurl
|
||||
pip_find_lib(curl HINTS "${MINGW_LIB}")
|
||||
if (curl_FOUND)
|
||||
pip_module(http_client curl "PIP HTTP client" "" "" "")
|
||||
endif()
|
||||
pip_module(opencl "${_opencl_lib}" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})")
|
||||
endif()
|
||||
|
||||
|
||||
if(sodium_FOUND)
|
||||
pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
|
||||
else()
|
||||
pip_module(io_utils "" "PIP I/O support" "" "" "")
|
||||
endif()
|
||||
|
||||
|
||||
# Lua module
|
||||
set(_lua_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/3rd/lua")
|
||||
set(_lua_bri_dir "${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd")
|
||||
set(_lua_src_hdr "${_lua_src_dir}/lua.hpp" "${_lua_src_dir}/lua.h" "${_lua_src_dir}/luaconf.h" "${_lua_src_dir}/lualib.h")
|
||||
pip_module(lua "" "PIP Lua support" "${_lua_src_dir};${_lua_bri_dir}" "${_lua_src_dir}" " (internal)")
|
||||
target_include_directories(pip_lua PUBLIC "${_lua_src_dir}" "${_lua_bri_dir}")
|
||||
if (WIN32)
|
||||
target_compile_definitions(pip_lua PRIVATE LUA_BUILD_AS_DLL LUA_CORE)
|
||||
endif()
|
||||
list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge")
|
||||
list(APPEND HDRS ${_lua_src_hdr})
|
||||
|
||||
|
||||
# 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)
|
||||
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()
|
||||
pip_module(crypt "" "PIP crypt support" "" "" "")
|
||||
pip_module(compress "" "PIP compression support" "" "" "")
|
||||
pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
|
||||
|
||||
if (PIP_BUILD_CRYPT)
|
||||
pip_module(crypt "" "PIP crypt support" "" "" "")
|
||||
endif()
|
||||
|
||||
if (PIP_BUILD_COMPRESS)
|
||||
pip_module(compress "" "PIP compression support" "" "" "")
|
||||
endif()
|
||||
|
||||
if (PIP_BUILD_IO_UTILS)
|
||||
pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
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)
|
||||
@@ -508,6 +633,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()
|
||||
@@ -521,6 +649,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)
|
||||
@@ -528,6 +657,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()
|
||||
@@ -543,6 +675,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()
|
||||
@@ -551,29 +686,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)
|
||||
@@ -588,18 +700,18 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
|
||||
find_package(Doxygen)
|
||||
if(DOXYGEN_FOUND)
|
||||
set(DOXY_DEFINES "${PIP_EXPORTS}")
|
||||
foreach (_m "console" "usb" "compress" "crypt" "cloud" "fftw" "opencl" "io_utils" "lua")
|
||||
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_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")
|
||||
set(DOXY_DOMAIN "${PIP_DOMAIN}.${PROJECT_NAME}.doc")
|
||||
if ("x${DOC_LANG}" STREQUAL "x")
|
||||
set(DOXY_OUTPUT_LANGUAGE English)
|
||||
set(DOXY_OUTPUT_DIR en)
|
||||
@@ -644,10 +756,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()
|
||||
@@ -659,7 +772,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)
|
||||
|
||||
@@ -33,10 +33,10 @@ You should add ${<out_var>} to your target.
|
||||
|
||||
## Documentation
|
||||
|
||||
[🇺🇸 Online documentation](https://shs.tools/pip/html/en/index.html)
|
||||
[🇺🇸 Online documentation](https://shstk.ru/pip/html/en/index.html)
|
||||
|
||||
[🇺🇸 Qt-help](https://shs.tools/pip/pip_en.qch)
|
||||
[🇺🇸 Qt-help](https://shstk.ru/pip/pip_en.qch)
|
||||
|
||||
[🇷🇺 Онлайн документация](https://shs.tools/pip/html/ru/index.html)
|
||||
[🇷🇺 Онлайн документация](https://shstk.ru/pip/html/ru/index.html)
|
||||
|
||||
[🇷🇺 Qt-help](https://shs.tools/pip/pip_ru.qch)
|
||||
[🇷🇺 Qt-help](https://shstk.ru/pip/pip_ru.qch)
|
||||
|
||||
@@ -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})
|
||||
@@ -80,23 +80,26 @@ if (NOT BUILDING_pip)
|
||||
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} "")
|
||||
@@ -104,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")
|
||||
@@ -133,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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -2282,7 +2282,7 @@ EXTERNAL_GROUPS = YES
|
||||
# be listed.
|
||||
# The default value is: YES.
|
||||
|
||||
EXTERNAL_PAGES = YES
|
||||
EXTERNAL_PAGES = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -7,19 +7,19 @@ class SomeIO: public PIIODevice {
|
||||
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;
|
||||
}
|
||||
void configureFromFullPath(const PIString & full_path) {
|
||||
void configureFromFullPathDevice(const PIString & full_path) override {
|
||||
// parse full_path and configure device here
|
||||
}
|
||||
};
|
||||
@@ -38,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));
|
||||
|
||||
@@ -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 _(){
|
||||
|
||||
|
||||
};
|
||||
|
||||
297
doc/pages/code_model.md
Normal file
297
doc/pages/code_model.md
Normal 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
125
doc/pages/iostream.md
Normal 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. Рекомендуется делать эту проверку после чтения
|
||||
данных для корректной обработки ошибки.
|
||||
@@ -3,19 +3,19 @@
|
||||
|
||||
\~english
|
||||
|
||||
* direct output to console (\a PICout)
|
||||
* containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
|
||||
* byte array (\a PIByteArray)
|
||||
* serialization (\a PIChunkStream)
|
||||
* string (\a PIConstChars, \a PIString, \a PIStringList)
|
||||
* base object (events and handlers) (\a PIObject)
|
||||
* multithreading
|
||||
* Direct output to console (\a PICout)
|
||||
* Containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
|
||||
* Byte array (\a PIByteArray)
|
||||
* Serialization (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON)
|
||||
* String (\a PIConstChars, \a PIString, \a PIStringList)
|
||||
* Base object (events and handlers) (\a PIObject)
|
||||
* Multithreading
|
||||
* thread (\a PIThread)
|
||||
* blocking (\a PIMutex, \a PISpinlock)
|
||||
* executor (\a PIThreadPoolExecutor)
|
||||
* blocking (\a PIMutex, \a PISpinlock, \a PIConditionVariable, \a PISemaphore, \a PIReadWriteLock)
|
||||
* executor (\a PIThreadPoolExecutor, \a PIThreadPoolLoop)
|
||||
* blocking dequeue (\a PIBlockingDequeue)
|
||||
* timer (\a PITimer)
|
||||
* tiling console (with widgets) (\a PIScreen)
|
||||
* timer (\a PITimer)
|
||||
* Tiling console (with widgets) (\a PIScreen)
|
||||
* simple text rows
|
||||
* scroll bar
|
||||
* list
|
||||
@@ -37,7 +37,8 @@
|
||||
* peering net node (\a PIPeer)
|
||||
* connection quality diagnotic (\a PIDiagnostics)
|
||||
* Run-time libraries
|
||||
* abstract (\a PILibrary)
|
||||
* external process (\a PIProcess)
|
||||
* external library (\a PILibrary)
|
||||
* plugin (\a PIPluginLoader)
|
||||
* Mathematics
|
||||
* complex numbers
|
||||
@@ -49,24 +50,33 @@
|
||||
* CRC checksum (\a PICRC)
|
||||
* Fourier transform (\a PIFFTW, \a PIFFT)
|
||||
* expression evaluator (\a PIEvaluator)
|
||||
* command-line arguments parser (\a PICLI)
|
||||
* process (\a PIProcess)
|
||||
* Application-level
|
||||
* command-line arguments parser (\a PICLI)
|
||||
* system resources monitoring (\a PISystemMonitor)
|
||||
* single-instance application control (\a PISingleApplication)
|
||||
* high-level log (\a PILog)
|
||||
* translation support (\a PITranslator)
|
||||
* State machine ([By stantard](https://www.w3.org/TR/scxml/)) (\a PIStateMachine)
|
||||
* High-level TCP client-server
|
||||
* server (\a PIClientServer::Server, \a PIClientServer::ServerClient)
|
||||
* client (\a PIClientServer::Client)
|
||||
* Crypt support (\a PICrypt, \a PIAuth)
|
||||
|
||||
\~russian
|
||||
|
||||
* общение с консолью (\a PICout)
|
||||
* контейнеры (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
|
||||
* байтовый массив (\a PIByteArray)
|
||||
* сериализация (\a PIChunkStream)
|
||||
* строка (\a PIConstChars, \a PIString, \a PIStringList)
|
||||
* базовый объект (события и обработчики) (\a PIObject)
|
||||
* многопоточность
|
||||
* Общение с консолью (\a PICout)
|
||||
* Контейнеры (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
|
||||
* Байтовый массив (\a PIByteArray)
|
||||
* Сериализация (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON)
|
||||
* Строка (\a PIConstChars, \a PIString, \a PIStringList)
|
||||
* Базовый объект (события и обработчики) (\a PIObject)
|
||||
* Многопоточность
|
||||
* поток (\a PIThread)
|
||||
* блокировки (\a PIMutex, \a PISpinlock)
|
||||
* исполнитель (\a PIThreadPoolExecutor)
|
||||
* блокировки (\a PIMutex, \a PISpinlock, \a PIConditionVariable, \a PISemaphore, \a PIReadWriteLock)
|
||||
* исполнитель (\a PIThreadPoolExecutor, \a PIThreadPoolLoop)
|
||||
* блокирующая очередь (\a PIBlockingDequeue)
|
||||
* таймер (\a PITimer)
|
||||
* тайлинговая консоль (с виджетами) (\a PIScreen)
|
||||
* таймер (\a PITimer)
|
||||
* Тайлинговая консоль (с виджетами) (\a PIScreen)
|
||||
* простой вывод строк
|
||||
* скроллбар
|
||||
* лист
|
||||
@@ -76,7 +86,7 @@
|
||||
* прогрессбар
|
||||
* вывод PICout
|
||||
* текстовый ввод
|
||||
* устройства ввода/вывода
|
||||
* Устройства ввода/вывода
|
||||
* базовый класс (\a PIIODevice)
|
||||
* файл (\a PIFile)
|
||||
* последовательный порт (\a PISerial)
|
||||
@@ -87,8 +97,9 @@
|
||||
* сложное составное устройство (\a PIConnection)
|
||||
* пиринговая сеть (\a PIPeer)
|
||||
* диагностика качества связи (\a PIDiagnostics)
|
||||
* поддержка библиотек времени выполнения
|
||||
* базовая функциональность (\a PILibrary)
|
||||
* Поддержка библиотек времени выполнения
|
||||
* внешний процесс (\a PIProcess)
|
||||
* внешняя библиотека (\a PILibrary)
|
||||
* плагин (\a PIPluginLoader)
|
||||
* Математика
|
||||
* комплексные числа
|
||||
@@ -100,5 +111,14 @@
|
||||
* CRC контрольная сумма (\a PICRC)
|
||||
* преобразования Фурье (\a PIFFTW, \a PIFFT)
|
||||
* вычислитель выражений (\a PIEvaluator)
|
||||
* парсер аргументов командной строки (\a PICLI)
|
||||
* процесс (\a PIProcess)
|
||||
* Уровень приложения
|
||||
* парсер аргументов командной строки (\a PICLI)
|
||||
* мониторинг ресурсов системы (\a PISystemMonitor)
|
||||
* контроль одного экземпляра приложения (\a PISingleApplication)
|
||||
* высокоуровневый лог (\a PILog)
|
||||
* поддержка перевода (\a PITranslator)
|
||||
* Машина состояний ([По стандарту](https://www.w3.org/TR/scxml/)) (\a PIStateMachine)
|
||||
* Высокоуровневый TCP клиент-сервер
|
||||
* сервер (\a PIClientServer::Server, \a PIClientServer::ServerClient)
|
||||
* клиент (\a PIClientServer::Client)
|
||||
* Поддержка шифрования (\a PICrypt, \a PIAuth)
|
||||
|
||||
@@ -56,7 +56,7 @@ class MainClass: public PITimer {
|
||||
public:
|
||||
MainClass() {}
|
||||
protected:
|
||||
void tick(void * data, int delimiter) {
|
||||
void tick(int delimiter) {
|
||||
piCout << "timer tick";
|
||||
// timer tick
|
||||
}
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
#include "pip.h"
|
||||
|
||||
|
||||
1
lang/compile.bat
Normal file
1
lang/compile.bat
Normal file
@@ -0,0 +1 @@
|
||||
pip_tr --Compile -o pip_ru.btf pip_ru.ts
|
||||
BIN
lang/pip_ru.btf
Normal file
BIN
lang/pip_ru.btf
Normal file
Binary file not shown.
531
lang/pip_ru.ts
Normal file
531
lang/pip_ru.ts
Normal file
@@ -0,0 +1,531 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="ru">
|
||||
<context>
|
||||
<name>PICLI</name>
|
||||
<message>
|
||||
<location filename="../libs/main/application/picli.cpp" line="120"/>
|
||||
<source>Arguments overflow, "%1" ignored</source>
|
||||
<translation>Переизбыток аргументов, "%1" проигнорирован</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIDiag</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/pidiagnostics.cpp" line="155"/>
|
||||
<source>/s</source>
|
||||
<translation>/сек</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIFile</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pifile.cpp" line="299"/>
|
||||
<source>Downsize is not supported yet :-(</source>
|
||||
<translation>Уменьшение размера не поддерживается</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PICloud</name>
|
||||
<message>
|
||||
<location filename="../libs/cloud/picloudtcp.cpp" line="139"/>
|
||||
<source>Invalid PICloud::TCP version!</source>
|
||||
<translation>Неверная версия PICloud::TCP!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/cloud/picloudserver.cpp" line="230"/>
|
||||
<source>Error: buffer overflow, drop %1 bytes</source>
|
||||
<translation>Ошибка: переполнение буфера, отброшено %1 байт</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/cloud/picloudserver.cpp" line="251"/>
|
||||
<source>Warning: reject client with duplicated ID</source>
|
||||
<translation>Предупреждение: отклонен клиент с дублирующимся ID</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PICrypt</name>
|
||||
<message>
|
||||
<location filename="../libs/crypt/picrypt.cpp" line="205"/>
|
||||
<source>internal error: bad hash size</source>
|
||||
<translation>внутренняя ошибка: плохой размер хэша</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/crypt/picrypt.cpp" line="39"/>
|
||||
<source>Error while initialize sodium!</source>
|
||||
<translation>Ошибка инициализации sodium!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/crypt/picrypt.cpp" line="209"/>
|
||||
<source>invalid key size %1, should be %2, filled with zeros</source>
|
||||
<translation>неверный размер ключа %1, должен быть %2, заполненный нулями</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/crypt/picrypt.cpp" line="29"/>
|
||||
<source>Warning: PICrypt is disabled, to enable install sodium library and rebuild pip</source>
|
||||
<translation>Предупреждение: PICrypt неактивен, для активации установите библиотеку sodium и пересоберите PIP</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIBinLog</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="436"/>
|
||||
<source>Read record error</source>
|
||||
<translation>Ошибка чтения записи</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="432"/>
|
||||
<source>End of BinLog file</source>
|
||||
<translation>Конец BinLog файла</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="776"/>
|
||||
<source>Error, can't open "%1"</source>
|
||||
<translation>Ошибка, невозможно открыть "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="262"/>
|
||||
<source>Creating directory "%1"</source>
|
||||
<translation>Создание директории "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="785"/>
|
||||
<source>Error, can't create "%1"</source>
|
||||
<translation>Ошибка, невозможно создать "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="140"/>
|
||||
<source>Error: File is null "%1"</source>
|
||||
<translation>Ошибка, Файл пуст "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="789"/>
|
||||
<source>Start join binlogs to "%1"</source>
|
||||
<translation>Начало слияния логов в "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="514"/>
|
||||
<source>BinLogFile has too old verion</source>
|
||||
<translation>BinLogFile очень старой версии</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="513"/>
|
||||
<source>BinLogFile has invalid version</source>
|
||||
<translation>BinLogFile неверной версии</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="515"/>
|
||||
<source>BinLogFile has too new version</source>
|
||||
<translation>BinLogFile очень новой версии</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="386"/>
|
||||
<source>Can't find record with id = %1</source>
|
||||
<translation>Невозможно найти запись с ID = %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="803"/>
|
||||
<source>Error, can't write to file "%1"</source>
|
||||
<translation>Ошибка, невозможно записать в "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="126"/>
|
||||
<source>Error: Can't open file "%1": %2</source>
|
||||
<translation>Ошибка: Невозможно открыть файл "%1": %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="149"/>
|
||||
<source>Warning: Empty BinLog file "%1"</source>
|
||||
<translation>Предупреждение: Пустой BinLog файл "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="825"/>
|
||||
<source>Finish join binlogs, total time %1</source>
|
||||
<translation>Завершение слияния логов, общее время %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="440"/>
|
||||
<source>too small read buffer: %1, data size: %2</source>
|
||||
<translation>слишком маленький буфер: %1, размер данных: %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="133"/>
|
||||
<source>Error: Can't write binlog file header "%1"</source>
|
||||
<translation>Ошибка: Невозможно записать заголовок в "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="319"/>
|
||||
<source>Error: can`t write with id = 0! ID must be > 0</source>
|
||||
<translation>Ошибка: Невозможно записать с ID = 0! ID должен быть > 0</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="495"/>
|
||||
<source>BinLogFile signature is corrupted or invalid file</source>
|
||||
<translation>Неверный заголовок BinLogFile, либо файл поврежден</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="295"/>
|
||||
<source>Can't create new file, maybe path "%1" is invalid</source>
|
||||
<translation>Невозможно создать новый файл, возможно путь "%1" неверен</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="286"/>
|
||||
<source>Can't create new file, maybe LogDir "%1" is invalid</source>
|
||||
<translation>Невозможно создать новый файл, возможно LogDir "%1" неверен</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="104"/>
|
||||
<source>Error: ReadWrite mode not supported, use WriteOnly or ReadOnly</source>
|
||||
<translation>Ошибка: Режим ReadWrite не поддерживается, используйте WriteOnly или ReadOnly</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIOpenCL</name>
|
||||
<message>
|
||||
<location filename="../libs/opencl/piopencl.cpp" line="509"/>
|
||||
<source>Error: empty range</source>
|
||||
<translation>Ошибка: пустой диапазон</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/opencl/piopencl.cpp" line="586"/>
|
||||
<source>setArgValue invalid index %1</source>
|
||||
<translation>setArgValue неверный индекс %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/opencl/piopencl.cpp" line="616"/>
|
||||
<source>bindArgValue invalid index %1</source>
|
||||
<translation>bindArgValue неверный индекс %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/opencl/piopencl.cpp" line="592"/>
|
||||
<source>setArgValue set scalar to "%1 %2"</source>
|
||||
<translation>setArgValue устанавливается скаляр в "%1 %2"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/opencl/piopencl.cpp" line="93"/>
|
||||
<source>Error: OpenCL platforms not found!</source>
|
||||
<translation>Ошибка: Платформы OpenCL не найдены!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/opencl/piopencl.cpp" line="622"/>
|
||||
<source>bindArgValue set buffer to "%1 %2"</source>
|
||||
<translation>bindArgValue устанавливается буфер в "%1 %2"</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PISerial</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piserial.cpp" line="887"/>
|
||||
<source>Read error: %1</source>
|
||||
<translation>Ошибка чтения: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piserial.cpp" line="726"/>
|
||||
<source>Unable to open "%1": %2</source>
|
||||
<translation>Невозможно открыть "%1": %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piserial.cpp" line="467"/>
|
||||
<source>Warning: Custom speed %1</source>
|
||||
<translation>Предупреждение: Нестандартная скорость %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piserial.cpp" line="695"/>
|
||||
<source>Unable to find device "%1"</source>
|
||||
<translation>Невозможно найти устройство "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piserial.cpp" line="826"/>
|
||||
<source>Can`t set attributes for "%1"</source>
|
||||
<translation>Невозможно установить атрибуты для "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piserial.cpp" line="792"/>
|
||||
<source>Unable to set comm state for "%1"</source>
|
||||
<translation>Невозможно установить comm state для "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piserial.cpp" line="470"/>
|
||||
<source>Warning: Unknown speed %1, using 115200</source>
|
||||
<translation>Предупреждение: Неизвестная скорость %1, используется 115200</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIString</name>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1774"/>
|
||||
<source>B</source>
|
||||
<translation>Б</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1794"/>
|
||||
<source>EiB</source>
|
||||
<translation>ЭиБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1791"/>
|
||||
<source>GiB</source>
|
||||
<translation>ГиБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1789"/>
|
||||
<source>KiB</source>
|
||||
<translation>КиБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1790"/>
|
||||
<source>MiB</source>
|
||||
<translation>МиБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1793"/>
|
||||
<source>PiB</source>
|
||||
<translation>ПиБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1792"/>
|
||||
<source>TiB</source>
|
||||
<translation>ТиБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1796"/>
|
||||
<source>YiB</source>
|
||||
<translation>ЙиБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/text/pistring.cpp" line="1795"/>
|
||||
<source>ZiB</source>
|
||||
<translation>ЗиБ</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIThread</name>
|
||||
<message>
|
||||
<location filename="../libs/main/thread/pithread.cpp" line="667"/>
|
||||
<source>Warning, terminate!</source>
|
||||
<translation>Предупреждение, прекращение потока!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/thread/pithread.cpp" line="785"/>
|
||||
<source>Error: Can`t start new thread: %1</source>
|
||||
<translation>Ошибка: Невозможно начать новый поток: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/thread/pithread.cpp" line="572"/>
|
||||
<source>[PIThread "%1"] Warning, terminate on destructor!</source>
|
||||
<translation>[PIThread "%1"] Предупреждение, прекращение в деструкторе!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIProcess</name>
|
||||
<message>
|
||||
<location filename="../libs/main/system/piprocess.cpp" line="200"/>
|
||||
<source>"CreateProcess" error: %1</source>
|
||||
<translation>Ошибка "CreateProcess": %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIVariant</name>
|
||||
<message>
|
||||
<location filename="../libs/main/types/pivariant.cpp" line="415"/>
|
||||
<source>Can`t initialize PIVariant from unregistered type "%1"!</source>
|
||||
<translation>Невозможно инициализировать PIVariant из незарегистрированного типа "%1"!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/types/pivariant.cpp" line="393"/>
|
||||
<source>Can`t initialize PIVariant from unregistered typeID "%1"!</source>
|
||||
<translation>Невозможно инициализировать PIVariant из незарегистрированного ID типа "%1"!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PICompress</name>
|
||||
<message>
|
||||
<location filename="../libs/compress/picompress.cpp" line="63"/>
|
||||
<source>Error: invalid input</source>
|
||||
<translation>Ошибка: неверный вход</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/compress/picompress.cpp" line="74"/>
|
||||
<source>Error: invalid input or not enought memory</source>
|
||||
<translation>Ошибка: неверный вход или недостаточно памяти</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/compress/picompress.cpp" line="80"/>
|
||||
<source>Warning: PICompress is disabled, to enable install zlib library and build pip_compress library</source>
|
||||
<translation>Предупреждение: PICompress неактивен, для активации установите библиотеку zlib и пересоберите PIP</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIEthernet</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piethernet.cpp" line="1233"/>
|
||||
<source>Can`t get interfaces: %1</source>
|
||||
<translation>Невозможно получить интерфейсы: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piethernet.cpp" line="903"/>
|
||||
<source>Can`t accept new connection, %1</source>
|
||||
<translation>Невозможно принять новое соединение, %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piethernet.cpp" line="1096"/>
|
||||
<source>Error allocating memory needed to call GetAdaptersInfo</source>
|
||||
<translation>Ошибка выделения памяти для вызова GetAdaptersInfo</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIIODevice</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piiodevice.cpp" line="226"/>
|
||||
<source>Error: Device is running after destructor!</source>
|
||||
<translation>Ошибка: Устройство в поточном выполнении после деструктора!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIIOString</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_devices/piiostring.cpp" line="54"/>
|
||||
<source>Error: ReadWrite mode not supported, use WriteOnly or ReadOnly</source>
|
||||
<translation>Ошибка: Режим ReadWrite не поддерживается, используйте WriteOnly или ReadOnly</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIConnection</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="146"/>
|
||||
<source>Error,</source>
|
||||
<translation>Ошибка,</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="922"/>
|
||||
<source>Null Device!</source>
|
||||
<translation>Нет Устройства!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="913"/>
|
||||
<source>No such device "%1"!</source>
|
||||
<translation>Нет устройства "%1"!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="903"/>
|
||||
<source>No such full path "%1"!</source>
|
||||
<translation>Нет полного пути "%1"!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="927"/>
|
||||
<source>Device "%1" can`t write!</source>
|
||||
<translation>Устройство "%1" не может писать!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="986"/>
|
||||
<source>Error: can`t create device "%1"!</source>
|
||||
<translation>Ошибка: Невозможно создать устройство "%1"!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="242"/>
|
||||
<source>"addFilter" error: no such device "%1"!</source>
|
||||
<translation>ошибка "addFilter": нет устройства "%1"!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="743"/>
|
||||
<source>"addSender" error: no such device "%1"!</source>
|
||||
<translation>ошибка "addSender": нет устройства "%1"!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="146"/>
|
||||
<source>names assigned to both devices and filters!</source>
|
||||
<translation>имена назначены одновременно устройствам и фильтрам!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/piconnection.cpp" line="512"/>
|
||||
<source>"addFilter" error: no such device or filter "%1"!</source>
|
||||
<translation>ошибка "addFilter": нет устройства или фильтра "%1"!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PISystemTime</name>
|
||||
<message>
|
||||
<location filename="../libs/main/types/pisystemtime.cpp" line="335"/>
|
||||
<source>fromSystemTime() Warning: null frequency</source>
|
||||
<translation>fromSystemTime() Предупреждение: нулевая частота</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/types/pisystemtime.cpp" line="325"/>
|
||||
<source>toSystemTime() Warning: invalid hertz: %1</source>
|
||||
<translation>toSystemTime() Предупреждение: неверная частота: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIEthUtilBase</name>
|
||||
<message>
|
||||
<location filename="../libs/io_utils/piethutilbase.cpp" line="91"/>
|
||||
<source>PICrypt wasn`t built!</source>
|
||||
<translation>PICrypt не был собран!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIBaseTransfer</name>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="125"/>
|
||||
<source>invalid CRC</source>
|
||||
<translation>неверная CRC</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="219"/>
|
||||
<source>restart receive</source>
|
||||
<translation>перезапуск приема</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="176"/>
|
||||
<source>invalid reply id</source>
|
||||
<translation>неверный ID ответа</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="102"/>
|
||||
<source>invalid packet signature</source>
|
||||
<translation>неверная подпись пакета</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIClientServer</name>
|
||||
<message>
|
||||
<location filename="../libs/client_server/piclientserver_server.cpp" line="39"/>
|
||||
<source>ClientFactory returns nullptr!</source>
|
||||
<translation>ClientFactory вернул nullptr!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/client_server/piclientserver_server.cpp" line="33"/>
|
||||
<source>Server::newConnection overflow clients count</source>
|
||||
<translation>Server::newConnection переполнение количества клиентов</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIStateMachine</name>
|
||||
<message>
|
||||
<location filename="../libs/main/state_machine/pistatemachine_state.cpp" line="111"/>
|
||||
<source>Error: "%1" no initial state!</source>
|
||||
<translation>Ошибка: "%1" без стартового состояния!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PIStreamPacker</name>
|
||||
<message>
|
||||
<location filename="../libs/io_utils/pistreampacker.cpp" line="218"/>
|
||||
<source>Warning! Not recommended to use with non-reliable device</source>
|
||||
<translation>Предупреждение! Не рекомендуется использовать с ненадежными устройствами</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PISystemMonitor</name>
|
||||
<message>
|
||||
<location filename="../libs/main/application/pisystemmonitor.cpp" line="111"/>
|
||||
<source>Can`t find process with ID = %1!</source>
|
||||
<translation>Невозможно найти процесс с ID = %1!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libs/main/application/pisystemmonitor.cpp" line="118"/>
|
||||
<source>Can`t open process with ID = %1, %2!</source>
|
||||
<translation>Невозможно открыть процесс с ID = %1, %2!</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
1
lang/update.bat
Normal file
1
lang/update.bat
Normal file
@@ -0,0 +1 @@
|
||||
pip_tr --Parse -r -l ru -o pip_ru.ts ../libs
|
||||
53
libs/client_server/piclientserver_client.cpp
Normal file
53
libs/client_server/piclientserver_client.cpp
Normal 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();
|
||||
}
|
||||
117
libs/client_server/piclientserver_client_base.cpp
Normal file
117
libs/client_server/piclientserver_client_base.cpp
Normal 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";
|
||||
}
|
||||
143
libs/client_server/piclientserver_server.cpp
Normal file
143
libs/client_server/piclientserver_server.cpp
Normal 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();
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "picloudbase.h"
|
||||
|
||||
|
||||
PICloudBase::PICloudBase() : eth(PIEthernet::TCP_Client), streampacker(ð), tcp(&streampacker) {
|
||||
PICloudBase::PICloudBase(): eth(PIEthernet::TCP_Client), streampacker(ð), tcp(&streampacker) {
|
||||
eth.setDebug(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,178 +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;
|
||||
is_deleted = false;
|
||||
// setReopenEnabled(false);
|
||||
CONNECTL(ð, connected, [this](){opened_ = true; tcp.sendStart();});
|
||||
CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
|
||||
CONNECTL(ð, disconnected, [this](bool){
|
||||
if (is_deleted) return;
|
||||
bool need_disconn = is_connected;
|
||||
//piCoutObj << "eth disconnected";
|
||||
static_cast<PIThread*>(ð)->stop();
|
||||
opened_ = false;
|
||||
internalDisconnect();
|
||||
if (need_disconn)
|
||||
disconnected();
|
||||
//piCoutObj << "eth disconnected done";
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
PICloudClient::~PICloudClient() {
|
||||
//piCoutObj << "~PICloudClient()";
|
||||
PIThread::stop();
|
||||
//eth.close();
|
||||
//if (is_connected) disconnected();
|
||||
close();
|
||||
//piCoutObj << "~PICloudClient() closed";
|
||||
internalDisconnect();
|
||||
// stop(false);
|
||||
is_deleted = true;
|
||||
internalDisconnect();
|
||||
//piCoutObj << "~PICloudClient() done";
|
||||
}
|
||||
|
||||
|
||||
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() {
|
||||
//piCoutObj << "open";// << path();
|
||||
bool op = eth.connect(PIEthernet::Address::resolve(path()), false);
|
||||
if (op) {
|
||||
mutex_connect.lock();
|
||||
eth.startThreadedRead();
|
||||
//piCoutObj << "connecting...";
|
||||
bool conn_ok = cond_connect.waitFor(mutex_connect, (int)eth.readTimeout());
|
||||
//piCoutObj << "conn_ok" << conn_ok << is_connected;
|
||||
mutex_connect.unlock();
|
||||
if (!conn_ok) {
|
||||
mutex_connect.lock();
|
||||
eth.stop();
|
||||
eth.close();
|
||||
mutex_connect.unlock();
|
||||
}
|
||||
return is_connected;
|
||||
} else {
|
||||
//eth.close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PICloudClient::closeDevice() {
|
||||
//PIThread::stop();
|
||||
if (is_connected) {
|
||||
internalDisconnect();
|
||||
}
|
||||
eth.stop();
|
||||
eth.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int PICloudClient::readDevice(void * read_to, int max_size) {
|
||||
if (is_deleted) return -1;
|
||||
//piCoutObj << "readDevice";
|
||||
if (!is_connected && eth.isClosed()) openDevice();
|
||||
int sz = -1;
|
||||
mutex_buff.lock();
|
||||
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;});
|
||||
if (is_connected) {
|
||||
sz = piMini(max_size, buff.size());
|
||||
memcpy(read_to, buff.data(), sz);
|
||||
buff.remove(0, sz);
|
||||
}
|
||||
mutex_buff.unlock();
|
||||
if (!is_connected) opened_ = false;
|
||||
//piCoutObj << "readDevice done" << sz;
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
int PICloudClient::writeDevice(const void * data, int size) {
|
||||
if (is_deleted) return -1;
|
||||
// piCoutObj << "writeDevice";
|
||||
return tcp.sendData(PIByteArray(data, size));
|
||||
}
|
||||
|
||||
|
||||
void PICloudClient::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:
|
||||
static_cast<PIThread*>(ð)->stop();
|
||||
opened_ = false;
|
||||
eth.close();
|
||||
break;
|
||||
case PICloud::TCP::Data:
|
||||
if (is_connected) {
|
||||
mutex_buff.lock();
|
||||
buff.append(ba);
|
||||
mutex_buff.unlock();
|
||||
cond_buff.notifyOne();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//piCoutObj << "readed" << ba.toHex();
|
||||
}
|
||||
while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad
|
||||
//piCoutObj << "_readed done";
|
||||
}
|
||||
|
||||
/*
|
||||
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(ð, connected, [this]() {
|
||||
opened_ = true;
|
||||
tcp.sendStart();
|
||||
});
|
||||
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed);
|
||||
CONNECTL(ð, 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";
|
||||
}
|
||||
|
||||
@@ -1,238 +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(ð, connected, [this](){opened_ = true; piCoutObj << "connected"; tcp.sendStart();});
|
||||
CONNECTL(ð, disconnected, [this](bool){
|
||||
piCoutObj << "disconnected";
|
||||
static_cast<PIThread*>(ð)->stop();
|
||||
opened_ = false;
|
||||
ping_timer.stop(false);
|
||||
piMSleep(100);
|
||||
});
|
||||
CONNECTL(&ping_timer, tickEvent, [this] (void *, int){
|
||||
if (eth.isConnected()) tcp.sendPing();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
ping_timer.start(5000);
|
||||
return true;
|
||||
}
|
||||
ping_timer.stop(false);
|
||||
eth.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PICloudServer::closeDevice() {
|
||||
eth.stop();
|
||||
ping_timer.stop(false);
|
||||
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";
|
||||
if (!opened_) openDevice();
|
||||
else 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() {
|
||||
PIThread::stop(false);
|
||||
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;
|
||||
int sz = -1;
|
||||
mutex_buff.lock();
|
||||
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;});
|
||||
if (is_connected) {
|
||||
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); // FIXME: sleep here is bad
|
||||
}
|
||||
|
||||
|
||||
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(ð, connected, [this]() {
|
||||
open_mutex.lock();
|
||||
opened_ = true;
|
||||
cvar.notifyOne();
|
||||
open_mutex.unlock();
|
||||
piCoutObj << "connected";
|
||||
tcp.sendStart();
|
||||
});
|
||||
CONNECTL(ð, 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();
|
||||
}
|
||||
|
||||
@@ -1,181 +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_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!";
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 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";
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,34 +1,38 @@
|
||||
/*
|
||||
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"
|
||||
// clang-format off
|
||||
#ifndef WINDOWS
|
||||
# include <sys/ioctl.h>
|
||||
# include <fcntl.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <termios.h>
|
||||
#else
|
||||
# include <wingdi.h>
|
||||
# include <wincon.h>
|
||||
# ifndef COMMON_LVB_UNDERSCORE
|
||||
# define COMMON_LVB_UNDERSCORE 0x8000
|
||||
# define COMMON_LVB_UNDERSCORE 0x8000
|
||||
# endif
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
|
||||
using namespace PIScreenTypes;
|
||||
@@ -51,14 +55,26 @@ PRIVATE_DEFINITION_END(PIScreen::SystemConsole)
|
||||
PIScreen::SystemConsole::SystemConsole() {
|
||||
width = height = pwidth = pheight = 0;
|
||||
mouse_x = mouse_y = -1;
|
||||
}
|
||||
|
||||
|
||||
PIScreen::SystemConsole::~SystemConsole() {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
|
||||
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::SystemConsole::begin() {
|
||||
int w, h;
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->ulcoord.X = 0;
|
||||
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
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->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);
|
||||
@@ -74,18 +90,6 @@ PIScreen::SystemConsole::SystemConsole() {
|
||||
# endif
|
||||
#endif
|
||||
resize(w, h);
|
||||
}
|
||||
|
||||
|
||||
PIScreen::SystemConsole::~SystemConsole() {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
|
||||
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::SystemConsole::begin() {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT);
|
||||
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
||||
@@ -93,6 +97,7 @@ void PIScreen::SystemConsole::begin() {
|
||||
PRIVATE->bc.Y = 0;
|
||||
#endif
|
||||
clear();
|
||||
clearScreen();
|
||||
hideCursor();
|
||||
}
|
||||
|
||||
@@ -134,9 +139,9 @@ 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);
|
||||
@@ -157,7 +162,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;
|
||||
@@ -185,10 +190,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;
|
||||
@@ -227,7 +232,7 @@ void PIScreen::SystemConsole::print() {
|
||||
if (!s.isEmpty()) {
|
||||
moveTo(si, sj);
|
||||
PICout::stdoutPIString(s);
|
||||
//printf("%s", s.data());
|
||||
// printf("%s", s.data());
|
||||
s.clear();
|
||||
}
|
||||
}
|
||||
@@ -239,33 +244,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;
|
||||
@@ -275,8 +284,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);
|
||||
@@ -291,36 +300,37 @@ 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 = PIStringAscii("\e[0");
|
||||
switch (c.format.color_char) {
|
||||
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 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;
|
||||
case Yellow: ts += PIStringAscii(";33"); break;
|
||||
case White: ts += PIStringAscii(";37"); break;
|
||||
}
|
||||
switch (c.format.color_back) {
|
||||
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 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;
|
||||
case Yellow: ts += PIStringAscii(";43"); break;
|
||||
case White: ts += PIStringAscii(";47"); break;
|
||||
}
|
||||
if ((c.format.flags & Bold ) == Bold ) ts += PIStringAscii(";1");
|
||||
if ((c.format.flags & Bold) == Bold) ts += PIStringAscii(";1");
|
||||
if ((c.format.flags & Underline) == Underline) ts += PIStringAscii(";4");
|
||||
if ((c.format.flags & Blink ) == Blink ) ts += PIStringAscii(";5");
|
||||
if ((c.format.flags & Inverse ) == Inverse ) ts += PIStringAscii(";7");
|
||||
if ((c.format.flags & Blink) == Blink) ts += PIStringAscii(";5");
|
||||
if ((c.format.flags & Inverse) == Inverse) ts += PIStringAscii(";7");
|
||||
return ts + 'm';
|
||||
}
|
||||
#endif // WINDOWS
|
||||
@@ -357,8 +367,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
|
||||
@@ -383,34 +401,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;
|
||||
}
|
||||
|
||||
@@ -422,14 +439,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_);
|
||||
@@ -437,14 +452,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();
|
||||
@@ -455,20 +470,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;
|
||||
@@ -476,27 +490,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)
|
||||
@@ -504,18 +516,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;
|
||||
@@ -525,16 +534,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;
|
||||
@@ -550,22 +559,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -587,8 +593,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);
|
||||
@@ -612,16 +624,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();
|
||||
@@ -635,10 +652,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,8 +673,7 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
|
||||
case PIKbdListener::F9:
|
||||
case PIKbdListener::F10:
|
||||
case PIKbdListener::F11:
|
||||
case PIKbdListener::F12:
|
||||
break;
|
||||
case PIKbdListener::F12: break;
|
||||
default:
|
||||
text.insert(cur, PIChar((ushort)key.key));
|
||||
cur++;
|
||||
|
||||
@@ -1,58 +1,60 @@
|
||||
/*
|
||||
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 MICRO_PIP
|
||||
#ifdef WINDOWS
|
||||
# include <windows.h>
|
||||
# include <wingdi.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>
|
||||
# ifdef WINDOWS
|
||||
# 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,
|
||||
@@ -65,22 +67,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;
|
||||
@@ -92,21 +94,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() {
|
||||
@@ -114,42 +116,42 @@ 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 =
|
||||
::write(PRIVATE->fd, d.data(), d.size_s());
|
||||
//piCout << "wrote" << wrote << d;
|
||||
// ssize_t wrote = 0;
|
||||
// wrote =
|
||||
auto _r = ::write(PRIVATE->fd, d.data(), d.size_s());
|
||||
NO_UNUSED(_r);
|
||||
// piCout << "wrote" << wrote << d;
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
cursor_tm.reset();
|
||||
cursor_blink = true;
|
||||
}
|
||||
@@ -157,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;
|
||||
@@ -173,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;
|
||||
@@ -206,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
|
||||
# ifdef WINDOWS
|
||||
ba << uchar(PIChar((ushort)ke.key).toConsole1Byte());
|
||||
#else
|
||||
# else
|
||||
ba = PIString(PIChar((ushort)ke.key)).toUTF8();
|
||||
#endif
|
||||
# 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;
|
||||
}
|
||||
|
||||
@@ -295,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
|
||||
# else
|
||||
x = PRIVATE->cur_x;
|
||||
y = PRIVATE->cur_y;
|
||||
#endif
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
@@ -370,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;
|
||||
@@ -395,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) {
|
||||
@@ -429,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 {
|
||||
@@ -444,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);
|
||||
@@ -475,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;
|
||||
@@ -498,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;
|
||||
}
|
||||
@@ -513,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;
|
||||
@@ -524,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) {
|
||||
@@ -544,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') {
|
||||
@@ -579,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
|
||||
@@ -616,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;
|
||||
}
|
||||
}
|
||||
@@ -684,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -705,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];
|
||||
@@ -721,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);
|
||||
memset(&PRIVATE->si, 0, sizeof(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);
|
||||
piZeroMemory(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));
|
||||
piZeroMemory(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();
|
||||
@@ -792,31 +851,32 @@ 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];
|
||||
piZeroMemory(pty, 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];
|
||||
char ** argv = new char *[2];
|
||||
PIByteArray shell = PRIVATE->shell.toByteArray();
|
||||
argv[0] = new char[shell.size() + 1];
|
||||
argv[0] = new char[shell.size() + 1];
|
||||
memcpy(argv[0], shell.data(), shell.size());
|
||||
argv[0][shell.size()] = 0;
|
||||
argv[1] = 0;
|
||||
argv[1] = 0;
|
||||
execvp(argv[0], argv);
|
||||
delete[] argv[0];
|
||||
delete[] argv;
|
||||
@@ -829,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;
|
||||
@@ -911,8 +969,8 @@ 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);
|
||||
|
||||
@@ -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());
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,448 +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;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PICrypt::hash(const PIByteArray & data, const unsigned char *key, size_t keylen) {
|
||||
PIByteArray hash;
|
||||
#ifdef PIP_CRYPT
|
||||
if (!init()) return hash;
|
||||
hash.resize(crypto_generichash_BYTES);
|
||||
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), key, keylen);
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
77
libs/http_client/curl_thread_pool_p.cpp
Normal file
77
libs/http_client/curl_thread_pool_p.cpp
Normal 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;
|
||||
}
|
||||
31
libs/http_client/curl_thread_pool_p.h
Normal file
31
libs/http_client/curl_thread_pool_p.h
Normal 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
|
||||
237
libs/http_client/pihttpclient.cpp
Normal file
237
libs/http_client/pihttpclient.cpp
Normal 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);
|
||||
}
|
||||
367
libs/http_server/microhttpd_server_p.cpp
Normal file
367
libs/http_server/microhttpd_server_p.cpp
Normal 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];
|
||||
piZeroMemory(buffer, 1_KiB);
|
||||
std::vsnprintf(buffer, 1_KiB, fmt, ap);
|
||||
piCout << buffer;
|
||||
}
|
||||
|
||||
|
||||
int iterate_post(void * conn_cls,
|
||||
MHD_ValueKind kind,
|
||||
const char * key,
|
||||
const char * filename,
|
||||
const char * content_type,
|
||||
const char * transfer_encoding,
|
||||
const char * data,
|
||||
uint64_t off,
|
||||
size_t size) {
|
||||
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)conn_cls;
|
||||
if (!conn) return MHD_NO;
|
||||
conn->post[PIString::fromUTF8(key)] = PIString::fromUTF8(data);
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
|
||||
void request_completed(void * cls, MHD_Connection * connection, void ** con_cls, MHD_RequestTerminationCode toe) {
|
||||
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
|
||||
// piCout << "request_completed" << conn << conn->headers << conn->post << '"' << conn->body << '"';
|
||||
if (!conn) return;
|
||||
if (conn->postprocessor) {
|
||||
MHD_destroy_post_processor(conn->postprocessor);
|
||||
conn->postprocessor = nullptr;
|
||||
}
|
||||
conn->ready();
|
||||
piDeleteSafety(conn);
|
||||
}
|
||||
|
||||
|
||||
int header_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
|
||||
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
|
||||
if (!conn) return MHD_NO;
|
||||
conn->headers[PIString::fromUTF8(key)] = PIString::fromUTF8(value);
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
|
||||
int args_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
|
||||
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
|
||||
if (!conn) return MHD_NO;
|
||||
conn->args[PIString::fromUTF8(key)] = PIString::fromUTF8(value);
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
|
||||
int answer_callback(void * cls,
|
||||
MHD_Connection * connection,
|
||||
const char * url,
|
||||
const char * method,
|
||||
const char * version,
|
||||
const char * upload_data,
|
||||
size_t * upload_data_size,
|
||||
void ** con_cls) {
|
||||
MicrohttpdServer * server = (MicrohttpdServer *)cls;
|
||||
|
||||
Method m = Method::Unknown;
|
||||
|
||||
if (0 == strcmp(method, "GET"))
|
||||
m = Method::Get;
|
||||
else if (0 == strcmp(method, "POST"))
|
||||
m = Method::Post;
|
||||
else if (0 == strcmp(method, "HEAD"))
|
||||
m = Method::Head;
|
||||
else if (0 == strcmp(method, "PUT"))
|
||||
m = Method::Put;
|
||||
else if (0 == strcmp(method, "DELETE"))
|
||||
m = Method::Delete;
|
||||
else if (0 == strcmp(method, "CONNECT"))
|
||||
m = Method::Connect;
|
||||
else if (0 == strcmp(method, "OPTIONS"))
|
||||
m = Method::Options;
|
||||
else if (0 == strcmp(method, "TRACE"))
|
||||
m = Method::Trace;
|
||||
else if (0 == strcmp(method, "PATCH"))
|
||||
m = Method::Patch;
|
||||
|
||||
if (m == Method::Unknown) {
|
||||
piCout << "[MicrohttpdServer]"
|
||||
<< "Warning:"
|
||||
<< "Unknown method!";
|
||||
return MHD_NO;
|
||||
}
|
||||
|
||||
// piCout << "answer" << url << method << (int)m << server;
|
||||
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
|
||||
if (!conn) {
|
||||
conn = new MicrohttpdServerConnection();
|
||||
conn->connection = connection;
|
||||
conn->server = server;
|
||||
conn->path = PIString::fromUTF8(url);
|
||||
conn->method = m;
|
||||
MHD_get_connection_values(connection, MHD_HEADER_KIND, (MHD_KeyValueIterator)header_iterate, *con_cls);
|
||||
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, (MHD_KeyValueIterator)args_iterate, *con_cls);
|
||||
if (server->isBasicAuthEnabled() && !conn->authorized) {
|
||||
if (!conn->checkBasicAuth()) return MHD_YES;
|
||||
}
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
if (m == Method::Unknown) {
|
||||
return conn->sendReply(MessageMutable::fromCode(Code::MethodNotAllowed));
|
||||
}
|
||||
|
||||
|
||||
if (*upload_data_size) {
|
||||
if (!conn->postprocessor) {
|
||||
conn->postprocessor = MHD_create_post_processor(connection, 64_KiB, (MHD_PostDataIterator)iterate_post, (void *)conn);
|
||||
}
|
||||
conn->body.append(upload_data, *upload_data_size);
|
||||
MHD_post_process(conn->postprocessor, upload_data, *upload_data_size);
|
||||
*upload_data_size = 0;
|
||||
} else {
|
||||
// qDebug() << "answer ok";
|
||||
if (!conn->ready()) return conn->sendReply(MessageMutable::fromCode(Code::InternalServerError));
|
||||
}
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE_DEFINITION_START(MicrohttpdServer)
|
||||
MHD_Daemon * daemon;
|
||||
PRIVATE_DEFINITION_END(MicrohttpdServer)
|
||||
|
||||
|
||||
MicrohttpdServer::MicrohttpdServer() {
|
||||
PRIVATE->daemon = nullptr;
|
||||
opts[Option::ConnectionLimit] = FD_SETSIZE - 4;
|
||||
opts[Option::ConnectionTimeout] = 0_s;
|
||||
realm = "Restricted"_a;
|
||||
}
|
||||
|
||||
|
||||
MicrohttpdServer::~MicrohttpdServer() {
|
||||
stop();
|
||||
}
|
||||
|
||||
|
||||
void MicrohttpdServer::setOption(Option o, PIVariant v) {
|
||||
opts[o] = std::move(v);
|
||||
}
|
||||
|
||||
|
||||
void MicrohttpdServer::setFavicon(const PIByteArray & im) {
|
||||
favicon = im;
|
||||
}
|
||||
|
||||
|
||||
bool MicrohttpdServer::listen(PINetworkAddress addr) {
|
||||
stop();
|
||||
uint flags = 0;
|
||||
#if MHD_VERSION <= 0x00095100
|
||||
flags |= MHD_USE_POLL_INTERNALLY;
|
||||
#else
|
||||
flags |= MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD;
|
||||
#endif
|
||||
if (opts.value(Option::HTTPSEnabled).toBool()) flags |= MHD_USE_TLS;
|
||||
mem_key = opts.value(Option::HTTPSMemKey).toByteArray();
|
||||
if (mem_key.isNotEmpty()) mem_key.append(0);
|
||||
mem_cert = opts.value(Option::HTTPSMemCert).toByteArray();
|
||||
if (mem_cert.isNotEmpty()) mem_cert.append(0);
|
||||
key_pass = opts.value(Option::HTTPSKeyPassword).toByteArray();
|
||||
if (key_pass.isNotEmpty()) key_pass.append(0);
|
||||
sockaddr_in sa_addr;
|
||||
piZeroMemory(sa_addr);
|
||||
sa_addr.sin_port = htons(addr.port());
|
||||
sa_addr.sin_addr.s_addr = addr.ip();
|
||||
sa_addr.sin_family = AF_INET;
|
||||
PIVector<MHD_OptionItem> options;
|
||||
options.append({MHD_OPTION_EXTERNAL_LOGGER, (intptr_t)log_callback, this});
|
||||
options.append({MHD_OPTION_NOTIFY_COMPLETED, (intptr_t)request_completed, nullptr});
|
||||
options.append({MHD_OPTION_CONNECTION_LIMIT, opts.value(Option::ConnectionLimit).toInt(), nullptr});
|
||||
options.append({MHD_OPTION_CONNECTION_TIMEOUT, piRound(opts.value(Option::ConnectionTimeout).toSystemTime().toSeconds()), nullptr});
|
||||
options.append({MHD_OPTION_SOCK_ADDR, 0, &sa_addr});
|
||||
if (opts.value(Option::HTTPSEnabled).toBool()) {
|
||||
options.append({MHD_OPTION_HTTPS_MEM_KEY, 0, mem_key.data()});
|
||||
options.append({MHD_OPTION_HTTPS_MEM_CERT, 0, mem_cert.data()});
|
||||
options.append({MHD_OPTION_HTTPS_KEY_PASSWORD, 0, key_pass.data()});
|
||||
}
|
||||
options.append({MHD_OPTION_END, 0, nullptr});
|
||||
PRIVATE->daemon = MHD_start_daemon(flags,
|
||||
addr.port(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
(MHD_AccessHandlerCallback)answer_callback,
|
||||
this,
|
||||
MHD_OPTION_ARRAY,
|
||||
options.data(),
|
||||
MHD_OPTION_END);
|
||||
return isListen();
|
||||
}
|
||||
|
||||
|
||||
bool MicrohttpdServer::isListen() const {
|
||||
return PRIVATE->daemon;
|
||||
}
|
||||
|
||||
|
||||
void MicrohttpdServer::stop() {
|
||||
if (PRIVATE->daemon) {
|
||||
MHD_stop_daemon(PRIVATE->daemon);
|
||||
PRIVATE->daemon = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MicrohttpdServer::addFixedHeaders(MessageMutable & msg) {
|
||||
if (!msg.headers().contains(Header::ContentType)) {
|
||||
if (msg.body().isNotEmpty()) {
|
||||
if (msg.body().startsWith(PIByteArray::fromAscii("<!DOCTYPE html>")))
|
||||
msg.addHeader(Header::ContentType, "text/html; charset=utf-8");
|
||||
else if (msg.body()[0] == '[' || msg.body()[0] == '{')
|
||||
msg.addHeader(Header::ContentType, "application/json; charset=utf-8");
|
||||
}
|
||||
}
|
||||
msg.addHeader(Header::AccessControlAllowOrigin, "*");
|
||||
}
|
||||
90
libs/http_server/pihttpserver.cpp
Normal file
90
libs/http_server/pihttpserver.cpp
Normal 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;
|
||||
}
|
||||
@@ -1,266 +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;
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
if (!isRunning()) {
|
||||
reinit();
|
||||
PIThread::start(3000);
|
||||
}
|
||||
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 (!isRunning()) {
|
||||
_started = false;
|
||||
reinit();
|
||||
PIThread::start(3000);
|
||||
}
|
||||
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() {
|
||||
if (isRunning()) stop();
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
199
libs/io_utils/pipackedtcp.cpp
Normal file
199
libs/io_utils/pipackedtcp.cpp
Normal 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();
|
||||
}
|
||||
@@ -1,202 +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::clear() {
|
||||
packet.clear();
|
||||
packet_size = -1;
|
||||
stream.clear();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
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(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;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
/*
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
60
libs/main/application/piapplicationmodule.h
Normal file
60
libs/main/application/piapplicationmodule.h
Normal 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
|
||||
256
libs/main/application/picli.cpp
Normal file
256
libs/main/application/picli.cpp
Normal 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;
|
||||
}
|
||||
136
libs/main/application/picli.h
Normal file
136
libs/main/application/picli.h
Normal 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
|
||||
247
libs/main/application/pilog.cpp
Normal file
247
libs/main/application/pilog.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
181
libs/main/application/pilog.h
Normal file
181
libs/main/application/pilog.h
Normal 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
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Single application
|
||||
Single application
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
@@ -18,7 +18,11 @@
|
||||
*/
|
||||
|
||||
#include "pisingleapplication.h"
|
||||
|
||||
#include "piliterals_bytes.h"
|
||||
#include "piliterals_time.h"
|
||||
#include "pisharedmemory.h"
|
||||
#include "pitime.h"
|
||||
|
||||
|
||||
//! \class PISingleApplication pisingleapplication.h
|
||||
@@ -60,22 +64,21 @@
|
||||
//!
|
||||
|
||||
|
||||
#define SHM_SIZE 1024*32
|
||||
#define SHM_SIZE 32_KiB
|
||||
|
||||
|
||||
PISingleApplication::PISingleApplication(const PIString & app_name): PIThread() {
|
||||
first = true;
|
||||
first = true;
|
||||
started = false;
|
||||
sacnt = 0;
|
||||
shm = new PISharedMemory("sa_" + app_name, SHM_SIZE);
|
||||
start(100);
|
||||
sacnt = 0;
|
||||
shm = new PISharedMemory("sa_" + app_name, SHM_SIZE);
|
||||
start(10_Hz);
|
||||
}
|
||||
|
||||
|
||||
PISingleApplication::~PISingleApplication() {
|
||||
stop();
|
||||
if (!waitForFinish(5000))
|
||||
terminate();
|
||||
if (!waitForFinish(5_s)) terminate();
|
||||
delete shm;
|
||||
}
|
||||
|
||||
@@ -102,7 +105,7 @@ void PISingleApplication::sendMessage(const PIByteArray & m) {
|
||||
|
||||
void PISingleApplication::begin() {
|
||||
int cnt[2] = {0, 0};
|
||||
int tcnt = 0;
|
||||
int tcnt = 0;
|
||||
shm->read(cnt, 8);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
tcnt = cnt[0];
|
||||
@@ -113,7 +116,7 @@ void PISingleApplication::begin() {
|
||||
}
|
||||
piMSleep(100);
|
||||
}
|
||||
//piCoutObj << "started" << first << shm->size();
|
||||
// piCoutObj << "started" << first << shm->size();
|
||||
readed.reserve(shm->size());
|
||||
started = true;
|
||||
}
|
||||
@@ -124,8 +127,8 @@ void PISingleApplication::run() {
|
||||
++sacnt;
|
||||
int st_[2] = {sacnt, sacnt};
|
||||
shm->write(st_, 8);
|
||||
//piCoutObj << "write" << sacnt;
|
||||
int ri[3] = {0, 0, 0};
|
||||
// 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]) {
|
||||
@@ -133,9 +136,9 @@ void PISingleApplication::run() {
|
||||
shm->read(readed.data(), readed.size(), hdr_sz);
|
||||
PIByteArray msg;
|
||||
readed >> msg;
|
||||
if (!msg.isEmpty()) {
|
||||
if (msg.isNotEmpty()) {
|
||||
messageReceived(msg);
|
||||
//piCoutObj << "message" << msg;
|
||||
// piCoutObj << "message" << msg;
|
||||
}
|
||||
int wi[3] = {sacnt, sacnt, 0};
|
||||
shm->write(wi, 12);
|
||||
@@ -1,26 +1,26 @@
|
||||
/*! \file pisingleapplication.h
|
||||
* \ingroup System
|
||||
* \ingroup Application
|
||||
* \~\brief
|
||||
* \~english Single-instance application control
|
||||
* \~russian Контроль одного экземпляра приложения
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Single application
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
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 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 PISINGLEAPPLICATION_H
|
||||
@@ -30,14 +30,14 @@
|
||||
|
||||
class PISharedMemory;
|
||||
|
||||
//! \ingroup System
|
||||
//! \ingroup Application
|
||||
//! \~\brief
|
||||
//! \~english Single-instance application control.
|
||||
//! \~russian Контроль одного экземпляра приложения.
|
||||
class PIP_EXPORT PISingleApplication: public PIThread {
|
||||
PIOBJECT_SUBCLASS(PISingleApplication, PIThread)
|
||||
public:
|
||||
PIOBJECT_SUBCLASS(PISingleApplication, PIThread);
|
||||
|
||||
public:
|
||||
//! \~english Construct %PISingleApplication with name "app_name"
|
||||
//! \~russian Создает %PISingleApplication с именем "app_name"
|
||||
PISingleApplication(const PIString & app_name = PIString());
|
||||
@@ -50,30 +50,30 @@ public:
|
||||
bool isFirst() const;
|
||||
|
||||
EVENT_HANDLER1(void, sendMessage, const PIByteArray &, m);
|
||||
EVENT1(messageReceived, PIByteArray, m)
|
||||
EVENT1(messageReceived, PIByteArray, m);
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void sendMessage(const PIByteArray & m)
|
||||
//! \brief
|
||||
//! \~english Send message "m" to first launched application
|
||||
//! \~russian Посылает сообщение "m" первому запущеному приложению
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void messageReceived(PIByteArray m)
|
||||
//! \brief
|
||||
//! \~english Raise on first launched application receive message from another
|
||||
//! \~russian Вызывается первым запущеным приложением по приему сообщения от других
|
||||
|
||||
//! \}
|
||||
//! \}
|
||||
|
||||
private:
|
||||
void begin();
|
||||
void run();
|
||||
void begin() override;
|
||||
void run() override;
|
||||
void waitFirst() const;
|
||||
|
||||
PISharedMemory * shm;
|
||||
@@ -81,7 +81,6 @@ private:
|
||||
PIByteArray readed;
|
||||
bool first, started;
|
||||
int sacnt;
|
||||
|
||||
};
|
||||
|
||||
#endif // PISINGLEAPPLICATION_H
|
||||
@@ -1,490 +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
|
||||
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
PISystemMonitor::~PISystemMonitor() {
|
||||
stop();
|
||||
}
|
||||
|
||||
|
||||
#ifndef MICRO_PIP
|
||||
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 MICRO_PIP
|
||||
bool ret = startOnProcess(PIProcess::currentPID(), interval_ms);
|
||||
cycle = -1;
|
||||
#else
|
||||
bool ret = start(interval_ms);
|
||||
#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::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 MICRO_PIP
|
||||
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;
|
||||
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 = 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) {
|
||||
piCout << "[PISystemMonitor] gatherThread(" << id << "):: OpenThread() error:" << errorString();
|
||||
return;
|
||||
}
|
||||
if (GetThreadTimes(thdl, &(times[0]), &(times[1]), &(times[2]), &(times[3])) == 0) {
|
||||
CloseHandle(thdl);
|
||||
piCout << "[PISystemMonitor] gatherThread(" << id << "):: GetThreadTimes() error:" << errorString();
|
||||
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;
|
||||
piZeroMemory(heap_info);
|
||||
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;
|
||||
piZeroMemory(heap_info);
|
||||
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;
|
||||
piZeroMemory(heap_info);
|
||||
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());
|
||||
}
|
||||
@@ -1,314 +1,323 @@
|
||||
/*! \file pisystemmonitor.h
|
||||
* \ingroup System
|
||||
* \~\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 "pithread.h"
|
||||
#include "pifile.h"
|
||||
|
||||
|
||||
//! \ingroup System
|
||||
//! \~\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 System
|
||||
//! \~\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 System
|
||||
//! \~\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 System
|
||||
//! \~\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 System
|
||||
//! \~\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, int interval_ms = 1000);
|
||||
#endif
|
||||
|
||||
//! \~english Starts monitoring of application process with update interval "interval_ms" milliseconds
|
||||
//! \~russian Начинает мониторинг процесса приложения с интервалом обновления "interval_ms" миллисекунд
|
||||
bool startOnSelf(int interval_ms = 1000);
|
||||
|
||||
//! \~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();
|
||||
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.setControl(0, true);
|
||||
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.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PISystemMonitor::ProcessStats & v);
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
PIP_EXPORT PIByteArray & operator >>(PIByteArray & s, PISystemMonitor::ProcessStats & v);
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PISystemMonitor::ThreadStats & v);
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
PIP_EXPORT PIByteArray & operator >>(PIByteArray & s, PISystemMonitor::ThreadStats & v);
|
||||
|
||||
#endif // PISYSTEMMONITOR_H
|
||||
/*! \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
|
||||
116
libs/main/application/pitranslator.cpp
Normal file
116
libs/main/application/pitranslator.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Translation support
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pitranslator.h"
|
||||
|
||||
#include "pidir.h"
|
||||
#include "pifile.h"
|
||||
#include "piliterals_string.h"
|
||||
#include "pitranslator_p.h"
|
||||
#include "pivaluetree_conversions.h"
|
||||
|
||||
|
||||
//! \class PITranslator pitranslator.h
|
||||
//! \details
|
||||
//! \~english \section PITranslator_sec0 Synopsis
|
||||
//! \~russian \section PITranslator_sec0 Краткий обзор
|
||||
//! \~english
|
||||
//!
|
||||
//! \~russian
|
||||
//!
|
||||
|
||||
|
||||
PRIVATE_DEFINITION_START(PITranslator)
|
||||
PITranslatorPrivate::Translation content;
|
||||
PRIVATE_DEFINITION_END(PITranslator)
|
||||
|
||||
|
||||
PIString PITranslator::tr(const PIString & in, const PIString & context) {
|
||||
return instance()->PRIVATEWB->content.translate(in, context);
|
||||
}
|
||||
|
||||
|
||||
void PITranslator::clear() {
|
||||
instance()->PRIVATEWB->content.clear();
|
||||
}
|
||||
|
||||
|
||||
void PITranslator::loadLang(const PIString & short_lang, PIString dir) {
|
||||
if (dir.isEmpty()) dir = PIDir::current().absolute("lang");
|
||||
clear();
|
||||
auto files = PIDir(dir).entries();
|
||||
for (const auto & f: files) {
|
||||
if (!f.baseName().endsWith(short_lang)) continue;
|
||||
loadFile(f.path);
|
||||
}
|
||||
piCout << "Loaded %1 string for lang \"%2\""_a.arg(instance()->PRIVATEWB->content.count()).arg(short_lang);
|
||||
/*auto s = instance();
|
||||
auto vt = PIValueTreeConversions::fromText(getBuiltinConfig());
|
||||
auto lang = vt.child(short_lang.toLowerCase().trim());
|
||||
for (const auto & cn: lang.children()) {
|
||||
auto c = s->PRIVATEWB->content.createContext(cn.name());
|
||||
for (const auto & s: cn.children())
|
||||
c->add(s.name(), s.value().toString());
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
void PITranslator::loadConfig(const PIString & content) {
|
||||
auto s = instance();
|
||||
auto lang = PIValueTreeConversions::fromText(content);
|
||||
for (const auto & cn: lang.children()) {
|
||||
auto c = s->PRIVATEWB->content.createContext(cn.name());
|
||||
for (const auto & s: cn.children())
|
||||
c->add(s.name(), s.value().toString());
|
||||
}
|
||||
auto c = s->PRIVATEWB->content.createContext("");
|
||||
for (const auto & s: lang.children()) {
|
||||
if (s.hasChildren()) continue;
|
||||
c->add(s.name(), s.value().toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PITranslator::load(const PIByteArray & content) {
|
||||
return instance()->PRIVATEWB->content.load(content);
|
||||
}
|
||||
|
||||
|
||||
bool PITranslator::loadFile(const PIString & path) {
|
||||
PIFile f(path, PIIODevice::ReadOnly);
|
||||
if (f.isClosed()) return false;
|
||||
if (!PITranslatorPrivate::checkHeader(&f)) return false;
|
||||
auto data = f.readAll();
|
||||
data.remove(0, PITranslatorPrivate::headerSize());
|
||||
return load(data);
|
||||
}
|
||||
|
||||
|
||||
PITranslator::PITranslator() {}
|
||||
|
||||
|
||||
PITranslator::~PITranslator() {
|
||||
PRIVATE->content.clear();
|
||||
}
|
||||
|
||||
|
||||
PITranslator * PITranslator::instance() {
|
||||
static PITranslator ret;
|
||||
return &ret;
|
||||
}
|
||||
98
libs/main/application/pitranslator.h
Normal file
98
libs/main/application/pitranslator.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*! \file pitranslator.h
|
||||
* \ingroup Application
|
||||
* \~\brief
|
||||
* \~english Translation support
|
||||
* \~russian Поддержка перевода
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Translation support
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef pitranslator_H
|
||||
#define pitranslator_H
|
||||
|
||||
#include "pistring.h"
|
||||
|
||||
|
||||
#define piTr PITranslator::tr
|
||||
#define piTrNoOp PITranslator::trNoOp
|
||||
|
||||
//! \ingroup Application
|
||||
//! \~\brief
|
||||
//! \~english Translation support
|
||||
//! \~russian Поддержка перевода
|
||||
class PIP_EXPORT PITranslator {
|
||||
public:
|
||||
static PIString tr(const PIString & in, const PIString & context = {});
|
||||
static PIString tr(const char * in, const PIString & context = {}) { return tr(PIString::fromUTF8(in), context); }
|
||||
static PIString trNoOp(const PIString & in, const PIString & context = {}) { return in; }
|
||||
static PIString trNoOp(const char * in, const PIString & context = {}) { return trNoOp(PIString::fromUTF8(in), context); }
|
||||
|
||||
static void clear();
|
||||
static void loadLang(const PIString & short_lang, PIString dir = {});
|
||||
static void loadConfig(const PIString & content);
|
||||
static bool load(const PIByteArray & content);
|
||||
static bool loadFile(const PIString & path);
|
||||
|
||||
private:
|
||||
PITranslator();
|
||||
~PITranslator();
|
||||
NO_COPY_CLASS(PITranslator)
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
|
||||
static PITranslator * instance();
|
||||
};
|
||||
|
||||
|
||||
class PIStringContextTr {
|
||||
public:
|
||||
PIStringContextTr(PIString && s): _s(s) {}
|
||||
operator PIString() const { return PITranslator::tr(_s); }
|
||||
PIString operator()(const PIString & ctx = {}) const { return PITranslator::tr(_s, ctx); }
|
||||
|
||||
private:
|
||||
PIString _s;
|
||||
};
|
||||
|
||||
|
||||
class PIStringContextTrNoOp {
|
||||
public:
|
||||
PIStringContextTrNoOp(PIString && s): _s(s) {}
|
||||
operator PIString() const { return _s; }
|
||||
PIString operator()(const PIString & ctx = {}) const { return _s; }
|
||||
|
||||
private:
|
||||
PIString _s;
|
||||
};
|
||||
|
||||
|
||||
//! \~\brief
|
||||
//! \~english Translate string with \a PITranslator::tr()
|
||||
//! \~russian Перевести строку с помощью \a PITranslator::tr()
|
||||
inline PIStringContextTr operator""_tr(const char * v, size_t sz) {
|
||||
return PIStringContextTr(PIString::fromUTF8(v, sz));
|
||||
}
|
||||
|
||||
//! \~\brief
|
||||
//! \~english Translate string with \a PITranslator::tr()
|
||||
//! \~russian Перевести строку с помощью \a PITranslator::tr()
|
||||
inline PIStringContextTrNoOp operator""_trNoOp(const char * v, size_t sz) {
|
||||
return PIStringContextTrNoOp(PIString::fromUTF8(v, sz));
|
||||
}
|
||||
|
||||
#endif
|
||||
124
libs/main/application/pitranslator_p.cpp
Normal file
124
libs/main/application/pitranslator_p.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Translation private
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pitranslator_p.h"
|
||||
|
||||
#include "pichunkstream.h"
|
||||
#include "piiodevice.h"
|
||||
|
||||
constexpr int currentVersion = 1;
|
||||
const PIByteArray fileHeader("PIPBTF", 6);
|
||||
|
||||
|
||||
void PITranslatorPrivate::Context::add(const PIMap<uint, PIString> & sm) {
|
||||
auto it = sm.makeIterator();
|
||||
while (it.next())
|
||||
strings[it.key()] = it.value();
|
||||
}
|
||||
|
||||
|
||||
void PITranslatorPrivate::Translation::clear() {
|
||||
piDeleteAll(contexts.values());
|
||||
contexts.clear();
|
||||
lang.clear();
|
||||
}
|
||||
|
||||
|
||||
PITranslatorPrivate::Context * PITranslatorPrivate::Translation::createContext(const PIString & context) {
|
||||
return createContext(context.hash());
|
||||
}
|
||||
|
||||
|
||||
PITranslatorPrivate::Context * PITranslatorPrivate::Translation::createContext(uint hash) {
|
||||
auto & ret(contexts[hash]);
|
||||
if (!ret) ret = new Context();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PITranslatorPrivate::Translation::translate(const PIString & in, const PIString & context) {
|
||||
auto c = contexts.value(context.hash());
|
||||
if (!c) return in;
|
||||
return c->strings.value(in.hash(), in);
|
||||
}
|
||||
|
||||
|
||||
bool PITranslatorPrivate::Translation::load(const PIByteArray & data) {
|
||||
if (data.size_s() <= 4) return false;
|
||||
PIChunkStream cs(data);
|
||||
Context * ctx = nullptr;
|
||||
PIMap<uint, PIString> strings;
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1: {
|
||||
int version = cs.getData<int>();
|
||||
if (version != currentVersion) {
|
||||
piCout << "Invalid translation version!";
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
case 3: {
|
||||
uint ctx_hash = cs.getData<uint>();
|
||||
ctx = createContext(ctx_hash);
|
||||
} break;
|
||||
case 4: {
|
||||
cs.get(strings);
|
||||
if (ctx) ctx->add(strings);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int PITranslatorPrivate::Translation::count() const {
|
||||
int ret = 0;
|
||||
auto cit = contexts.makeIterator();
|
||||
while (cit.next())
|
||||
ret += cit.value()->strings.size_s();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PITranslatorPrivate::Translation::save() {
|
||||
PIChunkStream cs;
|
||||
cs.add(1, currentVersion).add(2, lang);
|
||||
auto cit = contexts.makeIterator();
|
||||
while (cit.next()) {
|
||||
cs.add(3, cit.key()).add(4, cit.value()->strings);
|
||||
}
|
||||
return cs.data();
|
||||
}
|
||||
|
||||
|
||||
int PITranslatorPrivate::headerSize() {
|
||||
return fileHeader.size_s();
|
||||
}
|
||||
|
||||
|
||||
bool PITranslatorPrivate::checkHeader(PIIODevice * d) {
|
||||
if (!d) return false;
|
||||
return d->read(fileHeader.size_s()) == fileHeader;
|
||||
}
|
||||
|
||||
|
||||
void PITranslatorPrivate::writeHeader(PIIODevice * d) {
|
||||
if (!d) return;
|
||||
d->write(fileHeader);
|
||||
}
|
||||
53
libs/main/application/pitranslator_p.h
Normal file
53
libs/main/application/pitranslator_p.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Translation private
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef pitranslator_p_H
|
||||
#define pitranslator_p_H
|
||||
|
||||
#include "pistring.h"
|
||||
|
||||
class PIIODevice;
|
||||
|
||||
namespace PITranslatorPrivate {
|
||||
|
||||
struct PIP_EXPORT Context {
|
||||
void add(const PIString & in, const PIString & out) { strings[in.hash()] = out; }
|
||||
void add(const PIMap<uint, PIString> & sm);
|
||||
PIMap<uint, PIString> strings;
|
||||
};
|
||||
|
||||
struct PIP_EXPORT Translation {
|
||||
void clear();
|
||||
Context * createContext(const PIString & context);
|
||||
Context * createContext(uint hash);
|
||||
PIString translate(const PIString & in, const PIString & context);
|
||||
bool load(const PIByteArray & data);
|
||||
int count() const;
|
||||
PIByteArray save();
|
||||
PIString lang;
|
||||
PIMap<uint, Context *> contexts;
|
||||
};
|
||||
|
||||
PIP_EXPORT int headerSize();
|
||||
PIP_EXPORT bool checkHeader(PIIODevice * d);
|
||||
PIP_EXPORT void writeHeader(PIIODevice * d);
|
||||
|
||||
} // namespace PITranslatorPrivate
|
||||
|
||||
#endif
|
||||
69
libs/main/client_server/piclientserver_client.h
Normal file
69
libs/main/client_server/piclientserver_client.h
Normal 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
|
||||
88
libs/main/client_server/piclientserver_client_base.h
Normal file
88
libs/main/client_server/piclientserver_client_base.h
Normal 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
|
||||
79
libs/main/client_server/piclientserver_server.h
Normal file
79
libs/main/client_server/piclientserver_server.h
Normal 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
|
||||
57
libs/main/client_server/piclientservermodule.h
Normal file
57
libs/main/client_server/piclientservermodule.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Module includes
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//! \defgroup ClientServer ClientServer
|
||||
//! \~\brief
|
||||
//! \~english TCP Client-Server
|
||||
//! \~russian TCP Клиент-Сервер
|
||||
//!
|
||||
//! \~\details
|
||||
//! \~english \section cmake_module_ClientServer Building with CMake
|
||||
//! \~russian \section cmake_module_ClientServer Сборка с использованием CMake
|
||||
//!
|
||||
//! \~\code
|
||||
//! find_package(PIP REQUIRED)
|
||||
//! target_link_libraries([target] PIP::ClientServer)
|
||||
//! \endcode
|
||||
//!
|
||||
//! \~english \par Common
|
||||
//! \~russian \par Общее
|
||||
//!
|
||||
//! \~english
|
||||
//! These files provides server with clients dispatching for server-side and client for client-side.
|
||||
//!
|
||||
//! \~russian
|
||||
//! Эти файлы предоставляют сервер с диспетчеризацией клиентов для серверной стороны и клиента для клиентской стороны.
|
||||
//!
|
||||
//! \~\authors
|
||||
//! \~english
|
||||
//! Ivan Pelipenko peri4ko@yandex.ru;
|
||||
//! Andrey Bychkov work.a.b@yandex.ru;
|
||||
//! \~russian
|
||||
//! Иван Пелипенко peri4ko@yandex.ru;
|
||||
//! Андрей Бычков work.a.b@yandex.ru;
|
||||
//!
|
||||
|
||||
#ifndef PICLIENTSERVERMODULE_H
|
||||
#define PICLIENTSERVERMODULE_H
|
||||
|
||||
#include "piclientserver_client.h"
|
||||
#include "piclientserver_server.h"
|
||||
|
||||
#endif
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~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
|
||||
@@ -31,8 +31,7 @@
|
||||
#include "pistreampacker.h"
|
||||
|
||||
|
||||
class PIP_CLOUD_EXPORT PICloudBase
|
||||
{
|
||||
class PIP_CLOUD_EXPORT PICloudBase {
|
||||
public:
|
||||
PICloudBase();
|
||||
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~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
|
||||
@@ -32,26 +32,30 @@
|
||||
|
||||
//! \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);
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Module includes
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
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 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/>.
|
||||
*/
|
||||
//! \defgroup Cloud Cloud
|
||||
//! \~\brief
|
||||
@@ -51,8 +51,8 @@
|
||||
#ifndef PICLOUDMODULE_H
|
||||
#define PICLOUDMODULE_H
|
||||
|
||||
#include "picloudtcp.h"
|
||||
#include "picloudclient.h"
|
||||
#include "picloudserver.h"
|
||||
#include "picloudtcp.h"
|
||||
|
||||
#endif // PICLOUDMODULE_H
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
* \~russian Сервер PICloud
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
PICloud Server
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
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 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 PICLOUDSERVER_H
|
||||
@@ -30,26 +30,32 @@
|
||||
#include "piconditionvar.h"
|
||||
|
||||
|
||||
class PIP_CLOUD_EXPORT PICloudServer: public PIIODevice, public PICloudBase
|
||||
{
|
||||
PIIODEVICE(PICloudServer, "")
|
||||
class PIP_CLOUD_EXPORT PICloudServer
|
||||
: public PIIODevice
|
||||
, public PICloudBase {
|
||||
PIIODEVICE(PICloudServer, "");
|
||||
|
||||
public:
|
||||
//! PICloudServer
|
||||
explicit PICloudServer(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
|
||||
virtual ~PICloudServer();
|
||||
|
||||
class Client : public PIIODevice {
|
||||
PIIODEVICE(PICloudServer::Client, "")
|
||||
class Client: public PIIODevice {
|
||||
PIIODEVICE(PICloudServer::Client, "");
|
||||
friend class PICloudServer;
|
||||
|
||||
public:
|
||||
Client(PICloudServer * srv = nullptr, uint id = 0);
|
||||
virtual ~Client();
|
||||
|
||||
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; }
|
||||
ssize_t bytesAvailable() const override { return buff.size(); }
|
||||
void interrupt() override;
|
||||
|
||||
private:
|
||||
void pushBuffer(const PIByteArray & ba);
|
||||
@@ -65,13 +71,14 @@ public:
|
||||
|
||||
PIVector<PICloudServer::Client *> clients() const;
|
||||
|
||||
EVENT1(newConnection, PICloudServer::Client * , client)
|
||||
EVENT1(newConnection, PICloudServer::Client *, client);
|
||||
|
||||
protected:
|
||||
bool openDevice();
|
||||
bool closeDevice();
|
||||
int readDevice(void * read_to, int max_size);
|
||||
int writeDevice(const void * data, int max_size);
|
||||
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 max_size) override;
|
||||
void interrupt() override;
|
||||
|
||||
private:
|
||||
EVENT_HANDLER1(void, _readed, PIByteArray &, ba);
|
||||
@@ -80,9 +87,13 @@ private:
|
||||
int sendData(const PIByteArray & data, uint client_id);
|
||||
|
||||
PIVector<Client *> clients_;
|
||||
PIVector<Client *> removed_clients_;
|
||||
PIMap<uint, Client *> index_clients;
|
||||
PITimer ping_timer;
|
||||
PIThread ping_timer;
|
||||
PIConditionVariable cvar;
|
||||
PIMutex open_mutex;
|
||||
mutable PIMutex clients_mutex;
|
||||
std::atomic_bool is_deleted;
|
||||
};
|
||||
|
||||
#endif // PICLOUDSERVER_H
|
||||
|
||||
@@ -5,30 +5,30 @@
|
||||
* \~russian TCP слой PICloud
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
PICloud TCP transport
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
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 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 PICLOUDTCP_H
|
||||
#define PICLOUDTCP_H
|
||||
|
||||
#include "pimutex.h"
|
||||
#include "pip_cloud_export.h"
|
||||
#include "pistring.h"
|
||||
#include "pimutex.h"
|
||||
|
||||
|
||||
class PIEthernet;
|
||||
@@ -37,7 +37,6 @@ class PIStreamPacker;
|
||||
namespace PICloud {
|
||||
|
||||
|
||||
|
||||
class PIP_CLOUD_EXPORT TCP {
|
||||
public:
|
||||
enum Version {
|
||||
@@ -47,21 +46,21 @@ public:
|
||||
|
||||
enum Role {
|
||||
InvalidRole = 0,
|
||||
Server = 1,
|
||||
Client = 2,
|
||||
Server = 1,
|
||||
Client = 2,
|
||||
};
|
||||
|
||||
enum Type {
|
||||
InvalidType = 0,
|
||||
Connect = 1,
|
||||
Disconnect = 2,
|
||||
Data = 3,
|
||||
Ping = 4,
|
||||
Connect = 1,
|
||||
Disconnect = 2,
|
||||
Data = 3,
|
||||
Ping = 4,
|
||||
};
|
||||
|
||||
TCP(PIStreamPacker * s);
|
||||
void setRole(Role r);
|
||||
Role role() const {return (Role)header.role;}
|
||||
Role role() const { return (Role)header.role; }
|
||||
void setServerName(const PIString & server_name_);
|
||||
PIString serverName() const;
|
||||
|
||||
@@ -82,8 +81,8 @@ private:
|
||||
struct Header {
|
||||
Header();
|
||||
uchar version; // PICloud::Version
|
||||
uchar type; // PICloud::Type
|
||||
uchar role; // PICloud::Role
|
||||
uchar type; // PICloud::Type
|
||||
uchar role; // PICloud::Role
|
||||
};
|
||||
|
||||
Header header;
|
||||
@@ -91,9 +90,8 @@ private:
|
||||
PIString server_name;
|
||||
PIStreamPacker * streampacker;
|
||||
PIMutex mutex_send;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace PICloud
|
||||
|
||||
#endif // PICLOUDTCP_H
|
||||
|
||||
@@ -1,62 +1,85 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
C++ code info structs
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
C++ code info structs
|
||||
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 "picodeinfo.h"
|
||||
|
||||
#include "pivariant.h"
|
||||
|
||||
|
||||
PIString PICodeInfo::EnumInfo::memberName(int value_) const {
|
||||
piForeachC (PICodeInfo::EnumeratorInfo & e, members)
|
||||
if (e.value == value_)
|
||||
return e.name.toString();
|
||||
for (const auto & e: members)
|
||||
if (e.value == value_) return e.name.toString();
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
int PICodeInfo::EnumInfo::memberValue(const PIString & name_) const {
|
||||
piForeachC (PICodeInfo::EnumeratorInfo & e, members)
|
||||
if (e.name.toString() == name_)
|
||||
return e.value;
|
||||
for (const auto & e: members)
|
||||
if (e.name.toString() == name_) return e.value;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
PIVariantTypes::Enum PICodeInfo::EnumInfo::toPIVariantEnum() {
|
||||
PIVariantTypes::Enum en(name.toString());
|
||||
for (auto m: members) en << m.toPIVariantEnumerator();
|
||||
for (auto m: members)
|
||||
en << m.toPIVariantEnumerator();
|
||||
if (!en.isEmpty()) en.selectValue(members.front().value);
|
||||
return en;
|
||||
}
|
||||
|
||||
|
||||
PIMap<PIConstChars, PICodeInfo::ClassInfo * > * PICodeInfo::classesInfo;
|
||||
PIMap<PIConstChars, PICodeInfo::EnumInfo * > * PICodeInfo::enumsInfo;
|
||||
PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * PICodeInfo::accessValueFunctions;
|
||||
PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * PICodeInfo::accessTypeFunctions;
|
||||
|
||||
bool __PICodeInfoInitializer__::_inited_ = false;
|
||||
|
||||
|
||||
PIVariant PICodeInfo::getMemberAsVariant(const void * p, const char * class_name, const char * member_name) {
|
||||
if (!p || !class_name || !member_name || !accessTypeFunctions || !accessValueFunctions) return PIVariant();
|
||||
AccessTypeFunction atf = accessTypeFunctions->value(class_name, (AccessTypeFunction)0);
|
||||
AccessValueFunction avf = accessValueFunctions->value(class_name, (AccessValueFunction)0);
|
||||
if (!p || !class_name || !member_name) return PIVariant();
|
||||
AccessTypeFunction atf = PICODEINFO::accessTypeFunctions().value(class_name, (AccessTypeFunction) nullptr);
|
||||
AccessValueFunction avf = PICODEINFO::accessValueFunctions().value(class_name, (AccessValueFunction) nullptr);
|
||||
if (!atf || !avf) return PIVariant();
|
||||
return PIVariant::fromValue(avf(p, member_name), PIStringAscii(atf(member_name)));
|
||||
}
|
||||
|
||||
|
||||
PICodeInfo::__Storage__::__Storage__() {
|
||||
classesInfo = new PIMap<PIConstChars, ClassInfo *>;
|
||||
enumsInfo = new PIMap<PIConstChars, EnumInfo *>;
|
||||
accessValueFunctions = new PIMap<PIConstChars, AccessValueFunction>;
|
||||
accessTypeFunctions = new PIMap<PIConstChars, AccessTypeFunction>;
|
||||
(*enumsInfo)[""] = new EnumInfo();
|
||||
}
|
||||
|
||||
|
||||
PICodeInfo::__Storage__::~__Storage__() {
|
||||
piDeleteAll(classesInfo->values());
|
||||
piDeleteAll(enumsInfo->values());
|
||||
piDeleteSafety(classesInfo);
|
||||
piDeleteSafety(enumsInfo);
|
||||
piDeleteSafety(accessValueFunctions);
|
||||
piDeleteSafety(accessTypeFunctions);
|
||||
}
|
||||
|
||||
|
||||
PICodeInfo::__Storage__ * PICodeInfo::__Storage__::instance() {
|
||||
static __Storage__ ret;
|
||||
return &ret;
|
||||
}
|
||||
|
||||
|
||||
PICodeInfo::ClassInfoInterface classesInfo;
|
||||
PICodeInfo::EnumsInfoInterface enumsInfo;
|
||||
PICodeInfo::AccessValueFunctionInterface accessValueFunctions;
|
||||
PICodeInfo::AccessTypeFunctionInterface accessTypeFunctions;
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
/*! \file picodeinfo.h
|
||||
* \ingroup Code
|
||||
* \~\brief
|
||||
* \~english C++ code info structs
|
||||
* \~russian Структуры для C++ кода
|
||||
* \~english C++ code info structs. See \ref code_model.
|
||||
* \~russian Структуры для C++ кода. Подробнее \ref code_model.
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
C++ code info structs
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
C++ code info structs
|
||||
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/>.
|
||||
*/
|
||||
|
||||
|
||||
@@ -34,72 +34,181 @@
|
||||
|
||||
class PIVariant;
|
||||
|
||||
//! \~english Namespace contains structures for code generation. See \ref code_model.
|
||||
//! \~russian Пространство имен содержит структуры для кодогенерации. Подробнее \ref code_model.
|
||||
namespace PICodeInfo {
|
||||
|
||||
|
||||
//! \~english
|
||||
//! Type modifiers
|
||||
//! \~russian
|
||||
//! Модификаторы типа
|
||||
enum TypeFlag {
|
||||
NoFlag,
|
||||
Const = 0x01,
|
||||
Static = 0x02,
|
||||
Mutable = 0x04,
|
||||
Volatile = 0x08,
|
||||
Inline = 0x10,
|
||||
Virtual = 0x20,
|
||||
Extern = 0x40
|
||||
Const /** const */ = 0x01,
|
||||
Static /** static */ = 0x02,
|
||||
Mutable /** mutable */ = 0x04,
|
||||
Volatile /** volatile */ = 0x08,
|
||||
Inline /** inline */ = 0x10,
|
||||
Virtual /** virtual */ = 0x20,
|
||||
Extern /** extern */ = 0x40
|
||||
};
|
||||
|
||||
typedef PIFlags<PICodeInfo::TypeFlag> TypeFlags;
|
||||
typedef PIMap<PIString, PIString> MetaMap;
|
||||
typedef PIByteArray(*AccessValueFunction)(const void *, const char *);
|
||||
typedef const char*(*AccessTypeFunction)(const char *);
|
||||
typedef PIByteArray (*AccessValueFunction)(const void *, const char *);
|
||||
typedef const char * (*AccessTypeFunction)(const char *);
|
||||
|
||||
|
||||
//! \~english Type information
|
||||
//! \~russian Информация о типе
|
||||
struct PIP_EXPORT TypeInfo {
|
||||
TypeInfo(const PIConstChars & n = PIConstChars(), const PIConstChars & t = PIConstChars(), PICodeInfo::TypeFlags f = 0, int b = -1) {name = n; type = t; flags = f; bits = b;}
|
||||
bool isBitfield() const {return bits > 0;}
|
||||
TypeInfo(const PIConstChars & n = PIConstChars(), const PIConstChars & t = PIConstChars(), PICodeInfo::TypeFlags f = 0, int b = -1) {
|
||||
name = n;
|
||||
type = t;
|
||||
flags = f;
|
||||
bits = b;
|
||||
}
|
||||
|
||||
//! \~english Returns if variable if bitfield
|
||||
//! \~russian Возвращает битовым ли полем является переменная
|
||||
bool isBitfield() const { return bits > 0; }
|
||||
|
||||
//! \~english Custom PIMETA content
|
||||
//! \~russian Произвольное содержимое PIMETA
|
||||
MetaMap meta;
|
||||
|
||||
//! \~english Name
|
||||
//! \~russian Имя
|
||||
PIConstChars name;
|
||||
|
||||
//! \~english Type
|
||||
//! \~russian Тип
|
||||
PIConstChars type;
|
||||
|
||||
//! \~english Modifiers
|
||||
//! \~russian Модификаторы
|
||||
PICodeInfo::TypeFlags flags;
|
||||
|
||||
//! \~english Bitfield variable bit count
|
||||
//! \~russian Количество бит битового поля
|
||||
int bits;
|
||||
};
|
||||
|
||||
|
||||
//! \~english Method information
|
||||
//! \~russian Информация о методе
|
||||
struct PIP_EXPORT FunctionInfo {
|
||||
//! \~english Custom PIMETA content
|
||||
//! \~russian Произвольное содержимое PIMETA
|
||||
MetaMap meta;
|
||||
|
||||
//! \~english Name
|
||||
//! \~russian Имя
|
||||
PIConstChars name;
|
||||
|
||||
//! \~english Return type
|
||||
//! \~russian Возвращаемые тип
|
||||
TypeInfo return_type;
|
||||
|
||||
//! \~english Arguments types
|
||||
//! \~russian Типы аргументов
|
||||
PIVector<PICodeInfo::TypeInfo> arguments;
|
||||
};
|
||||
|
||||
|
||||
//! \~english Class or struct information
|
||||
//! \~russian Информация о классе или структуре
|
||||
struct PIP_EXPORT ClassInfo {
|
||||
ClassInfo() {has_name = true;}
|
||||
ClassInfo() { has_name = true; }
|
||||
|
||||
//! \~english Custom PIMETA content
|
||||
//! \~russian Произвольное содержимое PIMETA
|
||||
MetaMap meta;
|
||||
|
||||
//! \~english Has name or not
|
||||
//! \~russian Имеет или нет имя
|
||||
bool has_name;
|
||||
|
||||
//! \~english Type
|
||||
//! \~russian Тип
|
||||
PIConstChars type;
|
||||
|
||||
//! \~english Name
|
||||
//! \~russian Имя
|
||||
PIConstChars name;
|
||||
|
||||
//! \~english Parent names
|
||||
//! \~russian Имена родителей
|
||||
PIVector<PIConstChars> parents;
|
||||
|
||||
//! \~english Variables
|
||||
//! \~russian Переменные
|
||||
PIVector<PICodeInfo::TypeInfo> variables;
|
||||
|
||||
//! \~english Methods
|
||||
//! \~russian Методы
|
||||
PIVector<PICodeInfo::FunctionInfo> functions;
|
||||
PIVector<PICodeInfo::ClassInfo * > children_info;
|
||||
|
||||
//! \~english Subclass list
|
||||
//! \~russian Список наследников
|
||||
PIVector<PICodeInfo::ClassInfo *> children_info;
|
||||
};
|
||||
|
||||
|
||||
//! \~english Enumerator information
|
||||
//! \~russian Информация об элементе перечисления
|
||||
struct PIP_EXPORT EnumeratorInfo {
|
||||
EnumeratorInfo(const PIConstChars & n = PIConstChars(), int v = 0) {name = n; value = v;}
|
||||
PIVariantTypes::Enumerator toPIVariantEnumerator() {return PIVariantTypes::Enumerator(value, name.toString());}
|
||||
EnumeratorInfo(const PIConstChars & n = PIConstChars(), int v = 0) {
|
||||
name = n;
|
||||
value = v;
|
||||
}
|
||||
PIVariantTypes::Enumerator toPIVariantEnumerator() { return PIVariantTypes::Enumerator(value, name.toString()); }
|
||||
|
||||
//! \~english Custom PIMETA content
|
||||
//! \~russian Произвольное содержимое PIMETA
|
||||
MetaMap meta;
|
||||
|
||||
//! \~english Name
|
||||
//! \~russian Имя
|
||||
PIConstChars name;
|
||||
|
||||
//! \~english Value
|
||||
//! \~russian Значение
|
||||
int value;
|
||||
};
|
||||
|
||||
|
||||
//! \~english Enum information
|
||||
//! \~russian Информация о перечислении
|
||||
struct PIP_EXPORT EnumInfo {
|
||||
//! \~english Returns member name with value "value"
|
||||
//! \~russian Возвращает имя элемента со значением "value"
|
||||
PIString memberName(int value) const;
|
||||
|
||||
//! \~english Returns member value with name "name"
|
||||
//! \~russian Возвращает значение элемента с именем "name"
|
||||
int memberValue(const PIString & name) const;
|
||||
|
||||
//! \~english Returns as PIVariantTypes::Enum
|
||||
//! \~russian Возвращает как PIVariantTypes::Enum
|
||||
PIVariantTypes::Enum toPIVariantEnum();
|
||||
|
||||
//! \~english Custom PIMETA content
|
||||
//! \~russian Произвольное содержимое PIMETA
|
||||
MetaMap meta;
|
||||
|
||||
//! \~english Name
|
||||
//! \~russian Имя
|
||||
PIConstChars name;
|
||||
|
||||
//! \~english Members
|
||||
//! \~russian Элементы
|
||||
PIVector<PICodeInfo::EnumeratorInfo> members;
|
||||
};
|
||||
|
||||
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::TypeInfo & v) {
|
||||
inline PICout operator<<(PICout s, const PICodeInfo::TypeInfo & v) {
|
||||
if (v.flags[Inline]) s << "inline ";
|
||||
if (v.flags[Virtual]) s << "virtual ";
|
||||
if (v.flags[Mutable]) s << "mutable ";
|
||||
@@ -107,22 +216,26 @@ inline PICout operator <<(PICout s, const PICodeInfo::TypeInfo & v) {
|
||||
if (v.flags[Static]) s << "static ";
|
||||
if (v.flags[Const]) s << "const ";
|
||||
s << v.type;
|
||||
if (!v.name.isEmpty())
|
||||
s << " " << v.name;
|
||||
if (!v.name.isEmpty()) s << " " << v.name;
|
||||
return s;
|
||||
}
|
||||
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::EnumeratorInfo & v) {s << v.name << " = " << v.value << " Meta" << v.meta; return s;}
|
||||
inline PICout operator<<(PICout s, const PICodeInfo::EnumeratorInfo & v) {
|
||||
s << v.name << " = " << v.value << " Meta" << v.meta;
|
||||
return s;
|
||||
}
|
||||
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::ClassInfo & v) {
|
||||
s.setControl(0, true);
|
||||
inline PICout operator<<(PICout s, const PICodeInfo::ClassInfo & v) {
|
||||
s.saveAndSetControls(0);
|
||||
s << "class " << v.name;
|
||||
if (!v.parents.isEmpty()) {
|
||||
s << ": ";
|
||||
bool first = true;
|
||||
for (const auto & i: v.parents) {
|
||||
if (first) first = false;
|
||||
else s << ", ";
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
s << ", ";
|
||||
s << i;
|
||||
}
|
||||
}
|
||||
@@ -131,51 +244,132 @@ inline PICout operator <<(PICout s, const PICodeInfo::ClassInfo & v) {
|
||||
s << PICoutManipulators::Tab << i.return_type << " " << i.name << "(";
|
||||
bool fa = true;
|
||||
for (const auto & a: i.arguments) {
|
||||
if (fa) fa = false;
|
||||
else s << ", ";
|
||||
if (fa)
|
||||
fa = false;
|
||||
else
|
||||
s << ", ";
|
||||
s << a;
|
||||
}
|
||||
s << ") Meta" << i.meta << ";\n";
|
||||
}
|
||||
if (!v.functions.isEmpty() && !v.variables.isEmpty())
|
||||
s << "\n";
|
||||
if (!v.functions.isEmpty() && !v.variables.isEmpty()) s << "\n";
|
||||
for (const auto & i: v.variables) {
|
||||
s << PICoutManipulators::Tab << i << " Meta" << i.meta << ";\n";
|
||||
}
|
||||
s << "}\n";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::EnumInfo & v) {
|
||||
s.setControl(0, true);
|
||||
inline PICout operator<<(PICout s, const PICodeInfo::EnumInfo & v) {
|
||||
s.saveAndSetControls(0);
|
||||
s << "enum " << v.name << " Meta" << v.meta << " {\n";
|
||||
for (const auto & i: v.members) {
|
||||
bool f = true;
|
||||
if (f) f = false;
|
||||
else s << ", ";
|
||||
if (f)
|
||||
f = false;
|
||||
else
|
||||
s << ", ";
|
||||
s << PICoutManipulators::Tab << i << "\n";
|
||||
}
|
||||
s << "}\n";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::ClassInfo * > * classesInfo;
|
||||
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::EnumInfo * > * enumsInfo;
|
||||
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * accessValueFunctions;
|
||||
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * accessTypeFunctions;
|
||||
|
||||
class PIP_EXPORT __Storage__ {
|
||||
__Storage__();
|
||||
~__Storage__();
|
||||
|
||||
public:
|
||||
static __Storage__ * instance();
|
||||
|
||||
PIMap<PIConstChars, PICodeInfo::ClassInfo *> * classesInfo;
|
||||
PIMap<PIConstChars, PICodeInfo::EnumInfo *> * enumsInfo;
|
||||
PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * accessValueFunctions;
|
||||
PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * accessTypeFunctions;
|
||||
|
||||
private:
|
||||
NO_COPY_CLASS(__Storage__)
|
||||
};
|
||||
|
||||
class PIP_EXPORT __StorageAccess__ {
|
||||
public:
|
||||
//! \~english Getter for single storage of PICodeInfo::ClassInfo, access by name
|
||||
//! \~russian Доступ к единому хранилищу PICodeInfo::ClassInfo, доступ по имени
|
||||
static const PIMap<PIConstChars, PICodeInfo::ClassInfo *> & classes() { return *(__Storage__::instance()->classesInfo); }
|
||||
|
||||
//! \~english Getter for single storage of PICodeInfo::EnumInfo, access by name
|
||||
//! \~russian Доступ к единому хранилищу хранилище PICodeInfo::EnumInfo, доступ по имени
|
||||
static const PIMap<PIConstChars, PICodeInfo::EnumInfo *> & enums() { return *(__Storage__::instance()->enumsInfo); }
|
||||
|
||||
static const PIMap<PIConstChars, PICodeInfo::AccessValueFunction> & accessValueFunctions() {
|
||||
return *(__Storage__::instance()->accessValueFunctions);
|
||||
}
|
||||
|
||||
static const PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> & accessTypeFunctions() {
|
||||
return *(__Storage__::instance()->accessTypeFunctions);
|
||||
}
|
||||
};
|
||||
|
||||
#define PICODEINFO PICodeInfo::__StorageAccess__
|
||||
|
||||
|
||||
class PIP_EXPORT ClassInfoInterface {
|
||||
public:
|
||||
const PIMap<PIConstChars, PICodeInfo::ClassInfo *> * operator->() const DEPRECATEDM("use PICODEINFO::classes()") {
|
||||
return __Storage__::instance()->classesInfo;
|
||||
}
|
||||
};
|
||||
static ClassInfoInterface classesInfo;
|
||||
|
||||
|
||||
class PIP_EXPORT EnumsInfoInterface {
|
||||
public:
|
||||
const PIMap<PIConstChars, PICodeInfo::EnumInfo *> * operator->() const DEPRECATEDM("use PICODEINFO::enums()") {
|
||||
return __Storage__::instance()->enumsInfo;
|
||||
}
|
||||
};
|
||||
static EnumsInfoInterface enumsInfo;
|
||||
|
||||
|
||||
class PIP_EXPORT AccessValueFunctionInterface {
|
||||
public:
|
||||
const PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * operator->() const DEPRECATEDM("use PICODEINFO::accessValueFunctions()") {
|
||||
return __Storage__::instance()->accessValueFunctions;
|
||||
}
|
||||
};
|
||||
static AccessValueFunctionInterface accessValueFunctions;
|
||||
|
||||
|
||||
class PIP_EXPORT AccessTypeFunctionInterface {
|
||||
public:
|
||||
const PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * operator->() const DEPRECATEDM("use PICODEINFO::accessTypeFunctions()") {
|
||||
return __Storage__::instance()->accessTypeFunctions;
|
||||
}
|
||||
};
|
||||
static AccessTypeFunctionInterface accessTypeFunctions;
|
||||
|
||||
|
||||
STATIC_INITIALIZER_BEGIN
|
||||
NO_UNUSED(classesInfo);
|
||||
NO_UNUSED(enumsInfo);
|
||||
NO_UNUSED(accessValueFunctions);
|
||||
NO_UNUSED(accessTypeFunctions);
|
||||
STATIC_INITIALIZER_END
|
||||
|
||||
|
||||
inline PIByteArray getMemberValue(const void * p, const char * class_name, const char * member_name) {
|
||||
if (!p || !class_name || !member_name || !accessValueFunctions) return PIByteArray();
|
||||
AccessValueFunction af = accessValueFunctions->value(class_name, (AccessValueFunction)0);
|
||||
if (!p || !class_name || !member_name) return PIByteArray();
|
||||
AccessValueFunction af = PICODEINFO::accessValueFunctions().value(class_name, (AccessValueFunction)0);
|
||||
if (!af) return PIByteArray();
|
||||
return af(p, member_name);
|
||||
}
|
||||
|
||||
inline const char * getMemberType(const char * class_name, const char * member_name) {
|
||||
if (!class_name || !member_name || !accessTypeFunctions) return "";
|
||||
AccessTypeFunction af = accessTypeFunctions->value(class_name, (AccessTypeFunction)0);
|
||||
if (!class_name || !member_name) return "";
|
||||
AccessTypeFunction af = PICODEINFO::accessTypeFunctions().value(class_name, (AccessTypeFunction)0);
|
||||
if (!af) return "";
|
||||
return af(member_name);
|
||||
}
|
||||
@@ -183,27 +377,15 @@ inline const char * getMemberType(const char * class_name, const char * member_n
|
||||
PIP_EXPORT PIVariant getMemberAsVariant(const void * p, const char * class_name, const char * member_name);
|
||||
|
||||
|
||||
template<typename T, typename std::enable_if< std::is_assignable<T&, const T&>::value, int>::type = 0>
|
||||
void serialize(PIByteArray & ret, const T & v) {ret << v;}
|
||||
|
||||
template<typename T, typename std::enable_if<!std::is_assignable<T&, const T&>::value, int>::type = 0>
|
||||
void serialize(PIByteArray & ret, const T & v) {}
|
||||
|
||||
template<typename T, typename std::enable_if<std::is_assignable<T &, const T &>::value, int>::type = 0>
|
||||
void serialize(PIByteArray & ret, const T & v) {
|
||||
ret << v;
|
||||
}
|
||||
|
||||
class PIP_EXPORT __PICodeInfoInitializer__ {
|
||||
public:
|
||||
__PICodeInfoInitializer__() {
|
||||
if (_inited_) return;
|
||||
_inited_ = true;
|
||||
PICodeInfo::classesInfo = new PIMap<PIConstChars, PICodeInfo::ClassInfo * >;
|
||||
PICodeInfo::enumsInfo = new PIMap<PIConstChars, PICodeInfo::EnumInfo * >;
|
||||
PICodeInfo::accessValueFunctions = new PIMap<PIConstChars, PICodeInfo::AccessValueFunction>;
|
||||
PICodeInfo::accessTypeFunctions = new PIMap<PIConstChars, PICodeInfo::AccessTypeFunction>;
|
||||
}
|
||||
static bool _inited_;
|
||||
};
|
||||
template<typename T, typename std::enable_if<!std::is_assignable<T &, const T &>::value, int>::type = 0>
|
||||
void serialize(PIByteArray & ret, const T & v) {}
|
||||
|
||||
} // namespace PICodeInfo
|
||||
|
||||
static __PICodeInfoInitializer__ __picodeinfoinitializer__;
|
||||
|
||||
#endif // PICODEINFO_H
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Module includes
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Module includes
|
||||
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/>.
|
||||
*/
|
||||
//! \defgroup Code Code
|
||||
//! \~\brief
|
||||
@@ -35,9 +35,11 @@
|
||||
//!
|
||||
//! \~english
|
||||
//! These files provides parsing C++ code and storage to use results of \a pip_cmg utility.
|
||||
//! See \ref code_model.
|
||||
//!
|
||||
//! \~russian
|
||||
//! Эти файлы обеспечивают разбор C++ кода и хранение результатов работы утилиты \a pip_cmg.
|
||||
//! Подробнее \ref code_model.
|
||||
//!
|
||||
//! \~\authors
|
||||
//! \~english
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
C++ code parser
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
C++ code 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 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 "picodeparser.h"
|
||||
|
||||
|
||||
|
||||
PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
|
||||
PIStringList arg_vals;
|
||||
while (!args_.isEmpty()) {
|
||||
@@ -32,29 +31,32 @@ PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
|
||||
PIString ca;
|
||||
if (bi >= 0 && bi < ci) {
|
||||
ca = args_.left(args_.takeLeft(bi).toInt());
|
||||
ci -= ca.size_s(); bi -= ca.size_s();
|
||||
ci -= ca.size_s();
|
||||
bi -= ca.size_s();
|
||||
ca += '(' + args_.takeRange('(', ')') + ')';
|
||||
} else {
|
||||
ca = args_.takeLeft(ci);
|
||||
}
|
||||
arg_vals << ca;
|
||||
args_.trim(); args_.takeLeft(1); args_.trim();
|
||||
args_.trim();
|
||||
args_.takeLeft(1);
|
||||
args_.trim();
|
||||
}
|
||||
if (args.size() != arg_vals.size()) {
|
||||
piCout << ("Error: in expansion of macro \"" + name + '(' + args.join(", ") + ")\": expect")
|
||||
<< args.size() << "arguments but takes" << arg_vals.size() << "!";
|
||||
piCout << ("Error: in expansion of macro \"" + name + '(' + args.join(", ") + ")\": expect") << args.size() << "arguments but takes"
|
||||
<< arg_vals.size() << "!";
|
||||
if (ok != 0) *ok = false;
|
||||
return PIString();
|
||||
}
|
||||
PIString ret = value;
|
||||
for (int i = 0; i < args.size_s(); ++i) {
|
||||
const PIString & an(args[i]), av(arg_vals[i]);
|
||||
const PIString &an(args[i]), av(arg_vals[i]);
|
||||
int ind(-1);
|
||||
while ((ind = ret.find(an, ind + 1)) >= 0) {
|
||||
PIChar ppc, pc, nc;
|
||||
if (ind > 1) ppc = ret[ind - 2];
|
||||
if (ind > 0) pc = ret[ind - 1];
|
||||
if (ind + an.size_s() < ret.size_s()) nc = ret.mid(ind + an.size_s(),1)[0];
|
||||
if (ind + an.size_s() < ret.size_s()) nc = ret.mid(ind + an.size_s(), 1)[0];
|
||||
if (ppc != '#' && pc == '#' && !_isCChar(nc)) { // to chars
|
||||
ind--;
|
||||
ret.replace(ind, an.size_s() + 1, '\"' + av + '\"');
|
||||
@@ -72,9 +74,8 @@ PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
|
||||
}
|
||||
|
||||
|
||||
|
||||
PICodeParser::PICodeParser() {
|
||||
macros_iter = 32;
|
||||
macros_iter = 32;
|
||||
with_includes = true;
|
||||
clear();
|
||||
includes << "";
|
||||
@@ -85,63 +86,67 @@ void PICodeParser::parseFile(const PIString & file, bool follow_includes) {
|
||||
clear();
|
||||
parseFileInternal(file, follow_includes);
|
||||
/*piCout << "\n\n";
|
||||
piForeachC (Entity * c, entities) {
|
||||
piCout << "";
|
||||
piCout << c->type << c->name << c->parent_scope << c->parents << c->children << c->meta;
|
||||
if (c->parent_scope)
|
||||
piCout << "parent" << c->parent_scope->name;
|
||||
piCout << "Functions:";
|
||||
piForeachC (Member & m, c->functions)
|
||||
piCout << m.type << m.name << m.meta;
|
||||
piCout << "Members:";
|
||||
piForeachC (Member & m, c->members)
|
||||
piCout << m.type << m.name << m.meta;
|
||||
for (const auto * c: entities) {
|
||||
piCout << "";
|
||||
piCout << c->type << c->name << c->parent_scope << c->parents << c->children << c->meta;
|
||||
if (c->parent_scope)
|
||||
piCout << "parent" << c->parent_scope->name;
|
||||
piCout << "Functions:";
|
||||
for (const auto & m: c->functions)
|
||||
piCout << m.type << m.name << m.meta;
|
||||
piCout << "Members:";
|
||||
for (const auto & m: c->members)
|
||||
piCout << m.type << m.name << m.meta;
|
||||
}
|
||||
piCout << "\n\nDefines:";
|
||||
piForeachC (Define & m, defines)
|
||||
piCout << PIStringAscii("define") << m.first << m.second;
|
||||
for (const auto & m: defines)
|
||||
piCout << PIStringAscii("define") << m.first << m.second;
|
||||
piCout << "\n\nMacros:";
|
||||
piForeachC (Macro & m, macros)
|
||||
piCout << "Macro:" << m.name << m.args << m.value;
|
||||
for (const auto & m: macros)
|
||||
piCout << "Macro:" << m.name << m.args << m.value;
|
||||
piCout << "\n\nClasses:";
|
||||
piCout << "\n\nEnums:";
|
||||
piForeachC (Enum & c, enums) {
|
||||
piCout << PIStringAscii("enum") << c.name << c.meta;
|
||||
piForeachC (EnumeratorInfo & e, c.members)
|
||||
piCout << " " << e.name << '=' << e.value << e.meta;
|
||||
for (const auto & c: enums) {
|
||||
piCout << PIStringAscii("enum") << c.name << c.meta;
|
||||
for (const auto & e: c.members)
|
||||
piCout << " " << e.name << '=' << e.value << e.meta;
|
||||
}
|
||||
piCout << "\n\nTypedefs:";
|
||||
piForeachC (Typedef & c, typedefs)
|
||||
piCout << PIStringAscii("typedef") << c;*/
|
||||
for (const auto & c: typedefs)
|
||||
piCout << PIStringAscii("typedef") << c;*/
|
||||
}
|
||||
|
||||
|
||||
void PICodeParser::parseFiles(const PIStringList & files, bool follow_includes) {
|
||||
clear();
|
||||
piForeachC (PIString & f, files)
|
||||
for (const auto & f: files)
|
||||
parseFileInternal(f, follow_includes);
|
||||
/*piCout << "\n\nDefines:";
|
||||
piForeachC (Define & m, defines)
|
||||
piCout << PIStringAscii("define") << m.first << m.second;
|
||||
for (const auto & m: defines)
|
||||
piCout << PIStringAscii("define") << m.first << m.second;
|
||||
piCout << "\n\nMacros:";
|
||||
piForeachC (Macro & m, macros)
|
||||
piCout << "Macro:" << m.name << m.args << m.value;
|
||||
for (const auto & m: macros)
|
||||
piCout << "Macro:" << m.name << m.args << m.value;
|
||||
piCout << "\n\nClasses:";
|
||||
piForeachC (Entity * c, entities)
|
||||
piCout << PIStringAscii("class") << c->name << c->parents;
|
||||
for (const auto * c: entities)
|
||||
piCout << PIStringAscii("class") << c->name << c->parents;
|
||||
piCout << "\n\nEnums:";
|
||||
piForeachC (Enum & c, enums)
|
||||
piCout << PIStringAscii("enum") << c.name << c.members;
|
||||
for (const auto & c: enums)
|
||||
piCout << PIStringAscii("enum") << c.name << c.members;
|
||||
piCout << "\n\nTypedefs:";
|
||||
piForeachC (Typedef & c, typedefs)
|
||||
for (const auto & c: typedefs)
|
||||
piCout << PIStringAscii("typedef") << c;*/
|
||||
}
|
||||
|
||||
|
||||
void PICodeParser::parseFileContent(PIString fc) {
|
||||
parseFileContent(fc, false);
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::isEnum(const PIString & name) {
|
||||
piForeachC (Enum & e, enums)
|
||||
if (e.name == name)
|
||||
return true;
|
||||
for (const auto & e: enums)
|
||||
if (e.name == name) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -149,19 +154,19 @@ bool PICodeParser::isEnum(const PIString & name) {
|
||||
bool PICodeParser::parseFileInternal(const PIString & file, bool follow_includes) {
|
||||
if (proc_files[file]) return true;
|
||||
with_includes = follow_includes;
|
||||
cur_file = file;
|
||||
cur_file = file;
|
||||
PIFile f(file, PIIODevice::ReadOnly);
|
||||
int ii = 0;
|
||||
while (!f.isOpened() && ii < (includes.size_s() - 1)) {
|
||||
f.setPath(includes[++ii] + '/' + file);
|
||||
//piCout << "try" << f.path();
|
||||
// piCout << "try" << f.path();
|
||||
f.open(PIIODevice::ReadOnly);
|
||||
}
|
||||
if (!f.isOpened()) {
|
||||
piCout << ("Error: can`t open file \"" + file + "\"!");
|
||||
return false;
|
||||
}
|
||||
//piCout << "add" << file;
|
||||
// piCout << "add" << file;
|
||||
proc_files << f.path();
|
||||
PIString fc = PIString::fromUTF8(f.readAll());
|
||||
piCout << "parsing" << f.path() << "...";
|
||||
@@ -174,7 +179,8 @@ bool PICodeParser::parseFileInternal(const PIString & file, bool follow_includes
|
||||
|
||||
|
||||
void PICodeParser::clear() {
|
||||
piForeach (Entity * i, entities) delete i;
|
||||
for (auto * i: entities)
|
||||
delete i;
|
||||
defines.clear();
|
||||
macros.clear();
|
||||
enums.clear();
|
||||
@@ -184,40 +190,145 @@ void PICodeParser::clear() {
|
||||
cur_namespace.clear();
|
||||
main_file.clear();
|
||||
evaluator.clearCustomVariables();
|
||||
cur_def_vis = Global;
|
||||
anon_num = 0;
|
||||
cur_def_vis = Global;
|
||||
anon_num = 0;
|
||||
PIStringList defs = PIStringAscii(PICODE_DEFINES).split(",");
|
||||
piForeachC (PIString & d, defs)
|
||||
for (const auto & d: defs)
|
||||
defines << Define(d, "");
|
||||
defines << Define(PIStringAscii("PICODE"), "") << custom_defines;
|
||||
macros << Macro(PIStringAscii("PIOBJECT"), "", PIStringList() << "name")
|
||||
<< Macro(PIStringAscii("PIOBJECT_PARENT"), "", PIStringList() << "parent")
|
||||
<< Macro(PIStringAscii("PIOBJECT_SUBCLASS"), "", PIStringList() << "name" << "parent")
|
||||
<< Macro(PIStringAscii("PIOBJECT_SUBCLASS"),
|
||||
"",
|
||||
PIStringList() << "name"
|
||||
<< "parent")
|
||||
<< Macro(PIStringAscii("PIIODEVICE"), "", PIStringList() << "name")
|
||||
<< Macro(PIStringAscii("NO_COPY_CLASS"), "", PIStringList() << "name")
|
||||
<< Macro(PIStringAscii("PRIVATE_DECLARATION"))
|
||||
<< Macro(PIStringAscii("NO_COPY_CLASS"), "", PIStringList() << "name") << Macro(PIStringAscii("PRIVATE_DECLARATION"))
|
||||
|
||||
<< Macro(PIStringAscii("EVENT" ), "void name();", PIStringList() << "name")
|
||||
<< Macro(PIStringAscii("EVENT"), "void name();", PIStringList() << "name")
|
||||
<< Macro(PIStringAscii("EVENT0"), "void name();", PIStringList() << "name")
|
||||
<< Macro(PIStringAscii("EVENT1"), "void name(a0 n0);", PIStringList() << "name" << "a0" << "n0")
|
||||
<< Macro(PIStringAscii("EVENT2"), "void name(a0 n0, a1 n1);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1")
|
||||
<< Macro(PIStringAscii("EVENT3"), "void name(a0 n0, a1 n1, a2 n2);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2")
|
||||
<< Macro(PIStringAscii("EVENT4"), "void name(a0 n0, a1 n1, a2 n2, a3 n3);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2" << "a3" << "n3")
|
||||
<< Macro(PIStringAscii("EVENT1"),
|
||||
"void name(a0 n0);",
|
||||
PIStringList() << "name"
|
||||
<< "a0"
|
||||
<< "n0")
|
||||
<< Macro(PIStringAscii("EVENT2"),
|
||||
"void name(a0 n0, a1 n1);",
|
||||
PIStringList() << "name"
|
||||
<< "a0"
|
||||
<< "n0"
|
||||
<< "a1"
|
||||
<< "n1")
|
||||
<< Macro(PIStringAscii("EVENT3"),
|
||||
"void name(a0 n0, a1 n1, a2 n2);",
|
||||
PIStringList() << "name"
|
||||
<< "a0"
|
||||
<< "n0"
|
||||
<< "a1"
|
||||
<< "n1"
|
||||
<< "a2"
|
||||
<< "n2")
|
||||
<< Macro(PIStringAscii("EVENT4"),
|
||||
"void name(a0 n0, a1 n1, a2 n2, a3 n3);",
|
||||
PIStringList() << "name"
|
||||
<< "a0"
|
||||
<< "n0"
|
||||
<< "a1"
|
||||
<< "n1"
|
||||
<< "a2"
|
||||
<< "n2"
|
||||
<< "a3"
|
||||
<< "n3")
|
||||
|
||||
<< Macro(PIStringAscii("EVENT_HANDLER" ), "ret name()", PIStringList() << "ret" << "name")
|
||||
<< Macro(PIStringAscii("EVENT_HANDLER0"), "ret name()", PIStringList() << "ret" << "name")
|
||||
<< Macro(PIStringAscii("EVENT_HANDLER1"), "ret name(a0 n0)", PIStringList() << "ret" << "name" << "a0" << "n0")
|
||||
<< Macro(PIStringAscii("EVENT_HANDLER2"), "ret name(a0 n0, a1 n1)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1")
|
||||
<< Macro(PIStringAscii("EVENT_HANDLER3"), "ret name(a0 n0, a1 n1, a2 n2)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2")
|
||||
<< Macro(PIStringAscii("EVENT_HANDLER4"), "ret name(a0 n0, a1 n1, a2 n2, a3 n3)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2" << "a3" << "n3")
|
||||
<< Macro(PIStringAscii("EVENT_HANDLER"),
|
||||
"ret name()",
|
||||
PIStringList() << "ret"
|
||||
<< "name")
|
||||
<< Macro(PIStringAscii("EVENT_HANDLER0"),
|
||||
"ret name()",
|
||||
PIStringList() << "ret"
|
||||
<< "name")
|
||||
<< Macro(PIStringAscii("EVENT_HANDLER1"),
|
||||
"ret name(a0 n0)",
|
||||
PIStringList() << "ret"
|
||||
<< "name"
|
||||
<< "a0"
|
||||
<< "n0")
|
||||
<< Macro(PIStringAscii("EVENT_HANDLER2"),
|
||||
"ret name(a0 n0, a1 n1)",
|
||||
PIStringList() << "ret"
|
||||
<< "name"
|
||||
<< "a0"
|
||||
<< "n0"
|
||||
<< "a1"
|
||||
<< "n1")
|
||||
<< Macro(PIStringAscii("EVENT_HANDLER3"),
|
||||
"ret name(a0 n0, a1 n1, a2 n2)",
|
||||
PIStringList() << "ret"
|
||||
<< "name"
|
||||
<< "a0"
|
||||
<< "n0"
|
||||
<< "a1"
|
||||
<< "n1"
|
||||
<< "a2"
|
||||
<< "n2")
|
||||
<< Macro(PIStringAscii("EVENT_HANDLER4"),
|
||||
"ret name(a0 n0, a1 n1, a2 n2, a3 n3)",
|
||||
PIStringList() << "ret"
|
||||
<< "name"
|
||||
<< "a0"
|
||||
<< "n0"
|
||||
<< "a1"
|
||||
<< "n1"
|
||||
<< "a2"
|
||||
<< "n2"
|
||||
<< "a3"
|
||||
<< "n3")
|
||||
|
||||
<< Macro(PIStringAscii("EVENT_VHANDLER" ), "virtual ret name()", PIStringList() << "ret" << "name")
|
||||
<< Macro(PIStringAscii("EVENT_VHANDLER0"), "virtual ret name()", PIStringList() << "ret" << "name")
|
||||
<< Macro(PIStringAscii("EVENT_VHANDLER1"), "virtual ret name(a0 n0)", PIStringList() << "ret" << "name" << "a0" << "n0")
|
||||
<< Macro(PIStringAscii("EVENT_VHANDLER2"), "virtual ret name(a0 n0, a1 n1)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1")
|
||||
<< Macro(PIStringAscii("EVENT_VHANDLER3"), "virtual ret name(a0 n0, a1 n1, a2 n2)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2")
|
||||
<< Macro(PIStringAscii("EVENT_VHANDLER4"), "virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2" << "a3" << "n3")
|
||||
;
|
||||
<< Macro(PIStringAscii("EVENT_VHANDLER"),
|
||||
"virtual ret name()",
|
||||
PIStringList() << "ret"
|
||||
<< "name")
|
||||
<< Macro(PIStringAscii("EVENT_VHANDLER0"),
|
||||
"virtual ret name()",
|
||||
PIStringList() << "ret"
|
||||
<< "name")
|
||||
<< Macro(PIStringAscii("EVENT_VHANDLER1"),
|
||||
"virtual ret name(a0 n0)",
|
||||
PIStringList() << "ret"
|
||||
<< "name"
|
||||
<< "a0"
|
||||
<< "n0")
|
||||
<< Macro(PIStringAscii("EVENT_VHANDLER2"),
|
||||
"virtual ret name(a0 n0, a1 n1)",
|
||||
PIStringList() << "ret"
|
||||
<< "name"
|
||||
<< "a0"
|
||||
<< "n0"
|
||||
<< "a1"
|
||||
<< "n1")
|
||||
<< Macro(PIStringAscii("EVENT_VHANDLER3"),
|
||||
"virtual ret name(a0 n0, a1 n1, a2 n2)",
|
||||
PIStringList() << "ret"
|
||||
<< "name"
|
||||
<< "a0"
|
||||
<< "n0"
|
||||
<< "a1"
|
||||
<< "n1"
|
||||
<< "a2"
|
||||
<< "n2")
|
||||
<< Macro(PIStringAscii("EVENT_VHANDLER4"),
|
||||
"virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3)",
|
||||
PIStringList() << "ret"
|
||||
<< "name"
|
||||
<< "a0"
|
||||
<< "n0"
|
||||
<< "a1"
|
||||
<< "n1"
|
||||
<< "a2"
|
||||
<< "n2"
|
||||
<< "a3"
|
||||
<< "n3");
|
||||
}
|
||||
|
||||
|
||||
@@ -232,13 +343,14 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
static const PIString s_typedef = PIStringAscii("typedef");
|
||||
static const PIString s_namespace = PIStringAscii("namespace");
|
||||
static const PIString s_template = PIStringAscii("template");
|
||||
static const PIString s_L = PIStringAscii("$L");
|
||||
|
||||
bool mlc = false, cc = false;
|
||||
int mls = 0, ole = -1, /*ccs = 0,*/ end = 0;
|
||||
char c = 0, pc = 0;
|
||||
PIString pfc, line, ccmn, tmp;
|
||||
PIMap<PIString, PIString> cchars;
|
||||
|
||||
|
||||
/// Remove comments, join multiline '*' and replace '*' to $n (cchars)
|
||||
fc.replaceAll("\r\n", '\n');
|
||||
fc.replaceAll('\r', '\n');
|
||||
@@ -247,57 +359,76 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
if (i > 0) pc = c;
|
||||
c = fc[i].toAscii();
|
||||
if (c == '"' && !mlc && pc != '\'') {
|
||||
if (i > 0) if (fc[i - 1] == '\\') continue;
|
||||
if (i > 0)
|
||||
if (fc[i - 1] == '\\') continue;
|
||||
cc = !cc;
|
||||
continue;
|
||||
}
|
||||
if (i > 0)
|
||||
if (c == '\\' && fc[i - 1].toAscii() != '\\') {
|
||||
fc.cutMid(i, 2);
|
||||
--i;
|
||||
fc.cutMid(i, 1);
|
||||
fc.replace(i, 1, s_L);
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (cc) continue;
|
||||
if (fc.mid(i, 2) == "/*") {mlc = true; mls = i; ++i; continue;}
|
||||
if (fc.mid(i, 2) == "*/" && mlc) {mlc = false; fc.cutMid(mls, i - mls + 2); i = mls - 1; continue;}
|
||||
if (fc.mid(i, 2) == "//" && !mlc) {ole = fc.find('\n', i); fc.cutMid(i, ole < 0 ? -1 : ole - i); --i; continue;}
|
||||
if (fc.mid(i, 2) == "/*") {
|
||||
mlc = true;
|
||||
mls = i;
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (fc.mid(i, 2) == "*/" && mlc) {
|
||||
mlc = false;
|
||||
fc.cutMid(mls, i - mls + 2);
|
||||
i = mls - 1;
|
||||
continue;
|
||||
}
|
||||
if (fc.mid(i, 2) == "//" && !mlc) {
|
||||
ole = fc.find('\n', i);
|
||||
fc.cutMid(i, ole < 0 ? -1 : ole - i);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
pfc = procMacros(fc);
|
||||
|
||||
pfc.removeAll(s_L);
|
||||
|
||||
if (main) return true;
|
||||
|
||||
bool replaced = true;
|
||||
|
||||
bool replaced = true;
|
||||
int replaced_cnt = 0;
|
||||
while (replaced) {
|
||||
//piCout << "MACRO iter" << replaced_cnt;
|
||||
// piCout << "MACRO iter" << replaced_cnt;
|
||||
if (replaced_cnt >= macros_iter) {
|
||||
piCout << "Error: recursive macros detected!";
|
||||
break;//return false;
|
||||
break; // return false;
|
||||
}
|
||||
replaced_cnt++;
|
||||
replaced = false;
|
||||
piForeachC (Define & d, defines) {
|
||||
for (const auto & d: defines) {
|
||||
int ind(-1);
|
||||
while ((ind = pfc.find(d.first, ind + 1)) >= 0) {
|
||||
PIChar pc, nc;
|
||||
if (ind > 0) pc = pfc[ind - 1];
|
||||
if (ind + d.first.size_s() < pfc.size_s()) nc = pfc.mid(ind + d.first.size_s(),1)[0];
|
||||
if (ind + d.first.size_s() < pfc.size_s()) nc = pfc.mid(ind + d.first.size_s(), 1)[0];
|
||||
if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue;
|
||||
pfc.replace(ind, d.first.size_s(), d.second);
|
||||
ind -= d.first.size_s() - d.second.size_s();
|
||||
replaced = true;
|
||||
}
|
||||
}
|
||||
piForeachC (Macro & m, macros) {
|
||||
for (const auto & m: macros) {
|
||||
int ind(-1);
|
||||
while ((ind = pfc.find(m.name, ind + 1)) >= 0) {
|
||||
PIChar pc, nc;
|
||||
if (ind > 0) pc = pfc[ind - 1];
|
||||
if (ind + m.name.size_s() < pfc.size_s()) nc = pfc.mid(ind + m.name.size_s(),1)[0];
|
||||
if (ind + m.name.size_s() < pfc.size_s()) nc = pfc.mid(ind + m.name.size_s(), 1)[0];
|
||||
if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue;
|
||||
PIString ret, range; bool ok(false);
|
||||
PIString ret, range;
|
||||
bool ok(false);
|
||||
range = pfc.mid(ind + m.name.size_s()).takeRange('(', ')');
|
||||
ret = m.expand(range, &ok);
|
||||
ret = m.expand(range, &ok);
|
||||
if (!ok) return false;
|
||||
int rlen = pfc.find(range, ind + m.name.size_s()) + range.size_s() + 1 - ind;
|
||||
pfc.replace(ind, rlen, ret);
|
||||
@@ -308,9 +439,10 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
}
|
||||
|
||||
replaceMeta(pfc);
|
||||
|
||||
//piCout << PICoutManipulators::NewLine << "file" << cur_file << pfc;
|
||||
int pl = -1;
|
||||
|
||||
// piCout << PICoutManipulators::NewLine << "file" << cur_file << pfc;
|
||||
int pl = -1;
|
||||
cur_def_vis = Global;
|
||||
while (!pfc.isEmpty()) {
|
||||
pfc.trim();
|
||||
int nl = pfc.size_s();
|
||||
@@ -321,6 +453,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
PIString prev_namespace = cur_namespace, ccmn;
|
||||
cur_namespace += pfc.takeCWord() + s_ns;
|
||||
ccmn = pfc.takeRange('{', '}');
|
||||
// piCout << "namespace" << cur_namespace;
|
||||
parseClass(0, ccmn, true);
|
||||
cur_namespace = prev_namespace;
|
||||
continue;
|
||||
@@ -330,14 +463,25 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
pfc.takeRange('<', '>');
|
||||
bool def = !isDeclaration(pfc, 0, &end);
|
||||
pfc.cutLeft(end);
|
||||
if (def) pfc.takeRange('{', '}');
|
||||
else pfc.takeSymbol();
|
||||
if (def)
|
||||
pfc.takeRange('{', '}');
|
||||
else
|
||||
pfc.takeSymbol();
|
||||
continue;
|
||||
}
|
||||
if (pfc.left(5) == s_class || pfc.left(6) == s_struct || pfc.left(5) == s_union) {
|
||||
int dind = pfc.find('{', 0), find = pfc.find(';', 0);
|
||||
if (dind < 0 && find < 0) {pfc.cutLeft(6); continue;}
|
||||
if (dind < 0 || find < dind) {pfc.cutLeft(6); continue;}
|
||||
// piCout << pfc.left(6) << dind << find;
|
||||
if (dind < 0 && find < 0) {
|
||||
pfc.cutLeft(6);
|
||||
continue;
|
||||
}
|
||||
if (dind < 0 || find < dind) {
|
||||
// piCout << "skip FC" << (find + 1) << pfc.left(find + 1);
|
||||
pfc.cutLeft(find + 1);
|
||||
// pfc.cutLeft(6);
|
||||
continue;
|
||||
}
|
||||
ccmn = pfc.left(dind) + s_bo + pfc.mid(dind).takeRange('{', '}') + s_bc;
|
||||
pfc.remove(0, ccmn.size());
|
||||
parseClass(0, ccmn, false);
|
||||
@@ -348,6 +492,13 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
tmp = pfc.takeCWord();
|
||||
pfc.trim();
|
||||
MetaMap meta = maybeMeta(pfc);
|
||||
if (tmp == s_class || tmp == s_struct) {
|
||||
tmp = pfc.takeCWord();
|
||||
pfc.trim();
|
||||
MetaMap smeta = maybeMeta(pfc);
|
||||
meta << smeta;
|
||||
}
|
||||
// piCout << "pfc E" << cur_namespace << "," << tmp;
|
||||
parseEnum(0, cur_namespace + tmp, pfc.takeRange('{', '}'), meta);
|
||||
pfc.takeSymbol();
|
||||
continue;
|
||||
@@ -355,8 +506,10 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
if (pfc.left(7) == s_typedef) {
|
||||
pfc.cutLeft(7);
|
||||
typedefs << parseTypedef(pfc.takeLeft(pfc.find(';')));
|
||||
if (typedefs.back().first.isEmpty()) typedefs.pop_back();
|
||||
else root_.typedefs << typedefs.back();
|
||||
if (typedefs.back().first.isEmpty())
|
||||
typedefs.pop_back();
|
||||
else
|
||||
root_.typedefs << typedefs.back();
|
||||
pfc.takeSymbol();
|
||||
continue;
|
||||
}
|
||||
@@ -374,7 +527,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
}
|
||||
parseMember(&root_, str);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -383,43 +536,49 @@ PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc)
|
||||
static const PIString s_ss = PIStringAscii(" ");
|
||||
static const PIString s_M = PIStringAscii("$M");
|
||||
static const PIString s_class = PIStringAscii("class");
|
||||
PIString cd = fc.trimmed().removeAll('\n').replaceAll('\t', ' ').replaceAll(s_ss, ' '), pn;
|
||||
PIString cd = fc.trimmed().removeAll('\n').replaceAll('\t', ' ').replaceAll(s_ss, ' '), pn;
|
||||
MetaMap meta;
|
||||
int ind = cd.find(s_M);
|
||||
if (ind >= 0) {
|
||||
meta = tmp_meta.value(cd.takeMid(ind, 5));
|
||||
cd.replaceAll(s_ss, ' ');
|
||||
}
|
||||
//piCout << "found class <****\n" << cd << "\n****>";
|
||||
// piCout << "found class <****\n" << cd << "\n****>";
|
||||
ind = cd.find(':');
|
||||
PIVector<Entity * > parents;
|
||||
PIVector<Entity *> parents;
|
||||
if (ind > 0) {
|
||||
PIStringList pl = cd.takeMid(ind + 1).trim().split(',');
|
||||
cd.cutRight(1);
|
||||
Entity * pe = 0;
|
||||
piForeachC (PIString & p, pl) {
|
||||
if (p.contains(' ')) pn = p.mid(p.find(' ') + 1);
|
||||
else pn = p;
|
||||
for (const auto & p: pl) {
|
||||
if (p.contains(' '))
|
||||
pn = p.mid(p.find(' ') + 1);
|
||||
else
|
||||
pn = p;
|
||||
pe = findEntityByName(pn);
|
||||
if (pe == 0) ;//{piCout << "Error: can`t find" << pn;}
|
||||
else parents << pe;
|
||||
if (pe == 0)
|
||||
; //{piCout << "Error: can`t find" << pn;}
|
||||
else
|
||||
parents << pe;
|
||||
}
|
||||
}
|
||||
PIString typename_ = cd.left(6).trim();
|
||||
bool is_class = typename_ == s_class;
|
||||
cur_def_vis = (is_class ? Private : Public);
|
||||
PIString cn = cd.mid(6).trim();
|
||||
bool has_name = !cn.isEmpty();
|
||||
bool is_class = typename_ == s_class;
|
||||
Visibility vis = cur_def_vis;
|
||||
cur_def_vis = (is_class ? Private : Public);
|
||||
PIString cn = cd.mid(6).trim();
|
||||
bool has_name = !cn.isEmpty();
|
||||
if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>';
|
||||
//piCout << "found " << typename_ << cn;
|
||||
if (cn.isEmpty()) return 0;
|
||||
Entity * e = new Entity();
|
||||
e->meta = meta;
|
||||
e->name = cur_namespace + cn;
|
||||
e->type = typename_;
|
||||
e->has_name = has_name;
|
||||
e->parents = parents;
|
||||
e->file = cur_file;
|
||||
// piCout << "found " << typename_ << cn;
|
||||
if (cn.isEmpty()) return nullptr;
|
||||
Entity * e = new Entity();
|
||||
e->meta = meta;
|
||||
e->name = cur_namespace + cn;
|
||||
e->type = typename_;
|
||||
e->has_name = has_name;
|
||||
e->parents = parents;
|
||||
e->visibility = vis;
|
||||
e->file = cur_file;
|
||||
entities << e;
|
||||
return e;
|
||||
}
|
||||
@@ -438,37 +597,44 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
|
||||
static const PIString s_typedef = PIStringAscii("typedef");
|
||||
static const PIString s_namespace = PIStringAscii("namespace");
|
||||
static const PIString s_template = PIStringAscii("template");
|
||||
Visibility prev_vis = cur_def_vis;
|
||||
Visibility prev_vis = cur_def_vis;
|
||||
int dind = fc.find('{'), find = fc.find(';'), end = 0;
|
||||
if (dind < 0 && find < 0) return;
|
||||
if (dind < 0 || find < dind) {
|
||||
fc.left(find);
|
||||
return;
|
||||
}
|
||||
//piCout << "parse class <****\n" << fc << "\n****>";
|
||||
// piCout << "parse class <****\n" << fc << "\n****>";
|
||||
Entity * ce = parent;
|
||||
if (!is_namespace) {
|
||||
ce = parseClassDeclaration(fc.takeLeft(dind));
|
||||
fc.trim().cutLeft(1).cutRight(1).trim();
|
||||
}
|
||||
//piCout << "found class <****\n" << fc << "\n****>";
|
||||
///if (!ce) return PIString();
|
||||
// piCout << "found class <****\n" << fc << "\n****>";
|
||||
if (ce) {
|
||||
if (parent) parent->children << ce;
|
||||
ce->parent_scope = parent;
|
||||
}
|
||||
int ps = -1;
|
||||
bool def = false;
|
||||
int ps = -1;
|
||||
bool def = false;
|
||||
PIString prev_namespace = cur_namespace, stmp;
|
||||
if (ce) cur_namespace += ce->name + s_ns;
|
||||
//piCout << "parse class" << ce->name << "namespace" << cur_namespace;
|
||||
//piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
|
||||
if (ce) cur_namespace = ce->name + s_ns;
|
||||
// piCout << "parse class" << (ce ? ce->name : "NULL") << "namespace" << cur_namespace;
|
||||
// piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
|
||||
while (!fc.isEmpty()) {
|
||||
PIString cw = fc.takeCWord(), tmp;
|
||||
//piCout << "\ntaked word" << cw;
|
||||
if (cw == s_public ) {cur_def_vis = Public; fc.cutLeft(1); continue;}
|
||||
if (cw == s_protected) {cur_def_vis = Protected; fc.cutLeft(1); continue;}
|
||||
if (cw == s_private ) {cur_def_vis = Private; fc.cutLeft(1); continue;}
|
||||
// piCout << "\ntaked word" << cw;
|
||||
if (cw == s_public) {
|
||||
cur_def_vis = Public;
|
||||
fc.cutLeft(1);
|
||||
continue;
|
||||
}
|
||||
if (cw == s_protected) {
|
||||
cur_def_vis = Protected;
|
||||
fc.cutLeft(1);
|
||||
continue;
|
||||
}
|
||||
if (cw == s_private) {
|
||||
cur_def_vis = Private;
|
||||
fc.cutLeft(1);
|
||||
continue;
|
||||
}
|
||||
if (cw == s_namespace) {
|
||||
PIString prev_namespace = cur_namespace, ccmn;
|
||||
cur_namespace += fc.takeCWord() + s_ns;
|
||||
@@ -478,15 +644,16 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
|
||||
continue;
|
||||
}
|
||||
if (cw == s_class || cw == s_struct || cw == s_union) {
|
||||
// piCout << cw << isDeclaration(fc, 0, &end);
|
||||
if (isDeclaration(fc, 0, &end)) {
|
||||
fc.cutLeft(end);
|
||||
fc.takeSymbol();
|
||||
continue;
|
||||
}
|
||||
tmp = fc.takeLeft(fc.find('{'));
|
||||
tmp = fc.takeLeft(fc.find('{'));
|
||||
stmp = fc.takeRange('{', '}');
|
||||
fc.takeSymbol();
|
||||
stmp = cw + ' ' + tmp + '{' + stmp + '}';
|
||||
stmp = cw + ' ' + tmp + '{' + stmp + '}';
|
||||
parseClass(ce, stmp, false);
|
||||
continue;
|
||||
}
|
||||
@@ -494,18 +661,27 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
|
||||
tmp = fc.takeCWord();
|
||||
fc.trim();
|
||||
MetaMap meta = maybeMeta(fc);
|
||||
if (tmp == s_class || tmp == s_struct) {
|
||||
tmp = fc.takeCWord();
|
||||
fc.trim();
|
||||
MetaMap smeta = maybeMeta(fc);
|
||||
meta << smeta;
|
||||
}
|
||||
// piCout << "pc E" << cur_namespace << "," << tmp;
|
||||
parseEnum(ce, cur_namespace + tmp, fc.takeRange('{', '}'), meta);
|
||||
fc.takeSymbol();
|
||||
continue;
|
||||
}
|
||||
if (cw == s_friend) {fc.cutLeft(fc.find(';') + 1); continue;}
|
||||
if (cw == s_friend) {
|
||||
fc.cutLeft(fc.find(';') + 1);
|
||||
continue;
|
||||
}
|
||||
if (cw == s_typedef) {
|
||||
if (ce) {
|
||||
ce->typedefs << parseTypedef(fc.takeLeft(fc.find(';')));
|
||||
typedefs << ce->typedefs.back();
|
||||
typedefs.back().first.insert(0, cur_namespace);
|
||||
if (ce->typedefs.back().first.isEmpty())
|
||||
ce->typedefs.pop_back();
|
||||
if (ce->typedefs.back().first.isEmpty()) ce->typedefs.pop_back();
|
||||
}
|
||||
fc.takeSymbol();
|
||||
continue;
|
||||
@@ -514,20 +690,25 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
|
||||
fc.takeRange('<', '>');
|
||||
def = !isDeclaration(fc, 0, &end);
|
||||
fc.cutLeft(end);
|
||||
if (def) fc.takeRange('{', '}');
|
||||
else fc.takeSymbol();
|
||||
if (def)
|
||||
fc.takeRange('{', '}');
|
||||
else
|
||||
fc.takeSymbol();
|
||||
continue;
|
||||
}
|
||||
def = !isDeclaration(fc, 0, &end);
|
||||
tmp = (cw + fc.takeLeft(end)).trim();
|
||||
if (!tmp.isEmpty() && ce)
|
||||
parseMember(ce, tmp);
|
||||
if (def) fc.takeRange('{', '}');
|
||||
else fc.takeSymbol();
|
||||
if (ps == fc.size_s()) {fc.cutLeft(1);}
|
||||
if (!tmp.isEmpty() && ce) parseMember(ce, tmp);
|
||||
if (def)
|
||||
fc.takeRange('{', '}');
|
||||
else
|
||||
fc.takeSymbol();
|
||||
if (ps == fc.size_s()) {
|
||||
fc.cutLeft(1);
|
||||
}
|
||||
ps = fc.size_s();
|
||||
}
|
||||
cur_def_vis = prev_vis;
|
||||
cur_def_vis = prev_vis;
|
||||
cur_namespace = prev_namespace;
|
||||
}
|
||||
|
||||
@@ -536,7 +717,7 @@ PICodeParser::MetaMap PICodeParser::parseMeta(PIString & fc) {
|
||||
PICodeParser::MetaMap ret;
|
||||
if (fc.isEmpty()) return ret;
|
||||
PIStringList ml = fc.split(',');
|
||||
piForeachC (PIString & m, ml) {
|
||||
for (const auto & m: ml) {
|
||||
int i = m.find('=');
|
||||
if (i < 0) {
|
||||
ret[m.trimmed()] = PIString();
|
||||
@@ -547,55 +728,61 @@ PICodeParser::MetaMap PICodeParser::parseMeta(PIString & fc) {
|
||||
ret[m.left(i).trim()] = mv;
|
||||
}
|
||||
}
|
||||
//piCout << ms << ret;
|
||||
// piCout << ms << ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::parseEnum(Entity * parent, const PIString & name, PIString fc, const MetaMap & meta) {
|
||||
static const PIString s_ss = PIStringAscii(" ");
|
||||
static const PIString s_M = PIStringAscii("$M");
|
||||
//piCout << PIStringAscii("enum") << name << fc;
|
||||
static const PIString s_M = PIStringAscii("$M");
|
||||
// piCout << PIStringAscii("enum") << name << fc;
|
||||
Enum e(name);
|
||||
e.meta = meta;
|
||||
PIStringList vl(fc.split(','));
|
||||
PIString vn;
|
||||
int cv = -1, ind = 0;
|
||||
piForeach (PIString & v, vl) {
|
||||
for (auto & v: vl) {
|
||||
MetaMap meta;
|
||||
int mi = v.find(s_M);
|
||||
if (mi >= 0) {
|
||||
meta = tmp_meta.value(v.takeMid(mi, 5));
|
||||
v.replaceAll(s_ss, ' ');
|
||||
}
|
||||
vn = v; ind = v.find('=');
|
||||
if (ind > 0) {cv = v.right(v.size_s() - ind - 1).toInt(); vn = v.left(ind);}
|
||||
vn = v;
|
||||
ind = v.find('=');
|
||||
if (ind > 0) {
|
||||
cv = v.right(v.size_s() - ind - 1).toInt();
|
||||
vn = v.left(ind);
|
||||
}
|
||||
if (ind < 0) ++cv;
|
||||
e.members << EnumeratorInfo(vn.trim(), cv, meta);
|
||||
}
|
||||
if (!e.members.isEmpty())
|
||||
if (e.members.back().name.isEmpty())
|
||||
e.members.pop_back();
|
||||
if (e.members.back().name.isEmpty()) e.members.pop_back();
|
||||
enums << e;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PICodeParser::Typedef PICodeParser::parseTypedef(PIString fc) {
|
||||
//piCout << "parse typedef" << fc;
|
||||
// piCout << "parse typedef" << fc;
|
||||
Typedef td;
|
||||
fc.replaceAll('\t', ' ');
|
||||
|
||||
|
||||
if (fc.contains('(')) {
|
||||
int start = fc.find('('), end = fc.find(')');
|
||||
td.first = fc.takeMid(start + 1, end - start - 1).trim();
|
||||
if (td.first.left(1) == PIChar('*')) {td.first.cutLeft(1).trim(); fc.insert(start + 1, '*');}
|
||||
if (td.first.left(1) == PIChar('*')) {
|
||||
td.first.cutLeft(1).trim();
|
||||
fc.insert(start + 1, '*');
|
||||
}
|
||||
td.second = fc.trim();
|
||||
} else {
|
||||
td.first = fc.takeMid(fc.findLast(' ')).trim();
|
||||
td.first = fc.takeMid(fc.findLast(' ')).trim();
|
||||
td.second = fc.trim();
|
||||
}
|
||||
//piCout << "found typedef" << td;
|
||||
// piCout << "found typedef" << td;
|
||||
return td;
|
||||
}
|
||||
|
||||
@@ -631,22 +818,26 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
|
||||
if (fc.trim().isEmpty()) return true;
|
||||
if (fc.find(s_operator) >= 0) return true;
|
||||
tmp_temp.clear();
|
||||
//piCout << "parse member" << fc;
|
||||
// piCout << "parse member" << fc;
|
||||
int ts = fc.find('<'), te = 0;
|
||||
PIString ctemp, crepl;
|
||||
while (ts >= 0) {
|
||||
ctemp = fc.mid(ts).takeRange('<', '>');
|
||||
if (ctemp.isEmpty()) {te = ts + 1; ts = fc.find('<', te); continue;}
|
||||
if (ctemp.isEmpty()) {
|
||||
te = ts + 1;
|
||||
ts = fc.find('<', te);
|
||||
continue;
|
||||
}
|
||||
crepl = s_T + PIString::fromNumber(tmp_temp.size_s()).expandLeftTo(3, '0');
|
||||
fc.replace(ts, ctemp.size_s() + 2, crepl);
|
||||
tmp_temp[crepl] = '<' + ctemp + '>';
|
||||
ts = fc.find('<', te);
|
||||
ts = fc.find('<', te);
|
||||
}
|
||||
fc.replaceAll('\n', ' ').replaceAll('\t', ' ').replaceAll(s_ss, ' ').replaceAll(s_cs, ',').replaceAll(s_sb, '(').replaceAll(s_sM, s_M);
|
||||
//piCout << "parse member" << fc;
|
||||
// piCout << "parse member" << fc;
|
||||
PIStringList tl, al;
|
||||
Member me;
|
||||
//piCout << fc;
|
||||
// piCout << fc;
|
||||
if (fc.contains('(')) {
|
||||
MetaMap meta;
|
||||
int ind = fc.find(s_M);
|
||||
@@ -656,16 +847,16 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
|
||||
}
|
||||
fc.cutRight(fc.size_s() - fc.findLast(')') - 1);
|
||||
te = fc.find('(');
|
||||
//piCout << fc;
|
||||
// piCout << fc;
|
||||
for (ts = te - 1; ts >= 0; --ts)
|
||||
if (!_isCChar(fc[ts]) && !(fc[ts].isDigit())) break;
|
||||
//piCout << "takeMid" << ts + 1 << te - ts - 1;
|
||||
// piCout << "takeMid" << ts + 1 << te - ts - 1;
|
||||
me.meta = meta;
|
||||
me.name = fc.takeMid(ts + 1, te - ts - 1);
|
||||
if (me.name == parent->name) return true;
|
||||
me.arguments_full = fc.takeMid(ts + 2).cutRight(1).split(',');
|
||||
me.type = fc.cutRight(1).trim();
|
||||
me.visibility = cur_def_vis;
|
||||
me.type = fc.cutRight(1).trim();
|
||||
me.visibility = cur_def_vis;
|
||||
if (me.type.find(s_inline_s) >= 0) {
|
||||
me.attributes |= Inline;
|
||||
me.type.removeAll(s_inline_s);
|
||||
@@ -680,20 +871,18 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
|
||||
}
|
||||
normalizeEntityNamespace(me.type);
|
||||
int i = 0;
|
||||
//piCout << me.arguments_full;
|
||||
piForeach (PIString & a, me.arguments_full)
|
||||
if ((i = a.find('=')) > 0)
|
||||
a.cutRight(a.size_s() - i).trim();
|
||||
// piCout << me.arguments_full;
|
||||
for (auto & a: me.arguments_full)
|
||||
if ((i = a.find('=')) > 0) a.cutRight(a.size_s() - i).trim();
|
||||
for (int j = 0; j < me.arguments_full.size_s(); ++j)
|
||||
if (me.arguments_full[j] == s_void) {
|
||||
me.arguments_full.remove(j);
|
||||
--j;
|
||||
}
|
||||
me.arguments_type = me.arguments_full;
|
||||
piForeach (PIString & a, me.arguments_type) {
|
||||
for (auto & a: me.arguments_type) {
|
||||
crepl.clear();
|
||||
if (a.contains('['))
|
||||
crepl = a.takeMid(a.find('['), a.findLast(']') - a.find('[') + 1);
|
||||
if (a.contains('[')) crepl = a.takeMid(a.find('['), a.findLast(']') - a.find('[') + 1);
|
||||
for (ts = a.size_s() - 1; ts >= 0; --ts)
|
||||
if (!_isCChar(a[ts]) && !(a[ts].isDigit())) break;
|
||||
a.cutRight(a.size_s() - ts - 1);
|
||||
@@ -702,31 +891,34 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
|
||||
a.trim();
|
||||
}
|
||||
restoreTmpTemp(&me);
|
||||
//piCout << "func" << me.type << me.name << me.arguments_full << me.arguments_type;
|
||||
// piCout << "func" << me.type << me.name << me.arguments_full << me.arguments_type;
|
||||
parent->functions << me;
|
||||
} else {
|
||||
if (fc.endsWith(';')) fc.cutRight(1);
|
||||
//piCout << "member" << fc;
|
||||
// piCout << "member" << fc;
|
||||
if (fc.startsWith(s_using) || !(fc.contains(' ') || fc.contains('\t') || fc.contains('\n'))) return true;
|
||||
int bits = extractMemberBits(fc);
|
||||
tl = fc.split(',');
|
||||
//piCout << "member" << fc << tl;
|
||||
//piCout << "member after eb" << fc << ", bits =" << bits;
|
||||
tl = fc.split(',');
|
||||
// piCout << "member" << fc << tl;
|
||||
// piCout << "member after eb" << fc << ", bits =" << bits;
|
||||
if (tl.isEmpty()) return true;
|
||||
piForeach (PIString & v, tl)
|
||||
for (auto & v: tl)
|
||||
removeAssignment(v);
|
||||
bool vn = true;
|
||||
ctemp = tl.front().trim();
|
||||
ctemp = tl.front().trim();
|
||||
PIString meta_t;
|
||||
if (ctemp.contains(s_M)) {
|
||||
meta_t = ctemp.takeMid(ctemp.find(s_M), 5);
|
||||
ctemp.trim();
|
||||
}
|
||||
for (ts = ctemp.size_s() - 1; ts > 0; --ts) {
|
||||
if (vn) {if (!_isCChar(ctemp[ts]) && !ctemp[ts].isDigit() && ctemp[ts] != '[' && ctemp[ts] != ']') vn = false;}
|
||||
else {if (_isCChar(ctemp[ts]) || ctemp[ts].isDigit()) break;}
|
||||
if (vn) {
|
||||
if (!_isCChar(ctemp[ts]) && !ctemp[ts].isDigit() && ctemp[ts] != '[' && ctemp[ts] != ']') vn = false;
|
||||
} else {
|
||||
if (_isCChar(ctemp[ts]) || ctemp[ts].isDigit()) break;
|
||||
}
|
||||
}
|
||||
me.type = ctemp.takeLeft(ts + 1);
|
||||
me.type = ctemp.takeLeft(ts + 1);
|
||||
me.visibility = cur_def_vis;
|
||||
ctemp += meta_t;
|
||||
restoreTmpTemp(&me);
|
||||
@@ -754,21 +946,21 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
|
||||
type.trim();
|
||||
normalizeEntityNamespace(type);
|
||||
tl[0] = ctemp.trim();
|
||||
//piCout << "vars" << tl;
|
||||
piForeachC (PIString & v, tl) {
|
||||
// piCout << "vars" << tl;
|
||||
for (const auto & v: tl) {
|
||||
crepl.clear();
|
||||
|
||||
me.name = v.trimmed();
|
||||
me.type = type;
|
||||
restoreTmpMeta(&me);
|
||||
if (me.name.isEmpty()) continue;
|
||||
if (me.name.contains('['))
|
||||
crepl = me.name.takeMid(me.name.find('['), me.name.findLast(']') - me.name.find('[') + 1);
|
||||
if (me.name.contains('[')) crepl = me.name.takeMid(me.name.find('['), me.name.findLast(']') - me.name.find('[') + 1);
|
||||
while (!me.name.isEmpty()) {
|
||||
if (me.name.front() == PIChar('*') || me.name.front() == PIChar('&')) {
|
||||
me.type += me.name.takeLeft(1);
|
||||
me.name.trim();
|
||||
} else break;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
me.is_type_ptr = (me.type.right(1) == PIChar(']') || me.type.right(1) == PIChar('*'));
|
||||
me.type += crepl;
|
||||
@@ -778,12 +970,12 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
|
||||
if (cdim.isEmpty()) break;
|
||||
me.dims << cdim;
|
||||
}
|
||||
//PICout(PICoutManipulators::AddAll) << "var" << me.type << me.name << me.bits;
|
||||
//piCout << "var" << v << me.type << me.name << me.bits;
|
||||
// PICout(PICoutManipulators::AddAll) << "var" << me.type << me.name << me.bits;
|
||||
// piCout << "var" << v << me.type << me.name << me.bits;
|
||||
parent->members << me;
|
||||
}
|
||||
}
|
||||
//piCout << "parse member" << fc;
|
||||
// piCout << "parse member" << fc;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -815,13 +1007,25 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
|
||||
break;
|
||||
}
|
||||
n.push_front(' ');
|
||||
if (n.find(s_s_const_s) >= 0) {n.replaceAll(s_s_const_s, ""); pref += s_const_s;}
|
||||
if (n.find(s_s_static_s) >= 0) {n.replaceAll(s_s_static_s, ""); pref += s_static_s;}
|
||||
if (n.find(s_s_mutable_s) >= 0) {n.replaceAll(s_s_mutable_s, ""); pref += s_mutable_s;}
|
||||
if (n.find(s_s_volatile_s) >= 0) {n.replaceAll(s_s_volatile_s, ""); pref += s_volatile_s;}
|
||||
if (n.find(s_s_const_s) >= 0) {
|
||||
n.replaceAll(s_s_const_s, "");
|
||||
pref += s_const_s;
|
||||
}
|
||||
if (n.find(s_s_static_s) >= 0) {
|
||||
n.replaceAll(s_s_static_s, "");
|
||||
pref += s_static_s;
|
||||
}
|
||||
if (n.find(s_s_mutable_s) >= 0) {
|
||||
n.replaceAll(s_s_mutable_s, "");
|
||||
pref += s_mutable_s;
|
||||
}
|
||||
if (n.find(s_s_volatile_s) >= 0) {
|
||||
n.replaceAll(s_s_volatile_s, "");
|
||||
pref += s_volatile_s;
|
||||
}
|
||||
n.trim();
|
||||
int f = 0;
|
||||
piForeachC (Entity * e, entities) {
|
||||
for (const auto * e: entities) {
|
||||
if (e->name == n) {
|
||||
n = (pref + n + suff).trim();
|
||||
return;
|
||||
@@ -833,20 +1037,20 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
piForeachC (Enum & e, enums) {
|
||||
for (const auto & e: enums) {
|
||||
if ((f = e.name.find(n)) >= 0)
|
||||
if (e.name.at(f - 1) == PIChar(':'))
|
||||
if (e.name.find(cur_namespace) >= 0) {
|
||||
//piCout << "change" << n << "to" << e.name + suff;
|
||||
// piCout << "change" << n << "to" << e.name + suff;
|
||||
n = pref + e.name + suff;
|
||||
return;
|
||||
}
|
||||
}
|
||||
piForeachC (Typedef & e, typedefs) {
|
||||
for (const auto & e: typedefs) {
|
||||
if ((f = e.first.find(n)) >= 0)
|
||||
if (e.first.at(f - 1) == PIChar(':'))
|
||||
if (e.first.find(cur_namespace) >= 0) {
|
||||
//piCout << "change" << n << "to" << e.name + suff;
|
||||
// piCout << "change" << n << "to" << e.name + suff;
|
||||
n = pref + e.first + suff;
|
||||
return;
|
||||
}
|
||||
@@ -857,12 +1061,12 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
|
||||
|
||||
void PICodeParser::restoreTmpTemp(Member * e) {
|
||||
static const PIString s_T = PIStringAscii("$T");
|
||||
int i = 0;
|
||||
piForeach (PIString & a, e->arguments_full) {
|
||||
int i = 0;
|
||||
for (auto & a: e->arguments_full) {
|
||||
while ((i = a.find(s_T)) >= 0)
|
||||
a.replace(i, 5, tmp_temp[a.mid(i, 5)]);
|
||||
}
|
||||
piForeach (PIString & a, e->arguments_type) {
|
||||
for (auto & a: e->arguments_type) {
|
||||
while ((i = a.find(s_T)) >= 0)
|
||||
a.replace(i, 5, tmp_temp[a.mid(i, 5)]);
|
||||
}
|
||||
@@ -873,7 +1077,7 @@ void PICodeParser::restoreTmpTemp(Member * e) {
|
||||
|
||||
void PICodeParser::restoreTmpMeta(PICodeParser::Member * e) {
|
||||
static const PIString s_M = PIStringAscii("$M");
|
||||
int i = e->name.find(s_M);
|
||||
int i = e->name.find(s_M);
|
||||
if (i < 0) return;
|
||||
e->meta = tmp_meta[e->name.takeMid(i, 5)];
|
||||
}
|
||||
@@ -895,7 +1099,7 @@ bool PICodeParser::macroCondition(const PIString & mif, PIString mifcond) {
|
||||
static const PIString s_ifndef = PIStringAscii("ifndef");
|
||||
static const PIString s_if = PIStringAscii("if");
|
||||
static const PIString s_elif = PIStringAscii("elif");
|
||||
//piCout << "macroCondition" << mif << mifcond;
|
||||
// piCout << "macroCondition" << mif << mifcond;
|
||||
if (mif == s_ifdef) return isDefineExists(mifcond);
|
||||
if (mif == s_ifndef) return !isDefineExists(mifcond);
|
||||
if (mif == s_if || mif == s_elif) {
|
||||
@@ -914,52 +1118,65 @@ double PICodeParser::procMacrosCond(PIString fc) {
|
||||
char cc, nc;
|
||||
PIString ce;
|
||||
fc.removeAll(s_defined);
|
||||
//piCout << "procMacrosCond" << fc;
|
||||
// piCout << "procMacrosCond" << fc;
|
||||
while (!fc.isEmpty()) {
|
||||
cc = fc[0].toAscii();
|
||||
nc = (fc.size() > 1 ? fc[1].toAscii() : 0);
|
||||
if (cc == '!') {neg = true; fc.pop_front(); continue;}
|
||||
if (cc == '(') {br = true; brv = procMacrosCond(fc.takeRange('(', ')'));}
|
||||
if (cc == '&' && nc == '&') {fc.remove(0, 2); oper = 1; continue;}
|
||||
if (cc == '|' && nc == '|') {fc.remove(0, 2); oper = 2; continue;}
|
||||
if (cc == '!') {
|
||||
neg = true;
|
||||
fc.pop_front();
|
||||
continue;
|
||||
}
|
||||
if (cc == '(') {
|
||||
br = true;
|
||||
brv = procMacrosCond(fc.takeRange('(', ')'));
|
||||
}
|
||||
if (cc == '&' && nc == '&') {
|
||||
fc.remove(0, 2);
|
||||
oper = 1;
|
||||
continue;
|
||||
}
|
||||
if (cc == '|' && nc == '|') {
|
||||
fc.remove(0, 2);
|
||||
oper = 2;
|
||||
continue;
|
||||
}
|
||||
if (!br) {
|
||||
ce = fc.takeCWord();
|
||||
if (ce.isEmpty()) ce = fc.takeNumber();
|
||||
}
|
||||
if (first) {
|
||||
first = false;
|
||||
ret = br ? brv : defineValue(ce);
|
||||
ret = br ? brv : defineValue(ce);
|
||||
if (neg) ret = -ret;
|
||||
} else {
|
||||
//piCout << "oper" << oper << "with" << ce;
|
||||
// piCout << "oper" << oper << "with" << ce;
|
||||
if (!br) brv = defineValue(ce);
|
||||
switch (oper) {
|
||||
case 1: ret = ret && (neg ? -brv : brv); break;
|
||||
case 2: ret = ret || (neg ? -brv : brv); break;
|
||||
case 1: ret = ret && (neg ? -brv : brv); break;
|
||||
case 2: ret = ret || (neg ? -brv : brv); break;
|
||||
}
|
||||
}
|
||||
if (ps == fc.size_s()) fc.cutLeft(1);
|
||||
ps = fc.size_s();
|
||||
br = neg = false;
|
||||
}
|
||||
//piCout << "return" << ret;
|
||||
// piCout << "return" << ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::isDefineExists(const PIString & dn) {
|
||||
piForeachC (Define & d, defines) {
|
||||
if (d.first == dn)
|
||||
return true;
|
||||
for (const auto & d: defines) {
|
||||
if (d.first == dn) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
double PICodeParser::defineValue(const PIString & dn) {
|
||||
piForeachC (Define & d, defines) {
|
||||
if (d.first == dn)
|
||||
return d.second.isEmpty() ? 1. : d.second.toDouble();
|
||||
for (const auto & d: defines) {
|
||||
if (d.first == dn) return d.second.isEmpty() ? 1. : d.second.toDouble();
|
||||
}
|
||||
return dn.toDouble();
|
||||
}
|
||||
@@ -976,28 +1193,33 @@ void PICodeParser::replaceMeta(PIString & dn) {
|
||||
ms = dn.findRange('(', ')', '\\', s + 6, &ml);
|
||||
if (ms < 0) return;
|
||||
PIString meta = dn.mid(ms, ml).trim();
|
||||
PIString rm = s_M + PIString::fromNumber(tmp_meta.size_s()).expandLeftTo(3, '0');
|
||||
PIString rm = s_M + PIString::fromNumber(tmp_meta.size_s()).expandLeftTo(3, '0');
|
||||
dn.replace(s, ms + ml + 1 - s, rm);
|
||||
//piCout << "FOUND META \"" << meta << '\"';
|
||||
// piCout << "FOUND META \"" << meta << '\"';
|
||||
tmp_meta[rm] = parseMeta(meta);
|
||||
s = dn.find(s_PIMETA);
|
||||
s = dn.find(s_PIMETA);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) {
|
||||
piForeach (Entity * e, entities)
|
||||
if (e->name == en)
|
||||
return e;
|
||||
for (auto * e: entities)
|
||||
if (e->name == en) return e;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::isDeclaration(const PIString & fc, int start, int * end) {
|
||||
int dind = fc.find('{', start), find = fc.find(';', start);
|
||||
//piCout << "isDeclaration" << dind << find << fc.left(10);
|
||||
if (dind < 0 && find < 0) {if (end) *end = -1; return true;}
|
||||
if (dind < 0 || find < dind) {if (end) *end = find; return true;}
|
||||
// piCout << "isDeclaration" << dind << find << fc.left(10);
|
||||
if (dind < 0 && find < 0) {
|
||||
if (end) *end = -1;
|
||||
return true;
|
||||
}
|
||||
if (dind < 0 || find < dind) {
|
||||
if (end) *end = find;
|
||||
return true;
|
||||
}
|
||||
if (end) *end = dind;
|
||||
return false;
|
||||
}
|
||||
@@ -1010,7 +1232,7 @@ bool PICodeParser::isMainFile(const PIString & fc) {
|
||||
if (csi < 0) csi = fc.find(PIStringAscii("\tmain"), si);
|
||||
if (csi < 0) csi = fc.find(PIStringAscii("\nmain"), si);
|
||||
if (csi < 0) return false;
|
||||
si = csi;
|
||||
si = csi;
|
||||
int fi = fc.find('(', si + 5);
|
||||
if (fi < 0) return false;
|
||||
if (fi - si < 10) {
|
||||
@@ -1031,72 +1253,85 @@ PIString PICodeParser::procMacros(PIString fc) {
|
||||
static const PIString s_elif = PIStringAscii("elif");
|
||||
static const PIString s_else = PIStringAscii("else");
|
||||
static const PIString s_endif = PIStringAscii("endif");
|
||||
static const PIString s_L = PIStringAscii("$L");
|
||||
if (fc.isEmpty()) return PIString();
|
||||
int ifcnt = 0;
|
||||
bool grab = false, skip = false, cond_ok = false;
|
||||
PIString pfc, nfc, line, mif, mifcond;
|
||||
//piCout << "procMacros\n<******" << fc << "\n******>";
|
||||
// piCout << "procMacros\n<******" << fc << "\n******>";
|
||||
fc += '\n';
|
||||
while (!fc.isEmpty()) {
|
||||
line = fc.takeLine().trimmed();
|
||||
if (line.left(1) == PIChar('#')) {
|
||||
mifcond = line.mid(1);
|
||||
mif = mifcond.takeCWord();
|
||||
//piCout << mif;
|
||||
//piCout << "mif mifcond" << mif << mifcond << ifcnt;
|
||||
mif = mifcond.takeCWord();
|
||||
// piCout << mif;
|
||||
// piCout << "mif mifcond" << mif << mifcond << ifcnt;
|
||||
if (skip || grab) {
|
||||
if (mif.left(2) == s_if) ifcnt++;
|
||||
if (mif.left(5) == s_endif) {
|
||||
if (ifcnt > 0) ifcnt--;
|
||||
if (ifcnt > 0)
|
||||
ifcnt--;
|
||||
else {
|
||||
//piCout << "main endif" << skip << grab;
|
||||
if (grab) pfc << procMacros(nfc);
|
||||
// piCout << "main endif" << skip << grab;
|
||||
if (grab) pfc += procMacros(nfc);
|
||||
skip = grab = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (mif.left(4) == s_elif && ifcnt == 0) {
|
||||
//piCout << "main elif" << skip << grab << cond_ok;
|
||||
// piCout << "main elif" << skip << grab << cond_ok;
|
||||
if (cond_ok) {
|
||||
if (grab) {
|
||||
pfc << procMacros(nfc);
|
||||
skip = true; grab = false;
|
||||
pfc += procMacros(nfc);
|
||||
skip = true;
|
||||
grab = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (skip) {
|
||||
//piCout << "check elif" << skip << grab << cond_ok;
|
||||
// piCout << "check elif" << skip << grab << cond_ok;
|
||||
if (!macroCondition(mif, mifcond.trimmed())) continue;
|
||||
//piCout << "check elif ok";
|
||||
skip = false; grab = cond_ok = true;
|
||||
// piCout << "check elif ok";
|
||||
skip = false;
|
||||
grab = cond_ok = true;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (mif.left(4) == s_else && ifcnt == 0) {
|
||||
//piCout << "main else" << skip << grab;
|
||||
if (grab) pfc << procMacros(nfc);
|
||||
if (skip && !cond_ok) {skip = false; grab = true;}
|
||||
else {skip = true; grab = false;}
|
||||
// piCout << "main else" << skip << grab;
|
||||
if (grab) pfc += procMacros(nfc);
|
||||
if (skip && !cond_ok) {
|
||||
skip = false;
|
||||
grab = true;
|
||||
} else {
|
||||
skip = true;
|
||||
grab = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (grab) nfc << line << '\n';
|
||||
if (grab) nfc += line + '\n';
|
||||
continue;
|
||||
}
|
||||
if (mif.left(2) == s_if) {
|
||||
//piCout << "main if";
|
||||
// piCout << "main if";
|
||||
skip = grab = cond_ok = false;
|
||||
if (macroCondition(mif, mifcond.trimmed())) grab = cond_ok = true;
|
||||
else skip = true;
|
||||
if (macroCondition(mif, mifcond.trimmed()))
|
||||
grab = cond_ok = true;
|
||||
else
|
||||
skip = true;
|
||||
ifcnt = 0;
|
||||
nfc.clear();
|
||||
} else {
|
||||
parseDirective(line.cutLeft(1).trim());
|
||||
//return false; /// WARNING: now skip errors
|
||||
// return false; /// WARNING: now skip errors
|
||||
}
|
||||
} else {
|
||||
if (grab) nfc << line << '\n';
|
||||
else if (!skip) pfc << line << '\n';
|
||||
if (grab)
|
||||
nfc += line + '\n';
|
||||
else if (!skip)
|
||||
pfc += line + '\n';
|
||||
}
|
||||
}
|
||||
return pfc;
|
||||
@@ -1104,13 +1339,15 @@ PIString PICodeParser::procMacros(PIString fc) {
|
||||
|
||||
|
||||
bool PICodeParser::parseDirective(PIString d) {
|
||||
static const PIString s_include = PIStringAscii("include");
|
||||
static const PIString s_define = PIStringAscii("define");
|
||||
static const PIString s_undef = PIStringAscii("undef");
|
||||
static const PIString s_PIMETA = PIStringAscii("PIMETA");
|
||||
static const PIString s_include = PIStringAscii("include");
|
||||
static const PIString s_define = PIStringAscii("define");
|
||||
static const PIString s_undef = PIStringAscii("undef");
|
||||
static const PIString s_PIMETA = PIStringAscii("PIMETA");
|
||||
static const PIString s_L = PIStringAscii("$L");
|
||||
if (d.isEmpty()) return true;
|
||||
d.replaceAll(s_L, '\n');
|
||||
PIString dname = d.takeCWord();
|
||||
//piCout << "parseDirective" << d;
|
||||
// piCout << "parseDirective" << d;
|
||||
if (dname == s_include) {
|
||||
d.replaceAll('<', '\"').replaceAll('>', '\"');
|
||||
PIString cf = cur_file, ifc = d.takeRange('\"', '\"');
|
||||
@@ -1122,7 +1359,7 @@ bool PICodeParser::parseDirective(PIString d) {
|
||||
}
|
||||
if (dname == s_define) {
|
||||
PIString mname = d.takeCWord();
|
||||
//piCout << mname;
|
||||
// piCout << mname;
|
||||
if (mname == s_PIMETA) return true;
|
||||
if (d.left(1) == PIChar('(')) { // macro
|
||||
PIStringList args = d.takeRange('(', ')').split(',').trim();
|
||||
@@ -1147,7 +1384,10 @@ bool PICodeParser::parseDirective(PIString d) {
|
||||
if (dname == s_undef) {
|
||||
PIString mname = d.takeCWord();
|
||||
for (int i = 0; i < defines.size_s(); ++i)
|
||||
if (defines[i].first == mname) {defines.remove(i); --i;}
|
||||
if (defines[i].first == mname) {
|
||||
defines.remove(i);
|
||||
--i;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -5,49 +5,59 @@
|
||||
* \~russian Разбор C++ кода
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
C++ code parser
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
C++ code 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 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 PICODEPARSER_H
|
||||
#define PICODEPARSER_H
|
||||
|
||||
#include "pifile.h"
|
||||
#include "pievaluator.h"
|
||||
#include "pifile.h"
|
||||
|
||||
inline bool _isCChar(const PIChar & c) {return (c.isAlpha() || (c.toAscii() == '_'));}
|
||||
inline bool _isCChar(const PIString & c) {if (c.isEmpty()) return false; return _isCChar(c[0]);}
|
||||
inline bool _isCChar(const PIChar & c) {
|
||||
return (c.isAlpha() || (c.toAscii() == '_'));
|
||||
}
|
||||
inline bool _isCChar(const PIString & c) {
|
||||
if (c.isEmpty()) return false;
|
||||
return _isCChar(c[0]);
|
||||
}
|
||||
|
||||
class PIP_EXPORT PICodeParser {
|
||||
public:
|
||||
PICodeParser();
|
||||
|
||||
enum Visibility {Global, Public, Protected, Private};
|
||||
|
||||
enum Visibility {
|
||||
Global,
|
||||
Public,
|
||||
Protected,
|
||||
Private
|
||||
};
|
||||
enum Attribute {
|
||||
NoAttributes = 0x0,
|
||||
Const = 0x01,
|
||||
Static = 0x02,
|
||||
Mutable = 0x04,
|
||||
Volatile = 0x08,
|
||||
Inline = 0x10,
|
||||
Virtual = 0x20,
|
||||
Extern = 0x40
|
||||
Const = 0x01,
|
||||
Static = 0x02,
|
||||
Mutable = 0x04,
|
||||
Volatile = 0x08,
|
||||
Inline = 0x10,
|
||||
Virtual = 0x20,
|
||||
Extern = 0x40
|
||||
};
|
||||
|
||||
|
||||
typedef PIFlags<Attribute> Attributes;
|
||||
typedef PIPair<PIString, PIString> Define;
|
||||
typedef PIPair<PIString, PIString> Typedef;
|
||||
@@ -55,25 +65,25 @@ public:
|
||||
|
||||
struct PIP_EXPORT Macro {
|
||||
Macro(const PIString & n = PIString(), const PIString & v = PIString(), const PIStringList & a = PIStringList()) {
|
||||
name = n;
|
||||
name = n;
|
||||
value = v;
|
||||
args = a;
|
||||
args = a;
|
||||
}
|
||||
PIString expand(PIString args_, bool * ok = 0) const;
|
||||
PIString name;
|
||||
PIString value;
|
||||
PIStringList args;
|
||||
};
|
||||
|
||||
|
||||
struct PIP_EXPORT Member {
|
||||
Member() {
|
||||
visibility = Global;
|
||||
size = 0;
|
||||
bits = -1;
|
||||
visibility = Global;
|
||||
size = 0;
|
||||
bits = -1;
|
||||
is_type_ptr = false;
|
||||
attributes = NoAttributes;
|
||||
attributes = NoAttributes;
|
||||
}
|
||||
bool isBitfield() const {return bits > 0;}
|
||||
bool isBitfield() const { return bits > 0; }
|
||||
MetaMap meta;
|
||||
PIString type;
|
||||
PIString name;
|
||||
@@ -86,12 +96,12 @@ public:
|
||||
int size;
|
||||
int bits;
|
||||
};
|
||||
|
||||
|
||||
struct PIP_EXPORT Entity {
|
||||
Entity() {
|
||||
visibility = Global;
|
||||
has_name = true;
|
||||
size = 0;
|
||||
visibility = Global;
|
||||
has_name = true;
|
||||
size = 0;
|
||||
parent_scope = 0;
|
||||
}
|
||||
MetaMap meta;
|
||||
@@ -102,49 +112,52 @@ public:
|
||||
int size;
|
||||
bool has_name;
|
||||
Entity * parent_scope;
|
||||
PIVector<Entity * > parents;
|
||||
PIVector<Entity * > children;
|
||||
PIVector<Entity *> parents;
|
||||
PIVector<Entity *> children;
|
||||
PIVector<Member> functions;
|
||||
PIVector<Member> members;
|
||||
PIVector<Typedef> typedefs;
|
||||
};
|
||||
|
||||
struct PIP_EXPORT EnumeratorInfo {
|
||||
EnumeratorInfo(const PIString & n = PIString(), int v = 0, const MetaMap & m = MetaMap()) {name = n; value = v; meta = m;}
|
||||
EnumeratorInfo(const PIString & n = PIString(), int v = 0, const MetaMap & m = MetaMap()) {
|
||||
name = n;
|
||||
value = v;
|
||||
meta = m;
|
||||
}
|
||||
MetaMap meta;
|
||||
PIString name;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct PIP_EXPORT Enum {
|
||||
Enum(const PIString & n = PIString()) {
|
||||
name = n;
|
||||
}
|
||||
Enum(const PIString & n = PIString()) { name = n; }
|
||||
MetaMap meta;
|
||||
PIString name;
|
||||
PIVector<EnumeratorInfo> members;
|
||||
};
|
||||
|
||||
|
||||
void parseFile(const PIString & file, bool follow_includes = true);
|
||||
void parseFiles(const PIStringList & files, bool follow_includes = true);
|
||||
|
||||
void includeDirectory(const PIString & dir) {includes << dir;}
|
||||
void addDefine(const PIString & def_name, const PIString & def_value) {custom_defines << Define(def_name, def_value);}
|
||||
void parseFileContent(PIString fc);
|
||||
|
||||
void includeDirectory(const PIString & dir) { includes << dir; }
|
||||
void addDefine(const PIString & def_name, const PIString & def_value) { custom_defines << Define(def_name, def_value); }
|
||||
bool isEnum(const PIString & name);
|
||||
Entity * findEntityByName(const PIString & en);
|
||||
PIStringList parsedFiles() const {return PIStringList(proc_files.toVector());}
|
||||
PIString mainFile() const {return main_file;}
|
||||
const PICodeParser::Entity * global() const {return &root_;}
|
||||
|
||||
int macrosSubstitutionMaxIterations() const {return macros_iter;}
|
||||
void setMacrosSubstitutionMaxIterations(int value) {macros_iter = value;}
|
||||
|
||||
PIStringList parsedFiles() const { return PIStringList(proc_files.toVector()); }
|
||||
PIString mainFile() const { return main_file; }
|
||||
const PICodeParser::Entity * global() const { return &root_; }
|
||||
|
||||
int macrosSubstitutionMaxIterations() const { return macros_iter; }
|
||||
void setMacrosSubstitutionMaxIterations(int value) { macros_iter = value; }
|
||||
|
||||
PIVector<Define> defines, custom_defines;
|
||||
PIVector<Macro> macros;
|
||||
PIVector<Enum> enums;
|
||||
PIVector<Typedef> typedefs;
|
||||
PIVector<Entity * > entities;
|
||||
|
||||
PIVector<Entity *> entities;
|
||||
|
||||
private:
|
||||
void clear();
|
||||
bool parseFileInternal(const PIString & file, bool follow_includes);
|
||||
@@ -169,7 +182,7 @@ private:
|
||||
bool isDeclaration(const PIString & fc, int start, int * end);
|
||||
bool isMainFile(const PIString & fc);
|
||||
void normalizeEntityNamespace(PIString & n);
|
||||
|
||||
|
||||
int macros_iter, anon_num;
|
||||
bool with_includes;
|
||||
PIEvaluator evaluator;
|
||||
@@ -181,7 +194,6 @@ private:
|
||||
PIString cur_namespace;
|
||||
PIMap<PIString, PIString> tmp_temp;
|
||||
PIMap<PIString, MetaMap> tmp_meta;
|
||||
|
||||
};
|
||||
|
||||
#endif // PICODEPARSER_H
|
||||
|
||||
@@ -6,22 +6,22 @@
|
||||
* \~russian Сжатие с помощью zlib
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Compress class using zlib
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
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 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/>.
|
||||
*/
|
||||
//! \defgroup Compress Compress
|
||||
//! \~\brief
|
||||
@@ -58,8 +58,8 @@
|
||||
#ifndef PICOMPRESS_H
|
||||
#define PICOMPRESS_H
|
||||
|
||||
#include "pip_compress_export.h"
|
||||
#include "pibytearray.h"
|
||||
#include "pip_compress_export.h"
|
||||
|
||||
//! \~english Compress "ba" with compression level "level", return empty %PIByteArray if no compression supports
|
||||
//! \~russian Сжимает "ba" с уровнем сжатия "level", возвращает пустой %PIByteArray если нет поддержки
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Module includes
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Module includes
|
||||
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/>.
|
||||
*/
|
||||
//! \defgroup Console Console
|
||||
//! \~\brief
|
||||
|
||||
@@ -1,29 +1,34 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Keyboard grabber for console
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Keyboard grabber for console
|
||||
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 "pikbdlistener.h"
|
||||
|
||||
#include "piincludes_p.h"
|
||||
#include "piliterals.h"
|
||||
#include "piwaitevent_p.h"
|
||||
// clang-format off
|
||||
#ifndef WINDOWS
|
||||
# include <termios.h>
|
||||
#else
|
||||
# include <wingdi.h>
|
||||
# include <wincon.h>
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
/** \class PIKbdListener
|
||||
* \brief Keyboard console input listener
|
||||
@@ -47,80 +52,82 @@ PIKbdListener * PIKbdListener::_object = 0;
|
||||
#ifndef WINDOWS
|
||||
// unix
|
||||
const PIKbdListener::EscSeq PIKbdListener::esc_seq[] = {
|
||||
{"OA", PIKbdListener::UpArrow, 0, 0 , 1 },
|
||||
{"OA", PIKbdListener::UpArrow, 4, 0 , 0 },
|
||||
{"[1A", PIKbdListener::UpArrow, 0, 0 , 0 },
|
||||
{"[A", PIKbdListener::UpArrow, 0, vt_all , 0 },
|
||||
{"OB", PIKbdListener::DownArrow, 0, 0 , 1 },
|
||||
{"OB", PIKbdListener::DownArrow, 4, 0 , 0 },
|
||||
{"[1B", PIKbdListener::DownArrow, 0, 0 , 0 },
|
||||
{"[B", PIKbdListener::DownArrow, 0, vt_all , 0 },
|
||||
{"OC", PIKbdListener::RightArrow, 0, 0 , 1 },
|
||||
{"OC", PIKbdListener::RightArrow, 4, 0 , 0 },
|
||||
{"[1C", PIKbdListener::RightArrow, 0, 0 , 0 },
|
||||
{"[C", PIKbdListener::RightArrow, 0, vt_all , 0 },
|
||||
{"OD", PIKbdListener::LeftArrow, 0, 0 , 1 },
|
||||
{"OD", PIKbdListener::LeftArrow, 4, 0 , 0 },
|
||||
{"[1D", PIKbdListener::LeftArrow, 0, 0 , 0 },
|
||||
{"[D", PIKbdListener::LeftArrow, 0, vt_all , 0 },
|
||||
{"[H", PIKbdListener::Home, 0, vt_xterm , 0 },
|
||||
{"[1H", PIKbdListener::Home, 0, 0 , 0 },
|
||||
{"OH", PIKbdListener::Home, 0, 0 , 1 },
|
||||
{"[1~", PIKbdListener::Home, 0, vt_linux , 0 },
|
||||
{"[F", PIKbdListener::End, 0, vt_xterm , 0 },
|
||||
{"[1F", PIKbdListener::End, 0, 0 , 0 },
|
||||
{"OF", PIKbdListener::End, 0, 0 , 1 },
|
||||
{"[4~", PIKbdListener::End, 0, vt_linux , 0 },
|
||||
{"[2~", PIKbdListener::Insert, 0, vt_all , 0 },
|
||||
{"[3~", PIKbdListener::Delete, 0, vt_all , 0 },
|
||||
{"[5~", PIKbdListener::PageUp, 0, vt_all , 0 },
|
||||
{"[6~", PIKbdListener::PageDown, 0, vt_all , 0 },
|
||||
{"[Z", PIKbdListener::Tab, 1, vt_xterm , 0 },
|
||||
{"OP", PIKbdListener::F1, 0, vt_xterm , 0 },
|
||||
{"[[A", PIKbdListener::F1, 0, vt_linux , 0 },
|
||||
{"[11~", PIKbdListener::F1, 0, 0 , 0 },
|
||||
{"[25~", PIKbdListener::F1, 1, vt_linux , 0 },
|
||||
{"OQ", PIKbdListener::F2, 0, vt_xterm , 0 },
|
||||
{"[[B", PIKbdListener::F2, 0, vt_linux , 0 },
|
||||
{"[12~", PIKbdListener::F2, 0, 0 , 0 },
|
||||
{"[26~", PIKbdListener::F2, 1, vt_linux , 0 },
|
||||
{"OR", PIKbdListener::F3, 0, vt_xterm , 0 },
|
||||
{"[[C", PIKbdListener::F3, 0, vt_linux , 0 },
|
||||
{"[13~", PIKbdListener::F3, 0, 0 , 0 },
|
||||
{"[28~", PIKbdListener::F3, 1, vt_linux , 0 },
|
||||
{"OS", PIKbdListener::F4, 0, vt_xterm , 0 },
|
||||
{"[[D", PIKbdListener::F4, 0, vt_linux , 0 },
|
||||
{"[14~", PIKbdListener::F4, 0, 0 , 0 },
|
||||
{"[29~", PIKbdListener::F4, 1, vt_linux , 0 },
|
||||
{"[[E", PIKbdListener::F5, 0, vt_linux , 0 },
|
||||
{"OT", PIKbdListener::F5, 0, 0 , 0 },
|
||||
{"[15~", PIKbdListener::F5, 0, vt_xterm , 0 },
|
||||
{"[31~", PIKbdListener::F5, 1, vt_linux , 0 },
|
||||
{"OU", PIKbdListener::F6, 0, 0 , 0 },
|
||||
{"[17~", PIKbdListener::F6, 0, vt_all , 0 },
|
||||
{"[32~", PIKbdListener::F6, 1, vt_linux , 0 },
|
||||
{"OV", PIKbdListener::F7, 0, 0 , 0 },
|
||||
{"[18~", PIKbdListener::F7, 0, vt_all , 0 },
|
||||
{"[33~", PIKbdListener::F7, 1, vt_linux , 0 },
|
||||
{"OW", PIKbdListener::F8, 0, 0 , 0 },
|
||||
{"[19~", PIKbdListener::F8, 0, vt_all , 0 },
|
||||
{"[34~", PIKbdListener::F8, 1, vt_linux , 0 },
|
||||
{"OX", PIKbdListener::F9, 0, 0 , 0 },
|
||||
{"[20~", PIKbdListener::F9, 0, vt_all , 0 },
|
||||
{"[35~", PIKbdListener::F9, 1, vt_linux , 0 },
|
||||
{"OY", PIKbdListener::F10, 0, 0 , 0 },
|
||||
{"[21~", PIKbdListener::F10, 0, vt_all , 0 },
|
||||
{"[36~", PIKbdListener::F10, 1, vt_linux , 0 },
|
||||
{"OZ", PIKbdListener::F11, 0, 0 , 0 },
|
||||
{"[23~", PIKbdListener::F11, 0, vt_all , 0 },
|
||||
{"O[", PIKbdListener::F12, 0, 0 , 0 },
|
||||
{"[24~", PIKbdListener::F12, 0, vt_all , 0 },
|
||||
// End
|
||||
{0, 0, 0, 0, 0},
|
||||
{"OA", PIKbdListener::UpArrow, 0, 0, 1},
|
||||
{"OA", PIKbdListener::UpArrow, 4, 0, 0},
|
||||
{"[1A", PIKbdListener::UpArrow, 0, 0, 0},
|
||||
{"[A", PIKbdListener::UpArrow, 0, vt_all, 0},
|
||||
{"OB", PIKbdListener::DownArrow, 0, 0, 1},
|
||||
{"OB", PIKbdListener::DownArrow, 4, 0, 0},
|
||||
{"[1B", PIKbdListener::DownArrow, 0, 0, 0},
|
||||
{"[B", PIKbdListener::DownArrow, 0, vt_all, 0},
|
||||
{"OC", PIKbdListener::RightArrow, 0, 0, 1},
|
||||
{"OC", PIKbdListener::RightArrow, 4, 0, 0},
|
||||
{"[1C", PIKbdListener::RightArrow, 0, 0, 0},
|
||||
{"[C", PIKbdListener::RightArrow, 0, vt_all, 0},
|
||||
{"OD", PIKbdListener::LeftArrow, 0, 0, 1},
|
||||
{"OD", PIKbdListener::LeftArrow, 4, 0, 0},
|
||||
{"[1D", PIKbdListener::LeftArrow, 0, 0, 0},
|
||||
{"[D", PIKbdListener::LeftArrow, 0, vt_all, 0},
|
||||
{"[H", PIKbdListener::Home, 0, vt_xterm, 0},
|
||||
{"[1H", PIKbdListener::Home, 0, 0, 0},
|
||||
{"OH", PIKbdListener::Home, 0, 0, 1},
|
||||
{"[1~", PIKbdListener::Home, 0, vt_linux, 0},
|
||||
{"[F", PIKbdListener::End, 0, vt_xterm, 0},
|
||||
{"[1F", PIKbdListener::End, 0, 0, 0},
|
||||
{"OF", PIKbdListener::End, 0, 0, 1},
|
||||
{"[4~", PIKbdListener::End, 0, vt_linux, 0},
|
||||
{"[2~", PIKbdListener::Insert, 0, vt_all, 0},
|
||||
{"[3~", PIKbdListener::Delete, 0, vt_all, 0},
|
||||
{"[5~", PIKbdListener::PageUp, 0, vt_all, 0},
|
||||
{"[6~", PIKbdListener::PageDown, 0, vt_all, 0},
|
||||
{"[Z", PIKbdListener::Tab, 1, vt_xterm, 0},
|
||||
{"OP", PIKbdListener::F1, 0, vt_xterm, 0},
|
||||
{"[[A", PIKbdListener::F1, 0, vt_linux, 0},
|
||||
{"[11~", PIKbdListener::F1, 0, 0, 0},
|
||||
{"[25~", PIKbdListener::F1, 1, vt_linux, 0},
|
||||
{"OQ", PIKbdListener::F2, 0, vt_xterm, 0},
|
||||
{"[[B", PIKbdListener::F2, 0, vt_linux, 0},
|
||||
{"[12~", PIKbdListener::F2, 0, 0, 0},
|
||||
{"[26~", PIKbdListener::F2, 1, vt_linux, 0},
|
||||
{"OR", PIKbdListener::F3, 0, vt_xterm, 0},
|
||||
{"[[C", PIKbdListener::F3, 0, vt_linux, 0},
|
||||
{"[13~", PIKbdListener::F3, 0, 0, 0},
|
||||
{"[28~", PIKbdListener::F3, 1, vt_linux, 0},
|
||||
{"OS", PIKbdListener::F4, 0, vt_xterm, 0},
|
||||
{"[[D", PIKbdListener::F4, 0, vt_linux, 0},
|
||||
{"[14~", PIKbdListener::F4, 0, 0, 0},
|
||||
{"[29~", PIKbdListener::F4, 1, vt_linux, 0},
|
||||
{"[[E", PIKbdListener::F5, 0, vt_linux, 0},
|
||||
{"OT", PIKbdListener::F5, 0, 0, 0},
|
||||
{"[15~", PIKbdListener::F5, 0, vt_xterm, 0},
|
||||
{"[31~", PIKbdListener::F5, 1, vt_linux, 0},
|
||||
{"OU", PIKbdListener::F6, 0, 0, 0},
|
||||
{"[17~", PIKbdListener::F6, 0, vt_all, 0},
|
||||
{"[32~", PIKbdListener::F6, 1, vt_linux, 0},
|
||||
{"OV", PIKbdListener::F7, 0, 0, 0},
|
||||
{"[18~", PIKbdListener::F7, 0, vt_all, 0},
|
||||
{"[33~", PIKbdListener::F7, 1, vt_linux, 0},
|
||||
{"OW", PIKbdListener::F8, 0, 0, 0},
|
||||
{"[19~", PIKbdListener::F8, 0, vt_all, 0},
|
||||
{"[34~", PIKbdListener::F8, 1, vt_linux, 0},
|
||||
{"OX", PIKbdListener::F9, 0, 0, 0},
|
||||
{"[20~", PIKbdListener::F9, 0, vt_all, 0},
|
||||
{"[35~", PIKbdListener::F9, 1, vt_linux, 0},
|
||||
{"OY", PIKbdListener::F10, 0, 0, 0},
|
||||
{"[21~", PIKbdListener::F10, 0, vt_all, 0},
|
||||
{"[36~", PIKbdListener::F10, 1, vt_linux, 0},
|
||||
{"OZ", PIKbdListener::F11, 0, 0, 0},
|
||||
{"[23~", PIKbdListener::F11, 0, vt_all, 0},
|
||||
{"O[", PIKbdListener::F12, 0, 0, 0},
|
||||
{"[24~", PIKbdListener::F12, 0, vt_all, 0},
|
||||
// End
|
||||
{0, 0, 0, 0, 0},
|
||||
};
|
||||
void setupTerminal(bool on) {
|
||||
printf("\e[?1000"); printf(on ? "h" : "l");
|
||||
printf("\e[?1002"); printf(on ? "h" : "l");
|
||||
printf("\e[?1000");
|
||||
printf(on ? "h" : "l");
|
||||
printf("\e[?1002");
|
||||
printf(on ? "h" : "l");
|
||||
fflush(0);
|
||||
}
|
||||
#endif
|
||||
@@ -128,7 +135,7 @@ void setupTerminal(bool on) {
|
||||
|
||||
PRIVATE_DEFINITION_START(PIKbdListener)
|
||||
#ifdef WINDOWS
|
||||
void * hIn, * hOut;
|
||||
void *hIn, *hOut;
|
||||
DWORD smode, tmode;
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
#else
|
||||
@@ -139,32 +146,34 @@ PRIVATE_DEFINITION_START(PIKbdListener)
|
||||
#else
|
||||
int
|
||||
#endif
|
||||
ret;
|
||||
ret;
|
||||
PIWaitEvent event;
|
||||
PRIVATE_DEFINITION_END(PIKbdListener)
|
||||
|
||||
|
||||
PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread() {
|
||||
setName("keyboard_listener");
|
||||
setName("keyboard_listener"_a);
|
||||
_object = this;
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->hIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
PRIVATE->hIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
GetConsoleMode(PRIVATE->hIn, &PRIVATE->smode);
|
||||
#else
|
||||
tcgetattr(0, &PRIVATE->sterm);
|
||||
#endif
|
||||
is_active = true;
|
||||
ret_func = slot;
|
||||
kbddata_ = _d;
|
||||
ret_func = slot;
|
||||
kbddata_ = _d;
|
||||
dbl_interval = 400;
|
||||
PIKbdListener::exiting = exit_enabled = false;
|
||||
PRIVATE->event.create();
|
||||
PIKbdListener::exiting = false;
|
||||
if (startNow) start();
|
||||
}
|
||||
|
||||
|
||||
PIKbdListener::~PIKbdListener() {
|
||||
terminate();
|
||||
end();
|
||||
stop();
|
||||
if (!waitForFinish(100_ms)) terminate();
|
||||
PRIVATE->event.destroy();
|
||||
}
|
||||
|
||||
|
||||
@@ -191,9 +200,9 @@ PIKbdListener::KeyModifiers getModifiers(DWORD v, bool * shift = 0) {
|
||||
bool shi = v & SHIFT_PRESSED;
|
||||
bool alt = v & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED);
|
||||
if (ctrl) ret |= PIKbdListener::Ctrl;
|
||||
if (shi) ret |= PIKbdListener::Shift;
|
||||
if (alt) ret |= PIKbdListener::Alt;
|
||||
//if (meta) ret |= PIKbdListener::Meta;
|
||||
if (shi) ret |= PIKbdListener::Shift;
|
||||
if (alt) ret |= PIKbdListener::Alt;
|
||||
// if (meta) ret |= PIKbdListener::Meta;
|
||||
if (v & CAPSLOCK_ON) shi = !shi;
|
||||
if (shift) *shift = shi;
|
||||
return ret;
|
||||
@@ -201,7 +210,7 @@ PIKbdListener::KeyModifiers getModifiers(DWORD v, bool * shift = 0) {
|
||||
PIKbdListener::MouseButtons getButtons(DWORD v) {
|
||||
PIKbdListener::MouseButtons ret;
|
||||
if (v & FROM_LEFT_1ST_BUTTON_PRESSED) ret |= PIKbdListener::MouseLeft;
|
||||
if (v & RIGHTMOST_BUTTON_PRESSED) ret |= PIKbdListener::MouseRight;
|
||||
if (v & RIGHTMOST_BUTTON_PRESSED) ret |= PIKbdListener::MouseRight;
|
||||
if (v & FROM_LEFT_2ND_BUTTON_PRESSED) ret |= PIKbdListener::MouseMiddle;
|
||||
return ret;
|
||||
}
|
||||
@@ -209,77 +218,159 @@ PIKbdListener::MouseButtons getButtons(DWORD v) {
|
||||
|
||||
|
||||
void PIKbdListener::readKeyboard() {
|
||||
ke.key = 0;
|
||||
ke.key = 0;
|
||||
ke.modifiers = 0;
|
||||
memset(rc, 0, 8);
|
||||
char rc[8];
|
||||
piZeroMemory(rc, 8);
|
||||
#ifdef WINDOWS
|
||||
INPUT_RECORD ir;
|
||||
ReadConsoleInput(PRIVATE->hIn, &ir, 1, &(PRIVATE->ret));
|
||||
//piCout << ir.EventType;
|
||||
switch (ir.EventType) {
|
||||
case KEY_EVENT: {
|
||||
KEY_EVENT_RECORD ker = ir.Event.KeyEvent;
|
||||
if (ker.bKeyDown) {
|
||||
bool shift = false;
|
||||
bool shift = false;
|
||||
ke.modifiers = getModifiers(ker.dwControlKeyState, &shift);
|
||||
//piCout << "key" << int(ker.wVirtualKeyCode) << int(ker.uChar.AsciiChar);
|
||||
// piCout << "key" << int(ker.wVirtualKeyCode) << int(ker.uChar.AsciiChar);
|
||||
switch (ker.wVirtualKeyCode) {
|
||||
case 8: PRIVATE->ret = 1; ke.key = Backspace; break;
|
||||
case 33: PRIVATE->ret = 1; ke.key = PageUp; break;
|
||||
case 34: PRIVATE->ret = 1; ke.key = PageDown; break;
|
||||
case 35: PRIVATE->ret = 1; ke.key = End; break;
|
||||
case 36: PRIVATE->ret = 1; ke.key = Home; break;
|
||||
case 37: PRIVATE->ret = 1; ke.key = LeftArrow; break;
|
||||
case 38: PRIVATE->ret = 1; ke.key = UpArrow; break;
|
||||
case 39: PRIVATE->ret = 1; ke.key = RightArrow; break;
|
||||
case 40: PRIVATE->ret = 1; ke.key = DownArrow; break;
|
||||
case 45: PRIVATE->ret = 1; ke.key = Insert; break;
|
||||
case 46: PRIVATE->ret = 1; ke.key = Delete; break;
|
||||
case 8:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = Backspace;
|
||||
break;
|
||||
case 33:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = PageUp;
|
||||
break;
|
||||
case 34:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = PageDown;
|
||||
break;
|
||||
case 35:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = End;
|
||||
break;
|
||||
case 36:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = Home;
|
||||
break;
|
||||
case 37:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = LeftArrow;
|
||||
break;
|
||||
case 38:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = UpArrow;
|
||||
break;
|
||||
case 39:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = RightArrow;
|
||||
break;
|
||||
case 40:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = DownArrow;
|
||||
break;
|
||||
case 45:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = Insert;
|
||||
break;
|
||||
case 46:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = Delete;
|
||||
break;
|
||||
case '\r':
|
||||
case '\n': PRIVATE->ret = 1; ke.key = Return; break;
|
||||
case ' ': PRIVATE->ret = 1; ke.key = Space; break;
|
||||
case '\t': PRIVATE->ret = 1; ke.key = Tab; break;
|
||||
case 112: PRIVATE->ret = 1; ke.key = F1; break;
|
||||
case 113: PRIVATE->ret = 1; ke.key = F2; break;
|
||||
case 114: PRIVATE->ret = 1; ke.key = F3; break;
|
||||
case 115: PRIVATE->ret = 1; ke.key = F4; break;
|
||||
case 116: PRIVATE->ret = 1; ke.key = F5; break;
|
||||
case 117: PRIVATE->ret = 1; ke.key = F6; break;
|
||||
case 118: PRIVATE->ret = 1; ke.key = F7; break;
|
||||
case 119: PRIVATE->ret = 1; ke.key = F8; break;
|
||||
case 120: PRIVATE->ret = 1; ke.key = F9; break;
|
||||
case 121: PRIVATE->ret = 1; ke.key = F10; break;
|
||||
case 122: PRIVATE->ret = 1; ke.key = F11; break;
|
||||
case 123: PRIVATE->ret = 1; ke.key = F12; break;
|
||||
case '\n':
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = Return;
|
||||
break;
|
||||
case ' ':
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = Space;
|
||||
break;
|
||||
case '\t':
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = Tab;
|
||||
break;
|
||||
case 112:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = F1;
|
||||
break;
|
||||
case 113:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = F2;
|
||||
break;
|
||||
case 114:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = F3;
|
||||
break;
|
||||
case 115:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = F4;
|
||||
break;
|
||||
case 116:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = F5;
|
||||
break;
|
||||
case 117:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = F6;
|
||||
break;
|
||||
case 118:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = F7;
|
||||
break;
|
||||
case 119:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = F8;
|
||||
break;
|
||||
case 120:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = F9;
|
||||
break;
|
||||
case 121:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = F10;
|
||||
break;
|
||||
case 122:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = F11;
|
||||
break;
|
||||
case 123:
|
||||
PRIVATE->ret = 1;
|
||||
ke.key = F12;
|
||||
break;
|
||||
default:
|
||||
PRIVATE->ret = 1;
|
||||
rc[0] = 1;
|
||||
rc[0] = 1;
|
||||
{
|
||||
PIChar ch = PIChar::fromConsole(ker.uChar.AsciiChar);
|
||||
if (shift) ch = ch.toUpper();
|
||||
ke.key = ch.unicode16Code();
|
||||
PIChar ch = PIChar::fromConsole(ker.uChar.AsciiChar);
|
||||
if (shift) ch = ch.toUpper();
|
||||
ke.key = ch.unicode16Code();
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ke.key == 0) {piMSleep(10); return;}
|
||||
} else {piMSleep(10); return;}
|
||||
if (ke.key == 0) {
|
||||
piMSleep(10);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
piMSleep(10);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case MOUSE_EVENT: {
|
||||
MOUSE_EVENT_RECORD mer = ir.Event.MouseEvent;
|
||||
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
||||
me.modifiers = getModifiers(mer.dwControlKeyState);
|
||||
me.modifiers = getModifiers(mer.dwControlKeyState);
|
||||
MouseButtons mb = getButtons(mer.dwButtonState);
|
||||
if (mer.dwEventFlags & MOUSE_WHEELED) {
|
||||
memcpy((void*)(&we), (const void*)(&me), sizeof(me));
|
||||
we.action = MouseWheel;
|
||||
we.direction = short((mer.dwButtonState >> 8) & 0xFFFF) > 0;
|
||||
//piCout << "wheel" << we.direction;
|
||||
memcpy((void *)(&we), (const void *)(&me), sizeof(me));
|
||||
we.action = MouseWheel;
|
||||
we.direction = short((mer.dwButtonState >> 16) & 0xFFFF) > 0;
|
||||
wheelEvent(we, kbddata_);
|
||||
break;
|
||||
} else {
|
||||
me.x = mer.dwMousePosition.X;
|
||||
me.y = mer.dwMousePosition.Y - PRIVATE->sbi.srWindow.Top;
|
||||
me.x = mer.dwMousePosition.X;
|
||||
me.y = mer.dwMousePosition.Y - PRIVATE->sbi.srWindow.Top;
|
||||
bool move = mer.dwEventFlags & MOUSE_MOVED;
|
||||
if (move) {
|
||||
if (me.action == MouseButtonRelease) {
|
||||
@@ -297,38 +388,44 @@ void PIKbdListener::readKeyboard() {
|
||||
prev_p_me = me;
|
||||
}
|
||||
tm_dbl.reset();
|
||||
} else if (mb < me.buttons)
|
||||
me.action = MouseButtonRelease;
|
||||
else {
|
||||
if (mb != 0) piCoutObj << "WTF";
|
||||
break;
|
||||
}
|
||||
else if (mb < me.buttons) me.action = MouseButtonRelease;
|
||||
else {if (mb != 0) piCoutObj << "WTF"; break;}
|
||||
}
|
||||
me.buttons = mb;
|
||||
if (piCompareBinary(&prev_me, &me, sizeof(me)))
|
||||
break;
|
||||
memcpy((void*)(&prev_me), (const void*)(&me), sizeof(me));
|
||||
//PIString _s[] = {"press", "release", "dbl click", "move"};
|
||||
//piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
|
||||
if (piCompareBinary(&prev_me, &me, sizeof(me))) break;
|
||||
memcpy((void *)(&prev_me), (const void *)(&me), sizeof(me));
|
||||
// PIString _s[] = {"press", "release", "dbl click", "move"};
|
||||
// piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
|
||||
mouseEvent(me, kbddata_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
piMSleep(10);
|
||||
return;
|
||||
} break;
|
||||
default: piMSleep(10); return;
|
||||
}
|
||||
#else
|
||||
tcsetattr(0, TCSANOW, &PRIVATE->tterm);
|
||||
if (!PRIVATE->event.wait(0)) return;
|
||||
PRIVATE->ret = read(0, rc, 8);
|
||||
/*piCout << "key" << PIString(rc).replaceAll("\e", "\\e");
|
||||
for (int i = 0; i < PRIVATE->ret; ++i)
|
||||
PICout(0) << PICoutManipulators::Hex << int(((uchar * )&rc)[i]) << ' ';
|
||||
PICout(0) << PICoutManipulators::Hex << int(((uchar * )&rc)[i]) << ' ';
|
||||
PICout(0) << "\n";
|
||||
std::cout << PRIVATE->ret << " chars ";
|
||||
for (int i = 0; i < PRIVATE->ret; ++i)
|
||||
std::cout << "'" << (char)(rc[i]) << "' " << (int)(uchar)(rc[i]);
|
||||
std::cout << "'" << (char)(rc[i]) << "' " << (int)(uchar)(rc[i]);
|
||||
std::cout << std::endl;*/
|
||||
if (rc[0] == 0) {piMSleep(10); return;}
|
||||
if (PRIVATE->ret < 0 || PRIVATE->ret > 7) {piMSleep(10); return;}
|
||||
if (rc[0] == 0) {
|
||||
piMSleep(10);
|
||||
return;
|
||||
}
|
||||
if (PRIVATE->ret < 0 || PRIVATE->ret > 7) {
|
||||
piMSleep(10);
|
||||
return;
|
||||
}
|
||||
if (PRIVATE->ret == 1) {
|
||||
if (rc[0] == 8)
|
||||
ke.key = Backspace;
|
||||
@@ -343,25 +440,26 @@ void PIKbdListener::readKeyboard() {
|
||||
// 8 - ctrl+alt+shift 7
|
||||
if (rc[0] == '\e') { // search for Alt
|
||||
if (PRIVATE->ret == 2) {
|
||||
mod = 2;
|
||||
mod = 2;
|
||||
ke.key = PIChar::fromConsole(rc[1]).unicode16Code();
|
||||
} else {// escape-seq
|
||||
} else { // escape-seq
|
||||
if (rc[1] == '\e') { // search for Alt
|
||||
for (int i = 1; i < 7; ++i) rc[i] = rc[i + 1];
|
||||
for (int i = 1; i < 7; ++i)
|
||||
rc[i] = rc[i + 1];
|
||||
mod = 2;
|
||||
PRIVATE->ret--;
|
||||
}
|
||||
if (rc[1] == '[') {
|
||||
if (rc[2] == 'M') { // mouse
|
||||
if (PRIVATE->ret >= 5) {
|
||||
me.x = uchar(rc[4] - '!');
|
||||
me.y = uchar(rc[5] - '!');
|
||||
me.x = uchar(rc[4] - '!');
|
||||
me.y = uchar(rc[5] - '!');
|
||||
int b = rc[3] & 0x7, a = rc[3] & 0x60;
|
||||
if (a == 0x60) {
|
||||
memcpy((void*)(&we), (const void*)(&me), sizeof(me));
|
||||
we.action = MouseWheel;
|
||||
memcpy((void *)(&we), (const void *)(&me), sizeof(me));
|
||||
we.action = MouseWheel;
|
||||
we.direction = (b == 0);
|
||||
//piCout << "wheel" << we.direction;
|
||||
// piCout << "wheel" << we.direction;
|
||||
wheelEvent(we, kbddata_);
|
||||
} else {
|
||||
switch (b) {
|
||||
@@ -372,7 +470,7 @@ void PIKbdListener::readKeyboard() {
|
||||
}
|
||||
if (a == 0x20) {
|
||||
if (b == 3) {
|
||||
me.action = MouseButtonRelease;
|
||||
me.action = MouseButtonRelease;
|
||||
me.buttons = 0;
|
||||
} else {
|
||||
if (tm_dbl.elapsed_m() <= dbl_interval && prev_p_me.x == me.x && prev_p_me.y == me.y)
|
||||
@@ -385,18 +483,19 @@ void PIKbdListener::readKeyboard() {
|
||||
}
|
||||
}
|
||||
if (a == 0x40) me.action = MouseMove;
|
||||
//PIString _s[] = {"press", "release", "dbl click", "move"};
|
||||
//piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
|
||||
// PIString _s[] = {"press", "release", "dbl click", "move"};
|
||||
// piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
|
||||
mouseEvent(me, kbddata_);
|
||||
}
|
||||
//piCout << me.x << me.y << PICoutManipulators::Hex << b << a;
|
||||
// piCout << me.x << me.y << PICoutManipulators::Hex << b << a;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
for (int i = 2; i < 7; ++i) // search for modifier
|
||||
if (rc[i] == ';') {
|
||||
mod |= rc[i + 1] - '0' - 1;
|
||||
for (int j = i; j < 6; ++j) rc[j] = rc[j + 2];
|
||||
for (int j = i; j < 6; ++j)
|
||||
rc[j] = rc[j + 2];
|
||||
rc[6] = rc[7] = 0;
|
||||
PRIVATE->ret -= 2;
|
||||
break;
|
||||
@@ -406,14 +505,15 @@ void PIKbdListener::readKeyboard() {
|
||||
if (PRIVATE->ret >= 3 && rc[1] == 'O') { // search for modifier (F1-F4)
|
||||
if (rc[2] >= '1' && rc[2] <= '8') {
|
||||
mod |= rc[2] - '0' - 1;
|
||||
for (int j = 2; j < 6; ++j) rc[j] = rc[j + 1];
|
||||
for (int j = 2; j < 6; ++j)
|
||||
rc[j] = rc[j + 1];
|
||||
rc[7] = 0;
|
||||
PRIVATE->ret--;
|
||||
}
|
||||
}
|
||||
for (int i = 0; ; ++i) {
|
||||
for (int i = 0;; ++i) {
|
||||
if (!esc_seq[i].seq) break;
|
||||
//piCout << "search" << rc[1] << esc_seq[i].seq;
|
||||
// piCout << "search" << rc[1] << esc_seq[i].seq;
|
||||
if (strcmp(esc_seq[i].seq, &(rc[1])) == 0) {
|
||||
ke.key = esc_seq[i].key;
|
||||
mod |= esc_seq[i].mod;
|
||||
@@ -425,18 +525,16 @@ void PIKbdListener::readKeyboard() {
|
||||
if (mod & 0x1) ke.modifiers |= Shift;
|
||||
if (mod & 0x2) ke.modifiers |= Alt;
|
||||
if (mod & 0x4) ke.modifiers |= Ctrl;
|
||||
//if (mod & 0x8) ke.modifiers |= Meta;
|
||||
// if (mod & 0x8) ke.modifiers |= Meta;
|
||||
}
|
||||
/*cout << "wo mods (" << mod << ")\n";
|
||||
for (int i = 0; i < PRIVATE->ret; ++i)
|
||||
cout << "'" << (char)(rc[i]) << "' ";
|
||||
cout << endl;*/
|
||||
/*cout << "wo mods (" << mod << ")\n";
|
||||
for (int i = 0; i < PRIVATE->ret; ++i)
|
||||
cout << "'" << (char)(rc[i]) << "' ";
|
||||
cout << endl;*/
|
||||
}
|
||||
if (ke.key == 0 && PRIVATE->ret > 1)
|
||||
ke.key = PIChar(rc).unicode16Code();
|
||||
if (ke.key == 0 && PRIVATE->ret > 1) ke.key = PIChar::fromSystem(rc).unicode16Code();
|
||||
#endif
|
||||
if ((rc[0] == '\n' || rc[0] == '\r') && PRIVATE->ret == 1)
|
||||
ke.key = Return;
|
||||
if ((rc[0] == '\n' || rc[0] == '\r') && PRIVATE->ret == 1) ke.key = Return;
|
||||
if (exit_enabled && ke.key == exit_key) {
|
||||
PIKbdListener::exiting = true;
|
||||
return;
|
||||
@@ -448,8 +546,20 @@ void PIKbdListener::readKeyboard() {
|
||||
}
|
||||
|
||||
|
||||
void PIKbdListener::stop() {
|
||||
PIThread::stop();
|
||||
PRIVATE->event.interrupt();
|
||||
}
|
||||
|
||||
|
||||
bool PIKbdListener::stopAndWait(PISystemTime timeout) {
|
||||
stop();
|
||||
return waitForFinish(timeout);
|
||||
}
|
||||
|
||||
|
||||
void PIKbdListener::end() {
|
||||
//cout << "list end" << endl;
|
||||
// cout << "list end" << endl;
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(PRIVATE->hIn, PRIVATE->smode);
|
||||
#else
|
||||
|
||||
@@ -5,83 +5,91 @@
|
||||
* \~russian Консольный захват клавиатуры
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Keyboard grabber for console
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
PIP - Platform Independent Primitives
|
||||
Keyboard grabber for console
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef PIKBDLISTENER_H
|
||||
#define PIKBDLISTENER_H
|
||||
|
||||
#include "pithread.h"
|
||||
#include "pitime.h"
|
||||
|
||||
#define WAIT_FOR_EXIT while (!PIKbdListener::exiting) piMSleep(PIP_MIN_MSLEEP*5); // TODO: rewrite with condvar
|
||||
#define WAIT_FOR_EXIT \
|
||||
while (!PIKbdListener::exiting) \
|
||||
piMSleep(PIP_MIN_MSLEEP * 5); \
|
||||
if (PIKbdListener::instance()) { \
|
||||
if (!PIKbdListener::instance()->stopAndWait(PISystemTime::fromSeconds(1))) PIKbdListener::instance()->terminate(); \
|
||||
}
|
||||
|
||||
|
||||
class PIP_EXPORT PIKbdListener: public PIThread
|
||||
{
|
||||
PIOBJECT_SUBCLASS(PIKbdListener, PIThread)
|
||||
class PIP_EXPORT PIKbdListener: public PIThread {
|
||||
PIOBJECT_SUBCLASS(PIKbdListener, PIThread);
|
||||
friend class PIConsole;
|
||||
friend class PITerminal;
|
||||
public:
|
||||
|
||||
public:
|
||||
//! Special keyboard keys
|
||||
enum SpecialKey {
|
||||
Tab /** Tab key */ = 0x09,
|
||||
Return /** Enter key */ = 0x0a,
|
||||
Esc /** Escape key */ = 0x1b,
|
||||
Space /** Space key */ = 0x20,
|
||||
Backspace /** Backspace key */ = 0x7f,
|
||||
UpArrow /** Up arrow key */ = -1,
|
||||
DownArrow /** Down arrow key */ = -2,
|
||||
Tab /** Tab key */ = 0x09,
|
||||
Return /** Enter key */ = 0x0a,
|
||||
Esc /** Escape key */ = 0x1b,
|
||||
Space /** Space key */ = 0x20,
|
||||
Backspace /** Backspace key */ = 0x7f,
|
||||
UpArrow /** Up arrow key */ = -1,
|
||||
DownArrow /** Down arrow key */ = -2,
|
||||
RightArrow /** Right arrow key */ = -3,
|
||||
LeftArrow /** Left arrow key */ = -4,
|
||||
Home /** Home key */ = -5,
|
||||
End /** End key */ = -6,
|
||||
PageUp /** Page up key */ = -7,
|
||||
PageDown /** Page down key */ = -8,
|
||||
Insert /** Delete key */ = -9,
|
||||
Delete /** Delete key */ = -10,
|
||||
F1 /** F1 key */ = -11,
|
||||
F2 /** F2 key */ = -12,
|
||||
F3 /** F3 key */ = -13,
|
||||
F4 /** F4 key */ = -14,
|
||||
F5 /** F5 key */ = -15,
|
||||
F6 /** F6 key */ = -16,
|
||||
F7 /** F7 key */ = -17,
|
||||
F8 /** F8 key */ = -18,
|
||||
F9 /** F9 key */ = -19,
|
||||
F10 /** F10 key */ = -20,
|
||||
F11 /** F11 key */ = -21,
|
||||
F12 /** F12 key */ = -22
|
||||
LeftArrow /** Left arrow key */ = -4,
|
||||
Home /** Home key */ = -5,
|
||||
End /** End key */ = -6,
|
||||
PageUp /** Page up key */ = -7,
|
||||
PageDown /** Page down key */ = -8,
|
||||
Insert /** Delete key */ = -9,
|
||||
Delete /** Delete key */ = -10,
|
||||
F1 /** F1 key */ = -11,
|
||||
F2 /** F2 key */ = -12,
|
||||
F3 /** F3 key */ = -13,
|
||||
F4 /** F4 key */ = -14,
|
||||
F5 /** F5 key */ = -15,
|
||||
F6 /** F6 key */ = -16,
|
||||
F7 /** F7 key */ = -17,
|
||||
F8 /** F8 key */ = -18,
|
||||
F9 /** F9 key */ = -19,
|
||||
F10 /** F10 key */ = -20,
|
||||
F11 /** F11 key */ = -21,
|
||||
F12 /** F12 key */ = -22
|
||||
};
|
||||
|
||||
//! Keyboard modifiers
|
||||
enum KeyModifier {
|
||||
Ctrl /** Control key */ = 0x1,
|
||||
Shift /** Shift key */ = 0x2,
|
||||
Alt /** Alt key */ = 0x4
|
||||
//Meta /** Meta (windows) key */ = 0x8
|
||||
Shift /** Shift key */ = 0x2,
|
||||
Alt /** Alt key */ = 0x4
|
||||
// Meta /** Meta (windows) key */ = 0x8
|
||||
};
|
||||
|
||||
typedef PIFlags<KeyModifier> KeyModifiers;
|
||||
|
||||
//! This struct contains information about pressed keyboard key
|
||||
struct PIP_EXPORT KeyEvent {
|
||||
KeyEvent(int k = 0, KeyModifiers m = 0) {key = k; modifiers = m;}
|
||||
KeyEvent(int k = 0, KeyModifiers m = 0) {
|
||||
key = k;
|
||||
modifiers = m;
|
||||
}
|
||||
|
||||
//! Pressed key. It can be simple \b char or special key (see PIKbdListener::SpecialKey)
|
||||
int key;
|
||||
@@ -92,8 +100,8 @@ public:
|
||||
|
||||
//! Mouse buttons
|
||||
enum MouseButton {
|
||||
MouseLeft /** Left button */ = 0x01,
|
||||
MouseRight /** Right button */ = 0x02,
|
||||
MouseLeft /** Left button */ = 0x01,
|
||||
MouseRight /** Right button */ = 0x02,
|
||||
MouseMiddle /** Middle button */ = 0x04
|
||||
};
|
||||
|
||||
@@ -110,7 +118,12 @@ public:
|
||||
|
||||
//! This struct contains information about mouse action
|
||||
struct PIP_EXPORT MouseEvent {
|
||||
MouseEvent(MouseAction a = MouseButtonPress, MouseButtons b = 0, KeyModifiers m = 0) {x = y = 0; action = a; buttons = b; modifiers = m;}
|
||||
MouseEvent(MouseAction a = MouseButtonPress, MouseButtons b = 0, KeyModifiers m = 0) {
|
||||
x = y = 0;
|
||||
action = a;
|
||||
buttons = b;
|
||||
modifiers = m;
|
||||
}
|
||||
|
||||
//! Event X coordinate in view-space, from 0
|
||||
int x;
|
||||
@@ -130,7 +143,7 @@ public:
|
||||
|
||||
//! This struct contains information about mouse wheel action
|
||||
struct PIP_EXPORT WheelEvent: public MouseEvent {
|
||||
WheelEvent(): MouseEvent() {direction = false;}
|
||||
WheelEvent(): MouseEvent() { direction = false; }
|
||||
|
||||
//! Wheel direction, /b true - up, /b fasle - down
|
||||
bool direction;
|
||||
@@ -145,43 +158,52 @@ public:
|
||||
|
||||
|
||||
//! Returns custom data
|
||||
void * data() {return kbddata_;}
|
||||
void * data() { return kbddata_; }
|
||||
|
||||
//! Set custom data to "_data"
|
||||
void setData(void * _data) {kbddata_ = _data;}
|
||||
void setData(void * _data) { kbddata_ = _data; }
|
||||
|
||||
//! Set external function to "slot"
|
||||
void setSlot(KBFunc slot) {ret_func = slot;}
|
||||
void setSlot(KBFunc slot) { ret_func = slot; }
|
||||
|
||||
//! Set external function to "slot"
|
||||
void setSlot(std::function<void(KeyEvent)> slot) {ret_func = [slot](KeyEvent e, void *){slot(e);};}
|
||||
void setSlot(std::function<void(KeyEvent)> slot) {
|
||||
ret_func = [slot](KeyEvent e, void *) { slot(e); };
|
||||
}
|
||||
|
||||
//! Returns if exit key if awaiting
|
||||
bool exitCaptured() const {return exit_enabled;}
|
||||
bool exitCaptured() const { return exit_enabled; }
|
||||
|
||||
//! Returns exit key, default 'Q'
|
||||
int exitKey() const {return exit_key;}
|
||||
int exitKey() const { return exit_key; }
|
||||
|
||||
double doubleClickInterval() const {return dbl_interval;}
|
||||
void setDoubleClickInterval(double v) {dbl_interval = v;}
|
||||
double doubleClickInterval() const { return dbl_interval; }
|
||||
void setDoubleClickInterval(double v) { dbl_interval = v; }
|
||||
|
||||
void readKeyboard();
|
||||
|
||||
//! Returns if keyboard listening is active (not running!)
|
||||
bool isActive() {return is_active;}
|
||||
void stop();
|
||||
|
||||
EVENT_HANDLER( void, enableExitCapture) {enableExitCapture('Q');}
|
||||
EVENT_HANDLER1(void, enableExitCapture, int, key) {exit_enabled = true; exit_key = key;}
|
||||
EVENT_HANDLER(void, disableExitCapture) {exit_enabled = false;}
|
||||
EVENT_HANDLER(void, setActive) {setActive(true);}
|
||||
bool stopAndWait(PISystemTime timeout = {});
|
||||
|
||||
//! Returns if keyboard listening is active (not running!)
|
||||
bool isActive() { return is_active; }
|
||||
|
||||
EVENT_HANDLER(void, enableExitCapture) { enableExitCapture('Q'); }
|
||||
EVENT_HANDLER1(void, enableExitCapture, int, key) {
|
||||
exit_enabled = true;
|
||||
exit_key = key;
|
||||
}
|
||||
EVENT_HANDLER(void, disableExitCapture) { exit_enabled = false; }
|
||||
EVENT_HANDLER(void, setActive) { setActive(true); }
|
||||
EVENT_HANDLER1(void, setActive, bool, yes);
|
||||
|
||||
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
|
||||
EVENT2(mouseEvent, PIKbdListener::MouseEvent, mouse, void * , data)
|
||||
EVENT2(wheelEvent, PIKbdListener::WheelEvent, wheel, void * , data)
|
||||
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void *, data);
|
||||
EVENT2(mouseEvent, PIKbdListener::MouseEvent, mouse, void *, data);
|
||||
EVENT2(wheelEvent, PIKbdListener::WheelEvent, wheel, void *, data);
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void enableExitCapture(int key = 'Q')
|
||||
//! \brief Enable exit key "key" awaiting
|
||||
@@ -192,22 +214,22 @@ public:
|
||||
//! \fn void setActive(bool yes = true)
|
||||
//! \brief Set keyboard listening is active or not
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data)
|
||||
//! \brief Raise on key "key" pressed, "data" is custom data
|
||||
|
||||
//! \}
|
||||
//! \}
|
||||
|
||||
static bool exiting;
|
||||
static PIKbdListener * instance() {return _object;}
|
||||
static PIKbdListener * instance() { return _object; }
|
||||
|
||||
private:
|
||||
void begin();
|
||||
void run() {readKeyboard();}
|
||||
void end();
|
||||
void begin() override;
|
||||
void run() override { readKeyboard(); }
|
||||
void end() override;
|
||||
|
||||
#ifndef WINDOWS
|
||||
struct PIP_EXPORT EscSeq {
|
||||
@@ -225,7 +247,7 @@ private:
|
||||
vt_none,
|
||||
vt_xterm = 0x1,
|
||||
vt_linux = 0x2,
|
||||
vt_all = 0xFF
|
||||
vt_all = 0xFF
|
||||
};
|
||||
|
||||
static const EscSeq esc_seq[];
|
||||
@@ -234,26 +256,50 @@ private:
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
KBFunc ret_func;
|
||||
int exit_key;
|
||||
bool exit_enabled, is_active;
|
||||
bool exit_enabled = false, is_active = true;
|
||||
void * kbddata_;
|
||||
char rc[8];
|
||||
double dbl_interval;
|
||||
PITimeMeasurer tm_dbl;
|
||||
KeyEvent ke;
|
||||
MouseEvent me, prev_me, prev_p_me;
|
||||
WheelEvent we;
|
||||
static PIKbdListener * _object;
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::KeyEvent & v) {s << v.key << v.modifiers; return s;}
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::MouseEvent & v) {s << v.x << v.y << (int)v.action << v.buttons << v.modifiers; return s;}
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::WheelEvent & v) {s << (*(PIKbdListener::MouseEvent*)&v) << (uchar)v.direction; return s;}
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
BINARY_STREAM_WRITE(PIKbdListener::MouseEvent) {
|
||||
s << v.x << v.y << v.action << v.buttons << v.modifiers;
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
BINARY_STREAM_READ(PIKbdListener::MouseEvent) {
|
||||
s >> v.x >> v.y >> v.action >> v.buttons >> v.modifiers;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
BINARY_STREAM_WRITE(PIKbdListener::WheelEvent) {
|
||||
s << (*(PIKbdListener::MouseEvent *)&v) << v.direction;
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
BINARY_STREAM_READ(PIKbdListener::WheelEvent) {
|
||||
s >> (*(PIKbdListener::MouseEvent *)&v) >> v.direction;
|
||||
return s;
|
||||
}
|
||||
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::KeyEvent & v) {s >> v.key >> v.modifiers; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::MouseEvent & v) {int a(0); s >> v.x >> v.y >> a >> v.buttons >> v.modifiers; v.action = (PIKbdListener::MouseAction)a; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::WheelEvent & v) {uchar d(0); s >> (*(PIKbdListener::MouseEvent*)&v) >> d; v.direction = d; return s;}
|
||||
|
||||
REGISTER_PIVARIANTSIMPLE(PIKbdListener::KeyEvent)
|
||||
REGISTER_PIVARIANTSIMPLE(PIKbdListener::MouseEvent)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user