version 1.22.0
source tree changed detached PIConsole and PIScreen* in "pip_console" library
This commit is contained in:
25
lib/cloud/piccloudclient.cpp
Normal file
25
lib/cloud/piccloudclient.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
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 "piccloudclient.h"
|
||||
|
||||
|
||||
PICloudClient::PICloudClient() {
|
||||
}
|
||||
|
||||
25
lib/cloud/piccloudserver.cpp
Normal file
25
lib/cloud/piccloudserver.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
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 "piccloudserver.h"
|
||||
|
||||
|
||||
PICloudServer::PICloudServer() {
|
||||
}
|
||||
|
||||
28
lib/cloud/piccloudtcp.cpp
Normal file
28
lib/cloud/piccloudtcp.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
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 "piccloudtcp.h"
|
||||
#include "picrypt.h"
|
||||
|
||||
const char hash_def_key[] = "_picrypt_";
|
||||
|
||||
|
||||
PICloudTCP::PICloudTCP() {
|
||||
}
|
||||
|
||||
76
lib/compress/picompress.cpp
Normal file
76
lib/compress/picompress.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Compress class using zlib
|
||||
Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picompress.h"
|
||||
#ifdef PIP_COMPRESS
|
||||
# ifdef FREERTOS
|
||||
# include "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;
|
||||
}
|
||||
74
lib/concurrent/executor.cpp
Normal file
74
lib/concurrent/executor.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
|
||||
Stephan Fomenko
|
||||
|
||||
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 "executor.h"
|
||||
|
||||
|
||||
PIThreadPoolExecutor::PIThreadPoolExecutor(size_t corePoolSize, PIBlockingDequeue<std::function<void()>> *taskQueue_) : isShutdown_(false), taskQueue(taskQueue_) {
|
||||
for (size_t i = 0; i < corePoolSize; ++i) {
|
||||
PIThread * thread = new PIThread([&, i](){
|
||||
auto runnable = taskQueue->poll(100, std::function<void()>());
|
||||
if (runnable) {
|
||||
runnable();
|
||||
}
|
||||
if (isShutdown_ && taskQueue->size() == 0) threadPool[i]->stop();
|
||||
});
|
||||
threadPool.push_back(thread);
|
||||
thread->start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PIThreadPoolExecutor::awaitTermination(int timeoutMs) {
|
||||
PITimeMeasurer measurer;
|
||||
for (size_t i = 0; i < threadPool.size(); ++i) {
|
||||
int dif = timeoutMs - (int)measurer.elapsed_m();
|
||||
if (dif < 0) return false;
|
||||
if (!threadPool[i]->waitForFinish(dif)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIThreadPoolExecutor::shutdownNow() {
|
||||
isShutdown_ = true;
|
||||
for (size_t i = 0; i < threadPool.size(); ++i) threadPool[i]->stop();
|
||||
}
|
||||
|
||||
|
||||
PIThreadPoolExecutor::~PIThreadPoolExecutor() {
|
||||
shutdownNow();
|
||||
while (threadPool.size() > 0) delete threadPool.take_back();
|
||||
delete taskQueue;
|
||||
}
|
||||
|
||||
|
||||
void PIThreadPoolExecutor::execute(const std::function<void()> &runnable) {
|
||||
if (!isShutdown_) taskQueue->offer(runnable);
|
||||
}
|
||||
|
||||
|
||||
volatile bool PIThreadPoolExecutor::isShutdown() const {
|
||||
return isShutdown_;
|
||||
}
|
||||
|
||||
|
||||
void PIThreadPoolExecutor::shutdown() {
|
||||
isShutdown_ = true;
|
||||
}
|
||||
108
lib/concurrent/piconditionlock.cpp
Normal file
108
lib/concurrent/piconditionlock.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
|
||||
Stephan Fomenko
|
||||
|
||||
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 "piconditionlock.h"
|
||||
#ifdef WINDOWS
|
||||
#include "synchapi.h"
|
||||
#else
|
||||
#include "pthread.h"
|
||||
#endif
|
||||
|
||||
|
||||
PRIVATE_DEFINITION_START(PIConditionLock)
|
||||
#ifdef WINDOWS
|
||||
CRITICAL_SECTION
|
||||
#else
|
||||
pthread_mutex_t
|
||||
#endif
|
||||
nativeHandle;
|
||||
PRIVATE_DEFINITION_END(PIConditionLock)
|
||||
|
||||
|
||||
#ifdef WINDOWS
|
||||
PIConditionLock::PIConditionLock() {
|
||||
InitializeCriticalSection(&PRIVATE->nativeHandle);
|
||||
}
|
||||
|
||||
|
||||
PIConditionLock::~PIConditionLock() {
|
||||
DeleteCriticalSection(&PRIVATE->nativeHandle);
|
||||
}
|
||||
|
||||
|
||||
void PIConditionLock::lock() {
|
||||
EnterCriticalSection(&PRIVATE->nativeHandle);
|
||||
}
|
||||
|
||||
|
||||
void PIConditionLock::unlock() {
|
||||
LeaveCriticalSection(&PRIVATE->nativeHandle);
|
||||
}
|
||||
|
||||
|
||||
void *PIConditionLock::handle() {
|
||||
return &PRIVATE->nativeHandle;
|
||||
}
|
||||
|
||||
|
||||
bool PIConditionLock::tryLock() {
|
||||
return TryEnterCriticalSection(&PRIVATE->nativeHandle) != 0;
|
||||
}
|
||||
#else
|
||||
|
||||
|
||||
PIConditionLock::PIConditionLock() {
|
||||
pthread_mutexattr_t attr;
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
memset(&(PRIVATE->nativeHandle), 0, sizeof(PRIVATE->nativeHandle));
|
||||
pthread_mutex_init(&(PRIVATE->nativeHandle), &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
|
||||
|
||||
PIConditionLock::~PIConditionLock() {
|
||||
pthread_mutex_destroy(&(PRIVATE->nativeHandle));
|
||||
}
|
||||
|
||||
|
||||
void PIConditionLock::lock() {
|
||||
pthread_mutex_lock(&(PRIVATE->nativeHandle));
|
||||
}
|
||||
|
||||
|
||||
void PIConditionLock::unlock() {
|
||||
pthread_mutex_unlock(&(PRIVATE->nativeHandle));
|
||||
}
|
||||
|
||||
|
||||
void *PIConditionLock::handle() {
|
||||
return &PRIVATE->nativeHandle;
|
||||
}
|
||||
|
||||
|
||||
bool PIConditionLock::tryLock() {
|
||||
return (pthread_mutex_trylock(&(PRIVATE->nativeHandle)) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
142
lib/concurrent/piconditionvar.cpp
Normal file
142
lib/concurrent/piconditionvar.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
|
||||
Stephan Fomenko
|
||||
|
||||
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 "piplatform.h"
|
||||
#include "piconditionvar.h"
|
||||
#include "pithread.h"
|
||||
#include "pitime.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#include "synchapi.h"
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
|
||||
PRIVATE_DEFINITION_START(PIConditionVariable)
|
||||
#ifdef WINDOWS
|
||||
CONDITION_VARIABLE nativeHandle;
|
||||
#else
|
||||
pthread_cond_t nativeHandle;
|
||||
PIConditionLock* currentLock;
|
||||
#endif
|
||||
bool isDestroying;
|
||||
PRIVATE_DEFINITION_END(PIConditionVariable)
|
||||
|
||||
|
||||
PIConditionVariable::PIConditionVariable() {
|
||||
#ifdef WINDOWS
|
||||
InitializeConditionVariable(&PRIVATE->nativeHandle);
|
||||
#else
|
||||
PRIVATE->isDestroying = false;
|
||||
PRIVATE->currentLock = nullptr;
|
||||
memset(&(PRIVATE->nativeHandle), 0, sizeof(PRIVATE->nativeHandle));
|
||||
pthread_cond_init(&PRIVATE->nativeHandle, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PIConditionVariable::~PIConditionVariable() {
|
||||
#ifdef WINDOWS
|
||||
#else
|
||||
pthread_cond_destroy(&PRIVATE->nativeHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIConditionVariable::wait(PIConditionLock& lk) {
|
||||
#ifdef WINDOWS
|
||||
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE);
|
||||
#else
|
||||
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIConditionVariable::wait(PIConditionLock& lk, const std::function<bool()>& condition) {
|
||||
bool isCondition;
|
||||
while (true) {
|
||||
isCondition = condition();
|
||||
if (isCondition) break;
|
||||
#ifdef WINDOWS
|
||||
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE);
|
||||
#else
|
||||
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
|
||||
#endif
|
||||
if (PRIVATE->isDestroying) return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PIConditionVariable::waitFor(PIConditionLock &lk, int timeoutMs) {
|
||||
bool isNotTimeout;
|
||||
#ifdef WINDOWS
|
||||
isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs) != 0;
|
||||
#else
|
||||
timespec abstime = {.tv_sec = timeoutMs / 1000, .tv_nsec = timeoutMs * 1000 * 1000};
|
||||
isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &abstime) == 0;
|
||||
#endif
|
||||
if (PRIVATE->isDestroying) return false;
|
||||
return isNotTimeout;
|
||||
}
|
||||
|
||||
|
||||
bool PIConditionVariable::waitFor(PIConditionLock& lk, int timeoutMs, const std::function<bool()> &condition) {
|
||||
bool isCondition;
|
||||
PITimeMeasurer measurer;
|
||||
while (true) {
|
||||
isCondition = condition();
|
||||
if (isCondition) break;
|
||||
#ifdef WINDOWS
|
||||
WINBOOL isTimeout = SleepConditionVariableCS(
|
||||
&PRIVATE->nativeHandle,
|
||||
(PCRITICAL_SECTION)lk.handle(),
|
||||
timeoutMs - (int)measurer.elapsed_m());
|
||||
if (isTimeout == 0) return false;
|
||||
#else
|
||||
int timeoutCurr = timeoutMs - (int)measurer.elapsed_m();
|
||||
timespec abstime = {.tv_sec = timeoutCurr / 1000, .tv_nsec = timeoutCurr * 1000 * 1000};
|
||||
bool isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &abstime) == 0;
|
||||
if (isTimeout) return false;
|
||||
#endif
|
||||
if (PRIVATE->isDestroying) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIConditionVariable::notifyOne() {
|
||||
#ifdef WINDOWS
|
||||
WakeConditionVariable(&PRIVATE->nativeHandle);
|
||||
#else
|
||||
pthread_cond_signal(&PRIVATE->nativeHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIConditionVariable::notifyAll() {
|
||||
#ifdef WINDOWS
|
||||
WakeAllConditionVariable(&PRIVATE->nativeHandle);
|
||||
#else
|
||||
pthread_cond_broadcast(&PRIVATE->nativeHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
238
lib/concurrent/test/BlockingDequeueUnitTest.cpp
Normal file
238
lib/concurrent/test/BlockingDequeueUnitTest.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "piblockingdequeue.h"
|
||||
|
||||
class MockConditionVar: public PIConditionVariable {
|
||||
public:
|
||||
bool isWaitCalled = false;
|
||||
bool isWaitForCalled = false;
|
||||
bool isTrueCondition = false;
|
||||
int timeout = -1;
|
||||
|
||||
void wait(PIConditionLock& lk) override {
|
||||
isWaitCalled = true;
|
||||
}
|
||||
|
||||
void wait(PIConditionLock& lk, const std::function<bool()>& condition) override {
|
||||
isWaitCalled = true;
|
||||
lk.lock();
|
||||
isTrueCondition = condition();
|
||||
lk.unlock();
|
||||
}
|
||||
|
||||
bool waitFor(PIConditionLock& lk, int timeoutMs) override {
|
||||
isWaitForCalled = true;
|
||||
timeout = timeoutMs;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool waitFor(PIConditionLock& lk, int timeoutMs, const std::function<bool()>& condition) override {
|
||||
isWaitForCalled = true;
|
||||
lk.lock();
|
||||
isTrueCondition = condition();
|
||||
timeout = timeoutMs;
|
||||
lk.unlock();
|
||||
return isTrueCondition;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(BlockingDequeueUnitTest, put_is_block_when_capacity_reach) {
|
||||
size_t capacity = 0;
|
||||
auto conditionVarAdd = new MockConditionVar();
|
||||
auto conditionVarRem = new MockConditionVar();
|
||||
PIBlockingDequeue<int> dequeue(capacity, conditionVarAdd, conditionVarRem);
|
||||
dequeue.put(11);
|
||||
ASSERT_TRUE(conditionVarRem->isWaitCalled);
|
||||
ASSERT_FALSE(conditionVarRem->isTrueCondition);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, offer_timedout_is_false_when_capacity_reach) {
|
||||
size_t capacity = 0;
|
||||
int timeout = 11;
|
||||
auto conditionVarAdd = new MockConditionVar();
|
||||
auto conditionVarRem = new MockConditionVar();
|
||||
PIBlockingDequeue<int> dequeue(capacity, conditionVarAdd, conditionVarRem);
|
||||
ASSERT_FALSE(dequeue.offer(11, timeout));
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, offer_timedout_is_block_when_capacity_reach) {
|
||||
size_t capacity = 0;
|
||||
int timeout = 11;
|
||||
auto conditionVarAdd = new MockConditionVar();
|
||||
auto conditionVarRem = new MockConditionVar();
|
||||
PIBlockingDequeue<int> dequeue(capacity, conditionVarAdd, conditionVarRem);
|
||||
dequeue.offer(11, timeout);
|
||||
EXPECT_TRUE(conditionVarRem->isWaitForCalled);
|
||||
EXPECT_EQ(timeout, conditionVarRem->timeout);
|
||||
ASSERT_FALSE(conditionVarRem->isTrueCondition);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, offer_is_true_before_capacity_reach) {
|
||||
size_t capacity = 1;
|
||||
PIBlockingDequeue<int> dequeue(capacity);
|
||||
ASSERT_TRUE(dequeue.offer(10));
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, offer_is_false_when_capacity_reach) {
|
||||
size_t capacity = 1;
|
||||
PIBlockingDequeue<int> dequeue(capacity);
|
||||
dequeue.offer(11);
|
||||
ASSERT_FALSE(dequeue.offer(10));
|
||||
}
|
||||
|
||||
// TODO change take_is_block_when_empty to prevent segfault
|
||||
TEST(DISABLED_BlockingDequeueUnitTest, take_is_block_when_empty) {
|
||||
size_t capacity = 1;
|
||||
auto conditionVar = new MockConditionVar();
|
||||
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
|
||||
// May cause segfault because take front of empty queue
|
||||
dequeue.take();
|
||||
EXPECT_TRUE(conditionVar->isWaitCalled);
|
||||
ASSERT_FALSE(conditionVar->isTrueCondition);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, take_is_not_block_when_not_empty) {
|
||||
size_t capacity = 1;
|
||||
auto conditionVar = new MockConditionVar();
|
||||
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
|
||||
dequeue.offer(111);
|
||||
dequeue.take();
|
||||
|
||||
EXPECT_TRUE(conditionVar->isWaitCalled);
|
||||
ASSERT_TRUE(conditionVar->isTrueCondition);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, take_is_value_eq_to_offer_value) {
|
||||
size_t capacity = 1;
|
||||
auto conditionVar = new MockConditionVar();
|
||||
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
|
||||
|
||||
dequeue.offer(111);
|
||||
ASSERT_EQ(dequeue.take(), 111);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, take_is_last) {
|
||||
size_t capacity = 10;
|
||||
auto conditionVar = new MockConditionVar();
|
||||
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
|
||||
EXPECT_TRUE(dequeue.offer(111));
|
||||
EXPECT_TRUE(dequeue.offer(222));
|
||||
ASSERT_EQ(dequeue.take(), 111);
|
||||
ASSERT_EQ(dequeue.take(), 222);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, poll_is_block_when_empty) {
|
||||
size_t capacity = 1;
|
||||
int timeout = 11;
|
||||
auto conditionVar = new MockConditionVar();
|
||||
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
|
||||
dequeue.poll(timeout, 111);
|
||||
EXPECT_TRUE(conditionVar->isWaitForCalled);
|
||||
EXPECT_EQ(timeout, conditionVar->timeout);
|
||||
ASSERT_FALSE(conditionVar->isTrueCondition);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, poll_is_default_value_when_empty) {
|
||||
size_t capacity = 1;
|
||||
int timeout = 11;
|
||||
auto conditionVar = new MockConditionVar();
|
||||
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
|
||||
ASSERT_EQ(dequeue.poll(timeout, 111), 111);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, poll_is_not_block_when_not_empty) {
|
||||
size_t capacity = 1;
|
||||
int timeout = 11;
|
||||
auto conditionVar = new MockConditionVar();
|
||||
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
|
||||
dequeue.offer(111);
|
||||
dequeue.poll(timeout, -1);
|
||||
|
||||
EXPECT_TRUE(conditionVar->isWaitForCalled);
|
||||
ASSERT_TRUE(conditionVar->isTrueCondition);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, poll_is_offer_value_when_not_empty) {
|
||||
size_t capacity = 1;
|
||||
int timeout = 11;
|
||||
auto conditionVar = new MockConditionVar();
|
||||
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
|
||||
dequeue.offer(111);
|
||||
ASSERT_EQ(dequeue.poll(timeout, -1), 111);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, poll_is_last) {
|
||||
size_t capacity = 10;
|
||||
auto conditionVar = new MockConditionVar();
|
||||
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
|
||||
dequeue.offer(111);
|
||||
dequeue.offer(222);
|
||||
ASSERT_EQ(dequeue.poll(10, -1), 111);
|
||||
ASSERT_EQ(dequeue.poll(10, -1), 222);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, capacity_is_eq_constructor_capacity) {
|
||||
size_t capacity = 10;
|
||||
PIBlockingDequeue<int> dequeue(capacity);
|
||||
ASSERT_EQ(dequeue.capacity(), capacity);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, remainingCapacity_is_dif_of_capacity_and_size) {
|
||||
size_t capacity = 2;
|
||||
PIBlockingDequeue<int> dequeue(capacity);
|
||||
ASSERT_EQ(dequeue.remainingCapacity(), capacity);
|
||||
dequeue.offer(111);
|
||||
ASSERT_EQ(dequeue.remainingCapacity(), capacity - 1);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, remainingCapacity_is_zero_when_capacity_reach) {
|
||||
size_t capacity = 1;
|
||||
PIBlockingDequeue<int> dequeue(capacity);
|
||||
dequeue.offer(111);
|
||||
dequeue.offer(111);
|
||||
ASSERT_EQ(dequeue.remainingCapacity(), 0);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, size_is_eq_to_num_of_elements) {
|
||||
size_t capacity = 1;
|
||||
PIBlockingDequeue<int> dequeue(capacity);
|
||||
ASSERT_EQ(dequeue.size(), 0);
|
||||
dequeue.offer(111);
|
||||
ASSERT_EQ(dequeue.size(), 1);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, size_is_eq_to_capacity_when_capacity_reach) {
|
||||
size_t capacity = 1;
|
||||
PIBlockingDequeue<int> dequeue(capacity);
|
||||
dequeue.offer(111);
|
||||
dequeue.offer(111);
|
||||
ASSERT_EQ(dequeue.size(), capacity);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, drainTo_is_elements_moved) {
|
||||
size_t capacity = 10;
|
||||
PIDeque<int> refDeque;
|
||||
for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10);
|
||||
PIBlockingDequeue<int> blockingDequeue(refDeque);
|
||||
PIDeque<int> deque;
|
||||
blockingDequeue.drainTo(deque);
|
||||
ASSERT_EQ(blockingDequeue.size(), 0);
|
||||
ASSERT_TRUE(deque == refDeque);
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, drainTo_is_ret_eq_to_size_when_all_moved) {
|
||||
size_t capacity = 10;
|
||||
PIDeque<int> refDeque;
|
||||
for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10);
|
||||
PIBlockingDequeue<int> blockingDequeue(refDeque);
|
||||
PIDeque<int> deque;
|
||||
ASSERT_EQ(blockingDequeue.drainTo(deque), refDeque.size());
|
||||
}
|
||||
|
||||
TEST(BlockingDequeueUnitTest, drainTo_is_ret_eq_to_maxCount) {
|
||||
size_t capacity = 10;
|
||||
PIDeque<int> refDeque;
|
||||
for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10);
|
||||
PIBlockingDequeue<int> blockingDequeue(refDeque);
|
||||
PIDeque<int> deque;
|
||||
ASSERT_EQ(blockingDequeue.drainTo(deque, refDeque.size() - 1), refDeque.size() - 1);
|
||||
}
|
||||
53
lib/concurrent/test/ConditionLockIntegrationTest.cpp
Normal file
53
lib/concurrent/test/ConditionLockIntegrationTest.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
#include "piconditionvar.h"
|
||||
#include <pithread.h>
|
||||
#include "testutil.h"
|
||||
|
||||
class ConditionLock : public ::testing::Test, public TestUtil {
|
||||
public:
|
||||
PIConditionLock* m = new PIConditionLock();
|
||||
};
|
||||
|
||||
TEST_F(ConditionLock, lock_is_protect) {
|
||||
m->lock();
|
||||
bool* isProtect = new bool(true);
|
||||
|
||||
createThread([&](){
|
||||
m->lock();
|
||||
*isProtect = false;
|
||||
});
|
||||
EXPECT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
|
||||
ASSERT_TRUE(*isProtect);
|
||||
}
|
||||
|
||||
TEST_F(ConditionLock, unlock_is_release) {
|
||||
m->lock();
|
||||
bool* isReleased = new bool(false);
|
||||
m->unlock();
|
||||
|
||||
createThread([&](){
|
||||
m->lock();
|
||||
*isReleased = true;
|
||||
m->unlock();
|
||||
});
|
||||
ASSERT_TRUE(*isReleased);
|
||||
}
|
||||
|
||||
TEST_F(ConditionLock, tryLock_is_false_when_locked) {
|
||||
createThread([&](){
|
||||
m->lock();
|
||||
piMSleep(WAIT_THREAD_TIME_MS);
|
||||
});
|
||||
ASSERT_FALSE(m->tryLock());
|
||||
}
|
||||
|
||||
TEST_F(ConditionLock, tryLock_is_true_when_unlocked) {
|
||||
ASSERT_TRUE(m->tryLock());
|
||||
}
|
||||
|
||||
TEST_F(ConditionLock, tryLock_is_recursive_lock_enable) {
|
||||
m->lock();
|
||||
ASSERT_TRUE(m->tryLock());
|
||||
}
|
||||
200
lib/concurrent/test/ConditionVariableIntegrationTest.cpp
Normal file
200
lib/concurrent/test/ConditionVariableIntegrationTest.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "piconditionvar.h"
|
||||
#include "pithread.h"
|
||||
#include "testutil.h"
|
||||
|
||||
class ConditionVariable : public ::testing::Test, public TestUtil {
|
||||
public:
|
||||
PIConditionLock m;
|
||||
PIConditionVariable* variable;
|
||||
|
||||
protected:
|
||||
void SetUp() override {
|
||||
variable = new PIConditionVariable();
|
||||
adapterFunctionDefault = [&](){
|
||||
m.lock();
|
||||
variable->wait(m);
|
||||
m.unlock();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ConditionVariable, wait_is_block) {
|
||||
createThread();
|
||||
ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariable, wait_is_block_when_notifyOne_before_wait) {
|
||||
variable->notifyOne();
|
||||
createThread();
|
||||
ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariable, wait_is_block_when_notifyAll_before_wait) {
|
||||
variable->notifyAll();
|
||||
createThread();
|
||||
ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariable, wait_is_unblock_when_notifyOne_after_wait) {
|
||||
createThread();
|
||||
variable->notifyOne();
|
||||
ASSERT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariable, wait_is_unblock_when_notifyAll_after_wait) {
|
||||
PIVector<PIThread*> threads;
|
||||
|
||||
for (int i = 0; i < THREAD_COUNT; ++i) {
|
||||
threads.push_back(new PIThread([=](){ adapterFunctionDefault(); }));
|
||||
}
|
||||
|
||||
piForeach(PIThread* thread, threads) thread->startOnce();
|
||||
piMSleep(WAIT_THREAD_TIME_MS * THREAD_COUNT);
|
||||
variable->notifyAll();
|
||||
PITimeMeasurer measurer;
|
||||
piForeach(PIThread* thread, threads) {
|
||||
int timeout = WAIT_THREAD_TIME_MS * THREAD_COUNT - (int)measurer.elapsed_m();
|
||||
thread->waitForFinish(timeout > 0 ? timeout : 0);
|
||||
}
|
||||
for (size_t i = 0; i < threads.size(); ++i) EXPECT_FALSE(threads[i]->isRunning()) << "Thread " << i << " still running";
|
||||
piForeach(PIThread* thread, threads) delete thread;
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariable, wait_is_one_unblock_when_notifyOne) {
|
||||
PIVector<PIThread*> threads;
|
||||
|
||||
for (int i = 0; i < THREAD_COUNT; ++i) {
|
||||
threads.push_back(new PIThread(adapterFunctionDefault));
|
||||
}
|
||||
|
||||
piForeach(PIThread* thread, threads) thread->startOnce();
|
||||
piMSleep(WAIT_THREAD_TIME_MS * THREAD_COUNT);
|
||||
variable->notifyOne();
|
||||
piMSleep(WAIT_THREAD_TIME_MS * THREAD_COUNT);
|
||||
int runningThreadCount = 0;
|
||||
piForeach(PIThread* thread, threads) if (thread->isRunning()) runningThreadCount++;
|
||||
ASSERT_EQ(runningThreadCount, THREAD_COUNT - 1);
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariable, wait_is_protected_unblock_when_notifyOne) {
|
||||
createThread([&](){
|
||||
m.lock();
|
||||
variable->wait(m);
|
||||
piMSleep(2 * WAIT_THREAD_TIME_MS);
|
||||
// Missing unlock
|
||||
});
|
||||
variable->notifyOne();
|
||||
msleep(WAIT_THREAD_TIME_MS);
|
||||
ASSERT_FALSE(m.tryLock());
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariable, wait_condition_is_block) {
|
||||
createThread([&](){
|
||||
m.lock();
|
||||
variable->wait(m, [](){ return false; });
|
||||
m.unlock();
|
||||
});
|
||||
ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariable, wait_condition_is_check_condition_before_block) {
|
||||
bool isConditionChecked = false;
|
||||
createThread([&](){
|
||||
m.lock();
|
||||
variable->wait(m, [&](){
|
||||
isConditionChecked = true;
|
||||
return false;
|
||||
});
|
||||
m.unlock();
|
||||
});
|
||||
m.lock();
|
||||
ASSERT_TRUE(isConditionChecked);
|
||||
m.unlock();
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariable, wait_condition_is_check_condition_when_notifyOne) {
|
||||
bool isConditionChecked;
|
||||
createThread([&](){
|
||||
m.lock();
|
||||
variable->wait(m, [&](){
|
||||
isConditionChecked = true;
|
||||
return false;
|
||||
});
|
||||
m.unlock();
|
||||
});
|
||||
m.lock();
|
||||
isConditionChecked = false;
|
||||
m.unlock();
|
||||
variable->notifyOne();
|
||||
msleep(threadStartTime + 1);
|
||||
m.lock();
|
||||
ASSERT_TRUE(isConditionChecked);
|
||||
m.unlock();
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariable, wait_condition_is_unblock_when_condition_and_notifyOne) {
|
||||
bool condition = false;
|
||||
createThread([&](){
|
||||
m.lock();
|
||||
variable->wait(m, [&](){ return condition; });
|
||||
m.unlock();
|
||||
});
|
||||
m.lock();
|
||||
condition = true;
|
||||
m.unlock();
|
||||
variable->notifyOne();
|
||||
ASSERT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariable, DISABLED_waitFor_is_block_before_timeout) {
|
||||
createThread([&](){
|
||||
PITimeMeasurer measurer;
|
||||
m.lock();
|
||||
variable->waitFor(m, WAIT_THREAD_TIME_MS * 2);
|
||||
m.unlock();
|
||||
// Not reliable because spurious wakeup may happen
|
||||
ASSERT_GE(measurer.elapsed_m(), WAIT_THREAD_TIME_MS);
|
||||
});
|
||||
EXPECT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS * 3));
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariable, waitFor_is_unblock_when_timeout) {
|
||||
volatile bool isUnblock = false;
|
||||
createThread([&](){
|
||||
m.lock();
|
||||
variable->waitFor(m, WAIT_THREAD_TIME_MS);
|
||||
isUnblock = true;
|
||||
m.unlock();
|
||||
});
|
||||
// Test failed if suspend forever
|
||||
EXPECT_TRUE(thread->waitForFinish(2 * WAIT_THREAD_TIME_MS));
|
||||
ASSERT_TRUE(isUnblock);
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariable, waitFor_is_false_when_timeout) {
|
||||
bool waitRet = true;
|
||||
createThread([&](){
|
||||
m.lock();
|
||||
waitRet = variable->waitFor(m, WAIT_THREAD_TIME_MS);
|
||||
m.unlock();
|
||||
});
|
||||
EXPECT_TRUE(thread->waitForFinish(2 * WAIT_THREAD_TIME_MS));
|
||||
ASSERT_FALSE(waitRet);
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariable, waitFor_is_unblock_when_condition_and_notifyOne) {
|
||||
bool condition = false;
|
||||
createThread([&](){
|
||||
m.lock();
|
||||
variable->waitFor(m, 3 * WAIT_THREAD_TIME_MS, [&](){ return condition; });
|
||||
m.unlock();
|
||||
});
|
||||
EXPECT_TRUE(thread->isRunning());
|
||||
m.lock();
|
||||
condition = true;
|
||||
m.unlock();
|
||||
variable->notifyOne();
|
||||
msleep(WAIT_THREAD_TIME_MS);
|
||||
ASSERT_FALSE(thread->isRunning());
|
||||
}
|
||||
54
lib/concurrent/test/ExecutorIntegrationTest.cpp
Normal file
54
lib/concurrent/test/ExecutorIntegrationTest.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "executor.h"
|
||||
#include "pimutex.h"
|
||||
|
||||
const int WAIT_THREAD_TIME_MS = 30;
|
||||
|
||||
TEST(ExcutorIntegrationTest, execute_is_runnable_invoke) {
|
||||
PIMutex m;
|
||||
int invokedRunnables = 0;
|
||||
PIThreadPoolExecutor executorService(1);
|
||||
executorService.execute([&]() {
|
||||
m.lock();
|
||||
invokedRunnables++;
|
||||
m.unlock();
|
||||
});
|
||||
piMSleep(WAIT_THREAD_TIME_MS);
|
||||
ASSERT_EQ(invokedRunnables, 1);
|
||||
}
|
||||
|
||||
TEST(ExcutorIntegrationTest, execute_is_not_execute_after_shutdown) {
|
||||
bool isRunnableInvoke = false;
|
||||
PIThreadPoolExecutor executorService(1);
|
||||
executorService.shutdown();
|
||||
executorService.execute([&]() {
|
||||
isRunnableInvoke = true;
|
||||
});
|
||||
piMSleep(WAIT_THREAD_TIME_MS);
|
||||
ASSERT_FALSE(isRunnableInvoke);
|
||||
}
|
||||
|
||||
TEST(ExcutorIntegrationTest, execute_is_execute_before_shutdown) {
|
||||
bool isRunnableInvoke = false;
|
||||
PIThreadPoolExecutor executorService(1);
|
||||
executorService.execute([&]() {
|
||||
piMSleep(WAIT_THREAD_TIME_MS);
|
||||
isRunnableInvoke = true;
|
||||
});
|
||||
executorService.shutdown();
|
||||
piMSleep(2 * WAIT_THREAD_TIME_MS);
|
||||
ASSERT_TRUE(isRunnableInvoke);
|
||||
}
|
||||
|
||||
TEST(ExcutorIntegrationTest, execute_is_awaitTermination_wait) {
|
||||
PIThreadPoolExecutor executorService(1);
|
||||
executorService.execute([&]() {
|
||||
piMSleep(2 * WAIT_THREAD_TIME_MS);
|
||||
});
|
||||
executorService.shutdown();
|
||||
PITimeMeasurer measurer;
|
||||
ASSERT_TRUE(executorService.awaitTermination(3 * WAIT_THREAD_TIME_MS));
|
||||
double waitTime = measurer.elapsed_m();
|
||||
ASSERT_GE(waitTime, WAIT_THREAD_TIME_MS);
|
||||
ASSERT_LE(waitTime, 4 * WAIT_THREAD_TIME_MS);
|
||||
}
|
||||
57
lib/concurrent/test/testutil.h
Normal file
57
lib/concurrent/test/testutil.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef AWRCANFLASHER_TESTUTIL_H
|
||||
#define AWRCANFLASHER_TESTUTIL_H
|
||||
|
||||
#include "pithread.h"
|
||||
|
||||
/**
|
||||
* Minimum wait thread start, switch context or another interthread communication action time. Increase it if tests
|
||||
* write "Start thread timeout reach!" message. You can reduce it if you want increase test performance.
|
||||
*/
|
||||
const int WAIT_THREAD_TIME_MS = 40;
|
||||
|
||||
const int THREAD_COUNT = 5;
|
||||
|
||||
class TestUtil: public PIObject {
|
||||
PIOBJECT(TestUtil)
|
||||
public:
|
||||
double threadStartTime;
|
||||
PIThread* thread = new PIThread();
|
||||
volatile bool isRunning = false;
|
||||
std::function<void()> adapterFunctionDefault;
|
||||
|
||||
bool createThread(const std::function<void()>& fun = nullptr, PIThread* thread_ = nullptr) {
|
||||
std::function<void()> actualFun = fun == nullptr ? adapterFunctionDefault : fun;
|
||||
if (thread_ == nullptr) thread_ = thread;
|
||||
thread_->startOnce([=](void*){
|
||||
isRunning = true;
|
||||
actualFun();
|
||||
});
|
||||
return waitThread(thread_);
|
||||
}
|
||||
|
||||
bool waitThread(PIThread* thread_, bool runningStatus = true) {
|
||||
PITimeMeasurer measurer;
|
||||
bool isTimeout = !thread_->waitForStart(WAIT_THREAD_TIME_MS);
|
||||
while (!isRunning) {
|
||||
isTimeout = WAIT_THREAD_TIME_MS <= measurer.elapsed_m();
|
||||
if (isTimeout) break;
|
||||
piUSleep(100);
|
||||
}
|
||||
|
||||
threadStartTime = measurer.elapsed_m();
|
||||
|
||||
if (isTimeout) piCout << "Start thread timeout reach!";
|
||||
|
||||
if (threadStartTime > 1) {
|
||||
piCout << "Start time" << threadStartTime << "ms";
|
||||
} else if (threadStartTime > 0.001) {
|
||||
piCout << "Start time" << threadStartTime * 1000 << "mcs";
|
||||
} else {
|
||||
piCout << "Start time" << threadStartTime * 1000 * 1000 << "ns";
|
||||
}
|
||||
|
||||
return !isTimeout;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //AWRCANFLASHER_TESTUTIL_H
|
||||
1168
lib/console/piconsole.cpp
Normal file
1168
lib/console/piconsole.cpp
Normal file
@@ -0,0 +1,1168 @@
|
||||
/*
|
||||
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 distributed in the hope that 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 "piconsole.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "pipeer.h"
|
||||
#include "pidiagnostics.h"
|
||||
#include "pisystemmonitor.h"
|
||||
#ifndef WINDOWS
|
||||
# include <sys/ioctl.h>
|
||||
# include <fcntl.h>
|
||||
# include <termios.h>
|
||||
#else
|
||||
# include <wincon.h>
|
||||
# define COMMON_LVB_UNDERSCORE 0x8000
|
||||
#endif
|
||||
|
||||
|
||||
/** \class PIConsole
|
||||
* \brief Console output class
|
||||
* \details
|
||||
* \section PIConsole_sec0 Synopsis
|
||||
* This class provides output to console with automatic alignment and update.
|
||||
* It supports tabs, keyboard listening, formats and colors.
|
||||
*
|
||||
* \section PIConsole_sec1 Layout
|
||||
* %PIConsole works with variable pointers. You should add your variables with
|
||||
* functions \a addVariable() which receives label name, pointer to variable
|
||||
* and optional column and format. Columns count is dynamically increased if
|
||||
* new column used. E.g. if you add variable to empty tab to column 3, columns
|
||||
* count will be increased to 3, but two firsts columns will be empty. Each column
|
||||
* filled from top to bottom, but you can add just string with function
|
||||
* \a addString() or add empty line with function \a addEmptyLine(). Layout scheme:
|
||||
* \image html piconsole_layout.png
|
||||
*
|
||||
* \section PIConsole_sec2 Keyboard usage
|
||||
* %PIConsole should to be single in application. %PIConsole aggregate PIKbdListener
|
||||
* which grab keyboard and automatic switch tabs by theirs bind keys. If there is no
|
||||
* tab binded to pressed key external function "slot" will be called
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
PRIVATE_DEFINITION_START(PIConsole)
|
||||
#ifdef WINDOWS
|
||||
void getWinCurCoord() {GetConsoleScreenBufferInfo(hOut, &csbi); ccoord = csbi.dwCursorPosition;}
|
||||
COORD & getWinCoord(int dx = 0, int dy = 0) {getWinCurCoord(); ccoord.X += dx; ccoord.Y += dy; return ccoord;}
|
||||
void * hOut;
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi, csbi;
|
||||
CONSOLE_CURSOR_INFO curinfo;
|
||||
COORD ccoord, ulcoord;
|
||||
WORD dattr;
|
||||
DWORD smode, written;
|
||||
#endif
|
||||
PRIVATE_DEFINITION_END(PIConsole)
|
||||
|
||||
|
||||
PIConsole::PIConsole(bool startNow, PIKbdListener::KBFunc slot): PIThread() {
|
||||
setName("console");
|
||||
setPriority(piLow);
|
||||
needLockRun(true);
|
||||
ret_func = slot;
|
||||
num_format = systime_format = 0;
|
||||
vid = 0;
|
||||
cur_tab = width = height = pwidth = pheight = max_y = 0;
|
||||
def_align = Nothing;
|
||||
tabs.reserve(16);
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->ulcoord.X = 0;
|
||||
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
||||
PRIVATE->dattr = PRIVATE->sbi.wAttributes;
|
||||
width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
|
||||
height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
|
||||
PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top;
|
||||
GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode);
|
||||
GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
|
||||
#else
|
||||
# ifdef FREERTOS
|
||||
width = 80;
|
||||
height = 24;
|
||||
# else
|
||||
winsize ws;
|
||||
ioctl(0, TIOCGWINSZ, &ws);
|
||||
width = ws.ws_col;
|
||||
height = ws.ws_row;
|
||||
# endif
|
||||
#endif
|
||||
addTab("main");
|
||||
listener = new PIKbdListener(key_event, this);
|
||||
peer_timer = new PITimer();
|
||||
peer_timer->setName("__S__.PIConsole.peer_timer");
|
||||
peer = 0;
|
||||
server_mode = pause_ = false;
|
||||
state = Disconnected;
|
||||
peer_timer->addDelimiter(20);
|
||||
peer_timer->setName("__S__PIConsole::peer_timer");
|
||||
CONNECT2(void, void * , int, peer_timer, tickEvent, this, peerTimer);
|
||||
if (startNow) start();
|
||||
}
|
||||
|
||||
|
||||
PIConsole::~PIConsole() {
|
||||
stopPeer();
|
||||
if (isRunning())
|
||||
stop();
|
||||
clearTabs(false);
|
||||
delete listener;
|
||||
delete peer_timer;
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
|
||||
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int PIConsole::addTab(const PIString & name, char bind_key) {
|
||||
if (isRunning()) lock();
|
||||
tabs.push_back(Tab(name, bind_key));
|
||||
cur_tab = tabs.size() - 1;
|
||||
if (isRunning()) unlock();
|
||||
return tabs.size();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::removeTab(uint index) {
|
||||
if (index >= tabs.size()) return;
|
||||
if (isRunning()) lock();
|
||||
tabs.remove(index);
|
||||
if (cur_tab >= tabs.size()) cur_tab = tabs.size() - 1;
|
||||
if (isRunning()) unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::removeTab(const PIString & name) {
|
||||
uint index = tabs.size() + 1;
|
||||
for (uint i = 0; i < tabs.size(); ++i) {
|
||||
if (tabs[i].name == name) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
removeTab(index);
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::clearTab(uint index) {
|
||||
if (index >= tabs.size()) return;
|
||||
lock();
|
||||
tabs[index].columns.clear();
|
||||
if (cur_tab == index) {
|
||||
clearScreen();
|
||||
fillLabels();
|
||||
}
|
||||
if (cur_tab >= tabs.size()) cur_tab = tabs.size() - 1;
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::clearTab(const PIString & name) {
|
||||
uint index = tabs.size() + 1;
|
||||
for (uint i = 0; i < tabs.size(); ++i) {
|
||||
if (tabs[i].name == name) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
clearTab(index);
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::update() {
|
||||
lock();
|
||||
fillLabels();
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
bool PIConsole::setTab(uint index) {
|
||||
if (index >= tabs.size())
|
||||
return false;
|
||||
if (!isRunning()) {
|
||||
cur_tab = index;
|
||||
return true;
|
||||
}
|
||||
lock();
|
||||
PICout::__mutex__().lock();
|
||||
cur_tab = index;
|
||||
clearScreen();
|
||||
fillLabels();
|
||||
PICout::__mutex__().unlock();
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIConsole::setTab(const PIString & name) {
|
||||
uint index = tabs.size() + 1;
|
||||
for (uint i = 0; i < tabs.size(); ++i) {
|
||||
if (tabs[i].name == name) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return setTab(index);
|
||||
}
|
||||
|
||||
|
||||
bool PIConsole::setTabBindKey(uint index, char bind_key) {
|
||||
if (index >= tabs.size())
|
||||
return false;
|
||||
tabs[index].key = bind_key;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIConsole::setTabBindKey(const PIString & name, char bind_key) {
|
||||
uint index =tabs.size() + 1;
|
||||
for (uint i = 0; i < tabs.size(); ++i) {
|
||||
if (tabs[i].name == name) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return setTabBindKey(index, bind_key);
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::key_event(PIKbdListener::KeyEvent key, void * t) {
|
||||
PIConsole * p = (PIConsole * )t;
|
||||
int ct = p->cur_tab;
|
||||
if (key.key == PIKbdListener::LeftArrow) {
|
||||
do {
|
||||
ct--;
|
||||
if (ct < 0) return;
|
||||
} while (p->tabs[ct].key == 0);
|
||||
p->setTab(ct);
|
||||
return;
|
||||
}
|
||||
if (key.key == PIKbdListener::RightArrow) {
|
||||
do {
|
||||
ct++;
|
||||
if (ct >= p->tabs.size_s()) return;
|
||||
} while (p->tabs[ct].key == 0);
|
||||
p->setTab(ct);
|
||||
return;
|
||||
}
|
||||
for (uint i = 0; i < p->tabsCount(); ++i) {
|
||||
if (p->tabs[i].key == key.key) {
|
||||
p->setTab(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (p->ret_func != 0) p->ret_func(key, t);
|
||||
p->keyPressed(key, t);
|
||||
}
|
||||
|
||||
|
||||
int PIConsole::couts(const PIString & v) {
|
||||
return printf("%s", v.data());
|
||||
}
|
||||
|
||||
|
||||
int PIConsole::couts(const char * v) {
|
||||
return printf("%s", v);
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::clearVariables(bool clearScreen) {
|
||||
if (isRunning()) lock();
|
||||
if (clearScreen && isRunning()) {
|
||||
toUpperLeft();
|
||||
clearScreenLower();
|
||||
}
|
||||
columns().clear();
|
||||
if (isRunning()) unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::stop(bool clear) {
|
||||
PIThread::stop(true);
|
||||
if (clear) clearScreen();
|
||||
moveTo(0, max_y + 4);
|
||||
showCursor();
|
||||
couts(fstr(Normal));
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
|
||||
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
|
||||
#endif
|
||||
fflush(0);
|
||||
}
|
||||
|
||||
|
||||
PIString PIConsole::fstr(FormatFlags f) {
|
||||
num_format = systime_format = 0;
|
||||
if (f[PIConsole::Dec]) num_format = 0;
|
||||
if (f[PIConsole::Hex]) num_format = 1;
|
||||
if (f[PIConsole::Oct]) num_format = 2;
|
||||
if (f[PIConsole::Bin]) num_format = 4;
|
||||
if (f[PIConsole::Scientific]) num_format = 3;
|
||||
if (f[PIConsole::SystemTimeSplit]) systime_format = 0;
|
||||
if (f[PIConsole::SystemTimeSeconds]) systime_format = 1;
|
||||
|
||||
#ifdef WINDOWS
|
||||
WORD attr = 0;
|
||||
|
||||
if (f[PIConsole::Inverse]) {
|
||||
if (f[PIConsole::Red]) attr |= BACKGROUND_RED;
|
||||
if (f[PIConsole::Green]) attr |= BACKGROUND_GREEN;
|
||||
if (f[PIConsole::Blue]) attr |= BACKGROUND_BLUE;
|
||||
if (f[PIConsole::Yellow]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN);
|
||||
if (f[PIConsole::Magenta]) attr |= (BACKGROUND_RED | BACKGROUND_BLUE);
|
||||
if (f[PIConsole::Cyan]) attr |= (BACKGROUND_GREEN | BACKGROUND_BLUE);
|
||||
if (f[PIConsole::White]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
|
||||
if (f[PIConsole::BackRed]) attr |= FOREGROUND_RED;
|
||||
if (f[PIConsole::BackGreen]) attr |= FOREGROUND_GREEN;
|
||||
if (f[PIConsole::BackBlue]) attr |= FOREGROUND_BLUE;
|
||||
if (f[PIConsole::BackYellow]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN);
|
||||
if (f[PIConsole::BackMagenta]) attr |= (FOREGROUND_RED | FOREGROUND_BLUE);
|
||||
if (f[PIConsole::BackCyan]) attr |= (FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
if (f[PIConsole::BackWhite]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
if ((attr & BACKGROUND_RED) + (attr & BACKGROUND_GREEN) + (attr & BACKGROUND_BLUE) == 0)
|
||||
attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
||||
} else {
|
||||
if (f[PIConsole::Red]) attr |= FOREGROUND_RED;
|
||||
if (f[PIConsole::Green]) attr |= FOREGROUND_GREEN;
|
||||
if (f[PIConsole::Blue]) attr |= FOREGROUND_BLUE;
|
||||
if (f[PIConsole::Yellow]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN);
|
||||
if (f[PIConsole::Magenta]) attr |= (FOREGROUND_RED | FOREGROUND_BLUE);
|
||||
if (f[PIConsole::Cyan]) attr |= (FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
if (f[PIConsole::White]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
if (f[PIConsole::BackRed]) attr |= BACKGROUND_RED;
|
||||
if (f[PIConsole::BackGreen]) attr |= BACKGROUND_GREEN;
|
||||
if (f[PIConsole::BackBlue]) attr |= BACKGROUND_BLUE;
|
||||
if (f[PIConsole::BackYellow]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN);
|
||||
if (f[PIConsole::BackMagenta]) attr |= (BACKGROUND_RED | BACKGROUND_BLUE);
|
||||
if (f[PIConsole::BackCyan]) attr |= (BACKGROUND_GREEN | BACKGROUND_BLUE);
|
||||
if (f[PIConsole::BackWhite]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
|
||||
if ((attr & FOREGROUND_RED) + (attr & FOREGROUND_GREEN) + (attr & FOREGROUND_BLUE) == 0)
|
||||
attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
||||
}
|
||||
if (f[PIConsole::Bold]) attr |= FOREGROUND_INTENSITY;
|
||||
if (f[PIConsole::Underline]) attr |= COMMON_LVB_UNDERSCORE;
|
||||
|
||||
SetConsoleTextAttribute(PRIVATE->hOut, attr);
|
||||
return PIString();
|
||||
#else
|
||||
PIString ts("\e[0");
|
||||
|
||||
if (f[PIConsole::Bold]) ts += ";1";
|
||||
if (f[PIConsole::Faint]) ts += ";2";
|
||||
if (f[PIConsole::Italic]) ts += ";3";
|
||||
if (f[PIConsole::Underline]) ts += ";4";
|
||||
if (f[PIConsole::Blink]) ts += ";5";
|
||||
if (f[PIConsole::Inverse]) ts += ";7";
|
||||
|
||||
if (f[PIConsole::Black]) ts += ";30";
|
||||
if (f[PIConsole::Red]) ts += ";31";
|
||||
if (f[PIConsole::Green]) ts += ";32";
|
||||
if (f[PIConsole::Yellow]) ts += ";33";
|
||||
if (f[PIConsole::Blue]) ts += ";34";
|
||||
if (f[PIConsole::Magenta]) ts += ";35";
|
||||
if (f[PIConsole::Cyan]) ts += ";36";
|
||||
if (f[PIConsole::White]) ts += ";37";
|
||||
|
||||
if (f[PIConsole::BackBlack]) ts += ";40";
|
||||
if (f[PIConsole::BackRed]) ts += ";41";
|
||||
if (f[PIConsole::BackGreen]) ts += ";42";
|
||||
if (f[PIConsole::BackYellow]) ts += ";43";
|
||||
if (f[PIConsole::BackBlue]) ts += ";44";
|
||||
if (f[PIConsole::BackMagenta]) ts += ";45";
|
||||
if (f[PIConsole::BackCyan]) ts += ";46";
|
||||
if (f[PIConsole::BackWhite]) ts += ";47";
|
||||
|
||||
return ts + "m";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
inline int PIConsole::couts(const bool v) {return (v ? printf("true") : printf("false"));}
|
||||
inline int PIConsole::couts(const char v) {return printf("%c", v);}
|
||||
inline int PIConsole::couts(const short v) {
|
||||
switch (num_format) {case (1): return printf("0x%.4hX", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 2)); break; default: return printf("%hd", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const int v) {
|
||||
switch (num_format) {case (1): return printf("0x%.8X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 4)); break; default: return printf("%d", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const long v) {
|
||||
switch (num_format) {case (1): return printf("0x%.16lX", v); break; case (2): return printf("%lo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%ld", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const llong v) {
|
||||
switch (num_format) {case (1): return printf("0x%.16llX", v); break; case (2): return printf("%llo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%lld", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const uchar v) {
|
||||
switch (num_format) {case (1): return printf("0x%.2X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 1)); break; default: return printf("%u", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const ushort v) {
|
||||
switch (num_format) {case (1): return printf("0x%.4hX", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 2)); break; default: return printf("%hu", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const uint v) {
|
||||
switch (num_format) {case (1): return printf("0x%.8X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 4)); break; default: return printf("%u", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const ulong v) {
|
||||
switch (num_format) {case (1): return printf("0x%.16lX", v); break; case (2): return printf("%lo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%lu", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const ullong v) {
|
||||
switch (num_format) {case (1): return printf("0x%.16llX", v); break; case (2): return printf("%llo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%llu", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const float v) {
|
||||
switch (num_format) {case (3): return printf("%e", v); break; default: return printf("%.5g", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const double v) {
|
||||
switch (num_format) {case (3): return printf("%le", v); break; default: return printf("%.5lg", v); break;}
|
||||
}
|
||||
inline int PIConsole::couts(const PISystemTime & v) {
|
||||
switch (systime_format) {case (1): return printf("%.6lg", v.toSeconds()); break;
|
||||
default: return couts(v.seconds) + printf(" s, ") + couts(v.nanoseconds) + printf(" ns"); break;}
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::toUpperLeft() {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ulcoord);
|
||||
#else
|
||||
printf("\e[H");
|
||||
#endif
|
||||
}
|
||||
|
||||
void PIConsole::moveRight(int n) {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->getWinCoord(n));
|
||||
#else
|
||||
if (n > 0) printf("\e[%dC", n);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PIConsole::moveLeft(int n) {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->getWinCoord(-n));
|
||||
#else
|
||||
if (n > 0) printf("\e[%dD", n);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PIConsole::moveTo(int x, int y) {
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->ccoord.X = x;
|
||||
PRIVATE->ccoord.Y = PRIVATE->ulcoord.Y + y;
|
||||
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
|
||||
#else
|
||||
printf("\e[%d;%dH", y, x);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PIConsole::clearScreen() {
|
||||
#ifdef WINDOWS
|
||||
couts(fstr(Normal));
|
||||
toUpperLeft();
|
||||
FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written);
|
||||
FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written);
|
||||
#else
|
||||
couts(fstr(Normal)); printf("\e[H\e[J");
|
||||
#endif
|
||||
}
|
||||
|
||||
void PIConsole::clearScreenLower() {
|
||||
#ifdef WINDOWS
|
||||
couts(fstr(Normal));
|
||||
PRIVATE->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);
|
||||
#else
|
||||
couts(fstr(Normal)); printf("\e[J");
|
||||
#endif
|
||||
}
|
||||
|
||||
void PIConsole::clearLine() {
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->getWinCurCoord();
|
||||
FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
|
||||
FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
|
||||
#else
|
||||
printf("\e[K");
|
||||
#endif
|
||||
}
|
||||
|
||||
void PIConsole::newLine() {
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->getWinCurCoord();
|
||||
PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++;
|
||||
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
|
||||
#else
|
||||
printf("\eE");
|
||||
#endif
|
||||
}
|
||||
|
||||
void PIConsole::hideCursor() {
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->curinfo.bVisible = false;
|
||||
SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
|
||||
#else
|
||||
printf("\e[?25l");
|
||||
#endif
|
||||
}
|
||||
|
||||
void PIConsole::showCursor() {
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->curinfo.bVisible = true; SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
|
||||
#else
|
||||
printf("\e[?25h");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::begin() {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT);
|
||||
#endif
|
||||
max_y = 0;
|
||||
PICout::__mutex__().lock();
|
||||
clearScreen();
|
||||
hideCursor();
|
||||
fillLabels();
|
||||
PICout::__mutex__().unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::run() {
|
||||
if (pause_) return;
|
||||
uint cx, clen = 0;
|
||||
int j;
|
||||
#ifdef WINDOWS
|
||||
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
||||
width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
|
||||
height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
|
||||
#else
|
||||
# ifdef FREERTOS
|
||||
width = 80;
|
||||
height = 24;
|
||||
# else
|
||||
winsize ws;
|
||||
ioctl(0, TIOCGWINSZ, &ws);
|
||||
width = ws.ws_col;
|
||||
height = ws.ws_row;
|
||||
# endif
|
||||
#endif
|
||||
//fflush(0); return;
|
||||
PICout::__mutex__().lock();
|
||||
if (pwidth != width || pheight != height) {
|
||||
clearScreen();
|
||||
fillLabels();
|
||||
}
|
||||
pwidth = width;
|
||||
pheight = height;
|
||||
col_cnt = columns().size();
|
||||
col_wid = (col_cnt > 0) ? width / col_cnt : width;
|
||||
for (uint i = 0; i < col_cnt; ++i) {
|
||||
PIVector<Variable> & cvars(tabs[cur_tab].columns[i].variables);
|
||||
cx = col_wid * i;
|
||||
toUpperLeft();
|
||||
if (max_y < cvars.size()) max_y = cvars.size();
|
||||
j = 0;
|
||||
piForeachC (Variable & tv_, cvars) {
|
||||
if (j > height - 3) continue;
|
||||
j++;
|
||||
moveRight(cx);
|
||||
if (tv_.type == 15) {
|
||||
newLine();
|
||||
continue;
|
||||
}
|
||||
moveRight(tv_.offset);
|
||||
const void * ptr = 0;
|
||||
if (tv_.remote) {
|
||||
if (tv_.type == 0) {
|
||||
rstr.clear();
|
||||
rba = tv_.rdata;
|
||||
rba >> rstr;
|
||||
rstr.trim();
|
||||
ptr = &rstr;
|
||||
} else
|
||||
ptr = tv_.rdata.data();
|
||||
} else
|
||||
ptr = tv_.ptr;
|
||||
switch (tv_.type) {
|
||||
case 0: clen = printValue(ptr != 0 ? *(const PIString*)ptr : PIString(), tv_.format); break;
|
||||
case 1: clen = printValue(ptr != 0 ? *(const bool*)ptr : false, tv_.format); break;
|
||||
case 2: clen = printValue(ptr != 0 ? *(const int*)ptr : 0, tv_.format); break;
|
||||
case 3: clen = printValue(ptr != 0 ? *(const long*)ptr : 0l, tv_.format); break;
|
||||
case 4: clen = printValue(ptr != 0 ? *(const char*)ptr : char(0), tv_.format); break;
|
||||
case 5: clen = printValue(ptr != 0 ? *(const float*)ptr : 0.f, tv_.format); break;
|
||||
case 6: clen = printValue(ptr != 0 ? *(const double*)ptr : 0., tv_.format); break;
|
||||
case 7: clen = printValue(ptr != 0 ? *(const short*)ptr : short(0), tv_.format); break;
|
||||
case 8: clen = printValue(ptr != 0 ? *(const uint*)ptr : 0u, tv_.format); break;
|
||||
case 9: clen = printValue(ptr != 0 ? *(const ulong*)ptr : 0ul, tv_.format); break;
|
||||
case 10: clen = printValue(ptr != 0 ? *(const ushort*)ptr : ushort(0), tv_.format); break;
|
||||
case 11: clen = printValue(ptr != 0 ? *(const uchar*)ptr : uchar(0), tv_.format); break;
|
||||
case 12: clen = printValue(ptr != 0 ? *(const llong*)ptr : 0l, tv_.format); break;
|
||||
case 13: clen = printValue(ptr != 0 ? *(const ullong*)ptr: 0ull, tv_.format); break;
|
||||
case 20: clen = printValue(ptr != 0 ? *(const PISystemTime*)ptr: PISystemTime(), tv_.format); break;
|
||||
case 14: clen = printValue(bitsValue(ptr, tv_.bitFrom, tv_.bitCount), tv_.format); break;
|
||||
}
|
||||
if (clen + tv_.offset < (uint)col_wid) {
|
||||
PIString ts = PIString(
|
||||
#if defined(QNX) || defined(FREE_BSD)
|
||||
col_wid - clen - tv_.offset - 1, ' ');
|
||||
#else
|
||||
col_wid - clen - tv_.offset, ' ');
|
||||
#endif
|
||||
printf("%s", ts.data());
|
||||
}
|
||||
newLine();
|
||||
}
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
moveTo(0, max_y + 1);
|
||||
#else
|
||||
moveTo(0, max_y + 2);
|
||||
#endif
|
||||
fflush(0);
|
||||
PICout::__mutex__().unlock();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::fillLabels() {
|
||||
if (!isRunning()) return;
|
||||
uint cx, cy, mx = 0, dx;
|
||||
#ifdef WINDOWS
|
||||
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
||||
width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
|
||||
height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
|
||||
#else
|
||||
# ifdef FREERTOS
|
||||
width = 80;
|
||||
height = 24;
|
||||
# else
|
||||
winsize ws;
|
||||
ioctl(0, TIOCGWINSZ, &ws);
|
||||
width = ws.ws_col;
|
||||
height = ws.ws_row;
|
||||
# endif
|
||||
#endif
|
||||
max_y = 0;
|
||||
col_cnt = columns().size();
|
||||
col_wid = (col_cnt > 0) ? width / col_cnt : width;
|
||||
for (uint i = 0; i < col_cnt; ++i) {
|
||||
Column & ccol(tabs[cur_tab].columns[i]);
|
||||
PIVector<Variable> & cvars(ccol.variables);
|
||||
if (ccol.alignment != Nothing) {
|
||||
mx = 0;
|
||||
piForeachC (Variable & j, cvars)
|
||||
if (!j.isEmpty())
|
||||
if (mx < j.name.size())
|
||||
mx = j.name.size();
|
||||
mx += 2;
|
||||
}
|
||||
cx = col_wid * i;
|
||||
cy = 1;
|
||||
toUpperLeft();
|
||||
for (uint j = 0; j < cvars.size(); ++j) {
|
||||
if (int(j) > height - 3) continue;
|
||||
if (max_y < j) max_y = j;
|
||||
moveRight(cx);
|
||||
Variable & tv_(cvars[j]);
|
||||
cvars[j].nx = cx;
|
||||
cvars[j].ny = cy;
|
||||
if (tv_.name.isEmpty()) {
|
||||
cvars[j].offset = 0;
|
||||
clearLine();
|
||||
newLine();
|
||||
cy++;
|
||||
continue;
|
||||
}
|
||||
clearLine();
|
||||
//piCout << tv_.name << tv_.type << tv_.ptr;
|
||||
if (tv_.type == 15) {
|
||||
cvars[j].offset = cvars[j].name.length();
|
||||
cvars[j].nx += cvars[j].offset;
|
||||
printLine(tv_.name, cx, tv_.format);
|
||||
newLine();
|
||||
cy++;
|
||||
continue;
|
||||
}
|
||||
if (!tv_.isEmpty()) {
|
||||
switch (ccol.alignment) {
|
||||
case Nothing:
|
||||
cvars[j].offset = (tv_.name + ": ").length();
|
||||
cvars[j].nx += cvars[j].offset;
|
||||
printValue(tv_.name + ": ", tv_.format);
|
||||
break;
|
||||
case Left:
|
||||
cvars[j].offset = mx;
|
||||
cvars[j].nx += cvars[j].offset;
|
||||
printValue(tv_.name + ": ", tv_.format);
|
||||
break;
|
||||
case Right:
|
||||
cvars[j].offset = mx;
|
||||
cvars[j].nx += cvars[j].offset;
|
||||
dx = mx - (tv_.name + ": ").length();
|
||||
moveRight(dx);
|
||||
printValue(tv_.name + ": ", tv_.format);
|
||||
moveLeft(dx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
newLine();
|
||||
cy++;
|
||||
}
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
moveTo(0, max_y + 1);
|
||||
#else
|
||||
moveTo(0, max_y + 2);
|
||||
#endif
|
||||
if (!tabs[cur_tab].status.isEmpty()) {
|
||||
printValue(tabs[cur_tab].status);
|
||||
newLine();
|
||||
}
|
||||
status();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::status() {
|
||||
Tab * ctab;
|
||||
for (uint i = 0; i < tabsCount(); ++i) {
|
||||
ctab = &tabs[i];
|
||||
if (ctab->key == 0) continue;
|
||||
printValue(ctab->key, PIConsole::White | PIConsole::Bold);
|
||||
if (i == cur_tab)
|
||||
printValue(ctab->name + " ", PIConsole::BackYellow | PIConsole::Black);
|
||||
else
|
||||
printValue(ctab->name + " ", PIConsole::Cyan | PIConsole::Inverse);
|
||||
printValue(" ");
|
||||
}
|
||||
newLine();
|
||||
}
|
||||
|
||||
|
||||
int PIConsole::bitsValue(const void * src, int offset, int count) const {
|
||||
int ret = 0, stbyte = offset / 8, cbit = offset - stbyte * 8;
|
||||
char cbyte = reinterpret_cast<const char * >(src)[stbyte];
|
||||
for (int i = 0; i < count; i++) {
|
||||
ret |= ((cbyte >> cbit & 1) << i);
|
||||
cbit++;
|
||||
if (cbit == 8) {
|
||||
cbit = 0;
|
||||
stbyte++;
|
||||
cbyte = reinterpret_cast<const char * >(src)[stbyte];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
const char * PIConsole::toBin(const void * d, int s) {
|
||||
binstr.clear();
|
||||
uchar cc, b;
|
||||
for (int i = 0; i < s; ++i) {
|
||||
cc = ((const uchar *)d)[i];
|
||||
b = 1;
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
binstr << (cc & b ? "1" : "0");
|
||||
b <<= 1;
|
||||
}
|
||||
if (i < s - 1) binstr << " ";
|
||||
}
|
||||
binstr.reverse();
|
||||
return binstr.data();
|
||||
}
|
||||
|
||||
|
||||
#define ADD_VAR_BODY vid++; tv.id = vid; tv.name = name; tv.bitFrom = tv.bitCount = 0; tv.format = format; tv.remote = false; checkColumn(col);
|
||||
|
||||
void PIConsole::addString(const PIString & name, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 15; tv.size = 0; tv.ptr = 0; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const PIString * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 0; tv.size = 0; tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const bool * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 1; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const int * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 2; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const long * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 3; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const char * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 4; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const float * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 5; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const double * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 6; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const short * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 7; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const uint * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 8; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const ulong * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 9; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const ushort * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 10; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const uchar * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 11; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const llong * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 12; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const ullong * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 13; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
void PIConsole::addVariable(const PIString & name, const PISystemTime * ptr, int col, FormatFlags format) {
|
||||
ADD_VAR_BODY tv.type = 20; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
||||
/** \brief Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
* \details This function add to column "column" next lines:
|
||||
* * "<name> diagnostics"
|
||||
* * "Received count": \a PIDiagnostics::receiveCount
|
||||
* * "Invalid count": \a PIDiagnostics::wrongCount
|
||||
* * "Sended count": \a PIDiagnostics::sendCount
|
||||
* * "Immediate Frequency, Hz": \a PIDiagnostics::immediateFrequency
|
||||
* * "Integral Frequency, Hz": \a PIDiagnostics::integralFrequency
|
||||
* * "Receive speed": \a PIDiagnostics::receiveSpeed
|
||||
* * "Send speed": \a PIDiagnostics::sendSpeed
|
||||
* * "Quality": \a PIDiagnostics::quality
|
||||
* */
|
||||
void PIConsole::addVariable(const PIString & name, const PIDiagnostics * ptr, int col, FormatFlags format) {
|
||||
addString(name + " diagnostics", col, format | PIConsole::Bold);
|
||||
// addVariable("Received count", ptr->receiveCount_ptr(), col, format);
|
||||
// addVariable("Invalid count", ptr->wrongCount_ptr(), col, format);
|
||||
// addVariable("Sended count", ptr->sendCount_ptr(), col, format);
|
||||
// addVariable("Immediate Frequency, Hz", ptr->immediateFrequency_ptr(), col, format);
|
||||
// addVariable("Integral Frequency, Hz", ptr->integralFrequency_ptr(), col, format);
|
||||
// addVariable("Receive speed", ptr->receiveSpeed_ptr(), col, format);
|
||||
// addVariable("Send speed", ptr->sendSpeed_ptr(), col, format);
|
||||
// addVariable("Quality", ptr->quality_ptr(), col, format);
|
||||
}
|
||||
void PIConsole::addVariable(const PIString & name, const PISystemMonitor * ptr, int col, FormatFlags format) {
|
||||
addString("monitor " + name, col, format | PIConsole::Bold);
|
||||
//addVariable("PID", &(ptr->statistic().ID), col, format);
|
||||
//addVariable("state", &(ptr->statistic().state), col, format);
|
||||
//addVariable("threads", &(ptr->statistic().threads), col, format);
|
||||
//addVariable("priority", &(ptr->statistic().priority), col, format);
|
||||
//addVariable("memory physical", &(ptr->statistic().physical_memsize_readable), col, format);
|
||||
//addVariable("memory shared", &(ptr->statistic().share_memsize_readable), col, format);
|
||||
//addVariable("cpu load kernel", &(ptr->statistic().cpu_load_system), col, format);
|
||||
//addVariable("cpu load user", &(ptr->statistic().cpu_load_user), col, format);
|
||||
}
|
||||
void PIConsole::addBitVariable(const PIString & name, const void * ptr, int fromBit, int bitCount, int col, FormatFlags format) {
|
||||
vid++; tv.id = vid; tv.size = sizeof(ullong); tv.name = name; tv.bitFrom = fromBit; tv.bitCount = bitCount; tv.type = 14; tv.ptr = ptr; tv.format = format;
|
||||
checkColumn(col); column(col).push_back(tv);}
|
||||
void PIConsole::addEmptyLine(int col, uint count) {
|
||||
tv.id = 0; tv.size = 0; tv.name = ""; tv.type = 0; tv.ptr = 0; tv.format = Normal;
|
||||
for (uint i = 0; i < count; ++i) {
|
||||
checkColumn(col);
|
||||
column(col).push_back(tv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIString PIConsole::getString(int x, int y) {
|
||||
bool run = isRunning();
|
||||
if (run) PIThread::stop(true);
|
||||
listener->setActive(false);
|
||||
msleep(50);
|
||||
#ifdef WINDOWS
|
||||
moveTo(x - 1, y - 1);
|
||||
#else
|
||||
moveTo(x, y);
|
||||
#endif
|
||||
showCursor();
|
||||
PIByteArray ba(4096);
|
||||
#ifdef CC_VC
|
||||
int ret = scanf_s(" %s", ba.data());
|
||||
#else
|
||||
int ret = scanf(" %s", ba.data());
|
||||
#endif
|
||||
listener->setActive(true);
|
||||
if (run) start();
|
||||
if (ret >= 1) return PIString(ba);
|
||||
else return PIString();
|
||||
}
|
||||
|
||||
|
||||
PIString PIConsole::getString(const PIString & name) {
|
||||
piForeachC (Column & i, tabs[cur_tab].columns)
|
||||
piForeachC (Variable & j, i.variables)
|
||||
if (j.name == name)
|
||||
return getString(j.nx + 1, j.ny);
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
#define PRINT_VAR_BODY couts(fstr(format)); int ret = couts(value); couts(fstr(PIConsole::Dec)); return ret;
|
||||
|
||||
inline void PIConsole::printLine(const PIString & value, int dx, FormatFlags format) {
|
||||
int i = width - value.length() - dx;
|
||||
#if defined(QNX) || defined(FREE_BSD)
|
||||
--i;
|
||||
#endif
|
||||
PIString ts = fstr(format);
|
||||
couts(ts);
|
||||
if (i >= 0) ts = value + PIString(i, ' ');
|
||||
else ts = value.left(value.size() + i);
|
||||
couts(ts);
|
||||
couts(fstr(Dec));
|
||||
}
|
||||
inline int PIConsole::printValue(const PIString & value, FormatFlags format) {
|
||||
couts(fstr(format));
|
||||
int ret = couts(value);
|
||||
fstr(PIConsole::Dec);
|
||||
return ret;
|
||||
}
|
||||
inline int PIConsole::printValue(const char * value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const bool value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const int value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const long value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const llong value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const float value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const double value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const char value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const short value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const uchar value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const ushort value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const uint value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const ulong value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const ullong value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
inline int PIConsole::printValue(const PISystemTime & value, FormatFlags format) {PRINT_VAR_BODY}
|
||||
|
||||
|
||||
|
||||
void PIConsole::startServer(const PIString & name) {
|
||||
stopPeer();
|
||||
server_mode = true;
|
||||
peer = new PIPeer("_rcs_:" + name);
|
||||
CONNECT2(void, const PIString & , const PIByteArray &, peer, dataReceivedEvent, this, peerReceived);
|
||||
CONNECT1(void, const PIString & , peer, peerDisconnectedEvent, this, peerDisconnectedEvent);
|
||||
peer_timer->start(50.);
|
||||
serverSendInfo();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::stopPeer() {
|
||||
remote_clients.clear();
|
||||
peer_timer->stop();
|
||||
if (peer != 0) delete peer;
|
||||
peer = 0;
|
||||
state = Disconnected;
|
||||
}
|
||||
|
||||
|
||||
PIStringList PIConsole::clients() const {
|
||||
PIStringList sl;
|
||||
if (peer == 0) return sl;
|
||||
piForeachC (PIPeer::PeerInfo & i, peer->allPeers()) {
|
||||
if (i.name.left(6) != "_rcc_:") continue;
|
||||
sl << i.name.right(i.name.length() - 6);
|
||||
}
|
||||
return sl;
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::listenServers() {
|
||||
stopPeer();
|
||||
server_mode = false;
|
||||
server_name.clear();
|
||||
randomize();
|
||||
peer = new PIPeer("_rcc_:" + PIDateTime::current().toString("hhmmssddMMyy_") + PIString::fromNumber(randomi()));
|
||||
CONNECT2(void, const PIString & , const PIByteArray &, peer, dataReceivedEvent, this, peerReceived);
|
||||
peer_timer->start(100.);
|
||||
}
|
||||
|
||||
|
||||
PIStringList PIConsole::availableServers() const {
|
||||
PIStringList sl;
|
||||
if (peer == 0) return sl;
|
||||
piForeachC (PIPeer::PeerInfo & i, peer->allPeers()) {
|
||||
if (i.name.left(6) != "_rcs_:") continue;
|
||||
sl << i.name.right(i.name.length() - 6);
|
||||
}
|
||||
return sl;
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::connectToServer(const PIString & name) {
|
||||
if (peer == 0) listenServers();
|
||||
server_name = name;
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::disconnect() {
|
||||
stopPeer();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::serverSendInfo() {
|
||||
if (peer == 0) return;
|
||||
PIByteArray ba;
|
||||
ba << int(0xAA);
|
||||
peer->sendToAll(ba);
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::serverSendData() {
|
||||
if (peer == 0) return;
|
||||
PIByteArray ba;
|
||||
PIVector<VariableContent> content;
|
||||
piForeach (Tab & t, tabs)
|
||||
piForeach (Column & c, t.columns)
|
||||
piForeach (Variable & v, c.variables)
|
||||
if (!v.isEmpty() && v.id > 0) {
|
||||
VariableContent vc;
|
||||
vc.id = v.id;
|
||||
v.writeData(vc.rdata);
|
||||
content << vc;
|
||||
}
|
||||
piForeach (RemoteClient & rc, remote_clients) {
|
||||
ba.clear();
|
||||
switch (rc.state) {
|
||||
case FetchingData:
|
||||
ba << int(0xCC) << tabs;
|
||||
//piCout << "server send const data" << rc.name << ba.size_s();
|
||||
break;
|
||||
case Committing:
|
||||
ba << int(0xDD);
|
||||
break;
|
||||
case Connected:
|
||||
ba << int(0xEE) << content;
|
||||
//piCout << "send data" << ba.size();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
if (!ba.isEmpty())
|
||||
peer->send(rc.name, ba);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIConsole::RemoteClient & PIConsole::remoteClient(const PIString & fname) {
|
||||
piForeach (RemoteClient & i, remote_clients)
|
||||
if (i.name == fname)
|
||||
return i;
|
||||
remote_clients << RemoteClient(fname);
|
||||
return remote_clients.back();
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::peerReceived(const PIString & from, const PIByteArray & data) {
|
||||
int type;
|
||||
PIByteArray ba(data);
|
||||
ba >> type;
|
||||
//piCout << "rec packet from" << from << "type" << PICoutManipulators::Hex << type;
|
||||
if (server_mode) {
|
||||
if (from.left(5) != "_rcc_") return;
|
||||
//PIString rcn = from.right(from.length() - 6);
|
||||
RemoteClient & rc(remoteClient(from));
|
||||
switch (type) {
|
||||
case 0xBB: // fetch const data request
|
||||
//piCout << "fetch data request from" << from << rc.state;
|
||||
if (rc.state != Connected)
|
||||
rc.state = FetchingData;
|
||||
break;
|
||||
case 0xCC: // const data commit
|
||||
//piCout << "commit from" << from;
|
||||
if (rc.state != Connected)
|
||||
rc.state = Connected;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
} else {
|
||||
PIVector<VariableContent> content;
|
||||
PIMap<int, Variable * > vids;
|
||||
if (from.left(5) != "_rcs_") return;
|
||||
//PIString rcn = from.right(from.length() - 6);
|
||||
switch (type) {
|
||||
case 0xAA: // new server
|
||||
//piCout << "new server" << rcn;
|
||||
break;
|
||||
case 0xCC: // const data
|
||||
//piCout << "received const data";
|
||||
state = Committing;
|
||||
ba >> tabs;
|
||||
cur_tab = tabs.isEmpty() ? -1 : 0;
|
||||
piForeach (Tab & t, tabs)
|
||||
piForeach (Column & c, t.columns)
|
||||
piForeach (Variable & v, c.variables)
|
||||
v.remote = true;
|
||||
break;
|
||||
case 0xDD: // const data commit
|
||||
//piCout << "received commit";
|
||||
state = Connected;
|
||||
break;
|
||||
case 0xEE: // dynamic data
|
||||
//piCout << "received data" << ba.size_s();
|
||||
piForeach (Tab & t, tabs)
|
||||
piForeach (Column & c, t.columns)
|
||||
piForeach (Variable & v, c.variables)
|
||||
if (!v.isEmpty() && v.id > 0)
|
||||
vids[v.id] = &v;
|
||||
ba >> content;
|
||||
piForeach (VariableContent & vc, content) {
|
||||
if (vc.id <= 0) continue;
|
||||
Variable * v = vids.at(vc.id);
|
||||
if (v == 0) continue;
|
||||
//piCout << "read" << v->name << vc.rdata.size_s();
|
||||
v->rdata = vc.rdata;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::peerTimer(void * data, int delim) {
|
||||
if (peer == 0) return;
|
||||
//piCout << "timer" << delim;
|
||||
if (server_mode) {
|
||||
if (delim == 20)
|
||||
serverSendInfo();
|
||||
else
|
||||
serverSendData();
|
||||
} else {
|
||||
if (delim != 1 || server_name.isEmpty()) return;
|
||||
const PIPeer::PeerInfo * p = peer->getPeerByName("_rcs_:" + server_name);
|
||||
if (p == 0) return;
|
||||
PIByteArray ba;
|
||||
switch (state) {
|
||||
case Disconnected:
|
||||
peer_tm.reset();
|
||||
ba << int(0xBB);
|
||||
//piCout << "send to" << server_name << "fetch request disc";
|
||||
peer->send(p, ba);
|
||||
state = FetchingData;
|
||||
break;
|
||||
case FetchingData:
|
||||
if (peer_tm.elapsed_s() < 3.)
|
||||
return;
|
||||
peer_tm.reset();
|
||||
ba << int(0xBB);
|
||||
//piCout << "send to" << server_name << "fetch request fd";
|
||||
peer->send(p, ba);
|
||||
break;
|
||||
case Committing:
|
||||
peer_tm.reset();
|
||||
ba << int(0xCC);
|
||||
//piCout << "send to" << server_name << "committing";
|
||||
state = Connected;
|
||||
peer->send(p, ba);
|
||||
break;
|
||||
default: break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIConsole::peerDisconnectedEvent(const PIString & name) {
|
||||
for (int i = 0; i < remote_clients.size_s(); ++i)
|
||||
if (remote_clients[i].name == name) {
|
||||
remote_clients.remove(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
645
lib/console/piscreen.cpp
Normal file
645
lib/console/piscreen.cpp
Normal file
@@ -0,0 +1,645 @@
|
||||
/*
|
||||
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 distributed in the hope that 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 "piscreen.h"
|
||||
#include "piincludes_p.h"
|
||||
#ifndef WINDOWS
|
||||
# include <sys/ioctl.h>
|
||||
# include <fcntl.h>
|
||||
# include <termios.h>
|
||||
#else
|
||||
# include <wincon.h>
|
||||
# ifndef COMMON_LVB_UNDERSCORE
|
||||
# define COMMON_LVB_UNDERSCORE 0x8000
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
using namespace PIScreenTypes;
|
||||
|
||||
|
||||
PRIVATE_DEFINITION_START(PIScreen::SystemConsole)
|
||||
#ifdef WINDOWS
|
||||
void * hOut;
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi, csbi;
|
||||
CONSOLE_CURSOR_INFO curinfo;
|
||||
COORD ccoord, ulcoord, bs, bc;
|
||||
SMALL_RECT srect;
|
||||
WORD dattr;
|
||||
DWORD smode, written;
|
||||
PIVector<CHAR_INFO> chars;
|
||||
#endif
|
||||
PRIVATE_DEFINITION_END(PIScreen::SystemConsole)
|
||||
|
||||
|
||||
PIScreen::SystemConsole::SystemConsole() {
|
||||
width = height = pwidth = pheight = 0;
|
||||
mouse_x = mouse_y = -1;
|
||||
int w, h;
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->ulcoord.X = 0;
|
||||
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
||||
PRIVATE->dattr = PRIVATE->sbi.wAttributes;
|
||||
w = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
|
||||
h = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
|
||||
PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top;
|
||||
GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode);
|
||||
GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
|
||||
#else
|
||||
# ifdef FREERTOS
|
||||
w = 80;
|
||||
h = 24;
|
||||
# else
|
||||
winsize ws;
|
||||
ioctl(0, TIOCGWINSZ, &ws);
|
||||
w = ws.ws_col;
|
||||
h = ws.ws_row;
|
||||
# endif
|
||||
#endif
|
||||
resize(w, h);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
PRIVATE->bc.X = 0;
|
||||
PRIVATE->bc.Y = 0;
|
||||
#endif
|
||||
clear();
|
||||
hideCursor();
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::SystemConsole::end() {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
|
||||
#else
|
||||
printf("\e[0m");
|
||||
#endif
|
||||
moveTo(0, height);
|
||||
showCursor();
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::SystemConsole::prepare() {
|
||||
int w, h;
|
||||
#ifdef WINDOWS
|
||||
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi);
|
||||
w = PRIVATE->csbi.srWindow.Right - PRIVATE->csbi.srWindow.Left + 1;
|
||||
h = PRIVATE->csbi.srWindow.Bottom - PRIVATE->csbi.srWindow.Top + 1;
|
||||
#else
|
||||
# ifdef FREERTOS
|
||||
w = 80;
|
||||
h = 24;
|
||||
# else
|
||||
winsize ws;
|
||||
ioctl(0, TIOCGWINSZ, &ws);
|
||||
w = ws.ws_col;
|
||||
h = ws.ws_row;
|
||||
# endif
|
||||
#endif
|
||||
resize(w, h);
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::SystemConsole::clear() {
|
||||
for (int i = 0; i < cells.size_s(); ++i)
|
||||
cells[i].fill(Cell());
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::SystemConsole::resize(int w, int h) {
|
||||
if (w == pwidth && h == pheight) return;
|
||||
width = piMaxi(w, 0);
|
||||
height = piMaxi(h, 0);
|
||||
pwidth = width;
|
||||
pheight = height;
|
||||
cells.resize(height);
|
||||
pcells.resize(height);
|
||||
for (int i = 0; i < height; ++i) {
|
||||
cells[i].resize(width);
|
||||
pcells[i].resize(width, Cell(0));
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->sbi.srWindow = PRIVATE->csbi.srWindow;
|
||||
PRIVATE->chars.resize(width * height);
|
||||
#endif
|
||||
for (int i = 0; i < pcells.size_s(); ++i)
|
||||
pcells[i].fill(Cell());
|
||||
clear();
|
||||
clearScreen();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->srect = PRIVATE->sbi.srWindow;
|
||||
int dx0 = -1, dx1 = -1, dy0 = -1, dy1 = -1;
|
||||
for (int j = 0; j < height; ++j) {
|
||||
PIVector<Cell> & ccv(cells[j]);
|
||||
PIVector<Cell> & pcv(pcells[j]);
|
||||
for (int i = 0; i < width; ++i)
|
||||
if (ccv[i] != pcv[i]) {
|
||||
if (dx0 < 0) {
|
||||
dx0 = dx1 = i;
|
||||
dy0 = dy1 = j;
|
||||
} else {
|
||||
dx0 = piMini(dx0, i);
|
||||
dx1 = piMaxi(dx1, i);
|
||||
dy0 = piMini(dy0, j);
|
||||
dy1 = piMaxi(dy1, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dx0 < 0) return;
|
||||
int dw = dx1 - dx0 + 1, dh = dy1 - dy0 + 1;
|
||||
for (int i = 0; i < dw; ++i)
|
||||
for (int j = 0; j < dh; ++j) {
|
||||
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);
|
||||
}
|
||||
//piCout << "draw" << dw << dh;
|
||||
PRIVATE->bs.X = dw;
|
||||
PRIVATE->bs.Y = dh;
|
||||
PRIVATE->srect.Left += dx0;
|
||||
PRIVATE->srect.Top += dy0;
|
||||
PRIVATE->srect.Right -= width - dx1 - 1;
|
||||
PRIVATE->srect.Bottom -= height - dy1 - 1;
|
||||
WriteConsoleOutput(PRIVATE->hOut, PRIVATE->chars.data(), PRIVATE->bs, PRIVATE->bc, &PRIVATE->srect);
|
||||
#else
|
||||
PIString s;
|
||||
int si = 0, sj = 0;
|
||||
CellFormat prf(0xFFFF);
|
||||
for (int j = 0; j < height; ++j) {
|
||||
PIVector<Cell> & ccv(cells[j]);
|
||||
PIVector<Cell> & pcv(pcells[j]);
|
||||
for (int i = 0; i < width; ++i) {
|
||||
Cell & cc(ccv[i]);
|
||||
Cell & pc(pcv[i]);
|
||||
if (cc != pc) {
|
||||
if (s.isEmpty()) {
|
||||
si = i;
|
||||
sj = j;
|
||||
}
|
||||
if (prf != cc.format) {
|
||||
prf = cc.format;
|
||||
s += formatString(cc);
|
||||
}
|
||||
s += cc.symbol;
|
||||
} else {
|
||||
if (!s.isEmpty()) {
|
||||
moveTo(si, sj);
|
||||
printf("%s", s.data());
|
||||
s.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!s.isEmpty()) {
|
||||
moveTo(si, sj);
|
||||
printf("%s", s.data());
|
||||
s.clear();
|
||||
}
|
||||
}
|
||||
printf("\e[0m");
|
||||
fflush(0);
|
||||
#endif
|
||||
pcells = cells;
|
||||
}
|
||||
|
||||
|
||||
#ifdef WINDOWS
|
||||
#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;
|
||||
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 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;
|
||||
}
|
||||
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 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;
|
||||
}
|
||||
if ((c.format.flags & Inverse) == Inverse) {
|
||||
uchar f = attr & 0xFF;
|
||||
attr &= 0xFFFFFF00;
|
||||
f = (f << 4) | (f >> 4);
|
||||
attr |= f;
|
||||
}
|
||||
return attr;
|
||||
}
|
||||
#undef FOREGROUND_MASK
|
||||
#undef BACKGROUND_MASK
|
||||
|
||||
void PIScreen::SystemConsole::getWinCurCoord() {
|
||||
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi);
|
||||
PRIVATE->ccoord = PRIVATE->csbi.dwCursorPosition;
|
||||
}
|
||||
|
||||
void PIScreen::SystemConsole::clearLine() {
|
||||
getWinCurCoord();
|
||||
FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
|
||||
FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
|
||||
}
|
||||
|
||||
void PIScreen::SystemConsole::newLine() {
|
||||
getWinCurCoord();
|
||||
PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++;
|
||||
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
|
||||
}
|
||||
#else // WINDOWS
|
||||
PIString PIScreen::SystemConsole::formatString(const PIScreenTypes::Cell & c) {
|
||||
PIString ts("\e[0");
|
||||
switch (c.format.color_char) {
|
||||
case Black: ts += ";30"; break;
|
||||
case Red: ts += ";31"; break;
|
||||
case Green: ts += ";32"; break;
|
||||
case Blue: ts += ";34"; break;
|
||||
case Cyan: ts += ";36"; break;
|
||||
case Magenta: ts += ";35"; break;
|
||||
case Yellow: ts += ";33"; break;
|
||||
case White: ts += ";37"; break;
|
||||
}
|
||||
switch (c.format.color_back) {
|
||||
case Black: ts += ";40"; break;
|
||||
case Red: ts += ";41"; break;
|
||||
case Green: ts += ";42"; break;
|
||||
case Blue: ts += ";44"; break;
|
||||
case Cyan: ts += ";46"; break;
|
||||
case Magenta: ts += ";45"; break;
|
||||
case Yellow: ts += ";43"; break;
|
||||
case White: ts += ";47"; break;
|
||||
}
|
||||
if ((c.format.flags & Bold) == Bold) ts += ";1";
|
||||
if ((c.format.flags & Underline) == Underline) ts += ";4";
|
||||
if ((c.format.flags & Blink) == Blink) ts += ";5";
|
||||
if ((c.format.flags & Inverse) == Inverse) ts += ";7";
|
||||
return ts + "m";
|
||||
}
|
||||
#endif // WINDOWS
|
||||
|
||||
|
||||
void PIScreen::SystemConsole::toUpperLeft() {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ulcoord);
|
||||
#else
|
||||
printf("\e[H");
|
||||
#endif
|
||||
}
|
||||
|
||||
void PIScreen::SystemConsole::moveTo(int x, int y) {
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->ccoord.X = x;
|
||||
PRIVATE->ccoord.Y = PRIVATE->ulcoord.Y + y;
|
||||
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
|
||||
#else
|
||||
printf("\e[%d;%dH", y + 1, x + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PIScreen::SystemConsole::clearScreen() {
|
||||
#ifdef WINDOWS
|
||||
toUpperLeft();
|
||||
FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written);
|
||||
FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written);
|
||||
#else
|
||||
printf("\e[0m\e[H\e[J");
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
#else
|
||||
printf("\e[0m\e[J");
|
||||
#endif
|
||||
}
|
||||
|
||||
void PIScreen::SystemConsole::hideCursor() {
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->curinfo.bVisible = false;
|
||||
SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
|
||||
#else
|
||||
printf("\e[?25l");
|
||||
#endif
|
||||
}
|
||||
|
||||
void PIScreen::SystemConsole::showCursor() {
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->curinfo.bVisible = true;
|
||||
SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
|
||||
#else
|
||||
printf("\e[?25h");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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);
|
||||
if (startNow) start();
|
||||
}
|
||||
|
||||
|
||||
PIScreen::~PIScreen() {
|
||||
if (isRunning())
|
||||
stop();
|
||||
PIThread::waitForFinish(10);
|
||||
listener->waitForFinish(10);
|
||||
delete listener;
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::setMouseEnabled(bool on) {
|
||||
mouse_ = on;
|
||||
console.mouse_x = console.mouse_y = -1;
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::key_event(PIKbdListener::KeyEvent key) {
|
||||
/** DEBUG
|
||||
if (ret_func != 0) ret_func(key, t);
|
||||
keyPressed(key, t);
|
||||
return;
|
||||
*/
|
||||
PIScreenTile * rtile = rootTile();
|
||||
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 (ret_func != 0) ret_func(key, data_);
|
||||
keyPressed(key, data_);
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
if (!ff) {
|
||||
if (t->focus_flags[FocusOnMouse] && (e->action == PIKbdListener::MouseButtonPress)) {
|
||||
t->setFocus();
|
||||
ff = true;
|
||||
}
|
||||
if (t->focus_flags[FocusOnWheel] && (e->action == PIKbdListener::MouseWheel)) {
|
||||
t->setFocus();
|
||||
ff = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return tl;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
while (ct) {
|
||||
if (!f) ret << ct;
|
||||
f = false;
|
||||
ct = ct->childUnderMouse(x, y);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::mouse_event(PIKbdListener::MouseEvent me) {
|
||||
PIVector<PIScreenTile * > tl = prepareMouse(&me);
|
||||
if (tl.isEmpty()) return;
|
||||
piForeachR (PIScreenTile * t, tl)
|
||||
if (t->mouseEvent(me)) piBreak;
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::wheel_event(PIKbdListener::WheelEvent we) {
|
||||
PIVector<PIScreenTile * > tl = prepareMouse(&we);
|
||||
if (tl.isEmpty()) return;
|
||||
piForeachR (PIScreenTile * t, tl)
|
||||
if (t->wheelEvent(we)) piBreak;
|
||||
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
int ind = -1;
|
||||
for (int i = 0; i < ftl.size_s(); ++i)
|
||||
if (ftl[i] == tile_focus) {
|
||||
ind = i;
|
||||
break;
|
||||
}
|
||||
if (ind < 0)
|
||||
tile_focus = 0;
|
||||
if (ftl.isEmpty())
|
||||
tile_focus = 0;
|
||||
else {
|
||||
if (tile_focus)
|
||||
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[NextByArrowsHorizontal]) {
|
||||
if (key.key == PIKbdListener::LeftArrow) next = -1;
|
||||
if (key.key == PIKbdListener::RightArrow) next = 1;
|
||||
}
|
||||
if (tile_focus->focus_flags[NextByArrowsVertical]) {
|
||||
if (key.key == PIKbdListener::UpArrow) next = -1;
|
||||
if (key.key == PIKbdListener::DownArrow) next = 1;
|
||||
}
|
||||
}
|
||||
//piCout << ftl.size() << ind << next;
|
||||
if (next != 0) {
|
||||
PIVector<PIScreenTile*> tl = rt->children();
|
||||
piForeach (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->has_focus = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::tileEventInternal(PIScreenTile * t, TileEvent e) {
|
||||
tileEvent(t, e);
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::tileRemovedInternal(PIScreenTile * t) {
|
||||
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)
|
||||
i->has_focus = false;
|
||||
tile_focus = t;
|
||||
if (!tile_focus) return;
|
||||
if (tile_focus->focus_flags[CanHasFocus])
|
||||
tile_focus->has_focus = true;
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::setDialogTile(PIScreenTile * t) {
|
||||
tile_dialog = t;
|
||||
if (!tile_dialog) {
|
||||
nextFocus(&root);
|
||||
return;
|
||||
}
|
||||
tile_dialog->setScreen(this);
|
||||
tile_dialog->parent = 0;
|
||||
nextFocus(tile_dialog);
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::waitForFinish() {
|
||||
WAIT_FOR_EXIT
|
||||
stop();
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::stop(bool clear) {
|
||||
PIThread::stop(true);
|
||||
if (clear) console.clearScreen();
|
||||
#ifndef WINDOWS
|
||||
fflush(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::begin() {
|
||||
listener->start();
|
||||
nextFocus(&root);
|
||||
console.begin();
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::run() {
|
||||
console.prepare();
|
||||
root.width_ = drawer_.width = console.width;
|
||||
root.height_ = drawer_.height = console.height;
|
||||
root.layout();
|
||||
root.drawEventInternal(&drawer_);
|
||||
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;
|
||||
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);
|
||||
tile_dialog->drawEventInternal(&drawer_);
|
||||
}
|
||||
console.print();
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::end() {
|
||||
listener->stop();
|
||||
console.end();
|
||||
}
|
||||
|
||||
|
||||
PIScreenTile * PIScreen::tileByName(const PIString & name) {
|
||||
PIVector<PIScreenTile*> tl(tiles());
|
||||
piForeach (PIScreenTile * t, tl)
|
||||
if (t->name() == name)
|
||||
return t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
42
lib/console/piscreenconsole.cpp
Normal file
42
lib/console/piscreenconsole.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
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 distributed in the hope that 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 "piscreenconsole.h"
|
||||
|
||||
using namespace PIScreenTypes;
|
||||
|
||||
|
||||
TileVars::TileVars(const PIString &n) : PIScreenTile(n) {
|
||||
alignment = Left;
|
||||
}
|
||||
|
||||
|
||||
void TileVars::sizeHint(int &w, int &h) const {
|
||||
|
||||
}
|
||||
|
||||
void TileVars::drawEvent(PIScreenDrawer *d) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
PIScreenConsoleTile::PIScreenConsoleTile() {
|
||||
|
||||
}
|
||||
|
||||
271
lib/console/piscreendrawer.cpp
Normal file
271
lib/console/piscreendrawer.cpp
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
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 distributed in the hope that 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 "piscreendrawer.h"
|
||||
|
||||
// comment for use ascii instead of unicode symbols
|
||||
#define USE_UNICODE
|
||||
|
||||
using namespace PIScreenTypes;
|
||||
|
||||
|
||||
PIScreenDrawer::PIScreenDrawer(PIVector<PIVector<Cell> > & c): cells(c) {
|
||||
arts_[LineVertical] =
|
||||
#ifdef USE_UNICODE
|
||||
PIChar::fromUTF8("│");
|
||||
#else
|
||||
PIChar('|');
|
||||
#endif
|
||||
|
||||
arts_[LineHorizontal] =
|
||||
#ifdef USE_UNICODE
|
||||
PIChar::fromUTF8("─");
|
||||
#else
|
||||
PIChar('-');
|
||||
#endif
|
||||
|
||||
arts_[Cross] =
|
||||
#ifdef USE_UNICODE
|
||||
PIChar::fromUTF8("┼");
|
||||
#else
|
||||
PIChar('+');
|
||||
#endif
|
||||
|
||||
arts_[CornerTopLeft] =
|
||||
#ifdef USE_UNICODE
|
||||
PIChar::fromUTF8("┌");
|
||||
#else
|
||||
PIChar('+');
|
||||
#endif
|
||||
|
||||
arts_[CornerTopRight] =
|
||||
#ifdef USE_UNICODE
|
||||
PIChar::fromUTF8("┐");
|
||||
#else
|
||||
PIChar('+');
|
||||
#endif
|
||||
|
||||
arts_[CornerBottomLeft] =
|
||||
#ifdef USE_UNICODE
|
||||
PIChar::fromUTF8("└");
|
||||
#else
|
||||
PIChar('+');
|
||||
#endif
|
||||
|
||||
arts_[CornerBottomRight] =
|
||||
#ifdef USE_UNICODE
|
||||
PIChar::fromUTF8("┘");
|
||||
#else
|
||||
PIChar('+');
|
||||
#endif
|
||||
|
||||
arts_[Unchecked] =
|
||||
#ifdef USE_UNICODE
|
||||
PIChar::fromUTF8("☐");
|
||||
#else
|
||||
PIChar('O');
|
||||
#endif
|
||||
|
||||
arts_[Checked] =
|
||||
#ifdef USE_UNICODE
|
||||
PIChar::fromUTF8("☑");
|
||||
#else
|
||||
PIChar('0');
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIScreenDrawer::clear() {
|
||||
clear(cells);
|
||||
}
|
||||
|
||||
|
||||
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].format.color_char = col_char;
|
||||
cells[y][x].format.color_back = col_back;
|
||||
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.format.color_char = col_char;
|
||||
cc.format.color_back = col_back;
|
||||
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;
|
||||
cy += dy;
|
||||
}
|
||||
y = piRound(cy);
|
||||
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;
|
||||
cx += dx;
|
||||
}
|
||||
x = piRound(cx);
|
||||
if (x >= 0 && x < width && y1 >= 0 && y1 < height)
|
||||
cells[y1][x] = cc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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.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};
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
int i = x1, j = y1;
|
||||
if (i >= 0 && i < width && j >= 0 && j < height)
|
||||
cells[j][i] = cc;
|
||||
}
|
||||
|
||||
|
||||
void PIScreenDrawer::drawFrame(int x0, int y0, int x1, int y1, Color col_char, Color col_back, CharFlags flags_char) {
|
||||
if (x0 == x1 && y0 == y1) return;
|
||||
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};
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
|
||||
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);
|
||||
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
|
||||
}
|
||||
|
||||
|
||||
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.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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
int h = y1 - y0;
|
||||
for (int j = 0; j < h; ++j)
|
||||
if (j < piMini(height, content.size_s())) {
|
||||
if ((j + y0) >= 0 && (j + y0) < height) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIScreenDrawer::clear(PIVector<PIVector<Cell> > & cells) {
|
||||
for (int i = 0; i < cells.size_s(); ++i)
|
||||
cells[i].fill(Cell());
|
||||
}
|
||||
|
||||
|
||||
void PIScreenDrawer::drawText(int x, int y, const PIString & s, Color col_char, Color col_back, CharFlags flags_char) {
|
||||
if (x < 0 || x >= width || y < 0 || y >= height) return;
|
||||
PIVector<Cell> & cv(cells[y]);
|
||||
Cell cc;
|
||||
cc.format.color_char = col_char;
|
||||
cc.format.color_back = col_back;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
250
lib/console/piscreentile.cpp
Normal file
250
lib/console/piscreentile.cpp
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
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 distributed in the hope that 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 "piscreentile.h"
|
||||
#include "piscreendrawer.h"
|
||||
|
||||
|
||||
using namespace PIScreenTypes;
|
||||
|
||||
|
||||
PIScreenTile::PIScreenTile(const PIString & n, Direction d, SizePolicy p): PIObject(n) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
PIScreenTile::~PIScreenTile() {
|
||||
//piCout << this << "~";
|
||||
if (screen)
|
||||
screen->tileRemovedInternal(this);
|
||||
setScreen(0);
|
||||
deleteChildren();
|
||||
if (!parent) return;
|
||||
parent->tiles.removeOne(this);
|
||||
}
|
||||
|
||||
|
||||
void PIScreenTile::addTile(PIScreenTile * t) {
|
||||
if (t == 0) return;
|
||||
if (tiles.contains(t)) return;
|
||||
tiles << t;
|
||||
t->parent = this;
|
||||
t->setScreen(screen);
|
||||
}
|
||||
|
||||
|
||||
void PIScreenTile::takeTile(PIScreenTile * t) {
|
||||
if (!tiles.contains(t)) return;
|
||||
tiles.removeOne(t);
|
||||
t->parent = 0;
|
||||
t->setScreen(0);
|
||||
}
|
||||
|
||||
|
||||
void PIScreenTile::removeTile(PIScreenTile * t) {
|
||||
if (!tiles.contains(t)) return;
|
||||
tiles.removeOne(t);
|
||||
t->parent = 0;
|
||||
t->setScreen(0);
|
||||
delete 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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIScreenTile * PIScreenTile::childUnderMouse(int x, int y) {
|
||||
piForeach (PIScreenTile * t, tiles) {
|
||||
if (!t->visible) continue;
|
||||
if (x >= t->x_ && (x - t->x_) < t->width_ &&
|
||||
y >= t->y_ && (y - t->y_) < t->height_) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void PIScreenTile::raiseEvent(TileEvent e) {
|
||||
if (!screen) return;
|
||||
screen->tileEventInternal(this, e);
|
||||
}
|
||||
|
||||
|
||||
void PIScreenTile::setScreen(PIScreenBase * s) {
|
||||
screen = s;
|
||||
piForeach (PIScreenTile * t, tiles)
|
||||
t->setScreen(s);
|
||||
}
|
||||
|
||||
|
||||
void PIScreenTile::deleteChildren() {
|
||||
piForeach (PIScreenTile * t, tiles) {
|
||||
t->parent = 0;
|
||||
delete t;
|
||||
}
|
||||
tiles.clear();
|
||||
}
|
||||
|
||||
|
||||
void PIScreenTile::setFocus() {
|
||||
if (!screen || !focus_flags[CanHasFocus]) return;
|
||||
screen->tileSetFocusInternal(this);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
drawEvent(d);
|
||||
piForeach (PIScreenTile * t, tiles)
|
||||
t->drawEventInternal(d);
|
||||
}
|
||||
|
||||
|
||||
void PIScreenTile::sizeHint(int & w, int & h) const {
|
||||
w = 0;
|
||||
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 (!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);
|
||||
} else {
|
||||
h += ch; w = piMaxi(w, cw);
|
||||
}
|
||||
}
|
||||
w += marginLeft + marginRight;
|
||||
h += marginTop + marginBottom;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
ts2 = (direction != Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom);
|
||||
ts -= spacing * (tiles.size_s() - 1);
|
||||
PIVector<int> hints(tiles.size_s());
|
||||
PIVector<float> asizes(tiles.size_s());
|
||||
for (int i = 0; i < tiles.size_s(); ++i) {
|
||||
PIScreenTile * t(tiles[i]);
|
||||
int cw(0), ch(0), cs(0);
|
||||
if (t->visible && t->needLayout()) {
|
||||
t->sizeHint(cw, ch);
|
||||
cw = piClampi(cw, t->minimumWidth, t->maximumWidth);
|
||||
ch = piClampi(ch, t->minimumHeight, t->maximumHeight);
|
||||
if (t->size_policy == Expanding) ++ecnt;
|
||||
if (t->size_policy == Preferred) ++pcnt;
|
||||
cs = (direction == Horizontal) ? cw : ch;
|
||||
as += cs;
|
||||
}
|
||||
hints[i] = cs;
|
||||
asizes[i] = 0.f;
|
||||
}
|
||||
if (as <= ts) {
|
||||
int acnt(0);
|
||||
SizePolicy pol = Fixed;
|
||||
if (ecnt > 0) {
|
||||
acnt = ecnt;
|
||||
pol = Expanding;
|
||||
} else if (pcnt > 0) {
|
||||
acnt = pcnt;
|
||||
pol = Preferred;
|
||||
}
|
||||
if (acnt > 0) {
|
||||
float add_a = float(ts - as), add_s = add_a / acnt, add_da(0.);
|
||||
asizes.fill(add_s);
|
||||
PISet<int> max_tl;
|
||||
for (int i = 0; i < tiles.size_s(); ++i) {
|
||||
if (tiles[i]->size_policy == pol && tiles[i]->visible && tiles[i]->needLayout()) {
|
||||
float maxs = (direction == Horizontal) ? tiles[i]->maximumWidth : tiles[i]->maximumHeight;
|
||||
if (hints[i] + asizes[i] > maxs) {
|
||||
max_tl << i;
|
||||
float pas = asizes[i];
|
||||
asizes[i] = maxs - hints[i];
|
||||
acnt--;
|
||||
if (acnt > 0) {
|
||||
pas = (pas - asizes[i]) / acnt;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < tiles.size_s(); ++i) {
|
||||
if (tiles[i]->size_policy == pol && tiles[i]->visible && tiles[i]->needLayout()) {
|
||||
int a = piRound(asizes[i] + add_da);
|
||||
add_da += asizes[i] - a;
|
||||
hints[i] += a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int cx = x_ + marginLeft, cy = y_ + marginTop;
|
||||
for (int i = 0; i < tiles.size_s(); ++i) {
|
||||
PIScreenTile * t = tiles[i];
|
||||
if (!t->visible || !t->needLayout()) continue;
|
||||
t->x_ = cx;
|
||||
t->y_ = cy;
|
||||
if (direction == Horizontal) {
|
||||
t->width_ = hints[i];
|
||||
t->height_ = ts2;
|
||||
cx += hints[i] + spacing;
|
||||
} else {
|
||||
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_);
|
||||
t->pw = t->width_;
|
||||
t->ph = t->height_;
|
||||
t->layout();
|
||||
}
|
||||
}
|
||||
714
lib/console/piscreentiles.cpp
Normal file
714
lib/console/piscreentiles.cpp
Normal file
@@ -0,0 +1,714 @@
|
||||
/*
|
||||
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 distributed in the hope that 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 "piscreentiles.h"
|
||||
#include "piscreendrawer.h"
|
||||
|
||||
|
||||
using namespace PIScreenTypes;
|
||||
|
||||
|
||||
TileSimple::TileSimple(const PIString & n): PIScreenTile(n) {
|
||||
alignment = Left;
|
||||
}
|
||||
|
||||
|
||||
TileSimple::TileSimple(const TileSimple::Row & r): PIScreenTile() {
|
||||
alignment = Left;
|
||||
content << r;
|
||||
}
|
||||
|
||||
|
||||
void TileSimple::sizeHint(int & w, int & h) const {
|
||||
w = h = 0;
|
||||
piForeachC (Row & r, content)
|
||||
w = piMaxi(w, r.first.size_s());
|
||||
h = content.size_s();
|
||||
}
|
||||
|
||||
|
||||
void TileSimple::drawEvent(PIScreenDrawer * d) {
|
||||
for (int i = 0; i < content.size_s(); ++i) {
|
||||
Row & r(content[i]);
|
||||
int rx = 0;
|
||||
switch (alignment) {
|
||||
case Left: rx = x_; break;
|
||||
case Center: rx = x_ + (width_ - r.first.size_s()) / 2; break;
|
||||
case Right: rx = x_ + width_ - r.first.size_s(); break;
|
||||
};
|
||||
d->drawText(rx, y_ + i, r.first, (Color)r.second.color_char, (Color)r.second.color_back, r.second.flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TileScrollBar::TileScrollBar(const PIString & n) {
|
||||
direction = Vertical;
|
||||
thickness = 1;
|
||||
minimum_ = value_ = 0;
|
||||
maximum_ = 100;
|
||||
}
|
||||
|
||||
|
||||
void TileScrollBar::setMinimum(int v) {
|
||||
minimum_ = v;
|
||||
_check();
|
||||
}
|
||||
|
||||
|
||||
void TileScrollBar::setMaximum(int v) {
|
||||
maximum_ = v;
|
||||
_check();
|
||||
}
|
||||
|
||||
|
||||
void TileScrollBar::setValue(int v) {
|
||||
value_ = v;
|
||||
_check();
|
||||
}
|
||||
|
||||
|
||||
void TileScrollBar::_check() {
|
||||
value_ = piClampi(value_, minimum_, maximum_);
|
||||
}
|
||||
|
||||
|
||||
void TileScrollBar::sizeHint(int & w, int & h) const {
|
||||
w = h = 0;
|
||||
if (direction == Vertical) {
|
||||
w = thickness;
|
||||
h = 255;
|
||||
} else {
|
||||
h = thickness;
|
||||
w = 255;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TileScrollBar::drawEvent(PIScreenDrawer * d) {
|
||||
line_char = d->artChar(direction == Vertical ? PIScreenDrawer::LineVertical : PIScreenDrawer::LineHorizontal);
|
||||
d->fillRect(x_, y_, x_ + width_, y_ + height_, line_char, Green);
|
||||
if (value_ >= minimum_ && value_ <= maximum_) {
|
||||
if (direction == Vertical) {
|
||||
int c = piRoundf((float(value_ - minimum_) / (maximum_ - minimum_)) * (height_ - 1));
|
||||
d->drawLine(x_, y_ + c, x_ + width_ - 1, y_ + c, ' ', Green, Green);
|
||||
} else {
|
||||
int c = piRoundf((float(value_ - minimum_) / (maximum_ - minimum_)) * (width_ - 1));
|
||||
d->drawLine(x_ + c, y_, x_ + c, y_ + height_ - 1, ' ', Green, Green);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool TileScrollBar::mouseEvent(PIKbdListener::MouseEvent me) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TileList::TileList(const PIString & n): PIScreenTile(n) {
|
||||
alignment = Left;
|
||||
focus_flags = CanHasFocus | NextByArrowsHorizontal | NextByTab | FocusOnMouseOrWheel;
|
||||
lhei = offset = cur = 0;
|
||||
mouse_sel = false;
|
||||
selection_mode = NoSelection;
|
||||
scroll = new TileScrollBar();
|
||||
scroll->size_policy = Ignore;
|
||||
addTile(scroll);
|
||||
}
|
||||
|
||||
|
||||
void TileList::sizeHint(int & w, int & h) const {
|
||||
w = h = 0;
|
||||
piForeachC (Row & 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->height_ = height_;
|
||||
}
|
||||
|
||||
|
||||
void TileList::drawEvent(PIScreenDrawer * d) {
|
||||
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();
|
||||
for (int i = is; i < ie; ++i) {
|
||||
Row & r(content[i]);
|
||||
bool sel = i == cur && has_focus;
|
||||
if (sel) {
|
||||
int cy = y_ + i - is + 1;
|
||||
d->drawLine(x_, cy, x_ + width_ - 2, cy, ' ', Default, Blue);
|
||||
}
|
||||
int rx(0);
|
||||
switch (alignment) {
|
||||
case Left: rx = x_; break;
|
||||
case Center: rx = x_ + (width_ - 1 - r.first.size_s()) / 2; break;
|
||||
case Right: rx = x_ + width_ - 1 - r.first.size_s(); break;
|
||||
};
|
||||
CharFlags cf = r.second.flags;
|
||||
Color cc = (Color)r.second.color_char;
|
||||
if (selected[i]) {
|
||||
cf |= Bold;
|
||||
cc = Yellow;
|
||||
}
|
||||
d->drawText(rx, y_ + i - is + 1, r.first, cc, sel ? Blue : Default, cf);
|
||||
}
|
||||
scroll->setMaximum(piMaxi(0, content.size_s() - 1));
|
||||
scroll->setValue(cur);
|
||||
}
|
||||
|
||||
|
||||
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::UpArrow:
|
||||
cur--;
|
||||
oo--;
|
||||
if (key.modifiers[PIKbdListener::Ctrl]) {
|
||||
cur -= 4;
|
||||
oo -= 4;
|
||||
}
|
||||
if (cur < 0) cur = 0;
|
||||
if (cur - offset < osp) offset += oo;
|
||||
if (offset < 0) offset = 0;
|
||||
return true;
|
||||
case PIKbdListener::Space:
|
||||
if (cur < 0 || cur >= content.size_s()) return true;
|
||||
switch (selection_mode) {
|
||||
case NoSelection: return false;
|
||||
case SingleSelection:
|
||||
if (selected.isEmpty()) selected << cur;
|
||||
else {
|
||||
bool add = !selected[cur];
|
||||
selected.clear();
|
||||
if (add) selected << cur;
|
||||
}
|
||||
raiseEvent(TileEvent(SelectionChanged));
|
||||
return true;
|
||||
case MultiSelection:
|
||||
if (selected[cur]) selected.remove(cur);
|
||||
else selected << cur;
|
||||
raiseEvent(TileEvent(SelectionChanged));
|
||||
break;
|
||||
}
|
||||
case PIKbdListener::PageDown:
|
||||
if (key.key == PIKbdListener::PageDown) {
|
||||
cur += lhei / 2;
|
||||
oo += lhei / 2;
|
||||
}
|
||||
case PIKbdListener::DownArrow:
|
||||
cur++;
|
||||
oo++;
|
||||
if (key.modifiers[PIKbdListener::Ctrl]) {
|
||||
cur += 4;
|
||||
oo += 4;
|
||||
}
|
||||
if (cur >= content.size_s()) cur = content.size_s() - 1;
|
||||
if (cur - offset >= lhei - osp) offset += oo;
|
||||
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::End:
|
||||
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));
|
||||
return true;
|
||||
case '*':
|
||||
if (selection_mode == TileList::MultiSelection) {
|
||||
PISet<int> nsel;
|
||||
for (int i = 0; i < content.size_s(); ++i)
|
||||
if (!selected[i]) nsel << i;
|
||||
selected = nsel;
|
||||
}
|
||||
raiseEvent(TileEvent(SelectionChanged));
|
||||
return true;
|
||||
case 'A':
|
||||
if (selection_mode == TileList::MultiSelection) {
|
||||
selected.clear();
|
||||
for (int i = 0; i < content.size_s(); ++i)
|
||||
selected << i;
|
||||
}
|
||||
raiseEvent(TileEvent(SelectionChanged));
|
||||
return true;
|
||||
}
|
||||
return PIScreenTile::keyEvent(key);
|
||||
}
|
||||
|
||||
|
||||
bool TileList::mouseEvent(PIKbdListener::MouseEvent me) {
|
||||
if (me.action == PIKbdListener::MouseButtonRelease) return true;
|
||||
int mp = me.y - y() - 1 + offset;
|
||||
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;
|
||||
default: break;
|
||||
}
|
||||
if (me.buttons[PIKbdListener::MouseRight]) {
|
||||
switch (selection_mode) {
|
||||
case SingleSelection:
|
||||
selected.clear();
|
||||
selected << cur;
|
||||
raiseEvent(TileEvent(SelectionChanged));
|
||||
break;
|
||||
case MultiSelection:
|
||||
if (mouse_sel) selected << cur;
|
||||
else selected.remove(cur);
|
||||
raiseEvent(TileEvent(SelectionChanged));
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool TileList::wheelEvent(PIKbdListener::WheelEvent we) {
|
||||
keyEvent(PIKbdListener::KeyEvent(we.direction ? PIKbdListener::PageUp : PIKbdListener::PageDown));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TileButton::TileButton(const PIString & n): PIScreenTile(n) {
|
||||
focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse;
|
||||
}
|
||||
|
||||
|
||||
void TileButton::sizeHint(int & w, int & h) const {
|
||||
w = text.size_s() + 2;
|
||||
h = 1;
|
||||
}
|
||||
|
||||
|
||||
void TileButton::drawEvent(PIScreenDrawer * d) {
|
||||
Color cb = has_focus ? Blue : Cyan;
|
||||
Color ct = has_focus ? White : Black;
|
||||
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);
|
||||
d->drawText(x_ + width_ - 1, y_, "]", ct, Transparent, ff);
|
||||
}
|
||||
|
||||
|
||||
bool TileButton::keyEvent(PIKbdListener::KeyEvent key) {
|
||||
if (key.key == PIKbdListener::Space || key.key == PIKbdListener::Return) {
|
||||
raiseEvent(TileEvent(ButtonClicked));
|
||||
return true;
|
||||
}
|
||||
return PIScreenTile::keyEvent(key);
|
||||
}
|
||||
|
||||
|
||||
bool TileButton::mouseEvent(PIKbdListener::MouseEvent me) {
|
||||
if (me.action != PIKbdListener::MouseButtonRelease) return true;
|
||||
keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TileButtons::TileButtons(const PIString & n): PIScreenTile(n) {
|
||||
focus_flags = CanHasFocus | NextByTab | FocusOnMouse;
|
||||
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)
|
||||
w += b.first.size_s() + 4;
|
||||
w += piMaxi(0, content.size_s() - 1) * 2;
|
||||
h += 1;
|
||||
} else {
|
||||
piForeachC (Button & b, content)
|
||||
w = piMaxi(w, b.first.size_s() + 4);
|
||||
h += content.size_s();
|
||||
h += piMaxi(0, content.size_s() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TileButtons::drawEvent(PIScreenDrawer * d) {
|
||||
int cx = x_, cy = y_, shw, shh;
|
||||
sizeHint(shw, shh);
|
||||
btn_rects.resize(content.size());
|
||||
int dx = 0;
|
||||
switch (alignment) {
|
||||
case PIScreenTypes::Center: dx = (width_ - shw) / 2; break;
|
||||
case PIScreenTypes::Right: dx = width_ - shw; break;
|
||||
default: break;
|
||||
}
|
||||
if (direction == PIScreenTypes::Horizontal)
|
||||
cx += dx;
|
||||
for (int i = 0; i < content.size_s(); ++i) {
|
||||
Color cb = Cyan;
|
||||
Color ct = Black;
|
||||
int ff = 0;
|
||||
if (i == cur && has_focus) {
|
||||
cb = Blue;
|
||||
ct = White;
|
||||
ff = Bold;
|
||||
}
|
||||
Button & b(content[i]);
|
||||
int cw = b.first.size_s() + 2, xo(0);
|
||||
if (direction == Vertical) {
|
||||
cw = width_ - 2;
|
||||
xo = (cw - b.first.size_s()) / 2 - 1;
|
||||
}
|
||||
btn_rects[i] = Rect(cx, cy, cx + cw + 2, cy + 1);
|
||||
d->fillRect(cx, cy, cx + cw + 2, cy + 1, ' ', Default, cb);
|
||||
d->drawText(cx, cy, "[", ct, Transparent, ff);
|
||||
d->drawText(cx + xo + 2, cy, b.first, ct, Transparent, ff);
|
||||
d->drawText(cx + cw + 1, cy, "]", ct, Transparent, ff);
|
||||
if (direction == Horizontal)
|
||||
cx += b.first.size_s() + 6;
|
||||
else
|
||||
cy += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool TileButtons::keyEvent(PIKbdListener::KeyEvent key) {
|
||||
switch (key.key) {
|
||||
case PIKbdListener::LeftArrow:
|
||||
case PIKbdListener::UpArrow:
|
||||
cur--;
|
||||
if (cur < 0) cur = 0;
|
||||
return true;
|
||||
case PIKbdListener::RightArrow:
|
||||
case PIKbdListener::DownArrow:
|
||||
cur++;
|
||||
if (cur >= content.size_s()) cur = content.size_s() - 1;
|
||||
return true;
|
||||
case PIKbdListener::Space:
|
||||
case PIKbdListener::Return:
|
||||
raiseEvent(TileEvent(ButtonSelected, cur));
|
||||
return true;
|
||||
};
|
||||
return PIScreenTile::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) {
|
||||
cur = i;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (me.action != PIKbdListener::MouseButtonRelease) return true;
|
||||
keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TileCheck::TileCheck(const PIString & n): PIScreenTile(n) {
|
||||
focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse;
|
||||
toggled = false;
|
||||
}
|
||||
|
||||
|
||||
void TileCheck::sizeHint(int & w, int & h) const {
|
||||
w = text.size_s() + 4;
|
||||
h = 1;
|
||||
}
|
||||
|
||||
|
||||
void TileCheck::drawEvent(PIScreenDrawer * d) {
|
||||
Color cb = has_focus ? Blue : Cyan;
|
||||
Color ct = has_focus ? White : Black;
|
||||
int ff = has_focus ? Bold : 0;
|
||||
PIString cs("[ ]");
|
||||
if (toggled) cs[1] = '*';
|
||||
d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb);
|
||||
d->drawText(x_, y_, cs, ct, Transparent, ff);
|
||||
d->drawText(x_ + 4, y_, text, ct, Transparent, ff);
|
||||
}
|
||||
|
||||
|
||||
bool TileCheck::keyEvent(PIKbdListener::KeyEvent key) {
|
||||
if (key.key == PIKbdListener::Space || key.key == PIKbdListener::Return) {
|
||||
toggled = !toggled;
|
||||
raiseEvent(TileEvent(Toggled, toggled));
|
||||
return true;
|
||||
}
|
||||
return PIScreenTile::keyEvent(key);
|
||||
}
|
||||
|
||||
|
||||
bool TileCheck::mouseEvent(PIKbdListener::MouseEvent me) {
|
||||
if (me.action == PIKbdListener::MouseButtonPress) {
|
||||
keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TileProgress::TileProgress(const PIString & n): PIScreenTile(n) {
|
||||
maximum = 100.;
|
||||
value = 0.;
|
||||
suffix = " %";
|
||||
}
|
||||
|
||||
|
||||
void TileProgress::sizeHint(int & w, int & h) const {
|
||||
w = 20;
|
||||
h = 1;
|
||||
}
|
||||
|
||||
|
||||
void TileProgress::drawEvent(PIScreenDrawer * d) {
|
||||
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);
|
||||
d->fillRect(x_, y_, x_ + w, y_ + 1, ' ', Default, Blue);
|
||||
if (w < sx)
|
||||
d->drawText(x_ + sx, y_, s, Black, Transparent);
|
||||
else if (w >= sx + s.size_s())
|
||||
d->drawText(x_ + sx, y_, s, White, Transparent);
|
||||
else {
|
||||
int fw = w - sx;
|
||||
d->drawText(x_ + sx, y_, s.left(fw), White, Transparent);
|
||||
d->drawText(x_ + sx + fw, y_, s.cutLeft(fw), Black, Transparent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TilePICout::TilePICout(const PIString & n): TileList(n) {
|
||||
max_lines = 1024;
|
||||
selection_mode = TileList::SingleSelection;
|
||||
PICout::setOutputDevices(PICout::Buffer);
|
||||
PICout::setBufferActive(true);
|
||||
}
|
||||
|
||||
|
||||
void TilePICout::drawEvent(PIScreenDrawer * d) {
|
||||
PIString out = PICout::buffer(true);
|
||||
if (!out.isEmpty()) {
|
||||
PIStringList l = out.split("\n");
|
||||
bool scroll = (cur == content.size_s() - 1) || !has_focus;
|
||||
piForeachC (PIString & s, l)
|
||||
content << TileList::Row(s.trimmed(), format);
|
||||
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;
|
||||
}
|
||||
}
|
||||
TileList::drawEvent(d);
|
||||
}
|
||||
|
||||
|
||||
bool TilePICout::keyEvent(PIKbdListener::KeyEvent key) {
|
||||
if (key.key == 'C') {
|
||||
content.clear();
|
||||
cur = offset = 0;
|
||||
return true;
|
||||
}
|
||||
return TileList::keyEvent(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TileInput::TileInput(const PIString & n): PIScreenTile(n) {
|
||||
focus_flags = CanHasFocus | NextByTab | FocusOnMouse;
|
||||
back_format.color_back = White;
|
||||
format.color_char = Black;
|
||||
format.color_back = White;
|
||||
max_length = 1024;
|
||||
cur = offset = 0;
|
||||
inv = false;
|
||||
}
|
||||
|
||||
|
||||
void TileInput::sizeHint(int & w, int & h) const {
|
||||
w = 32;
|
||||
h = 1;
|
||||
}
|
||||
|
||||
|
||||
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 (!has_focus) return;
|
||||
Color cb = (Color)format.color_char, cc = (Color)format.color_back;
|
||||
if (tm_blink.elapsed_m() >= 650) {
|
||||
tm_blink.reset();
|
||||
inv = !inv;
|
||||
}
|
||||
if (inv) piSwap(cb, cc);
|
||||
d->drawText(x_ + 1 + cur - offset, y_, text.mid(cur, 1).expandLeftTo(1, ' '), cc, cb, (CharFlags)format.flags);
|
||||
}
|
||||
|
||||
|
||||
bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
|
||||
int lwid = piMaxi(0, width_ - 2);
|
||||
int oo(0), osp = piMini(3, lwid / 4);
|
||||
lwid--;
|
||||
switch (key.key) {
|
||||
case PIKbdListener::LeftArrow:
|
||||
cur--;
|
||||
oo--;
|
||||
if (key.modifiers[PIKbdListener::Ctrl]) {
|
||||
cur -= 4;
|
||||
oo -= 4;
|
||||
}
|
||||
if (cur < 0) cur = 0;
|
||||
if (cur - offset < osp) offset += oo;
|
||||
if (offset < 0) offset = 0;
|
||||
reserCursor();
|
||||
return true;
|
||||
case PIKbdListener::RightArrow:
|
||||
cur++;
|
||||
oo++;
|
||||
if (key.modifiers[PIKbdListener::Ctrl]) {
|
||||
cur += 4;
|
||||
oo += 4;
|
||||
}
|
||||
if (cur > text.size_s()) cur = text.size_s();
|
||||
if (cur - offset >= lwid - osp) offset += oo;
|
||||
if (offset >= text.size_s() - lwid) offset = text.size_s() - lwid;
|
||||
if (offset < 0) offset = 0;
|
||||
reserCursor();
|
||||
return true;
|
||||
case PIKbdListener::Home:
|
||||
cur = offset = 0;
|
||||
reserCursor();
|
||||
return true;
|
||||
case PIKbdListener::End:
|
||||
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;
|
||||
text.remove(cur - 1, 1);
|
||||
cur--;
|
||||
if (cur > text.size_s()) cur = text.size_s();
|
||||
if (cur - offset >= lwid - osp) offset += oo;
|
||||
if (offset >= text.size_s() - lwid) offset = text.size_s() - lwid;
|
||||
if (offset < 0) offset = 0;
|
||||
reserCursor();
|
||||
return true;
|
||||
case PIKbdListener::Delete:
|
||||
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();
|
||||
if (cur - offset < osp) offset += oo;
|
||||
if (offset < 0) offset = 0;
|
||||
reserCursor();
|
||||
return true;
|
||||
case PIKbdListener::UpArrow:
|
||||
case PIKbdListener::DownArrow:
|
||||
case PIKbdListener::PageUp:
|
||||
case PIKbdListener::PageDown:
|
||||
case PIKbdListener::Insert:
|
||||
case PIKbdListener::Return:
|
||||
case PIKbdListener::Esc:
|
||||
case PIKbdListener::F1:
|
||||
case PIKbdListener::F2:
|
||||
case PIKbdListener::F3:
|
||||
case PIKbdListener::F4:
|
||||
case PIKbdListener::F5:
|
||||
case PIKbdListener::F6:
|
||||
case PIKbdListener::F7:
|
||||
case PIKbdListener::F8:
|
||||
case PIKbdListener::F9:
|
||||
case PIKbdListener::F10:
|
||||
case PIKbdListener::F11:
|
||||
case PIKbdListener::F12:
|
||||
break;
|
||||
default:
|
||||
PIChar tc
|
||||
#ifdef WINDOWS
|
||||
= PIChar(key.key);
|
||||
#else
|
||||
= PIChar::fromUTF8((char *)&(key.key));
|
||||
#endif
|
||||
text.insert(cur, tc);
|
||||
cur++;
|
||||
oo++;
|
||||
if (cur - offset >= lwid - osp) offset += oo;
|
||||
if (offset >= text.size_s() - lwid) offset = text.size_s() - lwid;
|
||||
if (offset < 0) offset = 0;
|
||||
reserCursor();
|
||||
return true;
|
||||
}
|
||||
return PIScreenTile::keyEvent(key);
|
||||
}
|
||||
|
||||
|
||||
void TileInput::reserCursor() {
|
||||
tm_blink.reset();
|
||||
inv = false;
|
||||
}
|
||||
920
lib/console/piterminal.cpp
Normal file
920
lib/console/piterminal.cpp
Normal file
@@ -0,0 +1,920 @@
|
||||
/*
|
||||
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 distributed in the hope that 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 "piterminal.h"
|
||||
#include "pisharedmemory.h"
|
||||
#ifndef FREERTOS
|
||||
#ifdef WINDOWS
|
||||
# include <windows.h>
|
||||
# include <wincon.h>
|
||||
# include <winuser.h>
|
||||
#else
|
||||
# include "piprocess.h"
|
||||
# include <csignal>
|
||||
# include <fcntl.h>
|
||||
# include <sys/ioctl.h>
|
||||
# if defined(QNX) || defined(BLACKBERRY)
|
||||
# include <unix.h>
|
||||
# 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
|
||||
|
||||
|
||||
//extern PIMutex PICout::__mutex__;
|
||||
|
||||
#ifdef WINDOWS
|
||||
# define PIPE_BUFFER_SIZE 1024
|
||||
enum PITerminalAuxMessageType {
|
||||
mtKey = 1,
|
||||
mtResize,
|
||||
mtScroll
|
||||
};
|
||||
struct PITerminalAuxData {
|
||||
int cursor_x;
|
||||
int cursor_y;
|
||||
int size_x;
|
||||
int size_y;
|
||||
int cells_size;
|
||||
};
|
||||
#else
|
||||
# define BUFFER_SIZE 4096
|
||||
enum DECType {
|
||||
CKM = 1
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
PRIVATE_DEFINITION_START(PITerminal)
|
||||
#ifdef WINDOWS
|
||||
PISharedMemory * shm;
|
||||
HANDLE hConBuf;
|
||||
STARTUPINFOA si;
|
||||
PROCESS_INFORMATION pi;
|
||||
HANDLE pipe;
|
||||
#else
|
||||
PIString shell;
|
||||
PIByteArray read_buf, tmp_buf;
|
||||
PIScreenTypes::CellFormat cur_format, line_format;
|
||||
int term_type;
|
||||
int fd, cur_x, cur_y;
|
||||
int save_cur_x, save_cur_y;
|
||||
int win_y0, win_y1;
|
||||
pid_t pid;
|
||||
PIString esc_seq;
|
||||
bool is_esc_seq, last_read;
|
||||
PIMap<int, bool> DEC;
|
||||
PIVector<PIVector<PIScreenTypes::Cell> > cells_save;
|
||||
#endif
|
||||
PRIVATE_DEFINITION_END(PITerminal)
|
||||
|
||||
|
||||
#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();
|
||||
return int(wrote[0] + wrote[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
PITerminal::PITerminal(): PIThread() {
|
||||
setName("terminal");
|
||||
initPrivate();
|
||||
cursor_blink = false;
|
||||
cursor_x = cursor_y = 0;
|
||||
dsize_x = 80;
|
||||
dsize_y = 24;
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->shm = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PITerminal::~PITerminal() {
|
||||
if (isRunning())
|
||||
stop();
|
||||
PIThread::waitForFinish(10);
|
||||
destroy();
|
||||
#ifdef WINDOWS
|
||||
if (PRIVATE->shm) delete PRIVATE->shm;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PITerminal::write(const PIByteArray & d) {
|
||||
#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
|
||||
if (PRIVATE->fd == 0) return;
|
||||
//ssize_t wrote = 0;
|
||||
//wrote =
|
||||
::write(PRIVATE->fd, d.data(), d.size_s());
|
||||
//piCout << "wrote" << wrote << d;
|
||||
# endif
|
||||
#endif
|
||||
cursor_tm.reset();
|
||||
cursor_blink = true;
|
||||
}
|
||||
|
||||
|
||||
void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m) {
|
||||
PIByteArray ba;
|
||||
#ifdef WINDOWS
|
||||
switch (k) {
|
||||
case PIKbdListener::Tab: ba << uchar('\t'); break;
|
||||
case PIKbdListener::Return: ba << uchar('\r') << uchar('\n'); break;
|
||||
case PIKbdListener::Space: ba << uchar(' '); break;
|
||||
default: break;
|
||||
}
|
||||
//piCout << "write" << ba.size();
|
||||
if (!ba.isEmpty()) write(ba);
|
||||
else {
|
||||
PIByteArray msg;
|
||||
PIVector<PIKbdListener::KeyEvent> ke;
|
||||
ke << PIKbdListener::KeyEvent(k, m);
|
||||
msg << int(mtKey) << ke;
|
||||
writePipe(PRIVATE->pipe, msg);
|
||||
}
|
||||
#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::Home: //break;
|
||||
case PIKbdListener::End: //break;
|
||||
case PIKbdListener::PageUp: //ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break;
|
||||
case PIKbdListener::PageDown: //ba << uchar('\e') << uchar('[') << uchar('6') << uchar('~'); break;
|
||||
case PIKbdListener::Insert: //ba << uchar('\e') << uchar('[') << uchar('2') << uchar('~'); break;
|
||||
case PIKbdListener::Delete: //ba << uchar('\e') << uchar('[') << uchar('3') << uchar('~'); break;
|
||||
case PIKbdListener::F1: //break;
|
||||
case PIKbdListener::F2: //break;
|
||||
case PIKbdListener::F3: //break;
|
||||
case PIKbdListener::F4: //break;
|
||||
case PIKbdListener::F5: //break;
|
||||
case PIKbdListener::F6: //break;
|
||||
case PIKbdListener::F7: //break;
|
||||
case PIKbdListener::F8: //break;
|
||||
case PIKbdListener::F9: //break;
|
||||
case PIKbdListener::F10: //break;
|
||||
case PIKbdListener::F11: //break;
|
||||
case PIKbdListener::F12: //break;
|
||||
*/
|
||||
default: {
|
||||
//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) {
|
||||
const PIKbdListener::EscSeq & e(PIKbdListener::esc_seq[i]);
|
||||
if (!e.seq) break;
|
||||
//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");
|
||||
PIByteArray d = ("\e" + PIString(e.seq)).toByteArray();
|
||||
write(d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
//piCout << "write" << ba.size();
|
||||
if (!ba.isEmpty()) write(ba);
|
||||
#endif
|
||||
cursor_tm.reset();
|
||||
cursor_blink = true;
|
||||
}
|
||||
|
||||
|
||||
void PITerminal::write(PIKbdListener::KeyEvent ke) {
|
||||
if (isSpecialKey(ke.key)) write((PIKbdListener::SpecialKey)ke.key, ke.modifiers);
|
||||
else {
|
||||
PIByteArray ba;
|
||||
#ifdef WINDOWS
|
||||
ba << uchar(PIChar(ke.key).toConsole1Byte());
|
||||
#else
|
||||
ba = PIString(PIChar(ke.key)).toUTF8();
|
||||
#endif
|
||||
write(ba);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIVector<PIScreenTypes::Cell> > PITerminal::content() {
|
||||
readConsole();
|
||||
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;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PITerminal::isSpecialKey(int k) {
|
||||
switch (k) {
|
||||
case PIKbdListener::Tab:
|
||||
case PIKbdListener::Return:
|
||||
case PIKbdListener::Esc:
|
||||
case PIKbdListener::Space:
|
||||
case PIKbdListener::Backspace:
|
||||
case PIKbdListener::UpArrow:
|
||||
case PIKbdListener::DownArrow:
|
||||
case PIKbdListener::RightArrow:
|
||||
case PIKbdListener::LeftArrow:
|
||||
case PIKbdListener::Home:
|
||||
case PIKbdListener::End:
|
||||
case PIKbdListener::PageUp:
|
||||
case PIKbdListener::PageDown:
|
||||
case PIKbdListener::Insert:
|
||||
case PIKbdListener::Delete:
|
||||
case PIKbdListener::F1:
|
||||
case PIKbdListener::F2:
|
||||
case PIKbdListener::F3:
|
||||
case PIKbdListener::F4:
|
||||
case PIKbdListener::F5:
|
||||
case PIKbdListener::F6:
|
||||
case PIKbdListener::F7:
|
||||
case PIKbdListener::F8:
|
||||
case PIKbdListener::F9:
|
||||
case PIKbdListener::F10:
|
||||
case PIKbdListener::F11:
|
||||
case PIKbdListener::F12: return true;
|
||||
default: return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void PITerminal::initPrivate() {
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->hConBuf = INVALID_HANDLE_VALUE;
|
||||
PRIVATE->pipe = INVALID_HANDLE_VALUE;
|
||||
PRIVATE->pi.hProcess = 0;
|
||||
#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->esc_seq.clear();
|
||||
PRIVATE->cur_format = PIScreenTypes::CellFormat();
|
||||
#endif
|
||||
cursor_blink = cursor_visible = true;
|
||||
size_x = size_y = 0;
|
||||
}
|
||||
|
||||
|
||||
void PITerminal::readConsole() {
|
||||
#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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
void PITerminal::getCursor(int & x, int & y) {
|
||||
#ifdef WINDOWS
|
||||
if (!PRIVATE->shm) return;
|
||||
int sz = 0;
|
||||
PRIVATE->shm->read(&sz, 4);
|
||||
#else
|
||||
x = PRIVATE->cur_x;
|
||||
y = PRIVATE->cur_y;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
uchar PITerminal::invertColor(uchar c) {
|
||||
switch ((PIScreenTypes::Color)c) {
|
||||
case PIScreenTypes::Black: return PIScreenTypes::White;
|
||||
case PIScreenTypes::Red: return PIScreenTypes::Cyan;
|
||||
case PIScreenTypes::Green: return PIScreenTypes::Magenta;
|
||||
case PIScreenTypes::Blue: return PIScreenTypes::Yellow;
|
||||
case PIScreenTypes::Cyan: return PIScreenTypes::Red;
|
||||
case PIScreenTypes::Magenta: return PIScreenTypes::Green;
|
||||
case PIScreenTypes::Yellow: return PIScreenTypes::Blue;
|
||||
case PIScreenTypes::White: return PIScreenTypes::Black;
|
||||
default: break;
|
||||
}
|
||||
return PIScreenTypes::White;
|
||||
}
|
||||
|
||||
|
||||
void PITerminal::run() {
|
||||
getCursor(cursor_x, cursor_y);
|
||||
if (cursor_tm.elapsed_m() >= 500) {
|
||||
cursor_tm.reset();
|
||||
cursor_blink = !cursor_blink;
|
||||
}
|
||||
#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;
|
||||
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));
|
||||
PRIVATE->read_buf.append(PRIVATE->tmp_buf.resized(readed));
|
||||
for (;;) {
|
||||
int ind = -1;
|
||||
for (int i = PRIVATE->read_buf.size_s() - 1; i >= 0; --i)
|
||||
if (PRIVATE->read_buf[i] == uchar('\n') || PRIVATE->read_buf[i] == uchar('\e')) {
|
||||
ind = i;
|
||||
break;
|
||||
}
|
||||
if (ind <= 0) break;
|
||||
used = true;
|
||||
parseInput(PIString((const char *)PRIVATE->read_buf.data(), ind));
|
||||
PRIVATE->read_buf.remove(0, ind);
|
||||
}
|
||||
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 (parse) {
|
||||
parseInput(PIString(PRIVATE->read_buf));
|
||||
PRIVATE->read_buf.clear();
|
||||
}
|
||||
//printf("%s", PRIVATE->read_buf.data());
|
||||
}
|
||||
if (!used && !PRIVATE->last_read && !PRIVATE->read_buf.isEmpty()) {
|
||||
parseInput(PIString(PRIVATE->read_buf));
|
||||
PRIVATE->read_buf.clear();
|
||||
}
|
||||
PRIVATE->last_read = false;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifndef WINDOWS
|
||||
void PITerminal::parseInput(const PIString & s) {
|
||||
//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) {
|
||||
if (s[i] == '\e') {
|
||||
applyEscSeq(PRIVATE->esc_seq);
|
||||
PRIVATE->esc_seq.clear();
|
||||
PRIVATE->is_esc_seq = true;
|
||||
} else {
|
||||
PRIVATE->esc_seq += s[i];
|
||||
if (isCompleteEscSeq(PRIVATE->esc_seq)) {
|
||||
PRIVATE->is_esc_seq = false;
|
||||
applyEscSeq(PRIVATE->esc_seq);
|
||||
//piCoutObj << PRIVATE->esc_seq;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (s[i] == '\e') {
|
||||
PRIVATE->esc_seq.clear();
|
||||
PRIVATE->is_esc_seq = true;
|
||||
} else {
|
||||
if (s[i] == '\a') continue;
|
||||
if (s[i] == '\b') {
|
||||
moveCursor(-1, 0);
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
PRIVATE->line_format = PRIVATE->cur_format;
|
||||
PRIVATE->cur_x = 0;
|
||||
moveCursor(0, 1);
|
||||
continue;
|
||||
}
|
||||
//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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PITerminal::isCompleteEscSeq(const PIString & es) {
|
||||
if (es.size_s() < 2) return false;
|
||||
if (es.front() == ']') {
|
||||
if (es.back().toAscii() == '\\' || es.back().toAscii() == '\a') return true;
|
||||
} else {
|
||||
if (es.back().toAscii() >= 64 && es.back().toAscii() <= 126) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void PITerminal::applyEscSeq(PIString es) {
|
||||
piCoutObj << es;
|
||||
if (es.size_s() < 2) return;
|
||||
// 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();
|
||||
bool val = false;
|
||||
if (a == 'l') val = false;
|
||||
if (a == 'h') val = true;
|
||||
int dec = es.mid(2).toInt();
|
||||
piCoutObj << "DEC" << dec << val;
|
||||
PRIVATE->DEC[dec] = val;
|
||||
switch (dec) {
|
||||
case 25: cursor_visible = val; break;
|
||||
case 1049:
|
||||
if (val) {
|
||||
PRIVATE->save_cur_x = PRIVATE->cur_x;
|
||||
PRIVATE->save_cur_y = PRIVATE->cur_y;
|
||||
} else {
|
||||
PRIVATE->cur_x = PRIVATE->save_cur_x;
|
||||
PRIVATE->cur_y = PRIVATE->save_cur_y;
|
||||
}
|
||||
case 1047:
|
||||
if (val) {
|
||||
PRIVATE->cells_save = cells;
|
||||
for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell);
|
||||
} else {
|
||||
cells = PRIVATE->cells_save;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (es[0] == '[') { // CSI
|
||||
if (es.back() == 'm') {
|
||||
es.cutLeft(1).cutRight(1);
|
||||
if (es.isEmpty()) {
|
||||
PRIVATE->cur_format = PIScreenTypes::CellFormat();
|
||||
return;
|
||||
}
|
||||
PIStringList args = es.split(";");
|
||||
piForeachC (PIString & a, args) {
|
||||
int av = a.toInt();
|
||||
switch (av) {
|
||||
case 0: PRIVATE->cur_format = PIScreenTypes::CellFormat(); break;
|
||||
case 1: PRIVATE->cur_format.flags |= PIScreenTypes::Bold; break;
|
||||
case 4: PRIVATE->cur_format.flags |= PIScreenTypes::Underline; break;
|
||||
case 5: PRIVATE->cur_format.flags |= PIScreenTypes::Blink; break;
|
||||
case 7: PRIVATE->cur_format.flags |= PIScreenTypes::Inverse; break;
|
||||
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 (col) {
|
||||
int cfl = 0;
|
||||
switch (cid) {
|
||||
case 0: cfl = PIScreenTypes::Black; break;
|
||||
case 1: cfl = PIScreenTypes::Red; break;
|
||||
case 2: cfl = PIScreenTypes::Green; break;
|
||||
case 3: cfl = PIScreenTypes::Yellow; break;
|
||||
case 4: cfl = PIScreenTypes::Blue; break;
|
||||
case 5: cfl = PIScreenTypes::Magenta; break;
|
||||
case 6: cfl = PIScreenTypes::Cyan; break;
|
||||
case 7: cfl = PIScreenTypes::White; break;
|
||||
}
|
||||
if (target)
|
||||
PRIVATE->cur_format.color_back = cfl;
|
||||
else
|
||||
PRIVATE->cur_format.color_char = cfl;
|
||||
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;
|
||||
}*/
|
||||
}
|
||||
if (es.back() == 'r') {
|
||||
piCoutObj << es;
|
||||
es.cutLeft(1).cutRight(1);
|
||||
PIStringList args = es.split(";");
|
||||
args.resize(2);
|
||||
int y0(0), y1(0);
|
||||
if (!args[0].isEmpty()) y0 = args[0].toInt() - 1;
|
||||
if (!args[1].isEmpty()) y1 = args[1].toInt() - 1;
|
||||
PRIVATE->win_y0 = piClamp(y0, 0, size_y - 1);
|
||||
PRIVATE->win_y1 = piClamp(y1, 0, size_y - 1);
|
||||
}
|
||||
if (es.back() == 's') {
|
||||
PRIVATE->save_cur_x = PRIVATE->cur_x;
|
||||
PRIVATE->save_cur_y = PRIVATE->cur_y;
|
||||
}
|
||||
if (es.back() == 'u') {
|
||||
PRIVATE->cur_x = PRIVATE->save_cur_x;
|
||||
PRIVATE->cur_y = PRIVATE->save_cur_y;
|
||||
}
|
||||
if (es.back() == 'H' || es.back() == 'f' || es.back() == 'r') {
|
||||
es.cutLeft(1).cutRight(1);
|
||||
PIStringList args = es.split(";");
|
||||
args.resize(2);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
PRIVATE->line_format = PRIVATE->cur_format;
|
||||
}
|
||||
if (es.back() == 'G' || es.back() == '`') { // goto column
|
||||
es.cutLeft(1).cutRight(1);
|
||||
int v = es.toInt();
|
||||
if (v) PRIVATE->cur_x = piClamp(v - 1, 0, size_x - 1);
|
||||
PRIVATE->line_format = PRIVATE->cur_format;
|
||||
}
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
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];
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
case 2:
|
||||
for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell);
|
||||
//PRIVATE->cur_x = PRIVATE->cur_y = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (es.back() == 'K') { // erase in line
|
||||
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;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PITerminal::moveCursor(int dx, int dy) {
|
||||
PRIVATE->cur_x += dx;
|
||||
PRIVATE->cur_y += dy;
|
||||
if (PRIVATE->cur_x < 0) PRIVATE->cur_x = 0;
|
||||
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_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;
|
||||
PRIVATE->cur_y = size_y - 1;
|
||||
for (int y = 0; y < size_y - scroll; ++y)
|
||||
cells[y] = cells[y + scroll];
|
||||
for (int y = size_y - scroll; y < size_y; ++y)
|
||||
cells[y].fill(PIScreenTypes::Cell());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int PITerminal::termType(const PIString & t) {
|
||||
if (t == "xterm") return PIKbdListener::vt_xterm;
|
||||
else if (t == "linux") return PIKbdListener::vt_linux;
|
||||
return PIKbdListener::vt_none;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool PITerminal::initialize() {
|
||||
destroy();
|
||||
#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;
|
||||
}
|
||||
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;
|
||||
}*/
|
||||
//CreatePipe(&(PRIVATE->pipe_out[0]), &(PRIVATE->pipe_out[1]), &sa, 0);
|
||||
//SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0);
|
||||
//SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0);
|
||||
//GetStartupInfoA(&PRIVATE->si);
|
||||
memset(&PRIVATE->si, 0, sizeof(PRIVATE->si));
|
||||
PRIVATE->si.cb = sizeof(STARTUPINFO);
|
||||
//PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES;
|
||||
PRIVATE->si.dwFlags |= STARTF_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.dwXCountChars = 80;
|
||||
PRIVATE->si.dwYCountChars = 24;
|
||||
|
||||
memset(&PRIVATE->pi, 0, sizeof(PRIVATE->pi));
|
||||
|
||||
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)) {
|
||||
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);
|
||||
if (PRIVATE->pipe == INVALID_HANDLE_VALUE) {
|
||||
piCoutObj << "CreateNamedPipe error," << errorString();
|
||||
destroy();
|
||||
return false;
|
||||
}
|
||||
PITimeMeasurer tm;
|
||||
bool ok = false;
|
||||
while (tm.elapsed_m() < 1000) {
|
||||
if (ConnectNamedPipe(PRIVATE->pipe, 0) == TRUE) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
piCoutObj << "ConnectNamedPipe error," << errorString();
|
||||
destroy();
|
||||
return false;
|
||||
}
|
||||
if (PRIVATE->shm) delete PRIVATE->shm;
|
||||
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);
|
||||
winsize ws;
|
||||
ws.ws_col = dsize_x;
|
||||
ws.ws_row = dsize_y;
|
||||
PIStringList env = PIProcess::currentEnvironment();
|
||||
piForeachC (PIString & e, env)
|
||||
if (e.startsWith("TERM=")) {
|
||||
PRIVATE->term_type = termType(e.mid(5).trim().toLowerCase());
|
||||
//piCout << PRIVATE->term_type;
|
||||
piBreak;
|
||||
}
|
||||
pid_t fr = forkpty(&(PRIVATE->fd), pty, 0, &ws);
|
||||
//piCoutObj << fr << PRIVATE->fd << pty;
|
||||
if (fr == 0) {
|
||||
char ** argv = new char*[2];
|
||||
argv[0] = new char[PRIVATE->shell.lengthAscii() + 1];
|
||||
memcpy(argv[0], PRIVATE->shell.dataAscii(), PRIVATE->shell.lengthAscii());
|
||||
argv[0][PRIVATE->shell.lengthAscii()] = 0;
|
||||
argv[1] = 0;
|
||||
execvp(PRIVATE->shell.dataAscii(), argv);
|
||||
delete[] argv[0];
|
||||
delete[] argv;
|
||||
exit(0);
|
||||
} else {
|
||||
if (fr < 0 || PRIVATE->fd < 0) {
|
||||
piCoutObj << "forkpty error," << errorString();
|
||||
initPrivate();
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
*/
|
||||
size_x = dsize_x;
|
||||
size_y = dsize_y;
|
||||
resize(size_x, size_y);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
cursor_blink = false;
|
||||
cursor_tm.reset();
|
||||
start(40);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PITerminal::destroy() {
|
||||
//piCout << "destroy ...";
|
||||
stop();
|
||||
waitForFinish(1000);
|
||||
#ifdef WINDOWS
|
||||
if (PRIVATE->pi.hProcess) {
|
||||
//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);
|
||||
# endif
|
||||
#endif
|
||||
initPrivate();
|
||||
}
|
||||
|
||||
|
||||
bool PITerminal::resize(int cols, int rows) {
|
||||
bool ret = true;
|
||||
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
|
||||
if (PRIVATE->fd == 0) return false;
|
||||
size_x = dsize_x;
|
||||
size_y = dsize_y;
|
||||
//piCout << "resize" << PRIVATE->fd << size_x << size_y;
|
||||
winsize ws;
|
||||
ws.ws_col = cols;
|
||||
ws.ws_row = rows;
|
||||
ioctl(PRIVATE->fd, TIOCSWINSZ, &ws);
|
||||
PRIVATE->win_y0 = 0;
|
||||
PRIVATE->win_y1 = size_y - 1;
|
||||
PRIVATE->cells_save.resize(size_y);
|
||||
for (int i = 0; i < size_y; ++i)
|
||||
PRIVATE->cells_save[i].resize(size_x);
|
||||
# endif
|
||||
#endif
|
||||
cells.resize(size_y);
|
||||
for (int i = 0; i < size_y; ++i)
|
||||
cells[i].resize(size_x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // FREERTOS
|
||||
297
lib/crypt/piauth.cpp
Normal file
297
lib/crypt/piauth.cpp
Normal file
@@ -0,0 +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, PIByteArray::fromHex("PIAuth"));
|
||||
}
|
||||
|
||||
|
||||
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, PIByteArray::fromHex("PIAuth"));
|
||||
ps.fill(0);
|
||||
tba.clear();
|
||||
tba << ph << auth_sign << sign_pk;
|
||||
tba = crypt.crypt(tba, box_pk, box_sk);
|
||||
ba.clear();
|
||||
state = PassRequest;
|
||||
ba << (int)state << tba;
|
||||
rsign = crypt.signMessage(ba, sign_sk);
|
||||
ba << rsign;
|
||||
return state;
|
||||
}
|
||||
if ((state == AuthReply && rstate == KeyExchange) || (state == PassRequest && rstate == KeyExchange)) {
|
||||
PIByteArray tba, ctba;
|
||||
PIByteArray rsign;
|
||||
ba >> ctba >> rsign;
|
||||
bool ok = false;
|
||||
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
|
||||
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
|
||||
ba.clear();
|
||||
ba << (int)rstate << ctba;
|
||||
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
|
||||
tba >> secret_key;
|
||||
if (secret_key.size() != crypt.sizeKey()) return disconnect(ba, "Invalid key");
|
||||
ba.clear();
|
||||
state = Connected;
|
||||
connected(PIString());
|
||||
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
|
||||
return state;
|
||||
}
|
||||
if (state == Connected && rstate == Connected) {
|
||||
ba.clear();
|
||||
state = Connected;
|
||||
connected(PIString());
|
||||
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
// server side
|
||||
if (role == Server) {
|
||||
if (state == AuthProbe && rstate == AuthReply) {
|
||||
if (ba.size() < sizeof(int)*4) return disconnect(ba, "invalid data size");
|
||||
PIByteArray ctba, tba;
|
||||
PIByteArray noise;
|
||||
PIByteArray rsign1, rsign2;
|
||||
PIByteArray rsign_pk;
|
||||
PIByteArray pk, mpk;
|
||||
ba >> ctba >> pk >> noise >> rsign1;
|
||||
bool ok = false;
|
||||
tba = crypt.decrypt(ctba, pk, box_sk, &ok);
|
||||
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
|
||||
if (tba.size() < sizeof(int)*3) return disconnect(tba, "invalid data size");
|
||||
tba >> rsign_pk >> box_pk >> mpk >> rsign2;
|
||||
if (pk != box_pk || mpk != my_pk) return disconnect(ba, "Invalid public key");
|
||||
ba.clear();
|
||||
ba << (int)rstate << ctba << box_pk << noise;
|
||||
if (!crypt.verifySign(ba, rsign1, rsign_pk)) return disconnect(ba, "Incorrect sign");
|
||||
ba.clear();
|
||||
ba << rsign_pk << box_pk << my_pk;
|
||||
if (!crypt.verifySign(ba, rsign2, rsign_pk)) return disconnect(ba, "Incorrect sign");
|
||||
auth_sign = rsign_pk;
|
||||
if (isAuthorizedKey(rsign_pk)) {
|
||||
state = KeyExchange;
|
||||
ba = createSKMessage();
|
||||
return state;
|
||||
} else {
|
||||
ba.clear();
|
||||
tba.clear();
|
||||
state = PassRequest;
|
||||
noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
|
||||
tba << sign_pk << noise << box_pk;
|
||||
tba = crypt.crypt(tba, box_pk, box_sk);
|
||||
ba << (int)state << tba;
|
||||
rsign1 = crypt.signMessage(ba, sign_sk);
|
||||
ba << rsign1;
|
||||
return state;
|
||||
}
|
||||
}
|
||||
if (state == PassRequest && rstate == PassRequest) {
|
||||
PIByteArray tba, ctba;
|
||||
PIByteArray rsign_pk, rsign, mpk;
|
||||
ba >> ctba >> rsign;
|
||||
bool ok = false;
|
||||
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
|
||||
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
|
||||
ba.clear();
|
||||
ba << (int)rstate << ctba;
|
||||
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
|
||||
ctba.clear();
|
||||
tba >> ctba >> mpk >> rsign_pk;
|
||||
if (rsign_pk != auth_sign || mpk != sign_pk) return disconnect(ba, "Invalid public key");
|
||||
bool auth = (ctba == pass_hash);
|
||||
if (ctba.isEmpty() || pass_hash.isEmpty()) auth = false;
|
||||
passwordCheck(auth);
|
||||
if (!auth) {
|
||||
// piSleep(1);
|
||||
return disconnect(ba, "Invalid password");
|
||||
}
|
||||
state = KeyExchange;
|
||||
ba = createSKMessage();
|
||||
return state;
|
||||
}
|
||||
if ((state == KeyExchange && rstate == Connected) || (state == Connected && rstate == Connected)) {
|
||||
ba.clear();
|
||||
PIByteArray rinfo;
|
||||
ba >> rinfo;
|
||||
bool ok = false;
|
||||
rinfo = crypt.decrypt(rinfo, secret_key, &ok);
|
||||
if (!ok) return disconnect(ba, "Error while exchange keys");
|
||||
state = Connected;
|
||||
connected(rinfo);
|
||||
ba << (int)state << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
return disconnect(ba, "invalid state " + PIString::fromNumber((int)state));
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIAuth::getSecretKey() {
|
||||
if (state == Connected) return secret_key;
|
||||
return PIByteArray();
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIAuth::generateSign(const PIByteArray & seed) {
|
||||
PIByteArray pk, sk;
|
||||
PICrypt::generateSignKeys(pk, sk, seed);
|
||||
return sk;
|
||||
}
|
||||
|
||||
|
||||
PIAuth::State PIAuth::disconnect(PIByteArray & ba, const PIString & error) {
|
||||
if (!error.isEmpty()) piCoutObj << error;
|
||||
auth_sign.clear();
|
||||
box_sk.clear();
|
||||
box_pk.clear();
|
||||
my_pk.clear();
|
||||
secret_key.clear();
|
||||
ba.clear();
|
||||
state = NotConnected;
|
||||
disconnected(error);
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
bool PIAuth::isAuthorizedKey(const PIByteArray & pkey) {
|
||||
for (int i=0; i<auth_pkeys.size_s(); ++i) {
|
||||
if (pkey == auth_pkeys[i]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIAuth::createSKMessage() {
|
||||
secret_key = crypt.generateKey();
|
||||
PIByteArray tba;
|
||||
PIByteArray noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
|
||||
tba << secret_key << noise;
|
||||
tba = crypt.crypt(tba, box_pk, box_sk);
|
||||
PIByteArray ret;
|
||||
ret << (int)state << tba;
|
||||
PIByteArray sign = crypt.signMessage(ret, sign_sk);
|
||||
ret << sign;
|
||||
return ret;
|
||||
}
|
||||
421
lib/crypt/picrypt.cpp
Normal file
421
lib/crypt/picrypt.cpp
Normal file
@@ -0,0 +1,421 @@
|
||||
/*
|
||||
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_";
|
||||
|
||||
|
||||
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, sizeof(hash_def_key) - 1);
|
||||
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, sizeof(hash_def_key) - 1);
|
||||
#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, sizeof(hash_def_key) - 1);
|
||||
#else
|
||||
PICRYPT_DISABLED_WARNING
|
||||
#endif
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
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();
|
||||
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();
|
||||
//piCout << "[PICrypt]" << "init" << inited;
|
||||
return inited;
|
||||
#else
|
||||
PICRYPT_DISABLED_WARNING
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
34
lib/fftw/pifft.cpp
Normal file
34
lib/fftw/pifft.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
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)
|
||||
181
lib/fftw/pifft_p.h
Normal file
181
lib/fftw/pifft_p.h
Normal file
@@ -0,0 +1,181 @@
|
||||
/*! \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 "pimutex.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 PIP_EXPORT 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
|
||||
268
lib/io_utils/pibroadcast.cpp
Normal file
268
lib/io_utils/pibroadcast.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Broadcast for all interfaces, including loopback
|
||||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pibroadcast.h"
|
||||
|
||||
/** \class PIBroadcast
|
||||
* \brief Broadcast for all interfaces, including loopback
|
||||
*
|
||||
* \section PIBroadcast_synopsis Synopsis
|
||||
* %PIBroadcast used as multichannel IO device. It can use
|
||||
* multicast, broadcast and loopback ethernet channels to
|
||||
* send/receive packets. \a send() function send packet to
|
||||
* all initialized ethernets. \a receiveEvent() raised on
|
||||
* packet received by any ethernet. All multi/broadcast
|
||||
* ethernets created for all current addresses, obtained
|
||||
* by \a PIEthernets::allAddresses().
|
||||
*
|
||||
* * \a Multicast ethernets use \a multicastGroup() and \a multicastPort()
|
||||
* * \a Broadcast ethernets use \a broadcastPort()
|
||||
* * \a Loopback ethernet use \a loopbackPortsCount() started from \a loopbackPort()
|
||||
*
|
||||
* %PIBroadcast starts thread, which every 3 seconds check if
|
||||
* current \a PIEthernet::allAddresses() was changed and call
|
||||
* \a reinit() if it necessary.
|
||||
*
|
||||
*/
|
||||
|
||||
#define MULTICAST_TTL 4
|
||||
|
||||
|
||||
PIBroadcast::PIBroadcast(bool send_only): PIThread(), PIEthUtilBase() {
|
||||
_channels = All;
|
||||
eth_lo = 0;
|
||||
mcast_address.set("232.13.3.14", 14100);
|
||||
lo_port = 14200;
|
||||
lo_pcnt = 5;
|
||||
_started = false;
|
||||
_send_only = send_only;
|
||||
_reinit = true;
|
||||
//initMcast(PIEthernet::allAddresses());
|
||||
PIThread::start(3000);
|
||||
}
|
||||
|
||||
|
||||
PIBroadcast::~PIBroadcast() {
|
||||
PIThread::stop();
|
||||
mcast_mutex.unlock();
|
||||
destroyAll();
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::setChannels(PIBroadcast::Channels ch) {
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
_channels = ch;
|
||||
_reinit = true;
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::setMulticastGroup(const PIString & mg) {
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
mcast_address.setIP(mg);
|
||||
_reinit = true;
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::setMulticastPort(ushort port) {
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
mcast_address.setPort(port);
|
||||
_reinit = true;
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::setMulticastAddress(const PIEthernet::Address & addr) {
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
mcast_address = addr;
|
||||
_reinit = true;
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::setBroadcastPort(ushort port) {
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
bcast_port = port;
|
||||
_reinit = true;
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::setLoopbackPort(ushort port) {
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
lo_port = port;
|
||||
_reinit = true;
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::setLoopbackPortsCount(int count) {
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
lo_pcnt = count;
|
||||
_reinit = true;
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::destroyAll() {
|
||||
piForeach (PIEthernet * e, eth_mcast) {
|
||||
e->stopThreadedRead();
|
||||
delete e;
|
||||
}
|
||||
eth_mcast.clear();
|
||||
if (eth_lo) {
|
||||
eth_lo->stopThreadedRead();
|
||||
delete eth_lo;
|
||||
eth_lo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
destroyAll();
|
||||
_reinit = false;
|
||||
prev_al = al;
|
||||
al.removeAll(PIEthernet::Address("127.0.0.1"));
|
||||
al << mcast_address;
|
||||
eth_mcast.clear();
|
||||
PIEthernet::InterfaceList ifaces = PIEthernet::interfaces();
|
||||
piForeachC (PIEthernet::Address & a, al) {
|
||||
PIEthernet * ce = 0;
|
||||
//piCout << "mcast try" << a;
|
||||
|
||||
if (_channels[Multicast]) {
|
||||
ce = new PIEthernet();
|
||||
ce->setDebug(false);
|
||||
ce->setName("PIMulticast_" + a.toString());
|
||||
ce->setParameters(0);
|
||||
ce->setSendAddress(mcast_address);
|
||||
ce->setMulticastTTL(MULTICAST_TTL);
|
||||
if (!_send_only) {
|
||||
ce->setReadAddress(a.ipString(), mcast_address.port());
|
||||
ce->joinMulticastGroup(mcast_address.ipString());
|
||||
//piCout << "mcast " << ce->readAddress() << ce->sendAddress();
|
||||
if (ce->open()) {
|
||||
eth_mcast << ce;
|
||||
CONNECTU(ce, threadedReadEvent, this, mcastRead);
|
||||
} else {
|
||||
delete ce;
|
||||
}
|
||||
} else {
|
||||
eth_mcast << ce;
|
||||
}
|
||||
}
|
||||
|
||||
if (_channels[Broadcast]) {
|
||||
ce = new PIEthernet();
|
||||
ce->setDebug(false);
|
||||
ce->setName("PIMulticast_" + a.toString());
|
||||
ce->setParameters(PIEthernet::Broadcast);
|
||||
const PIEthernet::Interface * cint = ifaces.getByAddress(a.ipString());
|
||||
PIEthernet::Address nm((cint == 0) ? "255.255.255.0" : cint->netmask);
|
||||
ce->setSendAddress(PIEthernet::getBroadcast(a, nm).ipString(), bcast_port);
|
||||
if (!_send_only) {
|
||||
ce->setReadAddress(PIEthernet::Address(a.ip(), bcast_port));
|
||||
//piCout << "bcast " << ce->readAddress() << ce->sendAddress();
|
||||
if (ce->open()) {
|
||||
eth_mcast << ce;
|
||||
CONNECTU(ce, threadedReadEvent, this, mcastRead);
|
||||
} else {
|
||||
delete ce;
|
||||
}
|
||||
} else {
|
||||
eth_mcast << ce;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (_channels[Loopback]) {
|
||||
eth_lo = new PIEthernet();
|
||||
eth_lo->setDebug(false);
|
||||
eth_lo->setName("PIMulticast_loopback");
|
||||
if (!_send_only) {
|
||||
eth_lo->setParameter(PIEthernet::ReuseAddress, false);
|
||||
CONNECTU(eth_lo, threadedReadEvent, this, mcastRead);
|
||||
for (int i = 0; i < lo_pcnt; ++i) {
|
||||
eth_lo->setReadAddress("127.0.0.1", lo_port + i);
|
||||
if (eth_lo->open()) {
|
||||
//piCout << "bind local to" << (lo_port + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::send(const PIByteArray & data) {
|
||||
PIByteArray cd = cryptData(data);
|
||||
if (cd.isEmpty()) return;
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
piForeach (PIEthernet * e, eth_mcast)
|
||||
e->send(cd);
|
||||
if (eth_lo) {
|
||||
for (int i = 0; i < lo_pcnt; ++i) {
|
||||
eth_lo->send("127.0.0.1", lo_port + i, cd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::startRead() {
|
||||
if (_send_only) return;
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
piForeach (PIEthernet * e, eth_mcast)
|
||||
e->startThreadedRead();
|
||||
if (eth_lo)
|
||||
eth_lo->startThreadedRead();
|
||||
_started = true;
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::stopRead() {
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
piForeach (PIEthernet * e, eth_mcast)
|
||||
e->stopThreadedRead();
|
||||
if (eth_lo)
|
||||
eth_lo->stopThreadedRead();
|
||||
_started = false;
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::reinit() {
|
||||
initAll(PIEthernet::allAddresses());
|
||||
if (_started)
|
||||
startRead();
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::mcastRead(uchar * data, int size) {
|
||||
PIByteArray cd = decryptData(PIByteArray(data, size));
|
||||
if (cd.isEmpty()) return;
|
||||
received(cd);
|
||||
receiveEvent(cd);
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::run() {
|
||||
PIVector<PIEthernet::Address> al = PIEthernet::allAddresses();
|
||||
mcast_mutex.lock();
|
||||
bool r = _reinit, ac = (al != prev_al);
|
||||
mcast_mutex.unlock();
|
||||
if (ac || r)
|
||||
reinit();
|
||||
if (ac)
|
||||
addressesChanged();
|
||||
}
|
||||
121
lib/io_utils/piethutilbase.cpp
Normal file
121
lib/io_utils/piethutilbase.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
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
|
||||
}
|
||||
221
lib/io_utils/pistreampacker.cpp
Normal file
221
lib/io_utils/pistreampacker.cpp
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
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 = false;
|
||||
packet_size = -1;
|
||||
crypt_frag_size = 1024*1024;
|
||||
max_packet_size = 1400;
|
||||
packet_sign = 0xAFBE;
|
||||
assignDevice(dev);
|
||||
}
|
||||
|
||||
|
||||
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 << int(cd.size_s());
|
||||
cd.insert(0, hdr);
|
||||
int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
|
||||
if (pcnt > 1) {
|
||||
prog_s_mutex.lock();
|
||||
prog_s.active = true;
|
||||
prog_s.bytes_all = data.size_s();
|
||||
prog_s.bytes_current = 0;
|
||||
prog_s.progress = 0.;
|
||||
prog_s_mutex.unlock();
|
||||
}
|
||||
for (int i = 0; i < pcnt; ++i) {
|
||||
if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst);
|
||||
else part = PIByteArray(cd.data(pst), max_packet_size);
|
||||
//piCout << "send" << part.size();
|
||||
sendRequest(part);
|
||||
pst += max_packet_size;
|
||||
if (pcnt > 1) {
|
||||
prog_s_mutex.lock();
|
||||
prog_s.bytes_current += part.size_s();
|
||||
prog_s.progress = (double)prog_s.bytes_current / prog_s.bytes_all;
|
||||
prog_s_mutex.unlock();
|
||||
}
|
||||
}
|
||||
if (pcnt > 1) {
|
||||
prog_s_mutex.lock();
|
||||
prog_s.active = false;
|
||||
prog_s_mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIStreamPacker::received(uchar * readed, int size) {
|
||||
received(PIByteArray(readed, size));
|
||||
}
|
||||
|
||||
|
||||
void PIStreamPacker::received(const PIByteArray & data) {
|
||||
stream.append(data);
|
||||
//piCout << "rec" << data.size();
|
||||
while (stream.size_s() >= 6) {
|
||||
if (packet_size < 0) {
|
||||
ushort sign(0);
|
||||
memcpy(&sign, stream.data(), 2);
|
||||
if (sign != packet_sign) {
|
||||
stream.pop_front();
|
||||
continue;
|
||||
}
|
||||
int sz = -1;
|
||||
memcpy(&sz, stream.data(2), 4);
|
||||
if (sz < 0) {
|
||||
stream.pop_front();
|
||||
continue;
|
||||
}
|
||||
stream.remove(0, 6);
|
||||
packet.clear();
|
||||
packet_size = sz;
|
||||
if (packet_size == 0)
|
||||
packet_size = -1;
|
||||
else {
|
||||
prog_r_mutex.lock();
|
||||
prog_r.active = true;
|
||||
prog_r.bytes_all = packet_size;
|
||||
prog_r.bytes_current = 0;
|
||||
prog_r.progress = 0.;
|
||||
prog_r_mutex.unlock();
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
int ps = piMini(stream.size_s(), packet_size - packet.size_s());
|
||||
packet.append(stream.data(), ps);
|
||||
prog_r_mutex.lock();
|
||||
prog_r.bytes_current = packet.size_s();
|
||||
prog_r.progress = (double)prog_r.bytes_current / piMaxi(1, prog_r.bytes_all);
|
||||
prog_r_mutex.unlock();
|
||||
stream.remove(0, ps);
|
||||
if (packet.size_s() == packet_size) {
|
||||
PIByteArray cd;
|
||||
if (crypt_frag) {
|
||||
//piCout << "decrypt frags ..." << packet_size;
|
||||
while (packet.size_s() >= 4) {
|
||||
//piCout << "decrypt frags take data ...";
|
||||
PIByteArray frag;
|
||||
//piCout << "decrypt frags take data done" << frag.size_s();
|
||||
packet >> frag;
|
||||
if (frag.isEmpty()) {
|
||||
//piCout << "decrypt frags corrupt, break";
|
||||
cd.clear();
|
||||
break;
|
||||
}
|
||||
cd.append(decryptData(frag));
|
||||
//piCout << "decrypt frags add" << frag.size_s();
|
||||
}
|
||||
//piCout << "decrypt frags done" << cd.size();
|
||||
} else {
|
||||
cd = decryptData(packet);
|
||||
}
|
||||
//piCout << "decrypt" << packet.size() << "->" << cd.size() << key().size();
|
||||
if (!cd.isEmpty()) {
|
||||
packetReceived(cd);
|
||||
packetReceiveEvent(cd);
|
||||
}
|
||||
packet.clear();
|
||||
packet_size = -1;
|
||||
prog_r_mutex.lock();
|
||||
prog_r.active = false;
|
||||
prog_r_mutex.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIStreamPacker::assignDevice(PIIODevice * dev) {
|
||||
if (!dev) return;
|
||||
CONNECTU(dev, threadedReadEvent, this, received);
|
||||
CONNECTU(this, sendRequest, dev, write);
|
||||
}
|
||||
|
||||
|
||||
PIStreamPacker::Progress PIStreamPacker::progressSend() const {
|
||||
PIStreamPacker::Progress ret;
|
||||
prog_s_mutex.lock();
|
||||
ret = prog_s;
|
||||
prog_s_mutex.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIStreamPacker::Progress PIStreamPacker::progressReceive() const {
|
||||
PIStreamPacker::Progress ret;
|
||||
prog_r_mutex.lock();
|
||||
ret = prog_r;
|
||||
prog_r_mutex.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PIStreamPacker::Progress::Progress() {
|
||||
active = false;
|
||||
bytes_all = bytes_current = 0;
|
||||
progress = 0.;
|
||||
}
|
||||
5
lib/main/auxiliary/piterminal/CMakeLists.txt
Normal file
5
lib/main/auxiliary/piterminal/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
add_executable(piterminal "main.cpp")
|
||||
target_link_libraries(piterminal pip pip_console)
|
||||
if (DEFINED LIB)
|
||||
install(TARGETS piterminal DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
endif ()
|
||||
280
lib/main/auxiliary/piterminal/main.cpp
Normal file
280
lib/main/auxiliary/piterminal/main.cpp
Normal file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Terminal client for windows, used by PITerminal and pisd
|
||||
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"
|
||||
#ifndef WINDOWS
|
||||
int main (int argc, char * argv[]) {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
# include "piscreentypes.h"
|
||||
# include "pisharedmemory.h"
|
||||
# include "../../lib/console/piterminal.cpp"
|
||||
# include "pifile.h"
|
||||
# include <wincon.h>
|
||||
|
||||
|
||||
PIVector<PIVector<PIScreenTypes::Cell> > cells;
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
CHAR_INFO * chars = 0;
|
||||
HANDLE console = 0, cstdin = 0, pipe = 0, cmd_proc = 0;
|
||||
PITerminalAuxData data_out;
|
||||
PIMutex con_mutex;
|
||||
int con_w = -1, con_h = -1;
|
||||
|
||||
|
||||
PIScreenTypes::Cell CharInfo2Cell(const CHAR_INFO & c) {
|
||||
PIScreenTypes::Cell ret;
|
||||
ret.symbol = PIChar::fromConsole(c.Char.AsciiChar);
|
||||
ret.format.color_char = PIScreenTypes::Black;
|
||||
if ((c.Attributes & (FOREGROUND_RED)) == FOREGROUND_RED) ret.format.color_char = PIScreenTypes::Red;
|
||||
if ((c.Attributes & (FOREGROUND_GREEN)) == FOREGROUND_GREEN) ret.format.color_char = PIScreenTypes::Green;
|
||||
if ((c.Attributes & (FOREGROUND_BLUE)) == FOREGROUND_BLUE) ret.format.color_char = PIScreenTypes::Blue;
|
||||
if ((c.Attributes & (FOREGROUND_GREEN | FOREGROUND_BLUE)) == (FOREGROUND_GREEN | FOREGROUND_BLUE)) ret.format.color_char = PIScreenTypes::Cyan;
|
||||
if ((c.Attributes & (FOREGROUND_RED | FOREGROUND_BLUE)) == (FOREGROUND_RED | FOREGROUND_BLUE)) ret.format.color_char = PIScreenTypes::Magenta;
|
||||
if ((c.Attributes & (FOREGROUND_RED | FOREGROUND_GREEN)) == (FOREGROUND_RED | FOREGROUND_GREEN)) ret.format.color_char = PIScreenTypes::Yellow;
|
||||
if ((c.Attributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)) == (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)) ret.format.color_char = PIScreenTypes::White;
|
||||
ret.format.color_back = PIScreenTypes::Black;
|
||||
if ((c.Attributes & (BACKGROUND_RED)) == (BACKGROUND_RED)) ret.format.color_back = PIScreenTypes::Red;
|
||||
if ((c.Attributes & (BACKGROUND_GREEN)) == (BACKGROUND_GREEN)) ret.format.color_back = PIScreenTypes::Green;
|
||||
if ((c.Attributes & (BACKGROUND_BLUE)) == (BACKGROUND_BLUE)) ret.format.color_back = PIScreenTypes::Blue;
|
||||
if ((c.Attributes & (BACKGROUND_GREEN | BACKGROUND_BLUE)) == (BACKGROUND_GREEN | BACKGROUND_BLUE)) ret.format.color_back = PIScreenTypes::Cyan;
|
||||
if ((c.Attributes & (BACKGROUND_RED | BACKGROUND_BLUE)) == (BACKGROUND_RED | BACKGROUND_BLUE)) ret.format.color_back = PIScreenTypes::Magenta;
|
||||
if ((c.Attributes & (BACKGROUND_RED | BACKGROUND_GREEN)) == (BACKGROUND_RED | BACKGROUND_GREEN)) ret.format.color_back = PIScreenTypes::Yellow;
|
||||
if ((c.Attributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)) == (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)) ret.format.color_back = PIScreenTypes::White;
|
||||
if ((c.Attributes & (FOREGROUND_INTENSITY)) > 0) ret.format.flags |= PIScreenTypes::Bold;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int SpecialKey2VirtualKeyCode(PIKbdListener::SpecialKey k) {
|
||||
switch (k) {
|
||||
case PIKbdListener::Tab : return '\t'; break;
|
||||
case PIKbdListener::Return : return '\n'; break;
|
||||
case PIKbdListener::Space : return ' '; break;
|
||||
case PIKbdListener::Backspace : return 8 ;
|
||||
case PIKbdListener::PageUp : return 33 ;
|
||||
case PIKbdListener::PageDown : return 34 ;
|
||||
case PIKbdListener::End : return 35 ;
|
||||
case PIKbdListener::Home : return 36 ;
|
||||
case PIKbdListener::LeftArrow : return 37 ;
|
||||
case PIKbdListener::UpArrow : return 38 ;
|
||||
case PIKbdListener::RightArrow: return 39 ;
|
||||
case PIKbdListener::DownArrow : return 40 ;
|
||||
case PIKbdListener::Insert : return 45 ;
|
||||
case PIKbdListener::Delete : return 46 ;
|
||||
case PIKbdListener::F1 : return 112;
|
||||
case PIKbdListener::F2 : return 113;
|
||||
case PIKbdListener::F3 : return 114;
|
||||
case PIKbdListener::F4 : return 115;
|
||||
case PIKbdListener::F5 : return 116;
|
||||
case PIKbdListener::F6 : return 117;
|
||||
case PIKbdListener::F7 : return 118;
|
||||
case PIKbdListener::F8 : return 119;
|
||||
case PIKbdListener::F9 : return 120;
|
||||
case PIKbdListener::F10 : return 121;
|
||||
case PIKbdListener::F11 : return 122;
|
||||
case PIKbdListener::F12 : return 123;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int KeyModifiers2ControlKeyState(PIKbdListener::KeyModifiers m) {
|
||||
int ret(0);
|
||||
if (m[PIKbdListener::Ctrl]) ret |= LEFT_CTRL_PRESSED;
|
||||
if (m[PIKbdListener::Shift]) ret |= SHIFT_PRESSED;
|
||||
if (m[PIKbdListener::Alt]) ret |= LEFT_ALT_PRESSED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void readConsole(int x, int y, int w, int h) {
|
||||
GetConsoleScreenBufferInfo(console, &sbi);
|
||||
COORD bs, bc;
|
||||
bs.X = w;
|
||||
bs.Y = h;
|
||||
bc.X = bc.Y = 0;
|
||||
memset(chars, 0, w * h * sizeof(CHAR_INFO));
|
||||
ReadConsoleOutput(console, chars, bs, bc, &(sbi.srWindow));
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j)
|
||||
cells[i][j] = CharInfo2Cell(chars[i * w + j]);
|
||||
}
|
||||
|
||||
|
||||
void resizeCells(int w, int h) {
|
||||
if (chars) delete[] chars;
|
||||
chars = new CHAR_INFO[w * h];
|
||||
cells.resize(h);
|
||||
for (int i = 0; i < h; ++i)
|
||||
cells[i].resize(w);
|
||||
}
|
||||
|
||||
|
||||
void resizeConsole(int w, int h) {
|
||||
if (con_w == w && con_h == h) return;
|
||||
con_w = w;
|
||||
con_h = h;
|
||||
GetConsoleScreenBufferInfo(console, &sbi);
|
||||
sbi.srWindow.Left = 0;
|
||||
sbi.srWindow.Right = sbi.srWindow.Left + w - 1;
|
||||
sbi.srWindow.Bottom = sbi.srWindow.Top + h - 1;
|
||||
COORD sz; sz.X = w; sz.Y = h;
|
||||
SetConsoleScreenBufferSize(console, sz);
|
||||
SetConsoleWindowInfo(console, TRUE, &(sbi.srWindow));
|
||||
//system(("mode CON: COLS=" + PIString::fromNumber(w) + " LINES=" + PIString::fromNumber(h)).dataAscii());
|
||||
resizeCells(w, h);
|
||||
}
|
||||
|
||||
|
||||
class PipeReader: public PIThread {
|
||||
public:
|
||||
PipeReader(): PIThread() {
|
||||
wrote = readed = 0;
|
||||
msg_size = 0;
|
||||
start(1);
|
||||
}
|
||||
~PipeReader() {
|
||||
stop();
|
||||
}
|
||||
void run() {
|
||||
in.resize(PIPE_BUFFER_SIZE);
|
||||
ReadFile(pipe, in.data(), in.size_s(), &readed, 0);
|
||||
if (GetLastError() == ERROR_BROKEN_PIPE) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
//piCout << errorString();
|
||||
if (readed > 0) {
|
||||
in.resize(readed);
|
||||
stream.append(in);
|
||||
if (msg_size == 0) {
|
||||
if (stream.size_s() < 4) return;
|
||||
stream >> msg_size;
|
||||
}
|
||||
if (stream.size_s() >= msg_size) {
|
||||
msg = PIByteArray(stream.data(), msg_size);
|
||||
stream.remove(0, msg_size);
|
||||
msg_size = 0;
|
||||
parseMessage();
|
||||
}
|
||||
if (msg_size == 0 && stream.size_s() < 4) return;
|
||||
}
|
||||
}
|
||||
void parseMessage() {
|
||||
if (msg.size_s() < 4) return;
|
||||
PIMutexLocker _ml(con_mutex);
|
||||
int type; msg >> type;
|
||||
//piCout << "msg" << type;
|
||||
switch ((PITerminalAuxMessageType)type) {
|
||||
case mtKey: {
|
||||
PIVector<PIKbdListener::KeyEvent> ke;
|
||||
msg >> ke;
|
||||
PIVector<INPUT_RECORD> ir(ke.size() * 2);
|
||||
for (int i = 0; i < ke.size_s(); ++i) {
|
||||
PIKbdListener::KeyEvent k(ke[i]);
|
||||
int j = i+i, z = j+1;
|
||||
ir[j].EventType = KEY_EVENT;
|
||||
ir[j].Event.KeyEvent.wRepeatCount = 1;
|
||||
ir[j].Event.KeyEvent.dwControlKeyState = KeyModifiers2ControlKeyState(k.modifiers);
|
||||
if (PITerminal::isSpecialKey(k.key)) {
|
||||
ir[j].Event.KeyEvent.wVirtualKeyCode = SpecialKey2VirtualKeyCode((PIKbdListener::SpecialKey)k.key);
|
||||
ir[j].Event.KeyEvent.uChar.AsciiChar = PIChar(piMaxi(k.key, 0)).toAscii();
|
||||
} else
|
||||
ir[j].Event.KeyEvent.uChar.UnicodeChar = PIChar(piMaxi(k.key, 0)).toWChar();
|
||||
//piCout << ir[j].Event.KeyEvent.wVirtualKeyCode << int(ir[j].Event.KeyEvent.uChar.AsciiChar);
|
||||
ir[j].Event.KeyEvent.bKeyDown = true;
|
||||
ir[z] = ir[j];
|
||||
ir[z].Event.KeyEvent.bKeyDown = false;
|
||||
}
|
||||
WriteConsoleInput(cstdin, ir.data(), ir.size_s(), &wrote);
|
||||
} break;
|
||||
case mtResize: {
|
||||
int rw, rh;
|
||||
msg >> rw >> rh;
|
||||
resizeConsole(rw, rh);
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
DWORD wrote, readed;
|
||||
int msg_size;
|
||||
PIByteArray in, stream, msg;
|
||||
};
|
||||
|
||||
|
||||
void getCursor(int & x, int & y) {
|
||||
GetConsoleScreenBufferInfo(console, &sbi);
|
||||
x = sbi.dwCursorPosition.X - sbi.srWindow.Left;
|
||||
y = sbi.dwCursorPosition.Y - sbi.srWindow.Top;
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char * argv[]) {
|
||||
//piCout << "start";
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
memset(&si, 0, sizeof(si));
|
||||
memset(&pi, 0, sizeof(pi));
|
||||
memset(&sbi, 0, sizeof(sbi));
|
||||
PIString shmh, pname;
|
||||
if (argc > 1) shmh = argv[1];
|
||||
if (argc > 2) pname = argv[2];
|
||||
if(!CreateProcessA(0, (LPSTR)"cmd", 0, 0, true, 0, 0, 0, &si, &pi)) {
|
||||
return 1;
|
||||
}
|
||||
PISharedMemory shm("piterm_aux" + shmh, 1024*1024);
|
||||
pipe = CreateFile((LPSTR)pname.dataAscii(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
|
||||
if (pipe == INVALID_HANDLE_VALUE) {
|
||||
return 1;
|
||||
}
|
||||
CloseHandle(pi.hThread);
|
||||
cmd_proc = pi.hProcess;
|
||||
console = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
cstdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
resizeConsole(80, 24);
|
||||
PipeReader pipe_reader;
|
||||
pipe_reader.waitForStart();
|
||||
PIByteArray scr;
|
||||
while (true) {
|
||||
//piCout << "loop";
|
||||
if (!pipe_reader.isRunning()) break;
|
||||
con_mutex.lock();
|
||||
getCursor(data_out.cursor_x, data_out.cursor_y);
|
||||
readConsole(0, 0, con_w, con_h);
|
||||
scr.clear();
|
||||
scr << cells;
|
||||
data_out.size_x = con_w;
|
||||
data_out.size_y = con_h;
|
||||
data_out.cells_size = scr.size_s();
|
||||
con_mutex.unlock();
|
||||
shm.write(&data_out, sizeof(data_out));
|
||||
shm.write(scr, sizeof(data_out));
|
||||
piMSleep(25);
|
||||
}
|
||||
//piCout << "exit";
|
||||
TerminateProcess(pi.hProcess, 0);
|
||||
CloseHandle(pi.hProcess);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
38
lib/main/cloud/piccloudclient.h
Normal file
38
lib/main/cloud/piccloudclient.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*! \file piccloudclient.h
|
||||
* \brief PICloud Client
|
||||
*/
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef PICCLOUDCLIENT_H
|
||||
#define PICCLOUDCLIENT_H
|
||||
|
||||
#include "piiodevice.h"
|
||||
|
||||
|
||||
class PIP_EXPORT PICloudClient {
|
||||
public:
|
||||
//!
|
||||
explicit PICloudClient();
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif // PICCLOUDCLIENT_H
|
||||
27
lib/main/cloud/piccloudmodule.h
Normal file
27
lib/main/cloud/piccloudmodule.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef PICLOUDMODULE_H
|
||||
#define PICLOUDMODULE_H
|
||||
|
||||
#include "piccloudtcp.h"
|
||||
#include "piccloudclient.h"
|
||||
#include "piccloudserver.h"
|
||||
|
||||
#endif // PICLOUDMODULE_H
|
||||
39
lib/main/cloud/piccloudserver.h
Normal file
39
lib/main/cloud/piccloudserver.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*! \file piccloudserver.h
|
||||
* \brief PICloud Server
|
||||
*/
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef PICCLOUDSERVER_H
|
||||
#define PICCLOUDSERVER_H
|
||||
|
||||
#include "piiodevice.h"
|
||||
|
||||
|
||||
class PIP_EXPORT PICloudServer {
|
||||
public:
|
||||
//!
|
||||
explicit PICloudServer();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif // PICCLOUDSERVER_H
|
||||
38
lib/main/cloud/piccloudtcp.h
Normal file
38
lib/main/cloud/piccloudtcp.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*! \file piccloudtcp.h
|
||||
* \brief PICloud TCP transport
|
||||
*/
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef PICCLOUDTCP_H
|
||||
#define PICCLOUDTCP_H
|
||||
|
||||
#include "pistring.h"
|
||||
|
||||
class PIP_EXPORT PICloudTCP {
|
||||
public:
|
||||
//!
|
||||
PICloudTCP();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif // PICCLOUDTCP_H
|
||||
54
lib/main/code/picodeinfo.cpp
Normal file
54
lib/main/code/picodeinfo.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
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 distributed in the hope that 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 "picodeinfo.h"
|
||||
#include "pivariant.h"
|
||||
|
||||
|
||||
PIString PICodeInfo::EnumInfo::memberName(int value_) const {
|
||||
piForeachC (PICodeInfo::EnumeratorInfo & e, members)
|
||||
if (e.value == value_)
|
||||
return e.name;
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
int PICodeInfo::EnumInfo::memberValue(const PIString & name_) const {
|
||||
piForeachC (PICodeInfo::EnumeratorInfo & e, members)
|
||||
if (e.name == name_)
|
||||
return e.value;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
PIMap<PIString, PICodeInfo::ClassInfo * > * PICodeInfo::classesInfo;
|
||||
PIMap<PIString, PICodeInfo::EnumInfo * > * PICodeInfo::enumsInfo;
|
||||
PIMap<PIString, PICodeInfo::AccessValueFunction> * PICodeInfo::accessValueFunctions;
|
||||
PIMap<PIString, 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(PIStringAscii(class_name), (AccessTypeFunction)0);
|
||||
AccessValueFunction avf = accessValueFunctions->value(PIStringAscii(class_name), (AccessValueFunction)0);
|
||||
if (!atf || !avf) return PIVariant();
|
||||
return PIVariant::fromValue(avf(p, member_name), PIStringAscii(atf(member_name)));
|
||||
}
|
||||
194
lib/main/code/picodeinfo.h
Normal file
194
lib/main/code/picodeinfo.h
Normal file
@@ -0,0 +1,194 @@
|
||||
/*! \file picodeinfo.h
|
||||
* \brief C++ code info structs
|
||||
*/
|
||||
/*
|
||||
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 distributed in the hope that 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 PICODEINFO_H
|
||||
#define PICODEINFO_H
|
||||
|
||||
#include "pistringlist.h"
|
||||
|
||||
class PIVariant;
|
||||
|
||||
namespace PICodeInfo {
|
||||
|
||||
enum PIP_EXPORT TypeFlag {
|
||||
NoFlag,
|
||||
Const = 0x01,
|
||||
Static = 0x02,
|
||||
Mutable = 0x04,
|
||||
Volatile = 0x08,
|
||||
Inline = 0x10,
|
||||
Virtual = 0x20,
|
||||
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 *);
|
||||
|
||||
struct PIP_EXPORT TypeInfo {
|
||||
TypeInfo(const PIString & n = PIString(), const PIString & t = PIString(), PICodeInfo::TypeFlags f = 0, int b = -1) {name = n; type = t; flags = f; bits = b;}
|
||||
bool isBitfield() const {return bits > 0;}
|
||||
MetaMap meta;
|
||||
PIString name;
|
||||
PIString type;
|
||||
PICodeInfo::TypeFlags flags;
|
||||
int bits;
|
||||
};
|
||||
|
||||
struct PIP_EXPORT FunctionInfo {
|
||||
MetaMap meta;
|
||||
PIString name;
|
||||
TypeInfo return_type;
|
||||
PIVector<PICodeInfo::TypeInfo> arguments;
|
||||
};
|
||||
|
||||
struct PIP_EXPORT ClassInfo {
|
||||
ClassInfo() {has_name = true;}
|
||||
MetaMap meta;
|
||||
bool has_name;
|
||||
PIString type;
|
||||
PIString name;
|
||||
PIStringList parents;
|
||||
PIVector<PICodeInfo::TypeInfo> variables;
|
||||
PIVector<PICodeInfo::FunctionInfo> functions;
|
||||
PIVector<PICodeInfo::ClassInfo * > children_info;
|
||||
};
|
||||
|
||||
struct PIP_EXPORT EnumeratorInfo {
|
||||
EnumeratorInfo(const PIString & n = PIString(), int v = 0) {name = n; value = v;}
|
||||
MetaMap meta;
|
||||
PIString name;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct PIP_EXPORT EnumInfo {
|
||||
PIString memberName(int value) const;
|
||||
int memberValue(const PIString & name) const;
|
||||
MetaMap meta;
|
||||
PIString name;
|
||||
PIVector<PICodeInfo::EnumeratorInfo> members;
|
||||
};
|
||||
|
||||
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::TypeInfo & v) {
|
||||
if (v.flags[Inline]) s << "inline ";
|
||||
if (v.flags[Virtual]) s << "virtual ";
|
||||
if (v.flags[Mutable]) s << "mutable ";
|
||||
if (v.flags[Volatile]) s << "volatile ";
|
||||
if (v.flags[Static]) s << "static ";
|
||||
if (v.flags[Const]) s << "const ";
|
||||
s << v.type;
|
||||
if (!v.name.isEmpty())
|
||||
s << " " << v.name;
|
||||
return s;
|
||||
}
|
||||
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::EnumeratorInfo & v) {s << v.name << " = " << v.value << " Meta" << v.meta; return s;}
|
||||
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::ClassInfo & v) {
|
||||
s.setControl(0, true);
|
||||
s << "class " << v.name;
|
||||
if (!v.parents.isEmpty()) {
|
||||
s << ": ";
|
||||
bool first = true;
|
||||
piForeachC (PIString & i, v.parents) {
|
||||
if (first) first = false;
|
||||
else s << ", ";
|
||||
s << i;
|
||||
}
|
||||
}
|
||||
s << " Meta" << v.meta << " {\n";
|
||||
piForeachC (FunctionInfo & i, v.functions) {
|
||||
s << PICoutManipulators::Tab << i.return_type << " " << i.name << "(";
|
||||
bool fa = true;
|
||||
piForeachC (TypeInfo & a, i.arguments) {
|
||||
if (fa) fa = false;
|
||||
else s << ", ";
|
||||
s << a;
|
||||
}
|
||||
s << ") Meta" << i.meta << ";\n";
|
||||
}
|
||||
if (!v.functions.isEmpty() && !v.variables.isEmpty())
|
||||
s << "\n";
|
||||
piForeachC (TypeInfo & i, v.variables) {
|
||||
s << PICoutManipulators::Tab << i << " Meta" << i.meta << ";\n";
|
||||
}
|
||||
s << "}\n";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::EnumInfo & v) {
|
||||
s.setControl(0, true);
|
||||
s << "enum " << v.name << " Meta" << v.meta << " {\n";
|
||||
piForeachC (EnumeratorInfo & i, v.members) {
|
||||
bool f = true;
|
||||
if (f) f = false;
|
||||
else s << ", ";
|
||||
s << PICoutManipulators::Tab << i << "\n";
|
||||
}
|
||||
s << "}\n";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
extern PIMap<PIString, PICodeInfo::ClassInfo * > * classesInfo;
|
||||
extern PIMap<PIString, PICodeInfo::EnumInfo * > * enumsInfo;
|
||||
extern PIMap<PIString, PICodeInfo::AccessValueFunction> * accessValueFunctions;
|
||||
extern PIMap<PIString, PICodeInfo::AccessTypeFunction> * accessTypeFunctions;
|
||||
|
||||
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(PIStringAscii(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(PIStringAscii(class_name), (AccessTypeFunction)0);
|
||||
if (!af) return "";
|
||||
return af(member_name);
|
||||
}
|
||||
|
||||
PIVariant getMemberAsVariant(const void * p, const char * class_name, const char * member_name);
|
||||
|
||||
}
|
||||
|
||||
class __PICodeInfoInitializer__ {
|
||||
public:
|
||||
__PICodeInfoInitializer__() {
|
||||
if (_inited_) return;
|
||||
_inited_ = true;
|
||||
PICodeInfo::classesInfo = new PIMap<PIString, PICodeInfo::ClassInfo * >;
|
||||
PICodeInfo::enumsInfo = new PIMap<PIString, PICodeInfo::EnumInfo * >;
|
||||
PICodeInfo::accessValueFunctions = new PIMap<PIString, PICodeInfo::AccessValueFunction>;
|
||||
PICodeInfo::accessTypeFunctions = new PIMap<PIString, PICodeInfo::AccessTypeFunction>;
|
||||
}
|
||||
static bool _inited_;
|
||||
};
|
||||
|
||||
static __PICodeInfoInitializer__ __picodeinfoinitializer__;
|
||||
|
||||
#endif // PICODEINFO_H
|
||||
26
lib/main/code/picodemodule.h
Normal file
26
lib/main/code/picodemodule.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
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 distributed in the hope that 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 PICODEMODULE_H
|
||||
#define PICODEMODULE_H
|
||||
|
||||
#include "picodeinfo.h"
|
||||
#include "picodeparser.h"
|
||||
|
||||
#endif // PICODEMODULE_H
|
||||
989
lib/main/code/picodeparser.cpp
Normal file
989
lib/main/code/picodeparser.cpp
Normal file
@@ -0,0 +1,989 @@
|
||||
/*
|
||||
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 distributed in the hope that 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 "picodeparser.h"
|
||||
|
||||
|
||||
|
||||
PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
|
||||
PIStringList arg_vals;
|
||||
while (!args_.isEmpty()) {
|
||||
int ci = args_.find(","), bi = args_.find("(");
|
||||
if (ci < 0) {
|
||||
arg_vals << args_;
|
||||
break;
|
||||
}
|
||||
PIString ca;
|
||||
if (bi >= 0 && bi < ci) {
|
||||
ca = args_.left(args_.takeLeft(bi).toInt());
|
||||
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();
|
||||
}
|
||||
if (args.size() != arg_vals.size()) {
|
||||
piCout << ("Error: in expansion of macro \"" + name + "(" + args.join(", ") + ")\": expect")
|
||||
<< args.size() << "arguments but takes" << arg_vals.size() << "!";
|
||||
if (ok != 0) *ok = false;
|
||||
return PIString();
|
||||
}
|
||||
PIString ret = value;
|
||||
for (int i = 0; i < args.size_s(); ++i) {
|
||||
const PIString & an(args[i]), av(arg_vals[i]);
|
||||
int ind(-1);
|
||||
while ((ind = ret.find(an, ind + 1)) >= 0) {
|
||||
PIChar ppc(0), pc(0), nc(0);
|
||||
if (ind > 1) ppc = ret[ind - 2];
|
||||
if (ind > 0) pc = ret[ind - 1];
|
||||
if (ind + an.size_s() < ret.size_s()) nc = ret.mid(ind + an.size_s(),1)[0];
|
||||
if (ppc != '#' && pc == '#' && !_isCChar(nc)) { // to chars
|
||||
ind--;
|
||||
ret.replace(ind, an.size_s() + 1, "\"" + av + "\"");
|
||||
ind -= an.size_s() - av.size_s() - 1;
|
||||
continue;
|
||||
}
|
||||
if (_isCChar(pc) || _isCChar(nc)) continue;
|
||||
ret.replace(ind, an.size_s(), av);
|
||||
ind -= an.size_s() - av.size_s();
|
||||
}
|
||||
}
|
||||
ret.replaceAll("##", "");
|
||||
if (ok != 0) *ok = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PICodeParser::PICodeParser() {
|
||||
macros_iter = 32;
|
||||
with_includes = true;
|
||||
clear();
|
||||
includes << "";
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
piCout << "\n\nDefines:";
|
||||
piForeachC (Define & m, defines)
|
||||
piCout << "define" << m.first << m.second;
|
||||
piCout << "\n\nMacros:";
|
||||
piForeachC (Macro & m, macros)
|
||||
piCout << "Macro:" << m.name << m.args << m.value;
|
||||
piCout << "\n\nClasses:";
|
||||
piCout << "\n\nEnums:";
|
||||
piForeachC (Enum & c, enums) {
|
||||
piCout << "enum" << c.name << c.meta;
|
||||
piForeachC (EnumeratorInfo & e, c.members)
|
||||
piCout << " " << e.name << "=" << e.value << e.meta;
|
||||
}
|
||||
piCout << "\n\nTypedefs:";
|
||||
piForeachC (Typedef & c, typedefs)
|
||||
piCout << "typedef" << c;*/
|
||||
}
|
||||
|
||||
|
||||
void PICodeParser::parseFiles(const PIStringList & files, bool follow_includes) {
|
||||
clear();
|
||||
piForeachC (PIString & f, files)
|
||||
parseFileInternal(f, follow_includes);
|
||||
/*piCout << "\n\nDefines:";
|
||||
piForeachC (Define & m, defines)
|
||||
piCout << "define" << m.first << m.second;
|
||||
piCout << "\n\nMacros:";
|
||||
piForeachC (Macro & m, macros)
|
||||
piCout << "Macro:" << m.name << m.args << m.value;
|
||||
piCout << "\n\nClasses:";
|
||||
piForeachC (Entity * c, entities)
|
||||
piCout << "class" << c->name << c->parents;
|
||||
piCout << "\n\nEnums:";
|
||||
piForeachC (Enum & c, enums)
|
||||
piCout << "enum" << c.name << c.members;
|
||||
piCout << "\n\nTypedefs:";
|
||||
piForeachC (Typedef & c, typedefs)
|
||||
piCout << "typedef" << c;*/
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::isEnum(const PIString & name) {
|
||||
piForeachC (Enum & e, enums)
|
||||
if (e.name == name)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::parseFileInternal(const PIString & file, bool follow_includes) {
|
||||
if (proc_files[file]) return true;
|
||||
with_includes = follow_includes;
|
||||
cur_file = file;
|
||||
PIFile f(file, PIIODevice::ReadOnly);
|
||||
int ii = 0;
|
||||
while (!f.isOpened() && ii < (includes.size_s() - 1)) {
|
||||
f.setPath(includes[++ii] + "/" + file);
|
||||
//piCout << "try" << f.path();
|
||||
f.open(PIIODevice::ReadOnly);
|
||||
}
|
||||
if (!f.isOpened()) {
|
||||
piCout << ("Error: can`t open file \"" + file + "\"!");
|
||||
return false;
|
||||
}
|
||||
//piCout << "add" << file;
|
||||
proc_files << f.path();
|
||||
PIString fc = PIString::fromUTF8(f.readAll());
|
||||
piCout << "parsing" << f.path() << "...";
|
||||
bool is_main = isMainFile(fc);
|
||||
if (is_main) main_file = f.path();
|
||||
bool ret = parseFileContent(fc, is_main);
|
||||
piCout << "parsing" << f.path() << "done";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PICodeParser::clear() {
|
||||
piForeach (Entity * i, entities) delete i;
|
||||
defines.clear();
|
||||
macros.clear();
|
||||
enums.clear();
|
||||
typedefs.clear();
|
||||
entities.clear();
|
||||
proc_files.clear();
|
||||
cur_namespace.clear();
|
||||
main_file.clear();
|
||||
evaluator.clearCustomVariables();
|
||||
cur_def_vis = Global;
|
||||
anon_num = 0;
|
||||
defines << Define("PICODE", "") << custom_defines;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
bool mlc = false, cc = false;
|
||||
int mls = 0, ole = -1, /*ccs = 0,*/ end = 0;
|
||||
char c = 0, pc = 0;
|
||||
PIString pfc, line, ccmn, tmp;
|
||||
PIMap<PIString, PIString> cchars;
|
||||
|
||||
/// Remove comments, join multiline "*" and replace "*" to $n (cchars)
|
||||
fc.replaceAll("\r\n", "\n");
|
||||
fc.replaceAll("\r", "\n");
|
||||
for (int i = 0; i < fc.size_s() - 1; ++i) {
|
||||
if (fc[i].unicode16Code() >= 255) continue;
|
||||
if (i > 0) pc = c;
|
||||
c = fc[i].toAscii();
|
||||
if (c == '"' && !mlc && pc != '\'') {
|
||||
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;
|
||||
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;}
|
||||
}
|
||||
pfc = procMacros(fc);
|
||||
|
||||
replaceMeta(pfc);
|
||||
|
||||
if (main) return true;
|
||||
|
||||
bool replaced = true;
|
||||
int replaced_cnt = 0;
|
||||
while (replaced) {
|
||||
//piCout << "MACRO iter" << replaced_cnt;
|
||||
if (replaced_cnt >= macros_iter) {
|
||||
piCout << "Error: recursive macros detected!";
|
||||
break;//return false;
|
||||
}
|
||||
replaced_cnt++;
|
||||
replaced = false;
|
||||
piForeachC (Define & d, defines) {
|
||||
int ind(-1);
|
||||
while ((ind = pfc.find(d.first, ind + 1)) >= 0) {
|
||||
PIChar pc(0), nc(0);
|
||||
if (ind > 0) pc = pfc[ind - 1];
|
||||
if (ind + d.first.size_s() < pfc.size_s()) nc = pfc.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) {
|
||||
int ind(-1);
|
||||
while ((ind = pfc.find(m.name, ind + 1)) >= 0) {
|
||||
PIChar pc(0), nc(0);
|
||||
if (ind > 0) pc = pfc[ind - 1];
|
||||
if (ind + m.name.size_s() < pfc.size_s()) nc = pfc.mid(ind + m.name.size_s(),1)[0];
|
||||
if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue;
|
||||
PIString ret, range; bool ok(false);
|
||||
range = pfc.mid(ind + m.name.size_s()).takeRange("(", ")");
|
||||
ret = m.expand(range, &ok);
|
||||
if (!ok) return false;
|
||||
int rlen = pfc.find(range, ind + m.name.size_s()) + range.size_s() + 1 - ind;
|
||||
pfc.replace(ind, rlen, ret);
|
||||
ind -= rlen - ret.size_s();
|
||||
replaced = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//piCout << NewLine << "file" << cur_file << pfc;
|
||||
int pl = -1;
|
||||
while (!pfc.isEmpty()) {
|
||||
pfc.trim();
|
||||
int nl = pfc.size_s();
|
||||
if (pl == nl) break;
|
||||
pl = nl;
|
||||
if (pfc.left(9) == "namespace") {
|
||||
pfc.cutLeft(pfc.find("{") + 1);
|
||||
continue;
|
||||
}
|
||||
if (pfc.left(8) == "template") {
|
||||
pfc.cutLeft(8);
|
||||
pfc.takeRange("<", ">");
|
||||
bool def = !isDeclaration(pfc, 0, &end);
|
||||
pfc.cutLeft(end);
|
||||
if (def) pfc.takeRange("{", "}");
|
||||
else pfc.takeSymbol();
|
||||
continue;
|
||||
}
|
||||
if (pfc.left(5) == "class" || pfc.left(6) == "struct" || pfc.left(5) == "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;}
|
||||
ccmn = pfc.left(dind) + "{\n" + pfc.mid(dind).takeRange('{', '}') + "\n}\n";
|
||||
pfc.remove(0, ccmn.size());
|
||||
parseClass(0, ccmn);
|
||||
continue;
|
||||
}
|
||||
if (pfc.left(4) == "enum") {
|
||||
pfc.cutLeft(4);
|
||||
tmp = pfc.takeCWord();
|
||||
pfc.trim();
|
||||
MetaMap meta = maybeMeta(pfc);
|
||||
parseEnum(0, cur_namespace + tmp, pfc.takeRange("{", "}"), meta);
|
||||
pfc.takeSymbol();
|
||||
continue;
|
||||
}
|
||||
if (pfc.left(7) == "typedef") {
|
||||
pfc.cutLeft(7);
|
||||
typedefs << parseTypedef(pfc.takeLeft(pfc.find(";")));
|
||||
if (typedefs.back().first.isEmpty()) typedefs.pop_back();
|
||||
else root_.typedefs << typedefs.back();
|
||||
pfc.takeSymbol();
|
||||
continue;
|
||||
}
|
||||
int sci = pfc.find(";", 0), obi = pfc.find("{", 0);
|
||||
if (sci < 0 && obi < 0) {
|
||||
pfc.takeLeft(1);
|
||||
continue;
|
||||
}
|
||||
PIString str;
|
||||
if (sci < obi) {
|
||||
str = pfc.takeLeft(sci + 1);
|
||||
} else {
|
||||
str = pfc.takeLeft(obi);
|
||||
pfc.cutLeft(pfc.takeRange("{", "}").toInt());
|
||||
}
|
||||
parseMember(&root_, str);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc) {
|
||||
PIString cd = fc.trimmed().removeAll('\n').replaceAll("\t", " ").replaceAll(" ", " "), pn;
|
||||
MetaMap meta;
|
||||
int ind = cd.find("$M");
|
||||
if (ind >= 0) {
|
||||
meta = tmp_meta.value(cd.takeMid(ind, 5));
|
||||
cd.replaceAll(" ", " ");
|
||||
}
|
||||
//piCout << "found class <****\n" << cd << "\n****>";
|
||||
ind = cd.find(":");
|
||||
PIVector<Entity * > parents;
|
||||
if (ind > 0) {
|
||||
PIStringList pl = cd.takeMid(ind + 1).trim().split(",");
|
||||
cd.cutRight(1);
|
||||
Entity * pe = 0;
|
||||
piForeachC (PIString & p, pl) {
|
||||
if (p.contains(" ")) pn = p.mid(p.find(" ") + 1);
|
||||
else pn = p;
|
||||
pe = findEntityByName(pn);
|
||||
if (pe == 0) ;//{piCout << "Error: can`t find" << pn;}
|
||||
else parents << pe;
|
||||
}
|
||||
}
|
||||
PIString typename_ = cd.left(6).trim();
|
||||
bool is_class = typename_ == "class";
|
||||
cur_def_vis = (is_class ? Private : Public);
|
||||
PIString cn = cd.mid(6).trim();
|
||||
bool has_name = !cn.isEmpty();
|
||||
if (cn.isEmpty()) cn = "<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;
|
||||
entities << e;
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
PIString PICodeParser::parseClass(Entity * parent, PIString & fc) {
|
||||
Visibility prev_vis = cur_def_vis;
|
||||
int dind = fc.find("{"), find = fc.find(";"), end = 0;
|
||||
if (dind < 0 && find < 0) return PIString();
|
||||
if (dind < 0 || find < dind) return fc.left(find);
|
||||
//piCout << "parse class <****\n" << fc.left(20) << "\n****>";
|
||||
Entity * ce = parseClassDeclaration(fc.takeLeft(dind));
|
||||
fc.trim().cutLeft(1).cutRight(1).trim();
|
||||
//piCout << "found class <****\n" << fc << "\n****>";
|
||||
if (!ce) return PIString();
|
||||
if (parent) parent->children << ce;
|
||||
ce->parent_scope = parent;
|
||||
int ps = -1;
|
||||
bool def = false;
|
||||
PIString prev_namespace = cur_namespace, stmp;
|
||||
cur_namespace = ce->name + "::";
|
||||
//piCout << "parse class" << ce->name << "namespace" << cur_namespace;
|
||||
//piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
|
||||
while (!fc.isEmpty()) {
|
||||
PIString cw = fc.takeCWord(), tmp;
|
||||
//piCout << "\ntaked word" << cw;
|
||||
if (cw == "public") {cur_def_vis = Public; fc.cutLeft(1); continue;}
|
||||
if (cw == "protected") {cur_def_vis = Protected; fc.cutLeft(1); continue;}
|
||||
if (cw == "private") {cur_def_vis = Private; fc.cutLeft(1); continue;}
|
||||
if (cw == "class" || cw == "struct" || cw == "union") {
|
||||
if (isDeclaration(fc, 0, &end)) {
|
||||
fc.cutLeft(end);
|
||||
fc.takeSymbol();
|
||||
continue;
|
||||
}
|
||||
tmp = fc.takeLeft(fc.find("{"));
|
||||
stmp = fc.takeRange("{", "}");
|
||||
fc.takeSymbol();
|
||||
stmp = cw + " " + tmp + "{" + stmp + "}";
|
||||
parseClass(ce, stmp);
|
||||
continue;
|
||||
}
|
||||
if (cw == "enum") {
|
||||
tmp = fc.takeCWord();
|
||||
fc.trim();
|
||||
MetaMap meta = maybeMeta(fc);
|
||||
parseEnum(ce, cur_namespace + tmp, fc.takeRange("{", "}"), meta);
|
||||
fc.takeSymbol();
|
||||
continue;
|
||||
}
|
||||
if (cw == "friend") {fc.cutLeft(fc.find(";") + 1); continue;}
|
||||
if (cw == "typedef") {ce->typedefs << parseTypedef(fc.takeLeft(fc.find(";"))); typedefs << ce->typedefs.back(); typedefs.back().first.insert(0, cur_namespace); if (ce->typedefs.back().first.isEmpty()) ce->typedefs.pop_back(); fc.takeSymbol(); continue;}
|
||||
if (cw == "template") {
|
||||
fc.takeRange("<", ">");
|
||||
def = !isDeclaration(fc, 0, &end);
|
||||
fc.cutLeft(end);
|
||||
if (def) fc.takeRange("{", "}");
|
||||
else fc.takeSymbol();
|
||||
continue;
|
||||
}
|
||||
def = !isDeclaration(fc, 0, &end);
|
||||
tmp = (cw + fc.takeLeft(end)).trim();
|
||||
if (!tmp.isEmpty())
|
||||
parseMember(ce, tmp);
|
||||
if (def) fc.takeRange("{", "}");
|
||||
else fc.takeSymbol();
|
||||
if (ps == fc.size_s()) {fc.cutLeft(1);}
|
||||
ps = fc.size_s();
|
||||
}
|
||||
cur_def_vis = prev_vis;
|
||||
cur_namespace = prev_namespace;
|
||||
return ce->name;
|
||||
}
|
||||
|
||||
|
||||
PICodeParser::MetaMap PICodeParser::parseMeta(PIString & fc) {
|
||||
PICodeParser::MetaMap ret;
|
||||
if (fc.isEmpty()) return ret;
|
||||
PIStringList ml = fc.split(",");
|
||||
piForeachC (PIString & m, ml) {
|
||||
int i = m.find("=");
|
||||
if (i < 0) continue;
|
||||
PIString mv = m.mid(i + 1).trim();
|
||||
if (mv.startsWith("\"")) mv.cutLeft(1);
|
||||
if (mv.endsWith("\"")) mv.cutRight(1);
|
||||
ret[m.left(i).trim()] = mv;
|
||||
}
|
||||
//piCout << ms << ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::parseEnum(Entity * parent, const PIString & name, PIString fc, const MetaMap & meta) {
|
||||
//piCout << "enum" << name << fc;
|
||||
Enum e(name);
|
||||
e.meta = meta;
|
||||
PIStringList vl(fc.split(","));
|
||||
PIString vn;
|
||||
int cv = -1, ind = 0;
|
||||
piForeach (PIString & v, vl) {
|
||||
MetaMap meta;
|
||||
int mi = v.find("$M");
|
||||
if (mi >= 0) {
|
||||
meta = tmp_meta.value(v.takeMid(mi, 5));
|
||||
v.replaceAll(" ", " ");
|
||||
}
|
||||
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();
|
||||
enums << e;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PICodeParser::Typedef PICodeParser::parseTypedef(PIString fc) {
|
||||
//piCout << "parse typedef" << fc;
|
||||
Typedef td;
|
||||
fc.replaceAll("\t", " ");
|
||||
|
||||
if (fc.contains("(")) {
|
||||
int start = fc.find("("), end = fc.find(")");
|
||||
td.first = fc.takeMid(start + 1, end - start - 1).trim();
|
||||
if (td.first.left(1) == "*") {td.first.cutLeft(1).trim(); fc.insert(start + 1, "*");}
|
||||
td.second = fc.trim();
|
||||
} else {
|
||||
td.first = fc.takeMid(fc.findLast(" ")).trim();
|
||||
td.second = fc.trim();
|
||||
}
|
||||
//piCout << "found typedef" << td;
|
||||
return td;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
|
||||
if (fc.trim().isEmpty()) return true;
|
||||
if (fc.find("operator") >= 0) return true;
|
||||
tmp_temp.clear();
|
||||
//piCout << "parse member" << fc;
|
||||
int ts = fc.find("<"), te = 0;
|
||||
PIString ctemp, crepl;
|
||||
while (ts >= 0) {
|
||||
ctemp = fc.mid(ts).takeRange("<", ">");
|
||||
if (ctemp.isEmpty()) {te = ts + 1; ts = fc.find("<", te); continue;}
|
||||
crepl = "$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);
|
||||
}
|
||||
fc.replaceAll("\n", " ").replaceAll("\t", " ").replaceAll(" ", " ").replaceAll(", ", ",").replaceAll(" (", "(").replaceAll(" $M", "$M");
|
||||
//piCout << "parse member" << fc;
|
||||
PIStringList tl, al;
|
||||
Member me;
|
||||
//piCout << fc;
|
||||
if (fc.contains("(")) {
|
||||
MetaMap meta;
|
||||
int ind = fc.find("$M");
|
||||
if (ind >= 0) {
|
||||
meta = tmp_meta.value(fc.takeMid(ind, 5));
|
||||
fc.replaceAll(" ", " ").replaceAll(" (", "(");
|
||||
}
|
||||
fc.cutRight(fc.size_s() - fc.findLast(")") - 1);
|
||||
te = fc.find("(");
|
||||
//piCout << fc;
|
||||
for (ts = te - 1; ts >= 0; --ts)
|
||||
if (!_isCChar(fc[ts]) && !(fc[ts].isDigit())) break;
|
||||
//piCout << "takeMid" << ts + 1 << te - ts - 1;
|
||||
me.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;
|
||||
if (me.type.find("inline ") >= 0) {
|
||||
me.attributes |= Inline;
|
||||
me.type.removeAll("inline ");
|
||||
}
|
||||
if (me.type.find("static ") >= 0) {
|
||||
me.attributes |= Static;
|
||||
me.type.removeAll("static ");
|
||||
}
|
||||
if (me.type.find("virtual ") >= 0) {
|
||||
me.attributes |= Virtual;
|
||||
me.type.removeAll("virtual ");
|
||||
}
|
||||
normalizeEntityNamespace(me.type);
|
||||
int i = 0;
|
||||
//piCout << me.arguments_full;
|
||||
piForeach (PIString & 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] == "void") {
|
||||
me.arguments_full.remove(j);
|
||||
--j;
|
||||
}
|
||||
me.arguments_type = me.arguments_full;
|
||||
piForeach (PIString & a, me.arguments_type) {
|
||||
crepl.clear();
|
||||
if (a.contains("["))
|
||||
crepl = a.takeMid(a.find("["), a.findLast("]") - a.find("[") + 1);
|
||||
for (ts = a.size_s() - 1; ts >= 0; --ts)
|
||||
if (!_isCChar(a[ts]) && !(a[ts].isDigit())) break;
|
||||
a.cutRight(a.size_s() - ts - 1);
|
||||
normalizeEntityNamespace(a);
|
||||
a += crepl;
|
||||
a.trim();
|
||||
}
|
||||
restoreTmpTemp(&me);
|
||||
//piCout << "func" << me.type << me.name << me.arguments_full << me.arguments_type;
|
||||
parent->functions << me;
|
||||
} else {
|
||||
if (fc.endsWith(";")) fc.cutRight(1);
|
||||
if (fc.startsWith("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;
|
||||
if (tl.isEmpty()) return true;
|
||||
bool vn = true;
|
||||
ctemp = tl.front().trim();
|
||||
PIString meta_t;
|
||||
if (ctemp.contains("$M"))
|
||||
meta_t = ctemp.takeMid(ctemp.find("$M"));
|
||||
for (ts = ctemp.size_s() - 1; ts > 0; --ts) {
|
||||
if (vn) {if (!_isCChar(ctemp[ts]) && !ctemp[ts].isDigit() && ctemp[ts] != '[' && ctemp[ts] != ']') vn = false;}
|
||||
else {if (_isCChar(ctemp[ts]) || ctemp[ts].isDigit()) break;}
|
||||
}
|
||||
me.type = ctemp.takeLeft(ts + 1);
|
||||
me.visibility = cur_def_vis;
|
||||
ctemp += meta_t;
|
||||
restoreTmpTemp(&me);
|
||||
PIString type = " " + me.type;
|
||||
if (type.find(" const ") >= 0) {
|
||||
me.attributes |= Const;
|
||||
type.replaceAll(" const ", " ");
|
||||
}
|
||||
if (type.find(" static ") >= 0) {
|
||||
me.attributes |= Static;
|
||||
type.replaceAll(" static ", " ");
|
||||
}
|
||||
if (type.find(" mutable ") >= 0) {
|
||||
me.attributes |= Mutable;
|
||||
type.replaceAll(" mutable ", " ");
|
||||
}
|
||||
if (type.find(" volatile ") >= 0) {
|
||||
me.attributes |= Volatile;
|
||||
type.replaceAll(" volatile ", " ");
|
||||
}
|
||||
if (type.find(" extern ") >= 0) {
|
||||
me.attributes |= Extern;
|
||||
type.replaceAll(" extern ", " ");
|
||||
}
|
||||
type.trim();
|
||||
normalizeEntityNamespace(type);
|
||||
tl[0] = ctemp.trim();
|
||||
piForeachC (PIString & 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);
|
||||
while (!me.name.isEmpty()) {
|
||||
if (me.name.front() == "*" || me.name.front() == "&") {
|
||||
me.type += me.name.takeLeft(1);
|
||||
me.name.trim();
|
||||
} else break;
|
||||
}
|
||||
me.is_type_ptr = (me.type.right(1) == "]" || me.type.right(1) == "*");
|
||||
me.type += crepl;
|
||||
me.bits = bits;
|
||||
while (!crepl.isEmpty()) {
|
||||
PIString cdim = crepl.takeRange('[', ']').trim();
|
||||
if (cdim.isEmpty()) break;
|
||||
me.dims << cdim;
|
||||
}
|
||||
//PICout(PICoutManipulators::AddAll) << "var" << me.type << me.name << me.bits;
|
||||
//piCout << "var" << v;
|
||||
parent->members << me;
|
||||
}
|
||||
}
|
||||
//piCout << "parse member" << fc;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int PICodeParser::extractMemberBits(PIString & fc) {
|
||||
int i = fc.findLast(":");
|
||||
if (i <= 0) return -1;
|
||||
if (fc[i - 1].toAscii() == ':') return -1;
|
||||
PIString bs = fc.takeMid(i).mid(1).trim();
|
||||
if (bs.isEmpty()) return -1;
|
||||
return bs.toInt();
|
||||
}
|
||||
|
||||
|
||||
void PICodeParser::normalizeEntityNamespace(PIString & n) {
|
||||
PIString suff, pref;
|
||||
for (int i = n.size_s() - 1; i > 0; --i)
|
||||
if (_isCChar(n[i]) || n[i].isDigit()) {
|
||||
suff = n.right(n.size_s() - i - 1);
|
||||
n.cutRight(suff.size_s());
|
||||
break;
|
||||
}
|
||||
n.push_front(" ");
|
||||
if (n.find(" static ") >= 0) {n.replaceAll(" static ", ""); pref += "static ";}
|
||||
if (n.find(" const ") >= 0) {n.replaceAll(" const ", ""); pref += "const ";}
|
||||
if (n.find(" mutable ") >= 0) {n.replaceAll(" mutable ", ""); pref += "mutable ";}
|
||||
if (n.find(" volatile ") >= 0) {n.replaceAll(" volatile ", ""); pref += "volatile ";}
|
||||
n.trim();
|
||||
int f = 0;
|
||||
piForeachC (Entity * e, entities) {
|
||||
if (e->name == n) {
|
||||
n = (pref + n + suff).trim();
|
||||
return;
|
||||
}
|
||||
if ((f = e->name.find(n)) >= 0)
|
||||
if (e->name.mid(f - 1, 1) == ":")
|
||||
if (e->name.find(cur_namespace) >= 0) {
|
||||
n = pref + e->name + suff;
|
||||
return;
|
||||
}
|
||||
}
|
||||
piForeachC (Enum & e, enums)
|
||||
if ((f = e.name.find(n)) >= 0)
|
||||
if (e.name.mid(f - 1, 1) == ":")
|
||||
if (e.name.find(cur_namespace) >= 0) {
|
||||
//piCout << "change" << n << "to" << e.name + suff;
|
||||
n = pref + e.name + suff;
|
||||
return;
|
||||
}
|
||||
piForeachC (Typedef & e, typedefs)
|
||||
if ((f = e.first.find(n)) >= 0)
|
||||
if (e.first.mid(f - 1, 1) == ":")
|
||||
if (e.first.find(cur_namespace) >= 0) {
|
||||
//piCout << "change" << n << "to" << e.name + suff;
|
||||
n = pref + e.first + suff;
|
||||
return;
|
||||
}
|
||||
n = (pref + n + suff).trim();
|
||||
}
|
||||
|
||||
|
||||
void PICodeParser::restoreTmpTemp(Member * e) {
|
||||
int i = 0;
|
||||
piForeach (PIString & a, e->arguments_full) {
|
||||
while ((i = a.find("$T")) >= 0)
|
||||
a.replace(i, 5, tmp_temp[a.mid(i, 5)]);
|
||||
}
|
||||
piForeach (PIString & a, e->arguments_type) {
|
||||
while ((i = a.find("$T")) >= 0)
|
||||
a.replace(i, 5, tmp_temp[a.mid(i, 5)]);
|
||||
}
|
||||
while ((i = e->type.find("$T")) >= 0)
|
||||
e->type.replace(i, 5, tmp_temp[e->type.mid(i, 5)]);
|
||||
}
|
||||
|
||||
|
||||
void PICodeParser::restoreTmpMeta(PICodeParser::Member * e) {
|
||||
int i = e->name.find("$M");
|
||||
if (i < 0) return;
|
||||
e->meta = tmp_meta[e->name.takeMid(i, 5)];
|
||||
}
|
||||
|
||||
|
||||
PICodeParser::MetaMap PICodeParser::maybeMeta(PIString & fc) {
|
||||
PICodeParser::MetaMap ret;
|
||||
if (fc.left(2) == "$M") {
|
||||
ret = tmp_meta.value(fc.takeLeft(5));
|
||||
fc.trim();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::macroCondition(const PIString & mif, PIString mifcond) {
|
||||
//piCout << "macroCondition" << mif << mifcond;
|
||||
if (mif == "ifdef") return isDefineExists(mifcond);
|
||||
if (mif == "ifndef") return !isDefineExists(mifcond);
|
||||
if (mif == "if" || mif == "elif") {
|
||||
mifcond.removeAll(" ").removeAll("\t");
|
||||
return procMacrosCond(mifcond) > 0.;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
double PICodeParser::procMacrosCond(PIString fc) {
|
||||
bool neg = false, first = true, br = false;
|
||||
double ret = 0., brv = 0.;
|
||||
int oper = 0, ps = -1;
|
||||
char cc, nc;
|
||||
PIString ce;
|
||||
fc.removeAll("defined");
|
||||
//piCout << "procMacrosCond" << fc;
|
||||
while (!fc.isEmpty()) {
|
||||
cc = fc[0].toAscii();
|
||||
nc = (fc.size() > 1 ? fc[1].toAscii() : 0);
|
||||
if (cc == '!') {neg = true; fc.pop_front(); continue;}
|
||||
if (cc == '(') {br = true; brv = procMacrosCond(fc.takeRange('(', ')'));}
|
||||
if (cc == '&' && nc == '&') {fc.remove(0, 2); oper = 1; continue;}
|
||||
if (cc == '|' && nc == '|') {fc.remove(0, 2); oper = 2; continue;}
|
||||
if (!br) {
|
||||
ce = fc.takeCWord();
|
||||
if (ce.isEmpty()) ce = fc.takeNumber();
|
||||
}
|
||||
if (first) {
|
||||
first = false;
|
||||
ret = br ? brv : defineValue(ce);
|
||||
if (neg) ret = -ret;
|
||||
} else {
|
||||
//piCout << "oper" << oper << "with" << ce;
|
||||
if (!br) brv = defineValue(ce);
|
||||
switch (oper) {
|
||||
case 1: ret = ret && (neg ? -brv : brv); break;
|
||||
case 2: ret = ret || (neg ? -brv : brv); break;
|
||||
}
|
||||
}
|
||||
if (ps == fc.size_s()) fc.cutLeft(1);
|
||||
ps = fc.size_s();
|
||||
br = neg = false;
|
||||
}
|
||||
//piCout << "return" << ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::isDefineExists(const PIString & dn) {
|
||||
piForeachC (Define & d, defines) {
|
||||
if (d.first == dn)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
double PICodeParser::defineValue(const PIString & dn) {
|
||||
piForeachC (Define & d, defines) {
|
||||
if (d.first == dn)
|
||||
return d.second.isEmpty() ? 1. : d.second.toDouble();
|
||||
}
|
||||
return dn.toDouble();
|
||||
}
|
||||
|
||||
|
||||
void PICodeParser::replaceMeta(PIString & dn) {
|
||||
tmp_meta.clear();
|
||||
if (dn.isEmpty()) return;
|
||||
int s = dn.find("PIMETA");
|
||||
while (s >= 0) {
|
||||
int ms = 0, ml = 0;
|
||||
ms = dn.findRange('(', ')', '\\', s + 6, &ml);
|
||||
if (ms < 0) return;
|
||||
PIString meta = dn.mid(ms, ml).trim();
|
||||
PIString rm = "$M" + PIString::fromNumber(tmp_meta.size_s()).expandLeftTo(3, "0");
|
||||
dn.replace(s, ms + ml + 1 - s, rm);
|
||||
//piCout << "FOUND META \"" << meta << "\"";
|
||||
tmp_meta[rm] = parseMeta(meta);
|
||||
s = dn.find("PIMETA");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) {
|
||||
piForeach (Entity * e, entities)
|
||||
if (e->name == en)
|
||||
return e;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::isDeclaration(const PIString & fc, int start, int * end) {
|
||||
int dind = fc.find("{", start), find = fc.find(";", start);
|
||||
//piCout << "isDeclaration" << dind << find << 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;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::isMainFile(const PIString & fc) {
|
||||
int si = 0;
|
||||
while (si >= 0) {
|
||||
int csi = fc.find(" main", si);
|
||||
if (csi < 0) csi = fc.find("\tmain", si);
|
||||
if (csi < 0) csi = fc.find("\nmain", si);
|
||||
if (csi < 0) return false;
|
||||
si = csi;
|
||||
int fi = fc.find("(", si + 5);
|
||||
if (fi < 0) return false;
|
||||
if (fi - si < 10) {
|
||||
PIString ms(fc.mid(si, fi - si + 1));
|
||||
ms.removeAll(" ").removeAll("\t").removeAll("\n");
|
||||
if (ms == "main(") return true;
|
||||
}
|
||||
si += 5;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PIString PICodeParser::procMacros(PIString fc) {
|
||||
if (fc.isEmpty()) return PIString();
|
||||
int ifcnt = 0;
|
||||
bool grab = false, skip = false, cond_ok = false;
|
||||
PIString pfc, nfc, line, mif, mifcond;
|
||||
//piCout << "procMacros\n<******" << fc << "\n******>";
|
||||
fc += "\n";
|
||||
while (!fc.isEmpty()) {
|
||||
line = fc.takeLine().trimmed();
|
||||
if (line.left(1) == "#") {
|
||||
mifcond = line.mid(1);
|
||||
mif = mifcond.takeCWord();
|
||||
//piCout << mif;
|
||||
//piCout << "mif mifcond" << mif << mifcond << ifcnt;
|
||||
if (skip || grab) {
|
||||
if (mif.left(2) == "if") ifcnt++;
|
||||
if (mif.left(5) == "endif") {
|
||||
if (ifcnt > 0) ifcnt--;
|
||||
else {
|
||||
//piCout << "main endif" << skip << grab;
|
||||
if (grab) pfc << procMacros(nfc);
|
||||
skip = grab = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (mif.left(4) == "elif" && ifcnt == 0) {
|
||||
//piCout << "main elif" << skip << grab << cond_ok;
|
||||
if (cond_ok) {
|
||||
if (grab) {
|
||||
pfc << procMacros(nfc);
|
||||
skip = true; grab = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (skip) {
|
||||
//piCout << "check elif" << skip << grab << cond_ok;
|
||||
if (!macroCondition(mif, mifcond.trimmed())) continue;
|
||||
//piCout << "check elif ok";
|
||||
skip = false; grab = cond_ok = true;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (mif.left(4) == "else" && ifcnt == 0) {
|
||||
//piCout << "main else" << skip << grab;
|
||||
if (grab) pfc << procMacros(nfc);
|
||||
if (skip && !cond_ok) {skip = false; grab = true;}
|
||||
else {skip = true; grab = false;}
|
||||
continue;
|
||||
}
|
||||
if (grab) nfc << line << "\n";
|
||||
continue;
|
||||
}
|
||||
if (mif.left(2) == "if") {
|
||||
//piCout << "main if";
|
||||
skip = grab = cond_ok = false;
|
||||
if (macroCondition(mif, mifcond.trimmed())) grab = cond_ok = true;
|
||||
else skip = true;
|
||||
ifcnt = 0;
|
||||
nfc.clear();
|
||||
} else {
|
||||
parseDirective(line.cutLeft(1).trim());
|
||||
//return false; /// WARNING: now skip errors
|
||||
}
|
||||
} else {
|
||||
if (grab) nfc << line << "\n";
|
||||
else if (!skip) pfc << line << "\n";
|
||||
}
|
||||
}
|
||||
return pfc;
|
||||
}
|
||||
|
||||
|
||||
bool PICodeParser::parseDirective(PIString d) {
|
||||
if (d.isEmpty()) return true;
|
||||
PIString dname = d.takeCWord();
|
||||
//piCout << "parseDirective" << d;
|
||||
if (dname == "include") {
|
||||
d.replaceAll("<", "\"").replaceAll(">", "\"");
|
||||
PIString cf = cur_file, ifc = d.takeRange("\"", "\"");
|
||||
if (with_includes) {
|
||||
bool ret = parseFileInternal(ifc, with_includes);
|
||||
cur_file = cf;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (dname == "define") {
|
||||
PIString mname = d.takeCWord();
|
||||
//piCout << mname;
|
||||
if (mname == "PIMETA") return true;
|
||||
if (d.left(1) == "(") { // macro
|
||||
PIStringList args = d.takeRange("(", ")").split(",").trim();
|
||||
macros << Macro(mname, d.trim(), args);
|
||||
} else { // define
|
||||
d.trim();
|
||||
defines << Define(mname, d);
|
||||
evaluator.setVariable(mname, complexd_1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (dname == "undef") {
|
||||
PIString mname = d.takeCWord();
|
||||
for (int i = 0; i < defines.size_s(); ++i)
|
||||
if (defines[i].first == mname) {defines.remove(i); --i;}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
184
lib/main/code/picodeparser.h
Normal file
184
lib/main/code/picodeparser.h
Normal file
@@ -0,0 +1,184 @@
|
||||
/*! \file picodeparser.h
|
||||
* \brief C++ code parser
|
||||
*/
|
||||
/*
|
||||
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 distributed in the hope that 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 PICODEPARSER_H
|
||||
#define PICODEPARSER_H
|
||||
|
||||
#include "pifile.h"
|
||||
#include "pievaluator.h"
|
||||
|
||||
inline bool _isCChar(const PIChar & c) {return (c.isAlpha() || (c.toAscii() == '_'));}
|
||||
inline bool _isCChar(const PIString & c) {if (c.isEmpty()) return false; return _isCChar(c[0]);}
|
||||
|
||||
class PIP_EXPORT PICodeParser {
|
||||
public:
|
||||
PICodeParser();
|
||||
|
||||
enum PIP_EXPORT Visibility {Global, Public, Protected, Private};
|
||||
enum PIP_EXPORT Attribute {
|
||||
NoAttributes = 0x0,
|
||||
Const = 0x01,
|
||||
Static = 0x02,
|
||||
Mutable = 0x04,
|
||||
Volatile = 0x08,
|
||||
Inline = 0x10,
|
||||
Virtual = 0x20,
|
||||
Extern = 0x40
|
||||
};
|
||||
|
||||
typedef PIFlags<Attribute> Attributes;
|
||||
typedef PIPair<PIString, PIString> Define;
|
||||
typedef PIPair<PIString, PIString> Typedef;
|
||||
typedef PIMap<PIString, PIString> MetaMap;
|
||||
|
||||
struct PIP_EXPORT Macro {
|
||||
Macro(const PIString & n = PIString(), const PIString & v = PIString(), const PIStringList & a = PIStringList()) {
|
||||
name = n;
|
||||
value = v;
|
||||
args = a;
|
||||
}
|
||||
PIString expand(PIString args_, bool * ok = 0) const;
|
||||
PIString name;
|
||||
PIString value;
|
||||
PIStringList args;
|
||||
};
|
||||
|
||||
struct PIP_EXPORT Member {
|
||||
Member() {
|
||||
visibility = Global;
|
||||
size = 0;
|
||||
bits = -1;
|
||||
is_type_ptr = false;
|
||||
attributes = NoAttributes;
|
||||
}
|
||||
bool isBitfield() const {return bits > 0;}
|
||||
MetaMap meta;
|
||||
PIString type;
|
||||
PIString name;
|
||||
PIStringList arguments_full;
|
||||
PIStringList arguments_type;
|
||||
PIStringList dims;
|
||||
Visibility visibility;
|
||||
Attributes attributes;
|
||||
bool is_type_ptr;
|
||||
int size;
|
||||
int bits;
|
||||
};
|
||||
|
||||
struct PIP_EXPORT Entity {
|
||||
Entity() {
|
||||
visibility = Global;
|
||||
has_name = true;
|
||||
size = 0;
|
||||
parent_scope = 0;
|
||||
}
|
||||
MetaMap meta;
|
||||
PIString type;
|
||||
PIString name;
|
||||
PIString file;
|
||||
Visibility visibility;
|
||||
int size;
|
||||
bool has_name;
|
||||
Entity * parent_scope;
|
||||
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;}
|
||||
MetaMap meta;
|
||||
PIString name;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct PIP_EXPORT Enum {
|
||||
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);}
|
||||
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;}
|
||||
|
||||
PIVector<Define> defines, custom_defines;
|
||||
PIVector<Macro> macros;
|
||||
PIVector<Enum> enums;
|
||||
PIVector<Typedef> typedefs;
|
||||
PIVector<Entity * > entities;
|
||||
|
||||
private:
|
||||
void clear();
|
||||
bool parseFileInternal(const PIString & file, bool follow_includes);
|
||||
bool parseFileContent(PIString & fc, bool main);
|
||||
bool parseDirective(PIString d);
|
||||
Entity * parseClassDeclaration(const PIString & fc);
|
||||
PIString parseClass(Entity * parent, PIString & fc);
|
||||
MetaMap parseMeta(PIString & fc);
|
||||
bool parseEnum(Entity * parent, const PIString & name, PIString fc, const MetaMap & meta);
|
||||
Typedef parseTypedef(PIString fc);
|
||||
bool parseMember(Entity * parent, PIString & fc);
|
||||
int extractMemberBits(PIString & fc);
|
||||
void restoreTmpTemp(Member * e);
|
||||
void restoreTmpMeta(Member * e);
|
||||
MetaMap maybeMeta(PIString & fc);
|
||||
bool macroCondition(const PIString & mif, PIString mifcond);
|
||||
bool isDefineExists(const PIString & dn);
|
||||
double defineValue(const PIString & dn);
|
||||
void replaceMeta(PIString & dn);
|
||||
PIString procMacros(PIString fc);
|
||||
double procMacrosCond(PIString fc);
|
||||
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;
|
||||
PISet<PIString> proc_files;
|
||||
PIString cur_file, main_file;
|
||||
PIStringList includes;
|
||||
Entity root_;
|
||||
Visibility cur_def_vis;
|
||||
PIString cur_namespace;
|
||||
PIMap<PIString, PIString> tmp_temp;
|
||||
PIMap<PIString, MetaMap> tmp_meta;
|
||||
|
||||
};
|
||||
|
||||
#endif // PICODEPARSER_H
|
||||
63
lib/main/concurrent/executor.h
Normal file
63
lib/main/concurrent/executor.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
|
||||
Stephan Fomenko
|
||||
|
||||
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 PIP_TESTS_EXECUTOR_H
|
||||
#define PIP_TESTS_EXECUTOR_H
|
||||
|
||||
#include "piblockingdequeue.h"
|
||||
|
||||
/**
|
||||
* @brief Thread pools address two different problems: they usually provide improved performance when executing large
|
||||
* numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and
|
||||
* managing the resources, including threads, consumed when executing a collection of tasks.
|
||||
*/
|
||||
class PIThreadPoolExecutor {
|
||||
public:
|
||||
explicit PIThreadPoolExecutor(size_t corePoolSize = 1, PIBlockingDequeue<std::function<void()> >* taskQueue_ = new PIBlockingDequeue<std::function<void()> >());
|
||||
|
||||
virtual ~PIThreadPoolExecutor();
|
||||
|
||||
/**
|
||||
* @brief Executes the given task sometime in the future. The task execute in an existing pooled thread. If the task
|
||||
* cannot be submitted for execution, either because this executor has been shutdown or because its capacity has been
|
||||
* reached.
|
||||
*
|
||||
* @param runnable not empty function for thread pool execution
|
||||
*/
|
||||
void execute(const std::function<void()>& runnable);
|
||||
|
||||
void shutdownNow();
|
||||
|
||||
/**
|
||||
* @brief Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be
|
||||
* accepted. Invocation has no additional effect if already shut down. This method does not wait for previously
|
||||
* submitted tasks to complete execution. Use awaitTermination to do that.
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
volatile bool isShutdown() const;
|
||||
|
||||
bool awaitTermination(int timeoutMs);
|
||||
private:
|
||||
volatile bool isShutdown_;
|
||||
PIBlockingDequeue<std::function<void()> >* taskQueue;
|
||||
PIVector<PIThread*> threadPool;
|
||||
};
|
||||
|
||||
#endif //PIP_TESTS_EXECUTOR_H
|
||||
223
lib/main/concurrent/piblockingdequeue.h
Normal file
223
lib/main/concurrent/piblockingdequeue.h
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
|
||||
Stephan Fomenko
|
||||
|
||||
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 PIP_TESTS_PIBLOCKINGDEQUEUE_H
|
||||
#define PIP_TESTS_PIBLOCKINGDEQUEUE_H
|
||||
|
||||
#include "pideque.h"
|
||||
#include "piconditionvar.h"
|
||||
|
||||
/**
|
||||
* @brief A Queue that supports operations that wait for the queue to become non-empty when retrieving an element, and
|
||||
* wait for space to become available in the queue when storing an element.
|
||||
*/
|
||||
template <typename T>
|
||||
class PIBlockingDequeue: private PIDeque<T> {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
explicit inline PIBlockingDequeue(size_t capacity = SIZE_MAX,
|
||||
PIConditionVariable* cond_var_add = new PIConditionVariable(),
|
||||
PIConditionVariable* cond_var_rem = new PIConditionVariable())
|
||||
: cond_var_add(cond_var_add), cond_var_rem(cond_var_rem), max_size(capacity) { }
|
||||
|
||||
/**
|
||||
* @brief Copy constructor. Initialize queue with copy of other queue elements. Not thread-safe for other queue.
|
||||
*/
|
||||
explicit inline PIBlockingDequeue(const PIDeque<T>& other) : cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) {
|
||||
mutex.lock();
|
||||
max_size = SIZE_MAX;
|
||||
PIDeque<T>::append(other);
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Thread-safe copy constructor. Initialize queue with copy of other queue elements.
|
||||
*/
|
||||
inline PIBlockingDequeue(PIBlockingDequeue<T> & other) : cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) {
|
||||
other.mutex.lock();
|
||||
mutex.lock();
|
||||
max_size = other.max_size;
|
||||
PIDeque<T>::append(static_cast<PIDeque<T>&>(other));
|
||||
mutex.unlock();
|
||||
other.mutex.unlock();
|
||||
}
|
||||
|
||||
~PIBlockingDequeue() {
|
||||
delete cond_var_add;
|
||||
delete cond_var_rem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts the specified element into this queue, waiting if necessary for space to become available.
|
||||
*
|
||||
* @param v the element to add
|
||||
*/
|
||||
void put(const T & v) {
|
||||
mutex.lock();
|
||||
cond_var_rem->wait(mutex, [&]() { return PIDeque<T>::size() < max_size; });
|
||||
PIDeque<T>::push_back(v);
|
||||
mutex.unlock();
|
||||
cond_var_add->notifyOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts the specified element at the end of this queue if it is possible to do so immediately without
|
||||
* exceeding the queue's capacity, returning true upon success and false if this queue is full.
|
||||
*
|
||||
* @param v the element to add
|
||||
* @return true if the element was added to this queue, else false
|
||||
*/
|
||||
bool offer(const T & v) {
|
||||
mutex.lock();
|
||||
if (PIDeque<T>::size() >= max_size) {
|
||||
mutex.unlock();
|
||||
return false;
|
||||
}
|
||||
PIDeque<T>::push_back(v);
|
||||
mutex.unlock();
|
||||
cond_var_add->notifyOne();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts the specified element into this queue, waiting up to the specified wait time if necessary for
|
||||
* space to become available.
|
||||
*
|
||||
* @param v the element to add
|
||||
* @param timeoutMs how long to wait before giving up, in milliseconds
|
||||
* @return true if successful, or false if the specified waiting time elapses before space is available
|
||||
*/
|
||||
bool offer(const T & v, int timeoutMs) {
|
||||
mutex.lock();
|
||||
bool isOk = cond_var_rem->waitFor(mutex, timeoutMs, [&]() { return PIDeque<T>::size() < max_size; } );
|
||||
if (isOk) PIDeque<T>::push_back(v);
|
||||
mutex.unlock();
|
||||
if (isOk) cond_var_add->notifyOne();
|
||||
return isOk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves and removes the head of this queue, waiting if necessary until an element becomes available.
|
||||
*
|
||||
* @return the head of this queue
|
||||
*/
|
||||
T take() {
|
||||
T t;
|
||||
mutex.lock();
|
||||
cond_var_add->wait(mutex, [&]() { return !PIDeque<T>::isEmpty(); });
|
||||
t = T(PIDeque<T>::take_front());
|
||||
mutex.unlock();
|
||||
cond_var_rem->notifyOne();
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves and removes the head of this queue, waiting up to the specified wait time if necessary for an
|
||||
* element to become available.
|
||||
*
|
||||
* @param timeoutMs how long to wait before giving up, in milliseconds
|
||||
* @param defaultVal value, which returns if the specified waiting time elapses before an element is available
|
||||
* @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available
|
||||
*/
|
||||
T poll(int timeoutMs, const T & defaultVal, bool* isOk = nullptr) {
|
||||
T t;
|
||||
mutex.lock();
|
||||
bool isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return !PIDeque<T>::isEmpty(); });
|
||||
t = isNotEmpty ? T(PIDeque<T>::take_front()) : defaultVal;
|
||||
mutex.unlock();
|
||||
if (isNotEmpty) cond_var_rem->notifyOne();
|
||||
if (isOk != nullptr) *isOk = isNotEmpty;
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements that this queue can ideally (in the absence of memory or resource
|
||||
* constraints) contains. This is always equal to the initial capacity of this queue less the current size of this queue.
|
||||
*
|
||||
* @return the capacity
|
||||
*/
|
||||
size_t capacity() {
|
||||
size_t c;
|
||||
mutex.lock();
|
||||
c = max_size;
|
||||
mutex.unlock();
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of additional elements that this queue can ideally (in the absence of memory or resource
|
||||
* constraints) accept. This is always equal to the initial capacity of this queue less the current size of this queue.
|
||||
*
|
||||
* @return the remaining capacity
|
||||
*/
|
||||
size_t remainingCapacity() {
|
||||
mutex.lock();
|
||||
size_t c = max_size - PIDeque<T>::size();
|
||||
mutex.unlock();
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in this collection.
|
||||
*/
|
||||
size_t size() {
|
||||
mutex.lock();
|
||||
size_t s = PIDeque<T>::size();
|
||||
mutex.unlock();
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes all available elements from this queue and adds them to other given queue.
|
||||
*/
|
||||
size_t drainTo(PIDeque<T>& other, size_t maxCount = SIZE_MAX) {
|
||||
mutex.lock();
|
||||
size_t count = maxCount > PIDeque<T>::size() ? PIDeque<T>::size() : maxCount;
|
||||
for (size_t i = 0; i < count; ++i) other.push_back(PIDeque<T>::take_front());
|
||||
mutex.unlock();
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes all available elements from this queue and adds them to other given queue.
|
||||
*/
|
||||
size_t drainTo(PIBlockingDequeue<T>& other, size_t maxCount = SIZE_MAX) {
|
||||
mutex.lock();
|
||||
other.mutex.lock();
|
||||
size_t count = maxCount > PIDeque<T>::size() ? PIDeque<T>::size() : maxCount;
|
||||
size_t otherRemainingCapacity = other.max_size - static_cast<PIDeque<T> >(other).size();
|
||||
if (count > otherRemainingCapacity) count = otherRemainingCapacity;
|
||||
for (size_t i = 0; i < count; ++i) other.push_back(PIDeque<T>::take_front());
|
||||
other.mutex.unlock();
|
||||
mutex.unlock();
|
||||
return count;
|
||||
}
|
||||
|
||||
private:
|
||||
PIConditionLock mutex;
|
||||
PIConditionVariable* cond_var_add;
|
||||
PIConditionVariable* cond_var_rem;
|
||||
size_t max_size;
|
||||
};
|
||||
|
||||
|
||||
#endif //PIP_TESTS_PIBLOCKINGDEQUEUE_H
|
||||
51
lib/main/concurrent/piconditionlock.h
Normal file
51
lib/main/concurrent/piconditionlock.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
|
||||
Stephan Fomenko
|
||||
|
||||
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 AWRCANFLASHER_PICONDITIONLOCK_H
|
||||
#define AWRCANFLASHER_PICONDITIONLOCK_H
|
||||
|
||||
#include "pimutex.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief Continued
|
||||
*/
|
||||
class PIP_EXPORT PIConditionLock {
|
||||
public:
|
||||
explicit PIConditionLock();
|
||||
~PIConditionLock();
|
||||
|
||||
//! \brief lock
|
||||
void lock();
|
||||
|
||||
//! \brief unlock
|
||||
void unlock();
|
||||
|
||||
//! \brief tryLock
|
||||
bool tryLock();
|
||||
|
||||
void * handle();
|
||||
|
||||
private:
|
||||
NO_COPY_CLASS(PIConditionLock)
|
||||
PRIVATE_DECLARATION
|
||||
};
|
||||
|
||||
|
||||
#endif //AWRCANFLASHER_PICONDITIONLOCK_H
|
||||
120
lib/main/concurrent/piconditionvar.h
Normal file
120
lib/main/concurrent/piconditionvar.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
|
||||
Stephan Fomenko
|
||||
|
||||
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 PIP_TESTS_PICONDITIONVAR_H
|
||||
#define PIP_TESTS_PICONDITIONVAR_H
|
||||
|
||||
#include "piconditionlock.h"
|
||||
#include "pithread.h"
|
||||
#include "piinit.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief A condition variable is an object able to block the calling thread until notified to resume.
|
||||
*
|
||||
* It uses a PIConditionLock to lock the thread when one of its wait functions is called. The thread remains
|
||||
* blocked until woken up by another thread that calls a notification function on the same PIConditionVariable object.
|
||||
*/
|
||||
class PIP_EXPORT PIConditionVariable {
|
||||
public:
|
||||
explicit PIConditionVariable();
|
||||
virtual ~PIConditionVariable();
|
||||
|
||||
/**
|
||||
* @brief Unblocks one of the threads currently waiting for this condition. If no threads are waiting, the function
|
||||
* does nothing. If more than one, it is unspecified which of the threads is selected.
|
||||
*/
|
||||
void notifyOne();
|
||||
|
||||
/**
|
||||
* @brief Unblocks all threads currently waiting for this condition. If no threads are waiting, the function does
|
||||
* nothing.
|
||||
*/
|
||||
void notifyAll();
|
||||
|
||||
/**
|
||||
* @brief see wait(PIConditionLock&, const std::function<bool()>&)
|
||||
*/
|
||||
virtual void wait(PIConditionLock& lk);
|
||||
|
||||
/**
|
||||
* @brief Wait until notified
|
||||
*
|
||||
* The execution of the current thread (which shall have locked with lk method PIConditionLock::lock()) is blocked
|
||||
* until notified.
|
||||
*
|
||||
* At the moment of blocking the thread, the function automatically calls lk.unlock() (PIConditionLock::unlock()),
|
||||
* allowing other locked threads to continue.
|
||||
*
|
||||
* Once notified (explicitly, by some other thread), the function unblocks and calls lk.lock() (PIConditionLock::lock()),
|
||||
* leaving lk in the same state as when the function was called. Then the function returns (notice that this last mutex
|
||||
* locking may block again the thread before returning).
|
||||
*
|
||||
* Generally, the function is notified to wake up by a call in another thread either to member notifyOne() or to
|
||||
* member notifyAll(). But certain implementations may produce spurious wake-up calls without any of these functions
|
||||
* being called. Therefore, users of this function shall ensure their condition for resumption is met.
|
||||
*
|
||||
* If condition is specified, the function only blocks if condition returns false, and notifications can only unblock
|
||||
* the thread when it becomes true (which is specially useful to check against spurious wake-up calls).
|
||||
*
|
||||
* @param lk lock object used by method wait for data protection
|
||||
* @param condition A callable object or function that takes no arguments and returns a value that can be evaluated
|
||||
* as a bool. This is called repeatedly until it evaluates to true.
|
||||
*/
|
||||
virtual void wait(PIConditionLock& lk, const std::function<bool()>& condition);
|
||||
|
||||
/**
|
||||
* @brief see waitFor(PIConditionLock&, int, const std::function<bool()>&)
|
||||
*/
|
||||
virtual bool waitFor(PIConditionLock& lk, int timeoutMs);
|
||||
|
||||
/**
|
||||
* @brief Wait for timeout or until notified
|
||||
*
|
||||
* The execution of the current thread (which shall have locked with lk method PIConditionLock::lock()) is blocked
|
||||
* during timeoutMs, or until notified (if the latter happens first).
|
||||
*
|
||||
* At the moment of blocking the thread, the function automatically calls lk.lock() (PIConditionLock::lock()), allowing
|
||||
* other locked threads to continue.
|
||||
*
|
||||
* Once notified or once timeoutMs has passed, the function unblocks and calls lk.unlock() (PIConditionLock::unlock()),
|
||||
* leaving lk in the same state as when the function was called. Then the function returns (notice that this last
|
||||
* mutex locking may block again the thread before returning).
|
||||
*
|
||||
* Generally, the function is notified to wake up by a call in another thread either to member notifyOne() or to
|
||||
* member notifyAll(). But certain implementations may produce spurious wake-up calls without any of these functions
|
||||
* being called. Therefore, users of this function shall ensure their condition for resumption is met.
|
||||
*
|
||||
* If condition is specified, the function only blocks if condition returns false, and notifications can only unblock
|
||||
* the thread when it becomes true (which is especially useful to check against spurious wake-up calls).
|
||||
*
|
||||
* @param lk lock object used by method wait for data protection
|
||||
* @param condition A callable object or function that takes no arguments and returns a value that can be evaluated
|
||||
* as a bool. This is called repeatedly until it evaluates to true.
|
||||
* @return false if timeout reached or true if wakeup condition is true
|
||||
*/
|
||||
virtual bool waitFor(PIConditionLock& lk, int timeoutMs, const std::function<bool()>& condition);
|
||||
|
||||
private:
|
||||
NO_COPY_CLASS(PIConditionVariable)
|
||||
PRIVATE_DECLARATION
|
||||
};
|
||||
|
||||
|
||||
#endif //PIP_TESTS_PICONDITIONVAR_H
|
||||
461
lib/main/console/piconsole.h
Normal file
461
lib/main/console/piconsole.h
Normal file
@@ -0,0 +1,461 @@
|
||||
/*! \file piconsole.h
|
||||
* \brief Console output class
|
||||
*/
|
||||
/*
|
||||
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 distributed in the hope that 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 PICONSOLE_H
|
||||
#define PICONSOLE_H
|
||||
|
||||
#include "pikbdlistener.h"
|
||||
|
||||
class PIProtocol;
|
||||
class PIDiagnostics;
|
||||
class PISystemMonitor;
|
||||
class PIPeer;
|
||||
class PITimer;
|
||||
|
||||
class PIP_EXPORT PIConsole: public PIThread
|
||||
{
|
||||
PIOBJECT_SUBCLASS(PIConsole, PIThread)
|
||||
public:
|
||||
|
||||
//! Constructs %PIConsole with key handler "slot" and if "startNow" start it
|
||||
explicit PIConsole(bool startNow = true, PIKbdListener::KBFunc slot = 0);
|
||||
|
||||
~PIConsole();
|
||||
|
||||
|
||||
//! Variables output format
|
||||
enum Format {
|
||||
Normal /** Default console format */ = 0x01,
|
||||
Bold /** Bold text */ = 0x02,
|
||||
Faint = 0x04,
|
||||
Italic = 0x08,
|
||||
Underline /** Underlined text */ = 0x10,
|
||||
Blink /** Blinked text */ = 0x20,
|
||||
Inverse /** Swap text and background colors */ = 0x40,
|
||||
Black /** Black text */ = 0x100,
|
||||
Red /** Red text */ = 0x200,
|
||||
Green /** Green text */ = 0x400,
|
||||
Yellow /** Yellow text */ = 0x800,
|
||||
Blue /** Blue text */ = 0x1000,
|
||||
Magenta /** Magenta text */ = 0x2000,
|
||||
Cyan /** Cyan text */ = 0x4000,
|
||||
White /** White text */ = 0x8000,
|
||||
BackBlack /** Black background */ = 0x10000,
|
||||
BackRed /** Red background */ = 0x20000,
|
||||
BackGreen /** Green background */ = 0x40000,
|
||||
BackYellow /** Yellow background */ = 0x80000,
|
||||
BackBlue /** Blue background */ = 0x100000,
|
||||
BackMagenta /** Magenta background */ = 0x200000,
|
||||
BackCyan /** Cyan background */ = 0x400000,
|
||||
BackWhite /** White background */ = 0x800000,
|
||||
Dec /** Decimal base for integers */ = 0x1000000,
|
||||
Hex /** Hexadecimal base for integers */ = 0x2000000,
|
||||
Oct /** Octal base for integers */ = 0x4000000,
|
||||
Bin /** Binary base for integers */ = 0x8000000,
|
||||
Scientific /** Scientific representation of floats */ = 0x10000000,
|
||||
SystemTimeSplit /** PISystemTime split representation (* s, * ns) */ = 0x20000000,
|
||||
SystemTimeSeconds /** PISystemTime seconds representation (*.* s) */ = 0x40000000
|
||||
};
|
||||
|
||||
//! Column labels alignment
|
||||
enum Alignment {
|
||||
Nothing /** No alignment */ ,
|
||||
Left /** Labels align left and variables align left */ ,
|
||||
Right /** Labels align right and variables align left */
|
||||
};
|
||||
|
||||
typedef PIFlags<PIConsole::Format> FormatFlags;
|
||||
|
||||
//! Add to current tab to column "column" string "name" with format "format"
|
||||
void addString(const PIString & name, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const PIString * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const char * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const bool * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const short * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const int * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const long * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const llong * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const uchar * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const ushort * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const uint * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const ulong * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const ullong * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const float * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const double * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
||||
void addVariable(const PIString & name, const PISystemTime * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
void addVariable(const PIString & name, const PIDiagnostics * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
void addVariable(const PIString & name, const PISystemMonitor * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" bits field with label "name", pointer "ptr" and format "format"
|
||||
void addBitVariable(const PIString & name, const void * ptr, int fromBit, int bitsCount, int column = 1, FormatFlags format = PIConsole::Normal);
|
||||
|
||||
//! Add to current tab to column "column" "count" empty lines
|
||||
void addEmptyLine(int column = 1, uint count = 1);
|
||||
|
||||
PIString getString(int x, int y);
|
||||
short getShort(int x, int y) {return getString(x, y).toShort();}
|
||||
int getInt(int x, int y) {return getString(x, y).toInt();}
|
||||
float getFloat(int x, int y) {return getString(x, y).toFloat();}
|
||||
double getDouble(int x, int y) {return getString(x, y).toDouble();}
|
||||
PIString getString(const PIString & name);
|
||||
short getShort(const PIString & name) {return getString(name).toShort();}
|
||||
int getInt(const PIString & name) {return getString(name).toInt();}
|
||||
float getFloat(const PIString & name) {return getString(name).toFloat();}
|
||||
double getDouble(const PIString & name) {return getString(name).toDouble();}
|
||||
|
||||
|
||||
//! Returns tabs count
|
||||
uint tabsCount() const {return tabs.size();}
|
||||
|
||||
//! Returns current tab name
|
||||
PIString currentTab() const {return tabs[cur_tab].name;}
|
||||
|
||||
//! Returns current tab index
|
||||
int currentTabIndex() const {return cur_tab;}
|
||||
|
||||
//! Add new tab with name "name", bind key "bind_key" and returns this tab index
|
||||
int addTab(const PIString & name, char bind_key = 0);
|
||||
|
||||
//! Remove tab with index "index"
|
||||
void removeTab(uint index);
|
||||
|
||||
//! Remove tab with name "name"
|
||||
void removeTab(const PIString & name);
|
||||
|
||||
//! Clear content of tab with index "index"
|
||||
void clearTab(uint index);
|
||||
|
||||
//! Clear content of tab with name "name"
|
||||
void clearTab(const PIString & name);
|
||||
|
||||
//! Set current tab to tab with index "index", returns if tab exists
|
||||
bool setTab(uint index);
|
||||
|
||||
//! Set current tab to tab with name "name", returns if tab exists
|
||||
bool setTab(const PIString & name);
|
||||
|
||||
//! Set tab with index "index" bind key to "bind_key", returns if tab exists
|
||||
bool setTabBindKey(uint index, char bind_key);
|
||||
|
||||
//! Set tab with name "name" bind key to "bind_key", returns if tab exists
|
||||
bool setTabBindKey(const PIString & name, char bind_key);
|
||||
|
||||
//! Remove all tabs and if "clearScreen" clear the screen
|
||||
void clearTabs(bool clearScreen = true) {if (clearScreen && isRunning()) {toUpperLeft(); clearScreenLower();} tabs.clear();}
|
||||
|
||||
|
||||
//! Set custom status text of current tab to "str"
|
||||
void addCustomStatus(const PIString & str) {tabs[cur_tab].status = str;}
|
||||
|
||||
//! Clear custom status text of current tab
|
||||
void clearCustomStatus() {tabs[cur_tab].status.clear();}
|
||||
|
||||
//! Returns default alignment
|
||||
Alignment defaultAlignment() const {return def_align;}
|
||||
|
||||
//! Set default alignment to "align"
|
||||
void setDefaultAlignment(Alignment align) {def_align = align;}
|
||||
|
||||
//! Set column "col" alignment to "align"
|
||||
void setColumnAlignment(int col, Alignment align) {if (col < 0 || col >= columns().size_s()) return; column(col).alignment = align;}
|
||||
|
||||
//! Set all columns of all tabs alignment to "align"
|
||||
void setColumnAlignmentToAll(Alignment align) {piForeach (Tab & i, tabs) piForeach (Column & j, i.columns) j.alignment = align; fillLabels();}
|
||||
|
||||
|
||||
//! Directly call function from \a PIKbdListener
|
||||
void enableExitCapture(char key = 'Q') {listener->enableExitCapture(key);}
|
||||
|
||||
//! Directly call function from \a PIKbdListener
|
||||
void disableExitCapture() {listener->disableExitCapture();}
|
||||
|
||||
//! Directly call function from \a PIKbdListener
|
||||
bool exitCaptured() const {return listener->exitCaptured();}
|
||||
|
||||
//! Directly call function from \a PIKbdListener
|
||||
char exitKey() const {return listener->exitKey();}
|
||||
|
||||
|
||||
int windowWidth() const {return width;}
|
||||
int windowHeight() const {return height;}
|
||||
|
||||
PIString fstr(FormatFlags f);
|
||||
void update();
|
||||
void pause(bool yes) {pause_ = yes;}
|
||||
|
||||
// Server functions
|
||||
void startServer(const PIString & name);
|
||||
void stopPeer();
|
||||
bool isServerStarted() const {return peer != 0;}
|
||||
PIStringList clients() const;
|
||||
|
||||
// Client functions
|
||||
void listenServers();
|
||||
PIStringList availableServers() const;
|
||||
PIString selectedServer() const {return server_name;}
|
||||
void connectToServer(const PIString & name);
|
||||
void disconnect();
|
||||
bool isConnected() const {return state == Connected;}
|
||||
|
||||
void toUpperLeft();
|
||||
void moveRight(int n = 1);
|
||||
void moveLeft(int n = 1);
|
||||
void moveTo(int x = 0, int y = 0);
|
||||
void clearScreen();
|
||||
void clearScreenLower();
|
||||
void clearLine();
|
||||
void newLine();
|
||||
void hideCursor();
|
||||
void showCursor();
|
||||
|
||||
EVENT_HANDLER0(void, clearVariables) {clearVariables(true);}
|
||||
EVENT_HANDLER1(void, clearVariables, bool, clearScreen);
|
||||
|
||||
EVENT_HANDLER0(void, waitForFinish) {WAIT_FOR_EXIT}
|
||||
EVENT_HANDLER0(void, start) {start(false);}
|
||||
EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();}
|
||||
EVENT_HANDLER0(void, stop) {stop(false);}
|
||||
EVENT_HANDLER1(void, stop, bool, clear);
|
||||
|
||||
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void waitForFinish()
|
||||
//! \brief block until finished (exit key will be pressed)
|
||||
|
||||
//! \fn void clearVariables(bool clearScreen = true)
|
||||
//! \brief Remove all columns at current tab and if "clearScreen" clear the screen
|
||||
|
||||
//! \fn void start(bool wait = false)
|
||||
//! \brief Start console output and if "wait" block until finished (exit key will be pressed)
|
||||
|
||||
//! \fn void stop(bool clear = false)
|
||||
//! \brief Stop console output and if "clear" clear the screen
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data)
|
||||
//! \brief Raise on key "key" pressed, "data" is pointer to %PIConsole object
|
||||
|
||||
//! \}
|
||||
|
||||
private:
|
||||
void begin();
|
||||
void run();
|
||||
void fillLabels();
|
||||
void status();
|
||||
void checkColumn(uint col) {while (columns().size() < col) columns().push_back(Column(def_align));}
|
||||
int bitsValue(const void * src, int offset, int count) const;
|
||||
const char * toBin(const void * d, int s);
|
||||
inline void printLine(const PIString & str, int dx = 0, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const PIString & str, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const char * str, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const bool value, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const int value, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const long value, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const llong value, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const float value, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const double value, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const char value, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const short value, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const uchar value, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const ushort value, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const uint value, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const ulong value, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const ullong value, FormatFlags format = PIConsole::Normal);
|
||||
inline int printValue(const PISystemTime & value, FormatFlags format = PIConsole::Normal);
|
||||
static void key_event(PIKbdListener::KeyEvent key, void * t);
|
||||
|
||||
struct Variable {
|
||||
Variable() {nx = ny = type = offset = bitFrom = bitCount = size = 0; format = Normal; remote = false; ptr = 0; id = 1;}
|
||||
Variable(const Variable & src) {remote = src.remote; name = src.name; format = src.format; type = src.type; offset = src.offset; size = src.size;
|
||||
bitFrom = src.bitFrom; bitCount = src.bitCount; ptr = src.ptr; nx = src.nx; ny = src.ny; rdata = src.rdata; id = src.id;}
|
||||
bool isEmpty() const {return (remote ? false : ptr == 0);}
|
||||
const void * data() {return (remote ? rdata.data() : ptr);}
|
||||
void writeData(PIByteArray & ba) {
|
||||
if (remote) ba << rdata;
|
||||
else {
|
||||
if (type == 0) ba << (*(PIString * )ptr);
|
||||
else ba << PIByteArray::RawData(ptr, size);
|
||||
}
|
||||
}
|
||||
PIString name;
|
||||
FormatFlags format;
|
||||
int nx;
|
||||
int ny;
|
||||
int type;
|
||||
int offset;
|
||||
int bitFrom;
|
||||
int bitCount;
|
||||
int size;
|
||||
int id;
|
||||
bool remote;
|
||||
const void * ptr;
|
||||
PIByteArray rdata;
|
||||
void operator =(const Variable & src) {remote = src.remote; name = src.name; format = src.format; type = src.type; offset = src.offset; size = src.size;
|
||||
bitFrom = src.bitFrom; bitCount = src.bitCount; ptr = src.ptr; nx = src.nx; ny = src.ny; rdata = src.rdata; id = src.id;}
|
||||
};
|
||||
|
||||
struct VariableContent {
|
||||
int id;
|
||||
PIByteArray rdata;
|
||||
};
|
||||
|
||||
struct Column {
|
||||
Column(Alignment align = PIConsole::Right) {variables.reserve(32); alignment = align;}
|
||||
PIVector<Variable> variables;
|
||||
Alignment alignment;
|
||||
uint size() const {return variables.size();}
|
||||
Variable & operator [](int index) {return variables[index];}
|
||||
const Variable & operator [](int index) const {return variables[index];}
|
||||
void push_back(const Variable & v) {variables.push_back(v);}
|
||||
void operator =(const Column & src) {variables = src.variables; alignment = src.alignment;}
|
||||
};
|
||||
|
||||
struct Tab {
|
||||
Tab(PIString n = "", char k = 0) {columns.reserve(8); name = n; key = k;}
|
||||
PIVector<Column> columns;
|
||||
PIString name;
|
||||
PIString status;
|
||||
char key;
|
||||
};
|
||||
|
||||
enum ConnectedState {Disconnected, FetchingData, Committing, Connected};
|
||||
|
||||
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::VariableContent & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::VariableContent & v);
|
||||
|
||||
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Variable & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Variable & v);
|
||||
|
||||
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Column & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Column & v);
|
||||
|
||||
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Tab & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Tab & v);
|
||||
|
||||
PIVector<Column> & columns() {return tabs[cur_tab].columns;}
|
||||
Column & column(int index) {return tabs[cur_tab].columns[index - 1];}
|
||||
int couts(const PIString & v);
|
||||
int couts(const char * v);
|
||||
int couts(const bool v);
|
||||
int couts(const char v);
|
||||
int couts(const short v);
|
||||
int couts(const int v);
|
||||
int couts(const long v);
|
||||
int couts(const llong v);
|
||||
int couts(const uchar v);
|
||||
int couts(const ushort v);
|
||||
int couts(const uint v);
|
||||
int couts(const ulong v);
|
||||
int couts(const ullong v);
|
||||
int couts(const float v);
|
||||
int couts(const double v);
|
||||
int couts(const PISystemTime & v);
|
||||
|
||||
struct RemoteClient;
|
||||
|
||||
void serverSendInfo();
|
||||
void serverSendData();
|
||||
RemoteClient & remoteClient(const PIString & fname);
|
||||
EVENT_HANDLER2(void, peerReceived, const PIString &, from, const PIByteArray &, data);
|
||||
EVENT_HANDLER2(void, peerTimer, void * , data, int, delim);
|
||||
EVENT_HANDLER1(void, peerDisconnectedEvent, const PIString &, name);
|
||||
|
||||
PRIVATE_DECLARATION
|
||||
PIVector<Tab> tabs;
|
||||
PIString binstr, rstr;
|
||||
PIByteArray rba;
|
||||
Variable tv;
|
||||
PIKbdListener * listener;
|
||||
Alignment def_align;
|
||||
PIKbdListener::KBFunc ret_func;
|
||||
int width, height, pwidth, pheight, col_wid, num_format, systime_format;
|
||||
uint max_y;
|
||||
int vid;
|
||||
uint cur_tab, col_cnt;
|
||||
|
||||
PIPeer * peer;
|
||||
PITimer * peer_timer;
|
||||
PITimeMeasurer peer_tm;
|
||||
PIString server_name;
|
||||
bool server_mode, pause_;
|
||||
ConnectedState state;
|
||||
|
||||
struct RemoteClient {
|
||||
RemoteClient(const PIString & n = "") {name = n; state = Disconnected;}
|
||||
PIString name;
|
||||
ConnectedState state;
|
||||
};
|
||||
|
||||
PIVector<RemoteClient> remote_clients;
|
||||
|
||||
};
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::VariableContent & v) {ba << v.id << v.rdata; return ba;}
|
||||
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::VariableContent & v) {ba >> v.id; ba >> v.rdata; return ba;}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Variable & v) {ba << v.name << v.id << (int)v.format << v.type << v.size << v.bitFrom << v.bitCount; return ba;}
|
||||
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Variable & v) {ba >> v.name >> v.id >> (int & )v.format >> v.type >> v.size >> v.bitFrom >> v.bitCount; return ba;}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Column & v) {ba << (int)v.alignment << v.variables; return ba;}
|
||||
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Column & v) {int a; ba >> a >> v.variables; v.alignment = (PIConsole::Alignment)a; return ba;}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Tab & v) {ba << v.name << v.status << (uchar)v.key << v.columns; return ba;}
|
||||
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Tab & v) {ba >> v.name >> v.status >> (uchar&)v.key >> v.columns; return ba;}
|
||||
|
||||
#endif // PICONSOLE_H
|
||||
28
lib/main/console/piconsolemodule.h
Normal file
28
lib/main/console/piconsolemodule.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
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 distributed in the hope that 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 PICONSOLEMODULE_H
|
||||
#define PICONSOLEMODULE_H
|
||||
|
||||
#include "pikbdlistener.h"
|
||||
#include "piconsole.h"
|
||||
#include "piscreen.h"
|
||||
#include "piscreentiles.h"
|
||||
|
||||
#endif // PICONSOLEMODULE_H
|
||||
472
lib/main/console/pikbdlistener.cpp
Normal file
472
lib/main/console/pikbdlistener.cpp
Normal file
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
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 distributed in the hope that 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 "pikbdlistener.h"
|
||||
#ifndef WINDOWS
|
||||
# include <termios.h>
|
||||
#else
|
||||
# include <wincon.h>
|
||||
#endif
|
||||
|
||||
/** \class PIKbdListener
|
||||
* \brief Keyboard console input listener
|
||||
* \details This class provide listening of console keyboard input.
|
||||
* There is two ways to receive pressed key:
|
||||
* * external static function with format "void func(char key, void * data_)"
|
||||
* * event \a keyPressed()
|
||||
*
|
||||
* Also there is static variable \a exiting which by default is set to
|
||||
* \b false. If \a enableExitCapture() was called and listener was started
|
||||
* with function \a start(), this variable will be set to \b true if exit
|
||||
* key will be pressed. By default exit key is 'Q' = shift + 'q'.
|
||||
* To wait for this variable changes to \b true there is WAIT_FOR_EXIT macro
|
||||
* \snippet pikbdlistener.cpp main
|
||||
* */
|
||||
|
||||
bool PIKbdListener::exiting;
|
||||
PIKbdListener * PIKbdListener::_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},
|
||||
};
|
||||
void setupTerminal(bool on) {
|
||||
printf("\e[?1000"); printf(on ? "h" : "l");
|
||||
printf("\e[?1002"); printf(on ? "h" : "l");
|
||||
fflush(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
PRIVATE_DEFINITION_START(PIKbdListener)
|
||||
#ifdef WINDOWS
|
||||
void * hIn, * hOut;
|
||||
DWORD smode, tmode;
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
#else
|
||||
struct termios sterm, tterm;
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
DWORD
|
||||
#else
|
||||
int
|
||||
#endif
|
||||
ret;
|
||||
PRIVATE_DEFINITION_END(PIKbdListener)
|
||||
|
||||
|
||||
PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread() {
|
||||
setName("keyboard_listener");
|
||||
_object = this;
|
||||
#ifdef WINDOWS
|
||||
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;
|
||||
dbl_interval = 400;
|
||||
PIKbdListener::exiting = exit_enabled = false;
|
||||
if (startNow) start();
|
||||
}
|
||||
|
||||
|
||||
PIKbdListener::~PIKbdListener() {
|
||||
terminate();
|
||||
end();
|
||||
}
|
||||
|
||||
|
||||
void PIKbdListener::begin() {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleMode(PRIVATE->hIn, &PRIVATE->tmode);
|
||||
SetConsoleMode(PRIVATE->hIn, ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS);
|
||||
#else
|
||||
struct termios term;
|
||||
tcgetattr(0, &term);
|
||||
term.c_lflag &= ~(ECHO | ICANON);
|
||||
term.c_lflag |= NOFLSH | IEXTEN;
|
||||
PRIVATE->tterm = term;
|
||||
tcsetattr(0, TCSANOW, &term);
|
||||
setupTerminal(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef WINDOWS
|
||||
PIKbdListener::KeyModifiers getModifiers(DWORD v, bool * shift = 0) {
|
||||
PIKbdListener::KeyModifiers ret;
|
||||
bool ctrl = v & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED);
|
||||
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 (v & CAPSLOCK_ON) shi = !shi;
|
||||
if (shift) *shift = shi;
|
||||
return ret;
|
||||
}
|
||||
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 & FROM_LEFT_2ND_BUTTON_PRESSED) ret |= PIKbdListener::MouseMiddle;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void PIKbdListener::readKeyboard() {
|
||||
ke.key = 0;
|
||||
ke.modifiers = 0;
|
||||
memset(rc, 0, 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;
|
||||
ke.modifiers = getModifiers(ker.dwControlKeyState, &shift);
|
||||
//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 '\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;
|
||||
default:
|
||||
PRIVATE->ret = 1;
|
||||
rc[0] = 1;
|
||||
{
|
||||
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;}
|
||||
}
|
||||
break;
|
||||
case MOUSE_EVENT: {
|
||||
MOUSE_EVENT_RECORD mer = ir.Event.MouseEvent;
|
||||
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
||||
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;
|
||||
wheelEvent(we, kbddata_);
|
||||
break;
|
||||
} else {
|
||||
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) {
|
||||
me.action = MouseMove;
|
||||
return;
|
||||
}
|
||||
if (me.buttons == 0) return;
|
||||
me.action = MouseMove;
|
||||
} else {
|
||||
if (mb > me.buttons) {
|
||||
if (tm_dbl.elapsed_m() <= dbl_interval && prev_p_me.x == me.x && prev_p_me.y == me.y)
|
||||
me.action = MouseButtonDblClick;
|
||||
else {
|
||||
me.action = MouseButtonPress;
|
||||
prev_p_me = me;
|
||||
}
|
||||
tm_dbl.reset();
|
||||
}
|
||||
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;
|
||||
mouseEvent(me, kbddata_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
piMSleep(10);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
tcsetattr(0, TCSANOW, &PRIVATE->tterm);
|
||||
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) << "\n";
|
||||
for (int i = 0; i < PRIVATE->ret; ++i)
|
||||
cout << "'" << (char)(rc[i]) << "' ";
|
||||
cout << endl;*/
|
||||
if (rc[0] == 0) {piMSleep(10); return;}
|
||||
if (PRIVATE->ret < 0 || PRIVATE->ret > 7) {piMSleep(10); return;}
|
||||
if (PRIVATE->ret == 1) ke.key = PIChar::fromConsole(rc[0]).unicode16Code();
|
||||
int mod(0);
|
||||
// 2 - shift 1
|
||||
// 3 - alt 2
|
||||
// 4 - alt+shift 3
|
||||
// 5 - ctrl 4
|
||||
// 8 - ctrl+alt+shift 7
|
||||
if (rc[0] == '\e') { // search for Alt
|
||||
if (PRIVATE->ret == 2) {
|
||||
mod = 2;
|
||||
ke.key = PIChar::fromConsole(rc[1]).unicode16Code();
|
||||
} else {// escape-seq
|
||||
if (rc[1] == '\e') { // search for Alt
|
||||
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] - '!');
|
||||
int b = rc[3] & 0x7, a = rc[3] & 0x60;
|
||||
if (a == 0x60) {
|
||||
memcpy((void*)(&we), (const void*)(&me), sizeof(me));
|
||||
we.action = MouseWheel;
|
||||
we.direction = (b == 0);
|
||||
//piCout << "wheel" << we.direction;
|
||||
wheelEvent(we, kbddata_);
|
||||
} else {
|
||||
switch (b) {
|
||||
case 0: me.buttons = MouseLeft; break;
|
||||
case 1: me.buttons = MouseMiddle; break;
|
||||
case 2: me.buttons = MouseRight; break;
|
||||
default: break;
|
||||
}
|
||||
if (a == 0x20) {
|
||||
if (b == 3) {
|
||||
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)
|
||||
me.action = MouseButtonDblClick;
|
||||
else {
|
||||
me.action = MouseButtonPress;
|
||||
prev_p_me = me;
|
||||
}
|
||||
tm_dbl.reset();
|
||||
}
|
||||
}
|
||||
if (a == 0x40) me.action = MouseMove;
|
||||
//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;
|
||||
}
|
||||
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];
|
||||
rc[6] = rc[7] = 0;
|
||||
PRIVATE->ret -= 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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];
|
||||
rc[7] = 0;
|
||||
PRIVATE->ret--;
|
||||
}
|
||||
}
|
||||
for (int i = 0; ; ++i) {
|
||||
if (!esc_seq[i].seq) break;
|
||||
//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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mod >= 0 && mod <= 15) {
|
||||
if (mod & 0x1) ke.modifiers |= Shift;
|
||||
if (mod & 0x2) ke.modifiers |= Alt;
|
||||
if (mod & 0x4) ke.modifiers |= Ctrl;
|
||||
//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;*/
|
||||
}
|
||||
if (ke.key == 0 && PRIVATE->ret > 1)
|
||||
ke.key = PIChar(rc).unicode16Code();
|
||||
#endif
|
||||
if ((rc[0] == '\n' || rc[0] == '\r') && PRIVATE->ret == 1)
|
||||
ke.key = Return;
|
||||
if (exit_enabled && ke.key == exit_key) {
|
||||
PIKbdListener::exiting = true;
|
||||
return;
|
||||
}
|
||||
if (PRIVATE->ret > 0) {
|
||||
keyPressed(ke, kbddata_);
|
||||
if (ret_func != 0) ret_func(ke, kbddata_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIKbdListener::end() {
|
||||
//cout << "list end" << endl;
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(PRIVATE->hIn, PRIVATE->smode);
|
||||
#else
|
||||
tcsetattr(0, TCSANOW, &PRIVATE->sterm);
|
||||
setupTerminal(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIKbdListener::setActive(bool yes) {
|
||||
is_active = yes;
|
||||
if (is_active) {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(PRIVATE->hIn, PRIVATE->tmode);
|
||||
#else
|
||||
tcsetattr(0, TCSANOW, &PRIVATE->tterm);
|
||||
setupTerminal(true);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(PRIVATE->hIn, PRIVATE->smode);
|
||||
#else
|
||||
tcsetattr(0, TCSANOW, &PRIVATE->sterm);
|
||||
setupTerminal(false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
262
lib/main/console/pikbdlistener.h
Normal file
262
lib/main/console/pikbdlistener.h
Normal file
@@ -0,0 +1,262 @@
|
||||
/*! \file pikbdlistener.h
|
||||
* \brief Keyboard console input listener
|
||||
*/
|
||||
/*
|
||||
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 distributed in the hope that 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 PIKBDLISTENER_H
|
||||
#define PIKBDLISTENER_H
|
||||
|
||||
#include "pithread.h"
|
||||
|
||||
#define WAIT_FOR_EXIT while (!PIKbdListener::exiting) piMSleep(PIP_MIN_MSLEEP*5);
|
||||
|
||||
|
||||
class PIP_EXPORT PIKbdListener: public PIThread
|
||||
{
|
||||
PIOBJECT_SUBCLASS(PIKbdListener, PIThread)
|
||||
friend class PIConsole;
|
||||
friend class PITerminal;
|
||||
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,
|
||||
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
|
||||
};
|
||||
|
||||
//! Keyboard modifiers
|
||||
enum KeyModifier {
|
||||
Ctrl /** Control key */ = 0x1,
|
||||
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 KeyEvent {
|
||||
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;
|
||||
|
||||
//! Active keyboard modifiers. It contains PIKbdListener::KeyModifier bitfields
|
||||
KeyModifiers modifiers;
|
||||
};
|
||||
|
||||
//! Mouse buttons
|
||||
enum MouseButton {
|
||||
MouseLeft /** Left button */ = 0x01,
|
||||
MouseRight /** Right button */ = 0x02,
|
||||
MouseMiddle /** Middle button */ = 0x04
|
||||
};
|
||||
|
||||
//! Mouse actions
|
||||
enum MouseAction {
|
||||
MouseButtonPress /** Mouse button pressed */,
|
||||
MouseButtonRelease /** Mouse button released */,
|
||||
MouseButtonDblClick /** Mouse button double click */,
|
||||
MouseMove /** Mouse moved */,
|
||||
MouseWheel /** Mouse wheel rotated */
|
||||
};
|
||||
|
||||
typedef PIFlags<MouseButton> MouseButtons;
|
||||
|
||||
//! This struct contains information about mouse action
|
||||
struct MouseEvent {
|
||||
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;
|
||||
|
||||
//! Event Y coordinate in view-space, from 0
|
||||
int y;
|
||||
|
||||
//! Mouse action type
|
||||
MouseAction action;
|
||||
|
||||
//! Pressed buttons. It contains PIKbdListener::MouseButton bitfields
|
||||
MouseButtons buttons;
|
||||
|
||||
//! Active keyboard modifiers. It contains PIKbdListener::KeyModifier bitfields
|
||||
KeyModifiers modifiers;
|
||||
};
|
||||
|
||||
//! This struct contains information about mouse wheel action
|
||||
struct WheelEvent: public MouseEvent {
|
||||
WheelEvent(): MouseEvent() {direction = false;}
|
||||
|
||||
//! Wheel direction, /b true - up, /b fasle - down
|
||||
bool direction;
|
||||
};
|
||||
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
typedef std::function<void(KeyEvent, void *)> KBFunc;
|
||||
#else
|
||||
typedef void (*KBFunc)(KeyEvent, void * );
|
||||
#endif
|
||||
|
||||
//! Constructs keyboard listener with external function "slot" and custom data "data"
|
||||
explicit PIKbdListener(KBFunc slot = 0, void * data = 0, bool startNow = true);
|
||||
|
||||
~PIKbdListener();
|
||||
|
||||
|
||||
//! Returns custom data
|
||||
void * data() {return kbddata_;}
|
||||
|
||||
//! Set custom data to "_data"
|
||||
void setData(void * _data) {kbddata_ = _data;}
|
||||
|
||||
//! Set external function to "slot"
|
||||
void setSlot(KBFunc slot) {ret_func = slot;}
|
||||
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
//! Set external function to "slot"
|
||||
void setSlot(std::function<void(KeyEvent)> slot) {ret_func = [slot](KeyEvent e, void *){slot(e);};}
|
||||
#endif
|
||||
|
||||
//! Returns if exit key if awaiting
|
||||
bool exitCaptured() const {return exit_enabled;}
|
||||
|
||||
//! Returns exit key, default 'Q'
|
||||
int exitKey() const {return exit_key;}
|
||||
|
||||
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;}
|
||||
|
||||
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)
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void enableExitCapture(int key = 'Q')
|
||||
//! \brief Enable exit key "key" awaiting
|
||||
|
||||
//! \fn void disableExitCapture()
|
||||
//! \brief Disable exit key awaiting
|
||||
|
||||
//! \fn void setActive(bool yes = true)
|
||||
//! \brief Set keyboard listening is active or not
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data)
|
||||
//! \brief Raise on key "key" pressed, "data" is custom data
|
||||
|
||||
//! \}
|
||||
|
||||
static bool exiting;
|
||||
static PIKbdListener * instance() {return _object;}
|
||||
|
||||
private:
|
||||
void begin();
|
||||
void run() {readKeyboard();}
|
||||
void end();
|
||||
|
||||
#ifndef WINDOWS
|
||||
struct EscSeq {
|
||||
const char * seq;
|
||||
int key;
|
||||
int mod;
|
||||
int vt;
|
||||
int flags;
|
||||
// 1 - shift
|
||||
// 2 - alt
|
||||
// 4 - ctrl
|
||||
};
|
||||
|
||||
enum VTType {
|
||||
vt_none,
|
||||
vt_xterm = 0x1,
|
||||
vt_linux = 0x2,
|
||||
vt_all = 0xFF
|
||||
};
|
||||
|
||||
static const EscSeq esc_seq[];
|
||||
#endif
|
||||
|
||||
PRIVATE_DECLARATION
|
||||
KBFunc ret_func;
|
||||
int exit_key;
|
||||
bool exit_enabled, is_active;
|
||||
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;}
|
||||
|
||||
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;}
|
||||
|
||||
|
||||
#endif // PIKBDLISTENER_H
|
||||
159
lib/main/console/piscreen.h
Normal file
159
lib/main/console/piscreen.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/*! \file piscreen.h
|
||||
* \brief Console GUI class
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Console GUI
|
||||
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 PISCREEN_H
|
||||
#define PISCREEN_H
|
||||
|
||||
#include "piscreentile.h"
|
||||
#include "piscreendrawer.h"
|
||||
|
||||
|
||||
class PIP_EXPORT PIScreen: public PIThread, public PIScreenTypes::PIScreenBase
|
||||
{
|
||||
PIOBJECT_SUBCLASS(PIScreen, PIThread)
|
||||
class SystemConsole;
|
||||
public:
|
||||
|
||||
//! Constructs %PIScreen with key handler "slot" and if "startNow" start it
|
||||
PIScreen(bool startNow = true, PIKbdListener::KBFunc slot = 0);
|
||||
|
||||
~PIScreen();
|
||||
|
||||
//! Directly call function from \a PIKbdListener
|
||||
void enableExitCapture(int key = 'Q') {listener->enableExitCapture(key);}
|
||||
|
||||
//! Directly call function from \a PIKbdListener
|
||||
void disableExitCapture() {listener->disableExitCapture();}
|
||||
|
||||
//! Directly call function from \a PIKbdListener
|
||||
bool exitCaptured() const {return listener->exitCaptured();}
|
||||
|
||||
//! Directly call function from \a PIKbdListener
|
||||
int exitKey() const {return listener->exitKey();}
|
||||
|
||||
int windowWidth() const {return console.width;}
|
||||
int windowHeight() const {return console.height;}
|
||||
|
||||
bool isMouseEnabled() const {return mouse_;}
|
||||
void setMouseEnabled(bool on);
|
||||
|
||||
PIScreenTile * rootTile() {return &root;}
|
||||
PIScreenTile * tileByName(const PIString & name);
|
||||
|
||||
void setDialogTile(PIScreenTile * t);
|
||||
PIScreenTile * dialogTile() const {return tile_dialog;}
|
||||
|
||||
PIScreenDrawer * drawer() {return &drawer_;}
|
||||
void clear() {drawer_.clear();}
|
||||
void resize(int w, int h) {console.resize(w, h);}
|
||||
|
||||
EVENT_HANDLER0(void, waitForFinish);
|
||||
EVENT_HANDLER0(void, start) {start(false);}
|
||||
EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();}
|
||||
EVENT_HANDLER0(void, stop) {stop(false);}
|
||||
EVENT_HANDLER1(void, stop, bool, clear);
|
||||
|
||||
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
|
||||
EVENT2(tileEvent, PIScreenTile * , tile, PIScreenTypes::TileEvent, e)
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void waitForFinish()
|
||||
//! \brief block until finished (exit key will be pressed)
|
||||
|
||||
//! \fn void start(bool wait = false)
|
||||
//! \brief Start console output and if "wait" block until finished (exit key will be pressed)
|
||||
|
||||
//! \fn void stop(bool clear = false)
|
||||
//! \brief Stop console output and if "clear" clear the screen
|
||||
|
||||
//! \}
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data)
|
||||
//! \brief Raise on key "key" pressed, "data" is pointer to %PIConsole object
|
||||
|
||||
//! \fn void tileEvent(PIScreenTile * tile, PIScreenTypes::TileEvent e)
|
||||
//! \brief Raise on some event "e" from tile "tile"
|
||||
|
||||
//! \}
|
||||
|
||||
private:
|
||||
class SystemConsole {
|
||||
public:
|
||||
SystemConsole();
|
||||
~SystemConsole();
|
||||
void begin();
|
||||
void end();
|
||||
void prepare();
|
||||
void clear();
|
||||
void print();
|
||||
void resize(int w, int h);
|
||||
void toUpperLeft();
|
||||
void moveTo(int x = 0, int y = 0);
|
||||
void hideCursor();
|
||||
void showCursor();
|
||||
void clearScreen();
|
||||
void clearScreenLower();
|
||||
#ifdef WINDOWS
|
||||
void getWinCurCoord();
|
||||
void clearLine();
|
||||
void newLine();
|
||||
ushort attributes(const PIScreenTypes::Cell & c);
|
||||
#else
|
||||
PIString formatString(const PIScreenTypes::Cell & c);
|
||||
#endif
|
||||
PRIVATE_DECLARATION
|
||||
int width, height, pwidth, pheight;
|
||||
int mouse_x, mouse_y;
|
||||
PIVector<PIVector<PIScreenTypes::Cell> > cells, pcells;
|
||||
};
|
||||
|
||||
void begin();
|
||||
void run();
|
||||
void end();
|
||||
void key_event(PIKbdListener::KeyEvent key);
|
||||
EVENT_HANDLER1(void, mouse_event, PIKbdListener::MouseEvent, me);
|
||||
EVENT_HANDLER1(void, wheel_event, PIKbdListener::WheelEvent, we);
|
||||
static void key_eventS(PIKbdListener::KeyEvent key, void * t) {((PIScreen*)t)->key_event(key);}
|
||||
PIVector<PIScreenTile*> tiles() {return root.children();}
|
||||
PIVector<PIScreenTile*> prepareMouse(PIKbdListener::MouseEvent * e);
|
||||
PIVector<PIScreenTile*> tilesUnderMouse(int x, int y);
|
||||
bool nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key = PIKbdListener::KeyEvent());
|
||||
void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e);
|
||||
void tileRemovedInternal(PIScreenTile * t);
|
||||
void tileSetFocusInternal(PIScreenTile * t);
|
||||
|
||||
bool mouse_;
|
||||
SystemConsole console;
|
||||
PIScreenDrawer drawer_;
|
||||
PIKbdListener * listener;
|
||||
PIKbdListener::KBFunc ret_func;
|
||||
PIScreenTile root;
|
||||
PIScreenTile * tile_focus, * tile_dialog;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // PISCREEN_H
|
||||
77
lib/main/console/piscreenconsole.h
Normal file
77
lib/main/console/piscreenconsole.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*! \file piscreenconsole.h
|
||||
* \brief Tile for PIScreen with PIConsole API
|
||||
*
|
||||
* This file declares TileVars
|
||||
*/
|
||||
/*
|
||||
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 distributed in the hope that 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 PISCREENCONSOLE_H
|
||||
#define PISCREENCONSOLE_H
|
||||
|
||||
#include "piscreentiles.h"
|
||||
|
||||
/// NOTE: incomplete class
|
||||
/// TODO: write TileVars
|
||||
|
||||
class PIP_EXPORT TileVars: public PIScreenTile {
|
||||
public:
|
||||
TileVars(const PIString & n = PIString());
|
||||
protected:
|
||||
struct Variable {
|
||||
Variable() {nx = ny = type = offset = bitFrom = bitCount = size = 0; format = PIScreenTypes::CellFormat(); ptr = 0;}
|
||||
bool isEmpty() const {return (ptr == 0);}
|
||||
PIString name;
|
||||
PIScreenTypes::CellFormat format;
|
||||
int nx;
|
||||
int ny;
|
||||
int type;
|
||||
int offset;
|
||||
int bitFrom;
|
||||
int bitCount;
|
||||
int size;
|
||||
const void * ptr;
|
||||
/*void operator =(const Variable & src) {
|
||||
name = src.name;
|
||||
format = src.format;
|
||||
nx = src.nx;
|
||||
ny = src.ny;
|
||||
type = src.type;
|
||||
offset = src.offset;
|
||||
bitFrom = src.bitFrom;
|
||||
bitCount = src.bitCount;
|
||||
size = src.size;
|
||||
ptr = src.ptr;
|
||||
}*/
|
||||
};
|
||||
PIVector<Variable> variables;
|
||||
PIScreenTypes::Alignment alignment;
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
};
|
||||
|
||||
|
||||
|
||||
class PIP_EXPORT PIScreenConsoleTile : public PIScreenTile
|
||||
{
|
||||
public:
|
||||
PIScreenConsoleTile();
|
||||
};
|
||||
|
||||
#endif // PISCREENCONSOLE_H
|
||||
68
lib/main/console/piscreendrawer.h
Normal file
68
lib/main/console/piscreendrawer.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*! \file piscreendrawer.h
|
||||
* \brief Drawer for PIScreen
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Drawer 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 distributed in the hope that 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 PISCREENDRAWER_H
|
||||
#define PISCREENDRAWER_H
|
||||
|
||||
#include "piscreentypes.h"
|
||||
#include "pistring.h"
|
||||
|
||||
class PIP_EXPORT PIScreenDrawer
|
||||
{
|
||||
friend class PIScreen;
|
||||
PIScreenDrawer(PIVector<PIVector<PIScreenTypes::Cell> > & c);
|
||||
public:
|
||||
enum ArtChar {
|
||||
LineVertical = 1,
|
||||
LineHorizontal,
|
||||
Cross,
|
||||
CornerTopLeft,
|
||||
CornerTopRight,
|
||||
CornerBottomLeft,
|
||||
CornerBottomRight,
|
||||
Unchecked,
|
||||
Checked
|
||||
};
|
||||
|
||||
void clear();
|
||||
void clearRect(int x0, int y0, int x1, int y1) {fillRect(x0, y0, x1, y1, ' ');}
|
||||
void drawPixel(int x, int y, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0);
|
||||
void drawLine(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0);
|
||||
void drawRect(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0);
|
||||
void drawFrame(int x0, int y0, int x1, int y1, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0);
|
||||
void drawText(int x, int y, const PIString & s, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Transparent, PIScreenTypes::CharFlags flags_char = 0);
|
||||
void fillRect(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0);
|
||||
void fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<PIScreenTypes::Cell> > & content);
|
||||
|
||||
PIChar artChar(const ArtChar type) const {return arts_.value(type, PIChar(' '));}
|
||||
|
||||
static void clear(PIVector<PIVector<PIScreenTypes::Cell> > & cells);
|
||||
|
||||
private:
|
||||
PIVector<PIVector<PIScreenTypes::Cell> > & cells;
|
||||
int width, height;
|
||||
PIMap<ArtChar, PIChar> arts_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // PISCREENDRAWER_H
|
||||
106
lib/main/console/piscreentile.h
Normal file
106
lib/main/console/piscreentile.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*! \file piscreentile.h
|
||||
* \brief Basic PIScreen tile
|
||||
*/
|
||||
/*
|
||||
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 distributed in the hope that 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 PISCREENTILE_H
|
||||
#define PISCREENTILE_H
|
||||
|
||||
#include "piscreentypes.h"
|
||||
#include "pikbdlistener.h"
|
||||
|
||||
class PIScreenDrawer;
|
||||
|
||||
class PIP_EXPORT PIScreenTile: public PIObject {
|
||||
friend class PIScreen;
|
||||
PIOBJECT_SUBCLASS(PIScreenTile, PIObject)
|
||||
public:
|
||||
PIScreenTile(const PIString & n = PIString(), PIScreenTypes::Direction d = PIScreenTypes::Vertical, PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred);
|
||||
virtual ~PIScreenTile();
|
||||
|
||||
void addTile(PIScreenTile * t);
|
||||
void takeTile(PIScreenTile * t);
|
||||
void removeTile(PIScreenTile * t);
|
||||
PIScreenTile * parentTile() const {return parent;}
|
||||
PIVector<PIScreenTile * > children(bool only_visible = false);
|
||||
PIScreenTile * childUnderMouse(int x, int y);
|
||||
void show() {visible = true;}
|
||||
void hide() {visible = false;}
|
||||
void setFocus();
|
||||
bool hasFocus() const {return has_focus;}
|
||||
void setMargins(int m) {marginLeft = marginRight = marginTop = marginBottom = m;}
|
||||
void setMargins(int l, int r, int t, int b) {marginLeft = l; marginRight = r; marginTop = t; marginBottom = b;}
|
||||
|
||||
int x() const {return x_;}
|
||||
int y() const {return y_;}
|
||||
int width() const {return width_;}
|
||||
int height() const {return height_;}
|
||||
|
||||
PIScreenTypes::Direction direction;
|
||||
PIScreenTypes::SizePolicy size_policy;
|
||||
PIScreenTypes::FocusFlags focus_flags;
|
||||
PIScreenTypes::CellFormat back_format;
|
||||
PIChar back_symbol;
|
||||
int minimumWidth, minimumHeight;
|
||||
int maximumWidth, maximumHeight;
|
||||
int marginLeft, marginRight, marginTop, marginBottom;
|
||||
int spacing;
|
||||
bool visible;
|
||||
|
||||
protected:
|
||||
|
||||
//! Returns desired tile size in "w" and "h"
|
||||
virtual void sizeHint(int & w, int & h) const;
|
||||
|
||||
//! Tile has been resized to "w"x"h"
|
||||
virtual void resizeEvent(int w, int h) {}
|
||||
|
||||
//! Draw tile with drawer "d" in world-space coordinates
|
||||
virtual void drawEvent(PIScreenDrawer * d) {}
|
||||
|
||||
//! Return "true" if you process key
|
||||
virtual bool keyEvent(PIKbdListener::KeyEvent key) {return false;}
|
||||
|
||||
//! Return "true" if you process event
|
||||
virtual bool mouseEvent(PIKbdListener::MouseEvent me) {return false;}
|
||||
|
||||
//! Return "true" if you process wheel
|
||||
virtual bool wheelEvent(PIKbdListener::WheelEvent we) {return false;}
|
||||
|
||||
void raiseEvent(PIScreenTypes::TileEvent e);
|
||||
void setScreen(PIScreenTypes::PIScreenBase * s);
|
||||
void deleteChildren();
|
||||
void drawEventInternal(PIScreenDrawer * d);
|
||||
void layout();
|
||||
bool needLayout() {return size_policy != PIScreenTypes::Ignore;}
|
||||
|
||||
PIVector<PIScreenTile * > tiles;
|
||||
PIScreenTile * parent;
|
||||
PIScreenTypes::PIScreenBase * screen;
|
||||
int x_, y_, width_, height_;
|
||||
bool has_focus;
|
||||
|
||||
private:
|
||||
int pw, ph;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // PISCREENTILE_H
|
||||
213
lib/main/console/piscreentiles.h
Normal file
213
lib/main/console/piscreentiles.h
Normal file
@@ -0,0 +1,213 @@
|
||||
/*! \file piscreentiles.h
|
||||
* \brief Various tiles for PIScreen
|
||||
*/
|
||||
/*
|
||||
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 distributed in the hope that 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 PISCREENTILES_H
|
||||
#define PISCREENTILES_H
|
||||
|
||||
#include "piscreentile.h"
|
||||
|
||||
|
||||
class PIP_EXPORT TileSimple: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileSimple, PIScreenTile)
|
||||
public:
|
||||
typedef PIPair<PIString, PIScreenTypes::CellFormat> Row;
|
||||
TileSimple(const PIString & n = PIString());
|
||||
TileSimple(const Row & r);
|
||||
virtual ~TileSimple() {}
|
||||
PIVector<Row> content;
|
||||
PIScreenTypes::Alignment alignment;
|
||||
protected:
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
};
|
||||
|
||||
|
||||
class TileList;
|
||||
|
||||
class PIP_EXPORT TileScrollBar: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileScrollBar, PIScreenTile)
|
||||
friend class TileList;
|
||||
public:
|
||||
TileScrollBar(const PIString & n = PIString());
|
||||
virtual ~TileScrollBar() {}
|
||||
void setMinimum(int v);
|
||||
void setMaximum(int v);
|
||||
void setValue(int v);
|
||||
int minimum() const {return minimum_;}
|
||||
int maximum() const {return maximum_;}
|
||||
int value() const {return value_;}
|
||||
int thickness;
|
||||
protected:
|
||||
void _check();
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
||||
int minimum_, maximum_, value_;
|
||||
PIChar line_char;
|
||||
};
|
||||
|
||||
|
||||
class PIP_EXPORT TileList: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileList, PIScreenTile)
|
||||
public:
|
||||
TileList(const PIString & n = PIString());
|
||||
virtual ~TileList() {}
|
||||
enum SelectionMode {
|
||||
NoSelection,
|
||||
SingleSelection,
|
||||
MultiSelection
|
||||
};
|
||||
enum EventType {
|
||||
SelectionChanged,
|
||||
RowPressed
|
||||
};
|
||||
typedef PIPair<PIString, PIScreenTypes::CellFormat> Row;
|
||||
PIDeque<Row> content;
|
||||
PIScreenTypes::Alignment alignment;
|
||||
SelectionMode selection_mode;
|
||||
PISet<int> selected;
|
||||
int lhei, cur, offset;
|
||||
protected:
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void resizeEvent(int w, int h);
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
||||
bool wheelEvent(PIKbdListener::WheelEvent we);
|
||||
TileScrollBar * scroll;
|
||||
bool mouse_sel;
|
||||
};
|
||||
|
||||
|
||||
class PIP_EXPORT TileButton: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileButton, PIScreenTile)
|
||||
public:
|
||||
TileButton(const PIString & n = PIString());
|
||||
virtual ~TileButton() {}
|
||||
enum EventType {
|
||||
ButtonClicked
|
||||
};
|
||||
PIScreenTypes::CellFormat format;
|
||||
PIString text;
|
||||
protected:
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class PIP_EXPORT TileButtons: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileButtons, PIScreenTile)
|
||||
public:
|
||||
TileButtons(const PIString & n = PIString());
|
||||
virtual ~TileButtons() {}
|
||||
enum EventType {
|
||||
ButtonSelected
|
||||
};
|
||||
typedef PIPair<PIString, PIScreenTypes::CellFormat> Button;
|
||||
PIScreenTypes::Alignment alignment;
|
||||
PIVector<Button> content;
|
||||
int cur;
|
||||
protected:
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
||||
struct Rect {
|
||||
Rect(int _x0 = 0, int _y0 = 0, int _x1 = 0, int _y1 = 0): x0(_x0),y0(_y0),x1(_x1),y1(_y1) {}
|
||||
int x0,y0,x1,y1;
|
||||
};
|
||||
PIVector<Rect> btn_rects;
|
||||
};
|
||||
|
||||
|
||||
class PIP_EXPORT TileCheck: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileCheck, PIScreenTile)
|
||||
public:
|
||||
TileCheck(const PIString & n = PIString());
|
||||
virtual ~TileCheck() {}
|
||||
enum EventType {
|
||||
Toggled
|
||||
};
|
||||
PIScreenTypes::CellFormat format;
|
||||
PIString text;
|
||||
bool toggled;
|
||||
protected:
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
||||
};
|
||||
|
||||
|
||||
class PIP_EXPORT TileProgress: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileProgress, PIScreenTile)
|
||||
public:
|
||||
TileProgress(const PIString & n = PIString());
|
||||
virtual ~TileProgress() {}
|
||||
PIScreenTypes::CellFormat format;
|
||||
PIString prefix;
|
||||
PIString suffix;
|
||||
double maximum;
|
||||
double value;
|
||||
protected:
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
};
|
||||
|
||||
|
||||
class PIP_EXPORT TilePICout: public TileList {
|
||||
PIOBJECT_SUBCLASS(TilePICout, PIScreenTile)
|
||||
public:
|
||||
TilePICout(const PIString & n = PIString());
|
||||
virtual ~TilePICout() {}
|
||||
PIScreenTypes::CellFormat format;
|
||||
int max_lines;
|
||||
protected:
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
||||
};
|
||||
|
||||
|
||||
class PIP_EXPORT TileInput: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileInput, PIScreenTile)
|
||||
public:
|
||||
TileInput(const PIString & n = PIString());
|
||||
virtual ~TileInput() {}
|
||||
PIScreenTypes::CellFormat format;
|
||||
PIString text;
|
||||
int max_length;
|
||||
protected:
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
||||
void reserCursor();
|
||||
int cur, offset;
|
||||
bool inv;
|
||||
PITimeMeasurer tm_blink;
|
||||
};
|
||||
|
||||
|
||||
#endif // PISCREENTILES_H
|
||||
146
lib/main/console/piscreentypes.h
Normal file
146
lib/main/console/piscreentypes.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/*! \file piscreentypes.h
|
||||
* \brief Types for PIScreen
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Types 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 distributed in the hope that 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 PISCREENTYPES_H
|
||||
#define PISCREENTYPES_H
|
||||
|
||||
#include "pivariant.h"
|
||||
|
||||
class PIScreenTile;
|
||||
|
||||
namespace PIScreenTypes {
|
||||
|
||||
//! Color for chars or background
|
||||
enum PIP_EXPORT Color {
|
||||
Default /** Default */,
|
||||
Black /** Black */,
|
||||
Red /** Red */,
|
||||
Green /** Green */,
|
||||
Blue /** Blue */,
|
||||
Cyan /** Cyan */,
|
||||
Magenta /** Magenta */,
|
||||
Yellow /** Yellow */,
|
||||
White /** White */,
|
||||
Transparent /** Save previous color */
|
||||
};
|
||||
|
||||
//! Flags for chars
|
||||
enum PIP_EXPORT CharFlag {
|
||||
Bold /** Bold or bright */ = 0x1,
|
||||
Blink /** Blink text */ = 0x2,
|
||||
Underline /** Underline text */ = 0x4,
|
||||
Inverse = 0x08
|
||||
};
|
||||
|
||||
//! Alignment
|
||||
enum PIP_EXPORT Alignment {
|
||||
Left /** Left */ ,
|
||||
Center /** Center */ ,
|
||||
Right /** Right */
|
||||
};
|
||||
|
||||
//! Size policy
|
||||
enum PIP_EXPORT SizePolicy {
|
||||
Fixed /** Fixed size */ ,
|
||||
Preferred /** Preferred size */ ,
|
||||
Expanding /** Maximum available size */ ,
|
||||
Ignore /** Ignore layout logic */
|
||||
};
|
||||
|
||||
//! Direction
|
||||
enum PIP_EXPORT Direction {
|
||||
Horizontal /** Horizontal */ ,
|
||||
Vertical /** Vertical */
|
||||
};
|
||||
|
||||
//! Focus flags
|
||||
enum PIP_EXPORT FocusFlag {
|
||||
CanHasFocus /** Tile can has focus */ = 0x1,
|
||||
NextByTab /** Focus passed to next tile by tab key */ = 0x2,
|
||||
NextByArrowsHorizontal /** Focus passed to next tile by arrow keys left or right */ = 0x4,
|
||||
NextByArrowsVertical /** Focus passed to next tile by arrow keys up or down */ = 0x8,
|
||||
NextByArrowsAll /** Focus passed to next tile by any arrow key */ = NextByArrowsHorizontal | NextByArrowsVertical,
|
||||
FocusOnMouse /** Tile focused on mouse press */ = 0x10,
|
||||
FocusOnWheel /** Tile focused on wheel */ = 0x20,
|
||||
FocusOnMouseOrWheel /** Tile focused on mouse press or wheel */ = FocusOnMouse | FocusOnWheel
|
||||
};
|
||||
|
||||
typedef PIFlags<CharFlag> CharFlags;
|
||||
typedef PIFlags<FocusFlag> FocusFlags;
|
||||
|
||||
union PIP_EXPORT CellFormat {
|
||||
CellFormat(ushort f = 0) {raw_format = f;}
|
||||
CellFormat(Color col_char, Color col_back = Default, CharFlags flags_ = 0) {
|
||||
color_char = col_char;
|
||||
color_back = col_back;
|
||||
flags = flags_;
|
||||
}
|
||||
ushort raw_format;
|
||||
struct {
|
||||
ushort color_char : 4;
|
||||
ushort color_back : 4;
|
||||
ushort flags : 8;
|
||||
};
|
||||
bool operator ==(const CellFormat & c) const {return raw_format == c.raw_format;}
|
||||
bool operator !=(const CellFormat & c) const {return raw_format != c.raw_format;}
|
||||
};
|
||||
|
||||
struct PIP_EXPORT Cell {
|
||||
Cell(PIChar c = PIChar(' '), CellFormat f = CellFormat()) {symbol = c; format = f;}
|
||||
CellFormat format;
|
||||
PIChar symbol;
|
||||
bool operator ==(const Cell & c) const {return format == c.format && symbol == c.symbol;}
|
||||
bool operator !=(const Cell & c) const {return format != c.format || symbol != c.symbol;}
|
||||
Cell & operator =(const Cell & c) {
|
||||
symbol = c.symbol;
|
||||
if (c.format.color_back == Transparent) {
|
||||
format.color_char = c.format.color_char;
|
||||
format.flags = c.format.flags;
|
||||
} else format = c.format;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct PIP_EXPORT TileEvent {
|
||||
TileEvent(int t = -1, const PIVariant & d = PIVariant()): type(t), data(d) {}
|
||||
int type;
|
||||
PIVariant data;
|
||||
};
|
||||
|
||||
class PIScreenBase {
|
||||
public:
|
||||
PIScreenBase() {}
|
||||
virtual ~PIScreenBase() {}
|
||||
virtual void tileEventInternal(PIScreenTile * , TileEvent) {}
|
||||
virtual void tileRemovedInternal(PIScreenTile * ) {}
|
||||
virtual void tileSetFocusInternal(PIScreenTile * ) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIScreenTypes::Cell & v) {s << v.format.raw_format << v.symbol; return s;}
|
||||
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIScreenTypes::Cell & v) {s >> v.format.raw_format >> v.symbol; return s;}
|
||||
|
||||
|
||||
#endif // PISCREENTYPES_H
|
||||
76
lib/main/console/piterminal.h
Normal file
76
lib/main/console/piterminal.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*! \file piterminal.h
|
||||
* \brief Virtual terminal
|
||||
*/
|
||||
/*
|
||||
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 distributed in the hope that 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 PITERMINAL_H
|
||||
#define PITERMINAL_H
|
||||
|
||||
#include "pikbdlistener.h"
|
||||
#include "piscreentypes.h"
|
||||
|
||||
|
||||
class PIP_EXPORT PITerminal: public PIThread
|
||||
{
|
||||
PIOBJECT_SUBCLASS(PITerminal, PIThread)
|
||||
public:
|
||||
|
||||
//! Constructs %PITerminal
|
||||
PITerminal();
|
||||
|
||||
~PITerminal();
|
||||
|
||||
int columns() const {return size_x;}
|
||||
int rows() const {return size_y;}
|
||||
bool resize(int cols, int rows);
|
||||
|
||||
void write(const PIByteArray & d);
|
||||
void write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m);
|
||||
void write(PIKbdListener::KeyEvent ke);
|
||||
PIVector<PIVector<PIScreenTypes::Cell> > content();
|
||||
static bool isSpecialKey(int k);
|
||||
|
||||
bool initialize();
|
||||
void destroy();
|
||||
private:
|
||||
void initPrivate();
|
||||
void readConsole();
|
||||
void getCursor(int & x, int & y);
|
||||
uchar invertColor(uchar c);
|
||||
void run();
|
||||
#ifndef WINDOWS
|
||||
void parseInput(const PIString & s);
|
||||
bool isCompleteEscSeq(const PIString & es);
|
||||
void applyEscSeq(PIString es);
|
||||
void moveCursor(int dx, int dy);
|
||||
int termType(const PIString & t);
|
||||
#endif
|
||||
|
||||
PRIVATE_DECLARATION
|
||||
int dsize_x, dsize_y;
|
||||
int size_x, size_y, cursor_x, cursor_y;
|
||||
bool cursor_blink, cursor_visible;
|
||||
PITimeMeasurer cursor_tm;
|
||||
PIVector<PIVector<PIScreenTypes::Cell> > cells;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // PITERMINAL_H
|
||||
174
lib/main/containers/picontainers.cpp
Normal file
174
lib/main/containers/picontainers.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Generic containers
|
||||
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/>.
|
||||
*/
|
||||
|
||||
|
||||
/** \class PIVector
|
||||
* \brief Dynamic array of any type
|
||||
* \details This class used to store dynamic array of any
|
||||
* type of data. In memory data stored linear. You can insert
|
||||
* item in any place of remove some items from any place.
|
||||
* For quick add elements this is stream operator <<.
|
||||
|
||||
* \fn PIVector::PIVector();
|
||||
* Contructs an empty vector
|
||||
|
||||
* \fn PIVector::PIVector(ullong size, const Type & value = Type());
|
||||
* \brief Contructs vector with size "size" filled elements "value"
|
||||
* \details Example: \snippet picontainers.cpp PIVector::PIVector
|
||||
|
||||
* \fn const Type & PIVector::at(ullong index) const;
|
||||
* \brief Read-only access to element by index "index"
|
||||
* \details Example: \snippet picontainers.cpp PIVector::at_c
|
||||
* \sa \a operator[]
|
||||
|
||||
* \fn Type & PIVector::at(ullong index);
|
||||
* \brief Full access to element by index "index"
|
||||
* \details Example: \snippet picontainers.cpp PIVector::at
|
||||
* \sa \a operator[]
|
||||
|
||||
* \fn const Type * PIVector::data(ullong index = 0) const;
|
||||
* \brief Read-only pointer to element by index "index"
|
||||
* \details Example: \snippet picontainers.cpp PIVector::data_c
|
||||
|
||||
* \fn Type * PIVector::data(ullong index = 0);
|
||||
* \brief Pointer to element by index "index"
|
||||
* \details Example: \snippet picontainers.cpp PIVector::data
|
||||
|
||||
* \fn ullong PIVector::size() const;
|
||||
* \brief Elements count
|
||||
|
||||
* \fn int PIVector::size_s() const;
|
||||
* \brief Elements count
|
||||
|
||||
* \fn bool PIVector::isEmpty() const;
|
||||
* \brief Return \c "true" if vector is empty, i.e. size = 0
|
||||
|
||||
* \fn bool PIVector::has(const Type & t) const;
|
||||
|
||||
* \fn bool PIVector::contains(const Type & v) const;
|
||||
* \brief Return \c "true" if vector has at least one element equal "t"
|
||||
|
||||
* \fn int PIVector::etries(const Type & t) const;
|
||||
* \brief Return how many times element "t" appears in vector
|
||||
|
||||
* \fn static int PIVector::compare_func(const Type * t0, const Type * t1);
|
||||
* \brief Standard compare function for type "Type". Return 0 if t0 = t1, -1 if t0 < t1 and 1 if t0 > t1.
|
||||
|
||||
* \fn void PIVector::resize(ullong size, const Type & new_type = Type());
|
||||
* \brief Resize vector to size "size"
|
||||
* \details Elements removed from end of vector if new size < old size, or added new elements = "new_type" if new size > old size.\n
|
||||
* Example: \snippet picontainers.cpp PIVector::resize
|
||||
* \sa \a size(), \a clear()
|
||||
|
||||
* \fn PIVector<T> & PIVector::enlarge(ullong size);
|
||||
* \brief Increase vector size with "size" elements
|
||||
|
||||
* \fn void PIVector::clear();
|
||||
* \brief Clear vector. Equivalent to call <tt>"resize(0)"</tt>
|
||||
|
||||
* \fn PIVector<T> & PIVector::sort(CompareFunc compare = compare_func);
|
||||
* \brief Sort vector using quick sort algorithm and standard compare function
|
||||
* \details Example: \snippet picontainers.cpp PIVector::sort_0
|
||||
* With custom compare function: \snippet picontainers.cpp PIVector::sort_1
|
||||
|
||||
* \fn PIVector<T> & PIVector::fill(const Type & t);
|
||||
* \brief Fill vector with elements "t" leave size is unchanged and return reference to vector
|
||||
* \details Example: \snippet picontainers.cpp PIVector::fill
|
||||
|
||||
* \fn Type & PIVector::back();
|
||||
* \brief Last element of the vector
|
||||
|
||||
* \fn const Type & PIVector::back() const;
|
||||
* \brief Last element of the vector
|
||||
|
||||
* \fn Type & PIVector::front();
|
||||
* \brief First element of the vector
|
||||
|
||||
* \fn const Type & PIVector::front() const;
|
||||
* \brief First element of the vector
|
||||
|
||||
* \fn PIVector<T> & PIVector::push_back(const Type & t);
|
||||
* \brief Add new element "t" at the end of vector and return reference to vector
|
||||
|
||||
* \fn PIVector<T> & PIVector::push_front(const Type & t);
|
||||
* \brief Add new element "t" at the beginning of vector and return reference to vector
|
||||
|
||||
* \fn PIVector<T> & PIVector::pop_back();
|
||||
* \brief Remove one element from the end of vector and return reference to vector
|
||||
|
||||
* \fn PIVector<T> & PIVector::pop_front();
|
||||
* \brief Remove one element from the beginning of vector and return reference to vector
|
||||
|
||||
* \fn Type PIVector::take_back();
|
||||
* \brief Remove one element from the end of vector and return it
|
||||
|
||||
* \fn Type PIVector::take_front();
|
||||
* \brief Remove one element from the beginning of vector and return it
|
||||
|
||||
* \fn PIVector<T> & PIVector::remove(uint index);
|
||||
* \brief Remove one element by index "index" and return reference to vector
|
||||
* \details Example: \snippet picontainers.cpp PIVector::remove_0
|
||||
* \sa \a removeOne(), \a removeAll()
|
||||
|
||||
* \fn PIVector<T> & PIVector::remove(uint index, uint count);
|
||||
* \brief Remove "count" elements by first index "index" and return reference to vector
|
||||
* \details Example: \snippet picontainers.cpp PIVector::remove_1
|
||||
* \sa \a removeOne(), \a removeAll()
|
||||
|
||||
* \fn PIVector<T> & PIVector::removeOne(const Type & v);
|
||||
* \brief Remove no more than one element equal "v" and return reference to vector
|
||||
* \details Example: \snippet picontainers.cpp PIVector::removeOne
|
||||
* \sa \a remove(), \a removeAll()
|
||||
|
||||
* \fn PIVector<T> & PIVector::removeAll(const Type & v);
|
||||
* \brief Remove all elements equal "v" and return reference to vector
|
||||
* \details Example: \snippet picontainers.cpp PIVector::removeAll
|
||||
* \sa \a remove(), \a removeOne()
|
||||
|
||||
* \fn PIVector<T> & PIVector::insert(uint pos, const Type & t);
|
||||
* \brief Insert element "t" after index "pos" and return reference to vector
|
||||
* \details Example: \snippet picontainers.cpp PIVector::insert_0
|
||||
|
||||
* \fn PIVector<T> & PIVector::insert(uint pos, const PIVector<T> & t);
|
||||
* \brief Insert other vector "t" after index "pos" and return reference to vector
|
||||
* \details Example: \snippet picontainers.cpp PIVector::insert_1
|
||||
|
||||
* \fn Type & PIVector::operator [](uint index);
|
||||
* \brief Full access to element by index "index"
|
||||
* \details Example: \snippet picontainers.cpp PIVector::()
|
||||
* \sa \a at()
|
||||
|
||||
* \fn const Type & PIVector::operator [](uint index) const;
|
||||
* \brief Read-only access to element by index "index"
|
||||
* \details Example: \snippet picontainers.cpp PIVector::()_c
|
||||
* \sa \a at()
|
||||
|
||||
* \fn PIVector<T> & PIVector::operator <<(const Type & t);
|
||||
* \brief Add new element "t" at the end of vector and return reference to vector
|
||||
|
||||
* \fn PIVector<T> & PIVector::operator <<(const PIVector<T> & t);
|
||||
* \brief Add vector "t" at the end of vector and return reference to vector
|
||||
|
||||
* \fn bool PIVector::operator ==(const PIVector<T> & t);
|
||||
* \brief Compare with vector "t"
|
||||
|
||||
* \fn bool PIVector::operator !=(const PIVector<T> & t);
|
||||
* \brief Compare with vector "t"
|
||||
|
||||
* */
|
||||
239
lib/main/containers/picontainers.h
Normal file
239
lib/main/containers/picontainers.h
Normal file
@@ -0,0 +1,239 @@
|
||||
/*! \file picontainers.h
|
||||
* \brief Base for generic containers
|
||||
*
|
||||
* This file declare all containers and useful macros
|
||||
* to use them
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Base for generic containers
|
||||
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 PICONTAINERS_H
|
||||
#define PICONTAINERS_H
|
||||
|
||||
#include "picout.h"
|
||||
#include "piintrospection_containers.h"
|
||||
#ifdef PIP_DEBUG
|
||||
# ifdef NDEBUG
|
||||
# undef NDEBUG
|
||||
# endif
|
||||
# include <cassert>
|
||||
#endif
|
||||
#ifndef assert
|
||||
# define assert(x)
|
||||
#endif
|
||||
#ifdef MAC_OS
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <new>
|
||||
#ifndef PIP_MEMALIGN_BYTES
|
||||
# define PIP_MEMALIGN_BYTES (sizeof(void*)*4)
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
# ifdef CC_GCC
|
||||
# define amalloc(s) __mingw_aligned_malloc(s, PIP_MEMALIGN_BYTES)
|
||||
# define afree(p) __mingw_aligned_free(p)
|
||||
# else
|
||||
# ifdef CC_VC
|
||||
# define amalloc(s) _aligned_malloc(s, PIP_MEMALIGN_BYTES)
|
||||
# define afree(p) _aligned_free(p)
|
||||
# endif
|
||||
# endif
|
||||
#else
|
||||
# define amalloc(s) aligned_alloc(PIP_MEMALIGN_BYTES, s)
|
||||
# define afree(p) free(p)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
/*!\brief Macro for iterate any container
|
||||
* \details Use this macros instead of standard "for"
|
||||
* to get read/write access to each element of container.
|
||||
* Pass direction is direct \n
|
||||
* Example: \snippet picontainers.cpp foreach
|
||||
*/
|
||||
# define piForeach(i,c)
|
||||
|
||||
/*!\brief Macro for iterate any container only for read
|
||||
* \details Use this macros instead of standard "for"
|
||||
* to get read access to each element of container.
|
||||
* Pass direction is direct \n
|
||||
* Example: \snippet picontainers.cpp foreachC
|
||||
*/
|
||||
# define piForeachC(i,c)
|
||||
|
||||
/*!\brief Macro for iterate any container with reverse direction
|
||||
* \details Use this macros instead of standard "for"
|
||||
* to get read/write access to each element of container.
|
||||
* Pass direction is reverse \n
|
||||
* Example: \snippet picontainers.cpp foreachR
|
||||
*/
|
||||
# define piForeachR(i,c)
|
||||
|
||||
/*!\brief Macro for iterate any container only for read with reverse direction
|
||||
* \details Use this macros instead of standard "for"
|
||||
* to get read access to each element of container.
|
||||
* Pass direction is reverse \n
|
||||
* Example: \snippet picontainers.cpp foreachCR
|
||||
*/
|
||||
# define piForeachCR(i,c)
|
||||
|
||||
/*!\brief Macro for break from any piForeach* loop
|
||||
* \details \warning C++ ordinary "break" doesn`t work inside piForeach*
|
||||
* loops! Always use "piBreak" instead!
|
||||
*/
|
||||
# define piBreak
|
||||
|
||||
#else
|
||||
|
||||
# define piBreak {_for._end = true; break;}
|
||||
|
||||
# define piForTimes(c) for(int _i##c = 0; _i##c < c; ++_i##c)
|
||||
|
||||
#ifdef CC_GCC
|
||||
|
||||
template<typename Type>
|
||||
class _PIForeach {
|
||||
public:
|
||||
_PIForeach(Type & t): _t(t), _break(false), _end(false) {_it = _t.begin();}
|
||||
typename Type::value_type _var;
|
||||
typename Type::iterator _it;
|
||||
Type & _t;
|
||||
bool _break, _end;
|
||||
inline bool isEnd() {return _it == _t.end();}
|
||||
inline void operator ++() {if (_end) _it = _t.end(); else _it++; _break = false;}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
class _PIForeachR {
|
||||
public:
|
||||
_PIForeachR(Type & t): _t(t), _break(false), _end(false) {_rit = _t.rbegin();}
|
||||
typename Type::value_type _var;
|
||||
typename Type::reverse_iterator _rit;
|
||||
Type & _t;
|
||||
bool _break, _end;
|
||||
inline bool isEnd() {return _rit == _t.rend();}
|
||||
inline void operator ++() {if (_end) _rit = _t.rend(); else _rit++; _break = false;}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
class _PIForeachC {
|
||||
public:
|
||||
_PIForeachC(const Type & t): _t(t), _break(false), _end(false) {_it = _t.begin();}
|
||||
typename Type::value_type _var;
|
||||
typename Type::const_iterator _it;
|
||||
const Type & _t;
|
||||
bool _break, _end;
|
||||
inline bool isEnd() {return _it == _t.end();}
|
||||
inline void operator ++() {if (_end) _it = _t.end(); else _it++; _break = false;}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
class _PIForeachCR {
|
||||
public:
|
||||
_PIForeachCR(const Type & t): _t(t), _break(false), _end(false) {_rit = _t.rbegin();}
|
||||
typename Type::value_type _var;
|
||||
typename Type::const_reverse_iterator _rit;
|
||||
const Type & _t;
|
||||
bool _break, _end;
|
||||
inline bool isEnd() {return _rit == _t.rend();}
|
||||
inline void operator ++() {if (_end) _rit = _t.rend(); else _rit++; _break = false;}
|
||||
};
|
||||
|
||||
#define piForeach(i,c) for(_PIForeach<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(i(*_for._it); !_for._break; _for._break = true)
|
||||
#define piForeachR(i,c) for(_PIForeachR<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(i(*_for._rit); !_for._break; _for._break = true)
|
||||
#define piForeachA(i,c) for(_PIForeach<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(typeof(_for._var) & i(*_for._it); !_for._break; _for._break = true)
|
||||
#define piForeachAR(i,c) for(_PIForeachR<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(typeof(_for._var) & i(*_for._rit); !_for._break; _for._break = true)
|
||||
#define piForeachC(i,c) for(_PIForeachC<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(const i(*_for._it); !_for._break; _for._break = true)
|
||||
#define piForeachCR(i,c) for(_PIForeachCR<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(const i(*_for._rit); !_for._break; _for._break = true)
|
||||
#define piForeachCA(i,c) for(_PIForeachC<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(const typeof(_for._var) & i(*_for._it); !_for._break; _for._break = true)
|
||||
#define piForeachCAR(i,c) for(_PIForeachCR<typeof(c)> _for(c); !_for.isEnd(); ++_for) \
|
||||
for(const typeof(_for._var) & i(*_for._rit); !_for._break; _for._break = true)
|
||||
|
||||
#define piForeachRA piForeachAR
|
||||
#define piForeachAC piForeachCA
|
||||
#define piForeachCRA piForeachCAR
|
||||
#define piForeachARC piForeachCAR
|
||||
#define piForeachACR piForeachCAR
|
||||
#define piForeachRCA piForeachCAR
|
||||
#define piForeachRAC piForeachCAR
|
||||
|
||||
#else
|
||||
|
||||
class _PIForeachBase {public: mutable bool _break, _end; };
|
||||
|
||||
template<typename Type>
|
||||
class _PIForeach: public _PIForeachBase {
|
||||
public:
|
||||
_PIForeach(Type & t, bool i = false): _t(t), _inv(i) {_break = _end = false; if (_inv) _rit = _t.rbegin(); else _it = _t.begin();}
|
||||
mutable typename Type::value_type _var;
|
||||
mutable typename Type::iterator _it;
|
||||
mutable typename Type::reverse_iterator _rit;
|
||||
Type & _t;
|
||||
bool _inv;
|
||||
bool isEnd() {if (_inv) return _rit == _t.rend(); else return _it == _t.end();}
|
||||
void operator ++() {if (_inv) {if (_end) _rit = _t.rend(); else _rit++;} else {if (_end) _it = _t.end(); else _it++;} _break = false;}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
class _PIForeachC: public _PIForeachBase {
|
||||
public:
|
||||
_PIForeachC(const Type & t, bool i = false): _t(t), _inv(i) {_break = _end = false; if (_inv) _rit = _t.rbegin(); else _it = _t.begin();}
|
||||
mutable typename Type::value_type _var;
|
||||
mutable typename Type::const_iterator _it;
|
||||
mutable typename Type::const_reverse_iterator _rit;
|
||||
const Type & _t;
|
||||
bool _inv;
|
||||
bool isEnd() {if (_inv) return _rit == _t.rend(); else return _it == _t.end();}
|
||||
void operator ++() {if (_inv) {if (_end) _rit = _t.rend(); else _rit++;} else {if (_end) _it = _t.end(); else _it++;} _break = false;}
|
||||
};
|
||||
|
||||
template <typename T> inline _PIForeach<T> _PIForeachNew(T & t, bool i = false) {return _PIForeach<T>(t, i);}
|
||||
template <typename T> inline _PIForeach<T> * _PIForeachCast(_PIForeachBase & c, T & ) {return static_cast<_PIForeach<T> * >(&c);}
|
||||
|
||||
template <typename T> inline _PIForeachC<T> _PIForeachNewC(const T & t, bool i = false) {return _PIForeachC<T>(t, i);}
|
||||
template <typename T> inline _PIForeachC<T> * _PIForeachCastC(_PIForeachBase & c, const T & ) {return static_cast<_PIForeachC<T> * >(&c);}
|
||||
|
||||
#define piForeach(i,c) for(_PIForeachBase & _for = _PIForeachNew(c); !_PIForeachCast(_for, c)->isEnd(); ++(*_PIForeachCast(_for, c))) \
|
||||
for(i = *(_PIForeachCast(_for, c)->_it); !_for._break; _for._break = true)
|
||||
#define piForeachR(i,c) for(_PIForeachBase & _for = _PIForeachNew(c, true); !_PIForeachCast(_for, c)->isEnd(); ++(*_PIForeachCast(_for, c))) \
|
||||
for(i = *(_PIForeachCast(_for, c)->_rit); !_for._break; _for._break = true)
|
||||
#define piForeachC(i,c) for(_PIForeachBase & _for = _PIForeachNewC(c); !_PIForeachCastC(_for, c)->isEnd(); ++(*_PIForeachCastC(_for, c))) \
|
||||
for(const i = *(_PIForeachCastC(_for, c)->_it); !_for._break; _for._break = true)
|
||||
#define piForeachCR(i,c) for(_PIForeachBase & _for = _PIForeachNewC(c, false); !_PIForeachCastC(_for, c)->isEnd(); ++(*_PIForeachCastC(_for, c))) \
|
||||
for(const i = *(_PIForeachCastC(_for, c)->_rit); !_for._break; _for._break = true)
|
||||
|
||||
#endif
|
||||
|
||||
#define piForeachRC piForeachCR
|
||||
|
||||
#endif // DOXYGEN
|
||||
|
||||
|
||||
#endif // PICONTAINERS_H
|
||||
31
lib/main/containers/picontainersmodule.h
Normal file
31
lib/main/containers/picontainersmodule.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef PICONTAINERSMODULE_H
|
||||
#define PICONTAINERSMODULE_H
|
||||
|
||||
#include "pivector.h"
|
||||
#include "pideque.h"
|
||||
#include "pimap.h"
|
||||
#include "piqueue.h"
|
||||
#include "piset.h"
|
||||
#include "pistack.h"
|
||||
#include "pivector2d.h"
|
||||
|
||||
#endif // PICONTAINERSMODULE_H
|
||||
542
lib/main/containers/pideque.h
Normal file
542
lib/main/containers/pideque.h
Normal file
@@ -0,0 +1,542 @@
|
||||
/*! \file pideque.h
|
||||
* \brief Dynamic array of any type
|
||||
*
|
||||
* This file declares PIDeque
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Dynamic array of any type
|
||||
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 PIDEQUE_H
|
||||
#define PIDEQUE_H
|
||||
|
||||
#include "picontainers.h"
|
||||
|
||||
|
||||
template <typename T>
|
||||
class PIDeque {
|
||||
public:
|
||||
inline PIDeque(): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
|
||||
//piCout << "PIDeque";
|
||||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||||
}
|
||||
inline PIDeque(const PIDeque<T> & other): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
|
||||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||||
alloc(other.pid_size, true);
|
||||
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
|
||||
}
|
||||
inline PIDeque(const T * data, size_t size): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
|
||||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||||
alloc(size, true);
|
||||
newT(pid_data + pid_start, data, pid_size);
|
||||
}
|
||||
inline PIDeque(size_t pid_size, const T & f = T()): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
|
||||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||||
resize(pid_size, f);
|
||||
}
|
||||
inline virtual ~PIDeque() {
|
||||
//piCout << "~PIDeque";
|
||||
PIINTROSPECTION_CONTAINER_DELETE(T)
|
||||
PIINTROSPECTION_CONTAINER_FREE(T, (pid_rsize))
|
||||
deleteT(pid_data + pid_start, pid_size);
|
||||
dealloc();
|
||||
_reset();
|
||||
}
|
||||
|
||||
inline PIDeque<T> & operator =(const PIDeque<T> & other) {
|
||||
if (this == &other) return *this;
|
||||
deleteT(pid_data + pid_start, pid_size);
|
||||
alloc(other.pid_size, true);
|
||||
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
class iterator {
|
||||
friend class PIDeque<T>;
|
||||
private:
|
||||
inline iterator(PIDeque<T> * v, size_t p): parent(v), pos(p) {}
|
||||
PIDeque<T> * parent;
|
||||
size_t pos;
|
||||
public:
|
||||
inline iterator(): parent(0), pos(0) {}
|
||||
inline T & operator *() {return (*parent)[pos];}
|
||||
inline const T & operator *() const {return (*parent)[pos];}
|
||||
inline void operator ++() {++pos;}
|
||||
inline void operator ++(int) {++pos;}
|
||||
inline void operator --() {--pos;}
|
||||
inline void operator --(int) {--pos;}
|
||||
inline bool operator ==(const iterator & it) const {return (pos == it.pos);}
|
||||
inline bool operator !=(const iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
class const_iterator {
|
||||
friend class PIDeque<T>;
|
||||
private:
|
||||
inline const_iterator(const PIDeque<T> * v, size_t p): parent(v), pos(p) {}
|
||||
const PIDeque<T> * parent;
|
||||
size_t pos;
|
||||
public:
|
||||
inline const_iterator(): parent(0), pos(0) {}
|
||||
inline const T & operator *() const {return (*parent)[pos];}
|
||||
inline void operator ++() {++pos;}
|
||||
inline void operator ++(int) {++pos;}
|
||||
inline void operator --() {--pos;}
|
||||
inline void operator --(int) {--pos;}
|
||||
inline bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
|
||||
inline bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
class reverse_iterator {
|
||||
friend class PIDeque<T>;
|
||||
private:
|
||||
inline reverse_iterator(PIDeque<T> * v, size_t p): parent(v), pos(p) {}
|
||||
PIDeque<T> * parent;
|
||||
size_t pos;
|
||||
public:
|
||||
inline reverse_iterator(): parent(0), pos(0) {}
|
||||
inline T & operator *() {return (*parent)[pos];}
|
||||
inline const T & operator *() const {return (*parent)[pos];}
|
||||
inline void operator ++() {--pos;}
|
||||
inline void operator ++(int) {--pos;}
|
||||
inline void operator --() {++pos;}
|
||||
inline void operator --(int) {++pos;}
|
||||
inline bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);}
|
||||
inline bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
class const_reverse_iterator {
|
||||
friend class PIDeque<T>;
|
||||
private:
|
||||
inline const_reverse_iterator(const PIDeque<T> * v, size_t p): parent(v), pos(p) {}
|
||||
const PIDeque<T> * parent;
|
||||
size_t pos;
|
||||
public:
|
||||
inline const_reverse_iterator(): parent(0), pos(0) {}
|
||||
inline const T & operator *() const {return (*parent)[pos];}
|
||||
inline void operator ++() {--pos;}
|
||||
inline void operator ++(int) {--pos;}
|
||||
inline void operator --() {++pos;}
|
||||
inline void operator --(int) {++pos;}
|
||||
inline bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
|
||||
inline bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
inline iterator begin() {return iterator(this, 0);}
|
||||
inline iterator end() {return iterator(this, pid_size);}
|
||||
inline const_iterator begin() const {return const_iterator(this, 0);}
|
||||
inline const_iterator end() const {return const_iterator(this, pid_size);}
|
||||
inline reverse_iterator rbegin() {return reverse_iterator(this, pid_size - 1);}
|
||||
inline reverse_iterator rend() {return reverse_iterator(this, -1);}
|
||||
inline const_reverse_iterator rbegin() const {return const_reverse_iterator(this, pid_size - 1);}
|
||||
inline const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
|
||||
|
||||
inline size_t size() const {return pid_size;}
|
||||
inline ssize_t size_s() const {return pid_size;}
|
||||
inline size_t length() const {return pid_size;}
|
||||
inline size_t capacity() const {return pid_rsize;}
|
||||
inline size_t _start() const {return pid_start;}
|
||||
inline bool isEmpty() const {return (pid_size == 0);}
|
||||
|
||||
inline T & operator [](size_t index) {return pid_data[pid_start + index];}
|
||||
inline T & at(size_t index) {return pid_data[pid_start + index];}
|
||||
inline const T & operator [](size_t index) const {return pid_data[pid_start + index];}
|
||||
inline const T & at(size_t index) const {return pid_data[pid_start + index];}
|
||||
inline T & back() {return pid_data[pid_start + pid_size - 1];}
|
||||
inline const T & back() const {return pid_data[pid_start + pid_size - 1];}
|
||||
inline T & front() {return pid_data[pid_start];}
|
||||
inline const T & front() const {return pid_data[pid_start];}
|
||||
inline bool operator ==(const PIDeque<T> & t) const {
|
||||
if (pid_size != t.pid_size) return false;
|
||||
for (size_t i = 0; i < pid_size; ++i)
|
||||
if (t[i] != (*this)[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
inline bool operator !=(const PIDeque<T> & t) const {return !(*this == t);}
|
||||
inline bool contains(const T & v) const {
|
||||
for (size_t i = pid_start; i < pid_start + pid_size; ++i)
|
||||
if (v == pid_data[i])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
inline int etries(const T & v) const {
|
||||
int ec = 0;
|
||||
for (size_t i = pid_start; i < pid_start + pid_size; ++i)
|
||||
if (v == pid_data[i]) ++ec;
|
||||
return ec;
|
||||
}
|
||||
inline ssize_t indexOf(const T & v) const {
|
||||
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i)
|
||||
if (v == pid_data[i])
|
||||
return i - pid_start;
|
||||
return -1;
|
||||
}
|
||||
inline ssize_t lastIndexOf(const T & v) const {
|
||||
for (ssize_t i = pid_start + (ssize_t)pid_size - 1; i >= pid_start; --i)
|
||||
if (v == pid_data[i])
|
||||
return i - pid_start;
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline T * data(size_t index = 0) {return &(pid_data[pid_start + index]);}
|
||||
inline const T * data(size_t index = 0) const {return &(pid_data[pid_start + index]);}
|
||||
|
||||
inline PIDeque<T> & clear() {resize(0); return *this;}
|
||||
inline PIDeque<T> & fill(const T & f = T()) {
|
||||
deleteT(pid_data + pid_start, pid_size);
|
||||
PIINTROSPECTION_CONTAINER_USED(T, pid_size)
|
||||
for (size_t i = pid_start; i < pid_start + pid_size; ++i)
|
||||
elementNew(pid_data + i, f);
|
||||
return *this;
|
||||
}
|
||||
inline PIDeque<T> & assign(const T & f = T()) {return fill(f);}
|
||||
inline PIDeque<T> & assign(size_t new_size, const T & f) {
|
||||
resize(new_size);
|
||||
return fill(f);
|
||||
}
|
||||
|
||||
inline PIDeque<T> & resize(size_t new_size, const T & f = T()) {
|
||||
if (new_size < pid_size) {
|
||||
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
|
||||
pid_size = new_size;
|
||||
}
|
||||
if (new_size > pid_size) {
|
||||
size_t os = pid_size;
|
||||
alloc(new_size, true);
|
||||
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
|
||||
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) elementNew(pid_data + i, f);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
inline PIDeque<T> & _resizeRaw(size_t new_size) {
|
||||
piCout << "Error, \"resizeRaw()\" only allowed for simple type declared with __PIDEQUE_SIMPLE_TYPE__ macro!";
|
||||
assert(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIDeque<T> & reserve(size_t new_size) {
|
||||
if (new_size <= pid_rsize) return *this;
|
||||
size_t os = pid_size;
|
||||
alloc(new_size, true);
|
||||
pid_size = os;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIDeque<T> & insert(size_t index, const T & v = T()) {
|
||||
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
|
||||
if (dir) {
|
||||
alloc(pid_size + 1, true);
|
||||
if (index < pid_size - 1) {
|
||||
size_t os = pid_size - index - 1;
|
||||
memmove((void*)(&(pid_data[index + pid_start + 1])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
|
||||
}
|
||||
} else {
|
||||
alloc(pid_size + 1, false, -1);
|
||||
if (index > 0)
|
||||
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T));
|
||||
}
|
||||
PIINTROSPECTION_CONTAINER_USED(T, 1)
|
||||
elementNew(pid_data + pid_start + index, v);
|
||||
return *this;
|
||||
}
|
||||
inline PIDeque<T> & insert(size_t index, const PIDeque<T> & other) {
|
||||
if (other.isEmpty()) return *this;
|
||||
assert(&other != this);
|
||||
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
|
||||
if (dir) {
|
||||
ssize_t os = pid_size - index;
|
||||
alloc(pid_size + other.pid_size, true);
|
||||
if (os > 0)
|
||||
memmove((void*)(&(pid_data[index + pid_start + other.pid_size])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
|
||||
} else {
|
||||
alloc(pid_size + other.pid_size, false, -other.pid_size);
|
||||
if (index > 0)
|
||||
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + other.pid_size])), index * sizeof(T));
|
||||
}
|
||||
newT(pid_data + pid_start + index, other.pid_data + other.pid_start, other.pid_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIDeque<T> & remove(size_t index, size_t count = 1) {
|
||||
if (count == 0) return *this;
|
||||
if (index + count >= pid_size) {
|
||||
resize(index);
|
||||
return *this;
|
||||
}
|
||||
size_t os = pid_size - index - count;
|
||||
deleteT(&(pid_data[index + pid_start]), count);
|
||||
if (os <= index) {
|
||||
if (os > 0) memmove((void*)(&(pid_data[index + pid_start])), (const void*)(&(pid_data[index + pid_start + count])), os * sizeof(T));
|
||||
} else {
|
||||
if (index > 0) memmove((void*)(&(pid_data[pid_start + count])), (const void*)(&(pid_data[pid_start])), index * sizeof(T));
|
||||
pid_start += count;
|
||||
}
|
||||
pid_size -= count;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void swap(PIDeque<T> & other) {
|
||||
piSwap<T*>(pid_data, other.pid_data);
|
||||
piSwap<size_t>(pid_size, other.pid_size);
|
||||
piSwap<size_t>(pid_rsize, other.pid_rsize);
|
||||
piSwap<ssize_t>(pid_start, other.pid_start);
|
||||
}
|
||||
|
||||
typedef int (*CompareFunc)(const T * , const T * );
|
||||
static int compare_func(const T * t0, const T * t1) {return (*t0) < (*t1) ? -1 : ((*t0) == (*t1) ? 0 : 1);}
|
||||
inline PIDeque<T> & sort(CompareFunc compare = compare_func) {
|
||||
piqsort(pid_data + pid_start, pid_size, sizeof(T), (int(*)(const void * , const void * ))compare);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIDeque<T> & enlarge(llong pid_size) {
|
||||
llong ns = size_s() + pid_size;
|
||||
if (ns <= 0) clear();
|
||||
else resize(size_t(ns));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIDeque<T> & removeOne(const T & v) {
|
||||
for (size_t i = 0; i < pid_size; ++i)
|
||||
if (pid_data[i + pid_start] == v) {
|
||||
remove(i);
|
||||
return *this;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
inline PIDeque<T> & removeAll(const T & v) {
|
||||
for (ssize_t i = 0; i < ssize_t(pid_size); ++i)
|
||||
if (pid_data[i + pid_start] == v) {
|
||||
remove(i);
|
||||
--i;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIDeque<T> & push_back(const T & v) {
|
||||
alloc(pid_size + 1, true);
|
||||
PIINTROSPECTION_CONTAINER_USED(T, 1);
|
||||
elementNew(pid_data + pid_start + pid_size - 1, v);
|
||||
return *this;
|
||||
}
|
||||
inline PIDeque<T> & append(const T & v) {return push_back(v);}
|
||||
inline PIDeque<T> & append(const PIDeque<T> & t) {
|
||||
assert(&t != this);
|
||||
size_t ps = pid_size;
|
||||
alloc(pid_size + t.pid_size, true);
|
||||
newT(pid_data + ps + pid_start, t.pid_data + t.pid_start, t.pid_size);
|
||||
return *this;
|
||||
}
|
||||
inline PIDeque<T> & operator <<(const T & v) {return push_back(v);}
|
||||
inline PIDeque<T> & operator <<(const PIDeque<T> & t) {return append(t);}
|
||||
|
||||
inline PIDeque<T> & push_front(const T & v) {insert(0, v); return *this;}
|
||||
inline PIDeque<T> & prepend(const T & v) {return push_front(v);}
|
||||
|
||||
inline PIDeque<T> & pop_back() {if (pid_size == 0) return *this; resize(pid_size - 1); return *this;}
|
||||
inline PIDeque<T> & pop_front() {if (pid_size == 0) return *this; remove(0); return *this;}
|
||||
|
||||
inline T take_back() {T t(back()); pop_back(); return t;}
|
||||
inline T take_front() {T t(front()); pop_front(); return t;}
|
||||
|
||||
template <typename ST>
|
||||
PIDeque<ST> toType() const {
|
||||
PIDeque<ST> ret(pid_size);
|
||||
for (uint i = 0; i < pid_size; ++i)
|
||||
ret[i] = ST(pid_data[i + pid_start]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
const PIDeque<T> & forEach(std::function<void(const T &)> f) const {
|
||||
for (uint i = 0; i < pid_size; ++i)
|
||||
f(pid_data[i + pid_start]);
|
||||
return *this;
|
||||
}
|
||||
PIDeque<T> copyForEach(std::function<T(const T &)> f) const {
|
||||
PIDeque<T> ret; ret.reserve(pid_size);
|
||||
for (uint i = 0; i < pid_size; ++i)
|
||||
ret << f(pid_data[i + pid_start]);
|
||||
return ret;
|
||||
}
|
||||
PIDeque<T> & forEachInplace(std::function<T(const T &)> f) {
|
||||
for (uint i = 0; i < pid_size; ++i)
|
||||
pid_data[i + pid_start] = f(pid_data[i + pid_start]);
|
||||
return *this;
|
||||
}
|
||||
template <typename ST>
|
||||
PIDeque<ST> toType(std::function<ST(const T &)> f) const {
|
||||
PIDeque<ST> ret; ret.reserve(pid_size);
|
||||
for (uint i = 0; i < pid_size; ++i)
|
||||
ret << f(pid_data[i + pid_start]);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
inline void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;}
|
||||
inline size_t asize(ssize_t s) {
|
||||
if (s <= 0) return 0;
|
||||
if (pid_rsize + pid_rsize >= size_t(s) && pid_rsize < size_t(s))
|
||||
return pid_rsize + pid_rsize;
|
||||
ssize_t t = 0, s_ = s - 1;
|
||||
while (s_ >> t)
|
||||
++t;
|
||||
return (1 << t);
|
||||
}
|
||||
inline void newT(T * dst, const T * src, size_t s) {
|
||||
PIINTROSPECTION_CONTAINER_USED(T, s)
|
||||
for (size_t i = 0; i < s; ++i)
|
||||
elementNew(dst + i, src[i]);
|
||||
}
|
||||
inline void deleteT(T * d, size_t sz) {
|
||||
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
|
||||
if ((uchar*)d != 0) {
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
elementDelete(d[i]);
|
||||
}
|
||||
}
|
||||
inline void elementNew(T * to, const T & from) {new(to)T(from);}
|
||||
inline void elementDelete(T & from) {from.~T();}
|
||||
inline void dealloc() {
|
||||
if ((uchar*)pid_data != 0) free((uchar*)pid_data);
|
||||
pid_data = 0;
|
||||
}
|
||||
inline void checkMove(bool direction) {
|
||||
if (pid_size >= 4) {
|
||||
if (pid_size < pid_rsize / 6) {
|
||||
if (pid_start < ssize_t(pid_size + pid_size) || pid_start > (ssize_t(pid_rsize) - ssize_t(pid_size) - ssize_t(pid_size))) {
|
||||
ssize_t ns = (pid_rsize - pid_size) / 2;
|
||||
if (pid_start != ns) {
|
||||
memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
|
||||
pid_start = ns;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ssize_t ns = (pid_rsize - pid_size) / 2;
|
||||
if (pid_start != ns) {
|
||||
memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
|
||||
pid_start = ns;
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void alloc(size_t new_size, bool direction, ssize_t start_offset = 0) { // direction == true -> alloc forward
|
||||
if (direction) {
|
||||
if (pid_start + new_size <= pid_rsize) {
|
||||
pid_size = new_size;
|
||||
checkMove(direction);
|
||||
return;
|
||||
}
|
||||
pid_size = new_size;
|
||||
size_t as = asize(pid_start + new_size);
|
||||
if (as != pid_rsize) {
|
||||
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
|
||||
T * p_d = (T*)(realloc((void*)(pid_data), as*sizeof(T)));
|
||||
assert(p_d);
|
||||
pid_data = p_d;
|
||||
pid_rsize = as;
|
||||
}
|
||||
} else {
|
||||
size_t as;
|
||||
if (pid_start + start_offset < 0)
|
||||
as = asize(pid_rsize - start_offset);
|
||||
else as = pid_rsize;
|
||||
|
||||
if (as > pid_rsize) {
|
||||
T * td = (T*)(malloc(as * sizeof(T)));
|
||||
ssize_t ns = pid_start + as - pid_rsize;
|
||||
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
|
||||
if (pid_rsize > 0 && pid_data != 0) {
|
||||
memcpy((void*)(td + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
|
||||
dealloc();
|
||||
}
|
||||
pid_data = td;
|
||||
pid_rsize = as;
|
||||
pid_start = ns;
|
||||
}
|
||||
pid_start += start_offset;
|
||||
pid_size = new_size;
|
||||
checkMove(direction);
|
||||
}
|
||||
}
|
||||
|
||||
T * pid_data;
|
||||
size_t pid_size, pid_rsize;
|
||||
ssize_t pid_start;
|
||||
};
|
||||
|
||||
#define __PIDEQUE_SIMPLE_TYPE__(T) \
|
||||
template<> inline void PIDeque<T>::newT(T * dst, const T * src, size_t s) {PIINTROSPECTION_CONTAINER_USED(T, s); memcpy((void*)(dst), (const void*)(src), s * sizeof(T));} \
|
||||
template<> inline void PIDeque<T>::deleteT(T *, size_t sz) {PIINTROSPECTION_CONTAINER_UNUSED(T, sz);} \
|
||||
template<> inline void PIDeque<T>::elementNew(T * to, const T & from) {(*to) = from;} \
|
||||
template<> inline void PIDeque<T>::elementDelete(T &) {;} \
|
||||
template<> inline PIDeque<T> & PIDeque<T>::_resizeRaw(size_t new_size) { \
|
||||
if (new_size > pid_size) { \
|
||||
PIINTROSPECTION_CONTAINER_USED(T, (new_size-pid_size)); \
|
||||
} \
|
||||
if (new_size < pid_size) { \
|
||||
PIINTROSPECTION_CONTAINER_UNUSED(T, (pid_size-new_size)); \
|
||||
} \
|
||||
alloc(new_size, true); \
|
||||
return *this; \
|
||||
} \
|
||||
template<> inline PIDeque<T> & PIDeque<T>::clear() {PIINTROSPECTION_CONTAINER_UNUSED(T, pid_size); pid_size = 0; return *this;} \
|
||||
template<> inline PIDeque<T> & PIDeque<T>::assign(size_t new_size, const T & f) {_resizeRaw(new_size); return fill(f);}
|
||||
|
||||
|
||||
__PIDEQUE_SIMPLE_TYPE__(bool)
|
||||
__PIDEQUE_SIMPLE_TYPE__(char)
|
||||
__PIDEQUE_SIMPLE_TYPE__(uchar)
|
||||
__PIDEQUE_SIMPLE_TYPE__(short)
|
||||
__PIDEQUE_SIMPLE_TYPE__(ushort)
|
||||
__PIDEQUE_SIMPLE_TYPE__(int)
|
||||
__PIDEQUE_SIMPLE_TYPE__(uint)
|
||||
__PIDEQUE_SIMPLE_TYPE__(long)
|
||||
__PIDEQUE_SIMPLE_TYPE__(ulong)
|
||||
__PIDEQUE_SIMPLE_TYPE__(llong)
|
||||
__PIDEQUE_SIMPLE_TYPE__(ullong)
|
||||
__PIDEQUE_SIMPLE_TYPE__(float)
|
||||
__PIDEQUE_SIMPLE_TYPE__(double)
|
||||
__PIDEQUE_SIMPLE_TYPE__(ldouble)
|
||||
|
||||
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
template<typename T>
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIDeque<T> & v) {s << "{"; for (size_t i = 0; i < v.size(); ++i) {s << v[i]; if (i < v.size() - 1) s << ", ";} s << "}"; return s;}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
inline PICout operator <<(PICout s, const PIDeque<T> & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s << "{";
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
s << v[i];
|
||||
if (i < v.size() - 1)
|
||||
s << ", ";
|
||||
}
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
#endif // PIDEQUE_H
|
||||
346
lib/main/containers/pimap.h
Normal file
346
lib/main/containers/pimap.h
Normal file
@@ -0,0 +1,346 @@
|
||||
/*! \file pimap.h
|
||||
* \brief Associative array with custom types of key and value
|
||||
*
|
||||
* This file declares PIMap
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Associative array with custom types of key and value
|
||||
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 PIMAP_H
|
||||
#define PIMAP_H
|
||||
|
||||
#include "pivector.h"
|
||||
#include "pideque.h"
|
||||
#include "pipair.h"
|
||||
# define __PICONTAINERS_SIMPLE_TYPE__(T) \
|
||||
__PIDEQUE_SIMPLE_TYPE__(T)\
|
||||
__PIVECTOR_SIMPLE_TYPE__(T)
|
||||
|
||||
|
||||
template<class T>
|
||||
void piQuickSort(T * a, ssize_t N) {
|
||||
if (N < 1) return;
|
||||
if (N < 46) {
|
||||
T tmp;
|
||||
ssize_t i,j;
|
||||
for(i=1; i<=N; i++) {
|
||||
tmp = a[i];
|
||||
j = i-1;
|
||||
while(tmp<a[j] && j>=0) {
|
||||
a[j+1] = a[j];
|
||||
j = j-1;
|
||||
}
|
||||
a[j+1] = tmp;
|
||||
}
|
||||
} else {
|
||||
ssize_t i = 0, j = N;
|
||||
T & p(a[N >> 1]);
|
||||
do {
|
||||
while (a[i] < p) i++;
|
||||
while (a[j] > p) j--;
|
||||
if (i <= j) {
|
||||
if (i != j) {
|
||||
//piCout << "swap" << i << j << a[i] << a[j];
|
||||
piSwapBinary<T>(a[i], a[j]);
|
||||
}
|
||||
i++; j--;
|
||||
}
|
||||
} while (i <= j);
|
||||
if (j > 0) piQuickSort(a, j);
|
||||
if (N > i) piQuickSort(a + i, N - i);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key, typename T>
|
||||
class PIMap {
|
||||
template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIMap<Key1, T1> & v);
|
||||
template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIMap<Key1, T1> & v);
|
||||
public:
|
||||
PIMap() {;}
|
||||
PIMap(const PIMap<Key, T> & other) {*this = other;}
|
||||
virtual ~PIMap() {;}
|
||||
|
||||
PIMap<Key, T> & operator =(const PIMap<Key, T> & other) {
|
||||
if (this == &other) return *this;
|
||||
clear();
|
||||
pim_content = other.pim_content;
|
||||
pim_index = other.pim_index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef T mapped_type;
|
||||
typedef Key key_type;
|
||||
typedef PIPair<Key, T> value_type;
|
||||
|
||||
class iterator {
|
||||
friend class PIMap<Key, T>;
|
||||
private:
|
||||
iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
|
||||
const PIMap<Key, T> * parent;
|
||||
ssize_t pos;
|
||||
public:
|
||||
iterator(): parent(0), pos(0) {}
|
||||
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
|
||||
T & value() {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
|
||||
void operator ++() {++pos;}
|
||||
void operator ++(int) {++pos;}
|
||||
void operator --() {--pos;}
|
||||
void operator --(int) {--pos;}
|
||||
bool operator ==(const iterator & it) const {return (pos == it.pos);}
|
||||
bool operator !=(const iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
class reverse_iterator {
|
||||
friend class PIMap<Key, T>;
|
||||
private:
|
||||
reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
|
||||
const PIMap<Key, T> * parent;
|
||||
ssize_t pos;
|
||||
public:
|
||||
reverse_iterator(): parent(0), pos(0) {}
|
||||
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
|
||||
T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
|
||||
void operator ++() {--pos;}
|
||||
void operator ++(int) {--pos;}
|
||||
void operator --() {++pos;}
|
||||
void operator --(int) {++pos;}
|
||||
bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);}
|
||||
bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
class const_iterator {
|
||||
friend class PIMap<Key, T>;
|
||||
private:
|
||||
const_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
|
||||
const PIMap<Key, T> * parent;
|
||||
ssize_t pos;
|
||||
public:
|
||||
const_iterator(): parent(0), pos(0) {}
|
||||
const value_type operator *() const {return parent->_pair(pos);}
|
||||
const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
|
||||
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
|
||||
const T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
|
||||
void operator ++() {++pos;}
|
||||
void operator ++(int) {++pos;}
|
||||
void operator --() {--pos;}
|
||||
void operator --(int) {--pos;}
|
||||
bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
|
||||
bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
|
||||
mutable value_type cval;
|
||||
};
|
||||
|
||||
class const_reverse_iterator {
|
||||
friend class PIMap<Key, T>;
|
||||
private:
|
||||
const_reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
|
||||
const PIMap<Key, T> * parent;
|
||||
ssize_t pos;
|
||||
public:
|
||||
const_reverse_iterator(): parent(0), pos(0) {}
|
||||
const value_type operator *() const {return parent->_pair(pos);}
|
||||
const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
|
||||
void operator ++() {--pos;}
|
||||
void operator ++(int) {--pos;}
|
||||
void operator --() {++pos;}
|
||||
void operator --(int) {++pos;}
|
||||
bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
|
||||
bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
|
||||
mutable value_type cval;
|
||||
};
|
||||
|
||||
iterator begin() {return iterator(this, 0);}
|
||||
iterator end() {return iterator(this, size());}
|
||||
const_iterator begin() const {return const_iterator(this, 0);}
|
||||
const_iterator end() const {return const_iterator(this, size());}
|
||||
const_iterator constBegin() const {return const_iterator(this, 0);}
|
||||
const_iterator constEnd() const {return const_iterator(this, size());}
|
||||
reverse_iterator rbegin() {return reverse_iterator(this, size() - 1);}
|
||||
reverse_iterator rend() {return reverse_iterator(this, -1);}
|
||||
const_reverse_iterator rbegin() const {return const_reverse_iterator(this, size() - 1);}
|
||||
const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
|
||||
const_reverse_iterator constRbegin() const {return const_reverse_iterator(this, size() - 1);}
|
||||
const_reverse_iterator constRend() const {return const_reverse_iterator(this, -1);}
|
||||
|
||||
size_t size() const {return pim_content.size();}
|
||||
int size_s() const {return pim_content.size_s();}
|
||||
size_t length() const {return pim_content.size();}
|
||||
bool isEmpty() const {return (pim_content.size() == 0);}
|
||||
|
||||
T & operator [](const Key & key) {
|
||||
bool f(false);
|
||||
ssize_t i = _find(key, f);
|
||||
if (f) return pim_content[pim_index[i].index];
|
||||
pim_content.push_back(T());
|
||||
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
|
||||
return pim_content.back();
|
||||
}
|
||||
const T operator [](const Key & key) const {bool f(false); ssize_t i = _find(key, f); if (f) return pim_content[pim_index[i].index]; return T();}
|
||||
T & at(const Key & key) {return (*this)[key];}
|
||||
const T at(const Key & key) const {return (*this)[key];}
|
||||
|
||||
PIMap<Key, T> & operator <<(const PIMap<Key, T> & other) {
|
||||
assert(&other != this);
|
||||
if (other.isEmpty()) return *this;
|
||||
if (other.size() == 1) {insert(other.pim_index[0].key, other.pim_content[0]); return *this;}
|
||||
if (other.size() == 2) {insert(other.pim_index[0].key, other.pim_content[0]); insert(other.pim_index[1].key, other.pim_content[1]); return *this;}
|
||||
for (int i = 0; i < other.pim_index.size_s(); ++i)
|
||||
insert(other.pim_index[i].key, other.pim_content[other.pim_index[i].index]);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator ==(const PIMap<Key, T> & t) const {return (pim_content == t.pim_content && pim_index == t.pim_index);}
|
||||
bool operator !=(const PIMap<Key, T> & t) const {return (pim_content != t.pim_content || pim_index != t.pim_index);}
|
||||
bool contains(const Key & key) const {bool f(false); _find(key, f); return f;}
|
||||
|
||||
PIMap<Key, T> & reserve(size_t new_size) {pim_content.reserve(new_size); pim_index.reserve(new_size); return *this;}
|
||||
|
||||
PIMap<Key, T> & removeOne(const Key & key) {bool f(false); ssize_t i = _find(key, f); if (f) _remove(i); return *this;}
|
||||
PIMap<Key, T> & remove(const Key & key) {return removeOne(key);}
|
||||
PIMap<Key, T> & erase(const Key & key) {return removeOne(key);}
|
||||
PIMap<Key, T> & clear() {pim_content.clear(); pim_index.clear(); return *this;}
|
||||
|
||||
void swap(PIMap<Key, T> & other) {
|
||||
piSwapBinary<PIVector<T> >(pim_content, other.pim_content);
|
||||
piSwapBinary<PIDeque<MapIndex> >(pim_index, other.pim_index);
|
||||
}
|
||||
|
||||
PIMap<Key, T> & insert(const Key & key, const T & value) {
|
||||
bool f(false);
|
||||
ssize_t i = _find(key, f);
|
||||
//piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value;
|
||||
if (f) {
|
||||
pim_content[pim_index[i].index] = value;
|
||||
} else {
|
||||
pim_content.push_back(value);
|
||||
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
const T value(const Key & key, const T & default_ = T()) const {bool f(false); ssize_t i = _find(key, f); if (!f) return default_; return pim_content[pim_index[i].index];}
|
||||
PIVector<T> values() const {return pim_content;}
|
||||
Key key(const T & value_, const Key & default_ = Key()) const {for (int i = 0; i < pim_index.size_s(); ++i) if (pim_content[pim_index[i].index] == value_) return pim_index[i].key; return default_;}
|
||||
PIVector<Key> keys() const {
|
||||
PIVector<Key> ret;
|
||||
for (int i = 0; i < pim_index.size_s(); ++i)
|
||||
ret << pim_index[i].key;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dump() {
|
||||
piCout << "PIMap" << size() << "entries" << PICoutManipulators::NewLine << "content:";
|
||||
for (size_t i = 0; i < pim_content.size(); ++i)
|
||||
piCout << PICoutManipulators::Tab << i << ":" << pim_content[i];
|
||||
piCout << "index:";
|
||||
for (size_t i = 0; i < pim_index.size(); ++i)
|
||||
piCout << PICoutManipulators::Tab << i << ":" << pim_index[i].key << "->" << pim_index[i].index;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct MapIndex {
|
||||
MapIndex(Key k = Key(), size_t i = 0): key(k), index(i) {;}
|
||||
Key key;
|
||||
size_t index;
|
||||
bool operator ==(const MapIndex & s) const {return key == s.key;}
|
||||
bool operator !=(const MapIndex & s) const {return key != s.key;}
|
||||
bool operator <(const MapIndex & s) const {return key < s.key;}
|
||||
bool operator >(const MapIndex & s) const {return key > s.key;}
|
||||
};
|
||||
template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
|
||||
template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
|
||||
|
||||
ssize_t binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const {
|
||||
ssize_t mid;
|
||||
while (first <= last) {
|
||||
mid = (first + last) / 2;
|
||||
if (key > pim_index[mid].key) first = mid + 1;
|
||||
else if (key < pim_index[mid].key) last = mid - 1;
|
||||
else {found = true; return mid;}
|
||||
}
|
||||
found = false;
|
||||
return first;
|
||||
}
|
||||
void _sort() {piQuickSort<MapIndex>(pim_index.data(), pim_index.size_s() - 1);}
|
||||
ssize_t _find(const Key & k, bool & found) const {
|
||||
if (pim_index.isEmpty()) {
|
||||
found = false;
|
||||
return 0;
|
||||
}
|
||||
return binarySearch(0, pim_index.size_s() - 1, k, found);
|
||||
}
|
||||
void _remove(ssize_t index) {
|
||||
//if (index >= pim_index.size()) return;
|
||||
size_t ci = pim_index[index].index, bi = pim_index.size() - 1;
|
||||
pim_index.remove(index);
|
||||
for (size_t i = 0; i < pim_index.size(); ++i)
|
||||
if (pim_index[i].index == bi) {
|
||||
pim_index[i].index = ci;
|
||||
break;
|
||||
}
|
||||
piSwapBinary<T>(pim_content[ci], pim_content.back());
|
||||
pim_content.resize(pim_index.size());
|
||||
}
|
||||
const value_type _pair(ssize_t index) const {
|
||||
if (index < 0 || index >= pim_index.size_s())
|
||||
return value_type();
|
||||
//piCout << "_pair" << index << pim_index[index].index;
|
||||
return value_type(pim_index[index].key, pim_content[pim_index[index].index]);
|
||||
}
|
||||
Key & _key(ssize_t index) {return pim_index[index].key;}
|
||||
T & _value(ssize_t index) {return pim_content[pim_index[index].index];}
|
||||
|
||||
PIVector<T> pim_content;
|
||||
PIDeque<MapIndex> pim_index;
|
||||
};
|
||||
|
||||
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
template<typename Key, typename Type>
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIMap<Key, Type> & v) {
|
||||
s << "{";
|
||||
bool first = true;
|
||||
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
|
||||
if (!first)
|
||||
s << ", ";
|
||||
first = false;
|
||||
s << i->first << ": " << i->second;
|
||||
}
|
||||
s << "}";
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename Key, typename Type>
|
||||
inline PICout operator <<(PICout s, const PIMap<Key, Type> & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s << "{";
|
||||
bool first = true;
|
||||
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
|
||||
if (!first)
|
||||
s << ", ";
|
||||
first = false;
|
||||
s << i->first << ": " << i->second;
|
||||
}
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
#endif // PIMAP_H
|
||||
55
lib/main/containers/pipair.h
Normal file
55
lib/main/containers/pipair.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*! \file pipair.h
|
||||
* \brief pair
|
||||
*
|
||||
* This file declare PIPair
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
pair
|
||||
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 PIPAIR_H
|
||||
#define PIPAIR_H
|
||||
|
||||
#include "pibase.h"
|
||||
|
||||
class PICout;
|
||||
|
||||
template<typename Type0, typename Type1>
|
||||
class PIP_EXPORT PIPair {
|
||||
public:
|
||||
PIPair() {first = Type0(); second = Type1();}
|
||||
PIPair(const Type0 & value0, const Type1 & value1) {first = value0; second = value1;}
|
||||
Type0 first;
|
||||
Type1 second;
|
||||
};
|
||||
template<typename Type0, typename Type1>
|
||||
inline bool operator <(const PIPair<Type0, Type1> & value0, const PIPair<Type0, Type1> & value1) {return value0.first < value1.first;}
|
||||
template<typename Type0, typename Type1>
|
||||
inline bool operator ==(const PIPair<Type0, Type1> & value0, const PIPair<Type0, Type1> & value1) {return (value0.first == value1.first) && (value0.second == value1.second);}
|
||||
template<typename Type0, typename Type1>
|
||||
inline bool operator !=(const PIPair<Type0, Type1> & value0, const PIPair<Type0, Type1> & value1) {return (value0.first != value1.first) || (value0.second != value1.second);}
|
||||
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
template<typename Type0, typename Type1>
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIPair<Type0, Type1> & v) {s << "(" << v.first << ", " << v.second << ")"; return s;}
|
||||
#endif
|
||||
|
||||
template<typename Type0, typename Type1>
|
||||
inline PICout operator <<(PICout s, const PIPair<Type0, Type1> & v) {s.space(); s.setControl(0, true); s << "(" << v.first << ", " << v.second << ")"; s.restoreControl(); return s;}
|
||||
|
||||
#endif // PIPAIR_H
|
||||
49
lib/main/containers/piqueue.h
Normal file
49
lib/main/containers/piqueue.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*! \file pideque.h
|
||||
* \brief Queue container
|
||||
*
|
||||
* This file declare PIQueue
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Queue container
|
||||
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 PIQUEUE_H
|
||||
#define PIQUEUE_H
|
||||
|
||||
#include "pideque.h"
|
||||
#include "pivector.h"
|
||||
|
||||
|
||||
template<typename T>
|
||||
class PIP_EXPORT PIQueue: public PIDeque<T> {
|
||||
public:
|
||||
PIQueue() {}
|
||||
virtual ~PIQueue() {}
|
||||
PIDeque<T> & enqueue(const T & v) {PIDeque<T>::push_front(v); return *this;}
|
||||
T dequeue() {return PIDeque<T>::take_back();}
|
||||
T & head() {return PIDeque<T>::back();}
|
||||
const T & head() const {return PIDeque<T>::back();}
|
||||
PIVector<T> toVector() {
|
||||
PIVector<T> v(PIDeque<T>::size());
|
||||
for (uint i = 0; i < PIDeque<T>::size(); ++i)
|
||||
v[i] = PIDeque<T>::at(i);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // PIQUEUE_H
|
||||
161
lib/main/containers/piset.h
Normal file
161
lib/main/containers/piset.h
Normal file
@@ -0,0 +1,161 @@
|
||||
/*! \file piset.h
|
||||
* \brief Set container
|
||||
*
|
||||
* This file declare PISet
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Set container
|
||||
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 PISET_H
|
||||
#define PISET_H
|
||||
|
||||
#include "pimap.h"
|
||||
|
||||
/*! \brief Set of any type
|
||||
* \details This class used to store collection of unique elements
|
||||
* of any type. You can only add values to set with \a operator<< or
|
||||
* with function \a insert(). You can discover if value already in
|
||||
* set with \a operator[] or with function \a find(). These function
|
||||
* has logarithmic complexity.
|
||||
*/
|
||||
template <typename T>
|
||||
class PIP_EXPORT PISet: public PIMap<T, uchar> {
|
||||
typedef PIMap<T, uchar> _CSet;
|
||||
public:
|
||||
|
||||
//! Contructs an empty set
|
||||
PISet() {}
|
||||
|
||||
virtual ~PISet() {;}
|
||||
|
||||
//! Contructs set with one element "value"
|
||||
PISet(const T & value) {_CSet::insert(value, 0);}
|
||||
|
||||
//! Contructs set with elements "v0" and "v1"
|
||||
PISet(const T & v0, const T & v1) {_CSet::insert(v0, 0); _CSet::insert(v1, 0);}
|
||||
|
||||
//! Contructs set with elements "v0", "v1" and "v2"
|
||||
PISet(const T & v0, const T & v1, const T & v2) {_CSet::insert(v0, 0); _CSet::insert(v1, 0); _CSet::insert(v2, 0);}
|
||||
|
||||
//! Contructs set with elements "v0", "v1", "v2" and "v3"
|
||||
PISet(const T & v0, const T & v1, const T & v2, const T & v3) {_CSet::insert(v0, 0); _CSet::insert(v1, 0); _CSet::insert(v2, 0); _CSet::insert(v3, 0);}
|
||||
|
||||
//! Contructs set from vector of elements
|
||||
PISet(const PIVector<T> & values) {
|
||||
if (values.isEmpty()) return;
|
||||
for (int i = 0; i < values.size_s(); ++i) {
|
||||
_CSet::insert(values[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
//! Contructs set from deque of elements
|
||||
PISet(const PIDeque<T> & values) {
|
||||
if (values.isEmpty()) return;
|
||||
for (int i = 0; i < values.size_s(); ++i) {
|
||||
_CSet::insert(values[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
typedef T key_type;
|
||||
|
||||
PISet<T> & operator <<(const T & t) {_CSet::insert(t, 0); return *this;}
|
||||
PISet<T> & operator <<(const PISet<T> & other) {(*(_CSet*)this) << *((_CSet*)&other); return *this;}
|
||||
|
||||
//! Returns if element "t" exists in this set
|
||||
bool operator [](const T & t) const {return _CSet::contains(t);}
|
||||
|
||||
//! Returns if element "t" exists in this set
|
||||
PISet<T> & remove(const T & t) {_CSet::remove(t); return *this;}
|
||||
|
||||
//! Unite set with "v"
|
||||
PISet<T> & unite(const PISet<T> & v) {
|
||||
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i)
|
||||
_CSet::insert(i->first, 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Subtract set with "v"
|
||||
PISet<T> & subtract(const PISet<T> & v) {
|
||||
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i)
|
||||
_CSet::remove(i->first);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Intersect set with "v"
|
||||
PISet<T> & intersect(const PISet<T> & v) {
|
||||
for (typename _CSet::iterator i = _CSet::begin(); i != _CSet::end(); ++i)
|
||||
if (!v.contains(i.key())) {
|
||||
_CSet::remove(i.key());
|
||||
--i;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Unite set with "v"
|
||||
PISet<T> & operator +=(const PISet<T> & v) {return unite(v);}
|
||||
|
||||
//! Unite set with "v"
|
||||
PISet<T> & operator |=(const PISet<T> & v) {return unite(v);}
|
||||
|
||||
//! Subtract set with "v"
|
||||
PISet<T> & operator -=(const PISet<T> & v) {return subtract(v);}
|
||||
|
||||
//! Intersect set with "v"
|
||||
PISet<T> & operator &=(const PISet<T> & v) {return intersect(v);}
|
||||
|
||||
//! Returns content of set as PIVector
|
||||
PIVector<T> toVector() const {PIVector<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << (*i).first; return ret;}
|
||||
|
||||
//! Returns content of set as PIDeque
|
||||
PIDeque<T> toDeque() const {PIDeque<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << (*i).first; return ret;}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//! \relatesalso PISet \brief Returns unite of two sets
|
||||
template <typename T> PISet<T> operator +(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;}
|
||||
|
||||
//! \relatesalso PISet \brief Returns subtraction of two sets
|
||||
template <typename T> PISet<T> operator -(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.subtract(v1); return ret;}
|
||||
|
||||
//! \relatesalso PISet \brief Returns unite of two sets
|
||||
template <typename T> PISet<T> operator |(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;}
|
||||
|
||||
//! \relatesalso PISet \brief Returns intersetion of two sets
|
||||
template <typename T> PISet<T> operator &(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.intersect(v1); return ret;}
|
||||
|
||||
|
||||
template<typename Type>
|
||||
inline PICout operator <<(PICout s, const PISet<Type> & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s << "{";
|
||||
bool first = true;
|
||||
for (typename PIMap<Type, uchar>::const_iterator i = v.begin(); i != v.end(); ++i) {
|
||||
if (!first)
|
||||
s << ", ";
|
||||
first = false;
|
||||
s << i->first;
|
||||
}
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif // PISET_H
|
||||
42
lib/main/containers/pistack.h
Normal file
42
lib/main/containers/pistack.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*! \file pistack.h
|
||||
* \brief Stack container
|
||||
*
|
||||
* This file declare PIStack
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Stack container
|
||||
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 PISTACK_H
|
||||
#define PISTACK_H
|
||||
|
||||
#include "pivector.h"
|
||||
|
||||
template<typename T>
|
||||
class PIP_EXPORT PIStack: public PIVector<T> {
|
||||
public:
|
||||
PIStack() {;}
|
||||
virtual ~PIStack() {;}
|
||||
PIVector<T> & push(const T & v) {PIVector<T>::push_back(v); return *this;}
|
||||
T pop() {return PIVector<T>::take_back();}
|
||||
T & top() {return PIVector<T>::back();}
|
||||
const T & top() const {return PIVector<T>::back();}
|
||||
PIVector<T> toVector() {PIVector<T> v(PIVector<T>::size()); for (uint i = 0; i < PIVector<T>::size(); ++i) v[i] = PIVector<T>::at(i); return v;}
|
||||
};
|
||||
|
||||
#endif // PISTACK_H
|
||||
491
lib/main/containers/pivector.h
Normal file
491
lib/main/containers/pivector.h
Normal file
@@ -0,0 +1,491 @@
|
||||
/*! \file pivector.h
|
||||
* \brief Dynamic array of any type
|
||||
*
|
||||
* This file declares PIVector
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Dynamic array of any type
|
||||
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 PIVECTOR_H
|
||||
#define PIVECTOR_H
|
||||
|
||||
#include "picontainers.h"
|
||||
|
||||
|
||||
template <typename T>
|
||||
class PIVector {
|
||||
public:
|
||||
inline PIVector(): piv_data(0), piv_size(0), piv_rsize(0) {
|
||||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||||
}
|
||||
inline PIVector(const T * data, size_t size): piv_data(0), piv_size(0), piv_rsize(0) {
|
||||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||||
alloc(size);
|
||||
newT(piv_data, data, piv_size);
|
||||
}
|
||||
inline PIVector(const PIVector<T> & other): piv_data(0), piv_size(0), piv_rsize(0) {
|
||||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||||
alloc(other.piv_size);
|
||||
newT(piv_data, other.piv_data, piv_size);
|
||||
}
|
||||
inline PIVector(size_t piv_size, const T & f = T()): piv_data(0), piv_size(0), piv_rsize(0) {
|
||||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||||
resize(piv_size, f);
|
||||
}
|
||||
inline virtual ~PIVector() {
|
||||
PIINTROSPECTION_CONTAINER_DELETE(T)
|
||||
PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize))
|
||||
deleteT(piv_data, piv_size);
|
||||
dealloc();
|
||||
_reset();
|
||||
}
|
||||
|
||||
inline PIVector<T> & operator =(const PIVector<T> & other) {
|
||||
if (this == &other) return *this;
|
||||
clear();
|
||||
deleteT(piv_data, piv_size);
|
||||
alloc(other.piv_size);
|
||||
newT(piv_data, other.piv_data, piv_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
class iterator {
|
||||
friend class PIVector<T>;
|
||||
private:
|
||||
inline iterator(PIVector<T> * v, size_t p): parent(v), pos(p) {}
|
||||
PIVector<T> * parent;
|
||||
size_t pos;
|
||||
public:
|
||||
inline iterator(): parent(0), pos(0) {}
|
||||
inline T & operator *() {return (*parent)[pos];}
|
||||
inline const T & operator *() const {return (*parent)[pos];}
|
||||
inline void operator ++() {++pos;}
|
||||
inline void operator ++(int) {++pos;}
|
||||
inline void operator --() {--pos;}
|
||||
inline void operator --(int) {--pos;}
|
||||
inline bool operator ==(const iterator & it) const {return (pos == it.pos);}
|
||||
inline bool operator !=(const iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
class const_iterator {
|
||||
friend class PIVector<T>;
|
||||
private:
|
||||
inline const_iterator(const PIVector<T> * v, size_t p): parent(v), pos(p) {}
|
||||
const PIVector<T> * parent;
|
||||
size_t pos;
|
||||
public:
|
||||
inline const_iterator(): parent(0), pos(0) {}
|
||||
inline const T & operator *() const {return (*parent)[pos];}
|
||||
inline void operator ++() {++pos;}
|
||||
inline void operator ++(int) {++pos;}
|
||||
inline void operator --() {--pos;}
|
||||
inline void operator --(int) {--pos;}
|
||||
inline bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
|
||||
inline bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
class reverse_iterator {
|
||||
friend class PIVector<T>;
|
||||
private:
|
||||
inline reverse_iterator(PIVector<T> * v, size_t p): parent(v), pos(p) {}
|
||||
PIVector<T> * parent;
|
||||
size_t pos;
|
||||
public:
|
||||
inline reverse_iterator(): parent(0), pos(0) {}
|
||||
inline T & operator *() {return (*parent)[pos];}
|
||||
inline const T & operator *() const {return (*parent)[pos];}
|
||||
inline void operator ++() {--pos;}
|
||||
inline void operator ++(int) {--pos;}
|
||||
inline void operator --() {++pos;}
|
||||
inline void operator --(int) {++pos;}
|
||||
inline bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);}
|
||||
inline bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
class const_reverse_iterator {
|
||||
friend class PIVector<T>;
|
||||
private:
|
||||
inline const_reverse_iterator(const PIVector<T> * v, size_t p): parent(v), pos(p) {}
|
||||
const PIVector<T> * parent;
|
||||
size_t pos;
|
||||
public:
|
||||
inline const_reverse_iterator(): parent(0), pos(0) {}
|
||||
inline const T & operator *() const {return (*parent)[pos];}
|
||||
inline void operator ++() {--pos;}
|
||||
inline void operator ++(int) {--pos;}
|
||||
inline void operator --() {++pos;}
|
||||
inline void operator --(int) {++pos;}
|
||||
inline bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
|
||||
inline bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
|
||||
};
|
||||
|
||||
inline iterator begin() {return iterator(this, 0);}
|
||||
inline iterator end() {return iterator(this, piv_size);}
|
||||
inline const_iterator begin() const {return const_iterator(this, 0);}
|
||||
inline const_iterator end() const {return const_iterator(this, piv_size);}
|
||||
inline reverse_iterator rbegin() {return reverse_iterator(this, piv_size - 1);}
|
||||
inline reverse_iterator rend() {return reverse_iterator(this, -1);}
|
||||
inline const_reverse_iterator rbegin() const {return const_reverse_iterator(this, piv_size - 1);}
|
||||
inline const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
|
||||
|
||||
inline size_t size() const {return piv_size;}
|
||||
inline ssize_t size_s() const {return piv_size;}
|
||||
inline size_t length() const {return piv_size;}
|
||||
inline size_t capacity() const {return piv_rsize;}
|
||||
inline bool isEmpty() const {return (piv_size == 0);}
|
||||
|
||||
inline T & operator [](size_t index) {return piv_data[index];}
|
||||
inline T & at(size_t index) {return piv_data[index];}
|
||||
inline const T & operator [](size_t index) const {return piv_data[index];}
|
||||
inline const T & at(size_t index) const {return piv_data[index];}
|
||||
inline T & back() {return piv_data[piv_size - 1];}
|
||||
inline const T & back() const {return piv_data[piv_size - 1];}
|
||||
inline T & front() {return piv_data[0];}
|
||||
inline const T & front() const {return piv_data[0];}
|
||||
inline bool operator ==(const PIVector<T> & t) const {
|
||||
if (piv_size != t.piv_size)
|
||||
return false;
|
||||
for (size_t i = 0; i < piv_size; ++i)
|
||||
if (t[i] != piv_data[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
inline bool operator !=(const PIVector<T> & t) const {return !(*this == t);}
|
||||
inline bool contains(const T & v) const {
|
||||
for (size_t i = 0; i < piv_size; ++i)
|
||||
if (v == piv_data[i])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
inline int etries(const T & v) const {
|
||||
int ec = 0;
|
||||
for (size_t i = 0; i < piv_size; ++i)
|
||||
if (v == piv_data[i]) ++ec;
|
||||
return ec;
|
||||
}
|
||||
inline ssize_t indexOf(const T & v) const {
|
||||
for (size_t i = 0; i < piv_size; ++i)
|
||||
if (v == piv_data[i])
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
inline ssize_t lastIndexOf(const T & v) const {
|
||||
for (ssize_t i = piv_size - 1; i >= 0; --i)
|
||||
if (v == piv_data[i])
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline T * data(size_t index = 0) {return &(piv_data[index]);}
|
||||
inline const T * data(size_t index = 0) const {return &(piv_data[index]);}
|
||||
|
||||
inline PIVector<T> & clear() {resize(0); return *this;}
|
||||
inline PIVector<T> & fill(const T & f = T()) {
|
||||
deleteT(piv_data, piv_size);
|
||||
PIINTROSPECTION_CONTAINER_USED(T, piv_size)
|
||||
for (size_t i = 0; i < piv_size; ++i)
|
||||
elementNew(piv_data + i, f);
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> & assign(const T & f = T()) {return fill(f);}
|
||||
inline PIVector<T> & assign(size_t new_size, const T & f) {
|
||||
resize(new_size);
|
||||
return fill(f);
|
||||
}
|
||||
|
||||
inline PIVector<T> & resize(size_t new_size, const T & f = T()) {
|
||||
if (new_size < piv_size) {
|
||||
T * de = &(piv_data[new_size]);
|
||||
deleteT(de, piv_size - new_size);
|
||||
piv_size = new_size;
|
||||
}
|
||||
if (new_size > piv_size) {
|
||||
size_t os = piv_size;
|
||||
alloc(new_size);
|
||||
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
|
||||
for (size_t i = os; i < new_size; ++i)
|
||||
elementNew(piv_data + i, f);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> & _resizeRaw(size_t new_size) {
|
||||
piCout << "Error, \"resizeRaw()\" only allowed for simple type declared with __PIVECTOR_SIMPLE_TYPE__ macro!";
|
||||
assert(0);
|
||||
return *this;
|
||||
}
|
||||
inline void _copyRaw(T * dst, const T * src, size_t size) {
|
||||
newT(dst, src, size);
|
||||
}
|
||||
|
||||
inline PIVector<T> & reserve(size_t new_size) {
|
||||
if (new_size <= piv_rsize) return *this;
|
||||
size_t os = piv_size;
|
||||
alloc(new_size);
|
||||
piv_size = os;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIVector<T> & insert(size_t index, const T & v = T()) {
|
||||
alloc(piv_size + 1);
|
||||
if (index < piv_size - 1) {
|
||||
size_t os = piv_size - index - 1;
|
||||
memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T));
|
||||
}
|
||||
PIINTROSPECTION_CONTAINER_USED(T, 1)
|
||||
elementNew(piv_data + index, v);
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> & insert(size_t index, const PIVector<T> & other) {
|
||||
if (other.isEmpty()) return *this;
|
||||
assert(&other != this);
|
||||
ssize_t os = piv_size - index;
|
||||
alloc(piv_size + other.piv_size);
|
||||
if (os > 0)
|
||||
memmove((void*)(&(piv_data[index + other.piv_size])), (const void*)(&(piv_data[index])), os * sizeof(T));
|
||||
newT(piv_data + index, other.piv_data, other.piv_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIVector<T> & remove(size_t index, size_t count = 1) {
|
||||
if (count == 0) return *this;
|
||||
if (index + count >= piv_size) {
|
||||
resize(index);
|
||||
return *this;
|
||||
}
|
||||
size_t os = piv_size - index - count;
|
||||
deleteT(&(piv_data[index]), count);
|
||||
memmove((void*)(&(piv_data[index])), (const void*)(&(piv_data[index + count])), os * sizeof(T));
|
||||
piv_size -= count;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void swap(PIVector<T> & other) {
|
||||
piSwap<T*>(piv_data, other.piv_data);
|
||||
piSwap<size_t>(piv_size, other.piv_size);
|
||||
piSwap<size_t>(piv_rsize, other.piv_rsize);
|
||||
}
|
||||
|
||||
typedef int (*CompareFunc)(const T * , const T * );
|
||||
static int compare_func(const T * t0, const T * t1) {return (*t0) < (*t1) ? -1 : ((*t0) == (*t1) ? 0 : 1);}
|
||||
inline PIVector<T> & sort(CompareFunc compare = compare_func) {
|
||||
piqsort(piv_data, piv_size, sizeof(T), (int(*)(const void * , const void * ))compare);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIVector<T> & enlarge(llong piv_size) {
|
||||
llong ns = size_s() + piv_size;
|
||||
if (ns <= 0) clear();
|
||||
else resize(size_t(ns));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIVector<T> & removeOne(const T & v) {
|
||||
for (size_t i = 0; i < piv_size; ++i)
|
||||
if (piv_data[i] == v) {
|
||||
remove(i);
|
||||
return *this;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> & removeAll(const T & v) {
|
||||
for (ssize_t i = 0; i < ssize_t(piv_size); ++i)
|
||||
if (piv_data[i] == v) {
|
||||
remove(i);
|
||||
--i;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIVector<T> & push_back(const T & v) {
|
||||
alloc(piv_size + 1);
|
||||
PIINTROSPECTION_CONTAINER_USED(T, 1);
|
||||
elementNew(piv_data + piv_size - 1, v);
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> & append(const T & v) {return push_back(v);}
|
||||
inline PIVector<T> & append(const PIVector<T> & other) {
|
||||
assert(&other != this);
|
||||
size_t ps = piv_size;
|
||||
alloc(piv_size + other.piv_size);
|
||||
newT(piv_data + ps, other.piv_data, other.piv_size);
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> & operator <<(const T & v) {return push_back(v);}
|
||||
inline PIVector<T> & operator <<(const PIVector<T> & other) {return append(other);}
|
||||
|
||||
inline PIVector<T> & push_front(const T & v) {insert(0, v); return *this;}
|
||||
inline PIVector<T> & prepend(const T & v) {return push_front(v);}
|
||||
|
||||
inline PIVector<T> & pop_back() {
|
||||
if (piv_size == 0)
|
||||
return *this;
|
||||
resize(piv_size - 1);
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> & pop_front() {
|
||||
if (piv_size == 0)
|
||||
return *this;
|
||||
remove(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline T take_back() {T t(back()); pop_back(); return t;}
|
||||
inline T take_front() {T t(front()); pop_front(); return t;}
|
||||
|
||||
template <typename ST>
|
||||
PIVector<ST> toType() const {
|
||||
PIVector<ST> ret(piv_size);
|
||||
for (uint i = 0; i < piv_size; ++i)
|
||||
ret[i] = ST(piv_data[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
const PIVector<T> & forEach(std::function<void(const T &)> f) const {
|
||||
for (uint i = 0; i < piv_size; ++i)
|
||||
f(piv_data[i]);
|
||||
return *this;
|
||||
}
|
||||
PIVector<T> copyForEach(std::function<T(const T &)> f) const {
|
||||
PIVector<T> ret; ret.reserve(piv_size);
|
||||
for (uint i = 0; i < piv_size; ++i)
|
||||
ret << f(piv_data[i]);
|
||||
return ret;
|
||||
}
|
||||
PIVector<T> & forEachInplace(std::function<T(const T &)> f) {
|
||||
for (uint i = 0; i < piv_size; ++i)
|
||||
piv_data[i] = f(piv_data[i]);
|
||||
return *this;
|
||||
}
|
||||
template <typename ST>
|
||||
PIVector<ST> toType(std::function<ST(const T &)> f) const {
|
||||
PIVector<ST> ret; ret.reserve(piv_size);
|
||||
for (uint i = 0; i < piv_size; ++i)
|
||||
ret << f(piv_data[i]);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
inline void _reset() {piv_size = piv_rsize = 0; piv_data = 0;}
|
||||
inline size_t asize(size_t s) {
|
||||
if (s == 0) return 0;
|
||||
if (piv_rsize + piv_rsize >= s && piv_rsize < s)
|
||||
return piv_rsize + piv_rsize;
|
||||
ssize_t t = 0, s_ = s - 1;
|
||||
while (s_ >> t) ++t;
|
||||
return (1 << t);
|
||||
}
|
||||
inline void newT(T * dst, const T * src, size_t s) {
|
||||
PIINTROSPECTION_CONTAINER_USED(T, s)
|
||||
for (size_t i = 0; i < s; ++i)
|
||||
elementNew(dst + i, src[i]);
|
||||
}
|
||||
inline void deleteT(T * d, size_t sz) {
|
||||
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
|
||||
if ((uchar*)d != 0) {
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
elementDelete(d[i]);
|
||||
}
|
||||
}
|
||||
inline void elementNew(T * to, const T & from) {new(to)T(from);}
|
||||
inline void elementDelete(T & from) {from.~T();}
|
||||
inline void dealloc() {
|
||||
if ((uchar*)piv_data != 0) free((uchar*)piv_data);
|
||||
piv_data = 0;
|
||||
}
|
||||
inline void alloc(size_t new_size) {
|
||||
if (new_size <= piv_rsize) {
|
||||
piv_size = new_size;
|
||||
return;
|
||||
}
|
||||
piv_size = new_size;
|
||||
size_t as = asize(new_size);
|
||||
if (as == piv_rsize) return;
|
||||
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-piv_rsize))
|
||||
T * p_d = (T*)(realloc((void*)(piv_data), as*sizeof(T)));
|
||||
assert(p_d);
|
||||
piv_data = p_d;
|
||||
piv_rsize = as;
|
||||
}
|
||||
|
||||
T * piv_data;
|
||||
size_t piv_size, piv_rsize;
|
||||
};
|
||||
|
||||
|
||||
#define __PIVECTOR_SIMPLE_TYPE__(T) \
|
||||
template<> inline void PIVector<T>::newT(T * dst, const T * src, size_t s) {PIINTROSPECTION_CONTAINER_USED(T, s); memcpy((void*)(dst), (const void*)(src), s * sizeof(T));} \
|
||||
template<> inline void PIVector<T>::deleteT(T *, size_t sz) {PIINTROSPECTION_CONTAINER_UNUSED(T, sz);} \
|
||||
template<> inline void PIVector<T>::elementNew(T * to, const T & from) {(*to) = from;} \
|
||||
template<> inline void PIVector<T>::elementDelete(T &) {;} \
|
||||
template<> inline PIVector<T> & PIVector<T>::_resizeRaw(size_t new_size) { \
|
||||
if (new_size > piv_size) { \
|
||||
PIINTROSPECTION_CONTAINER_USED(T, (new_size-piv_size)); \
|
||||
} \
|
||||
if (new_size < piv_size) { \
|
||||
PIINTROSPECTION_CONTAINER_UNUSED(T, (piv_size-new_size)); \
|
||||
} \
|
||||
alloc(new_size); \
|
||||
return *this; \
|
||||
} \
|
||||
template<> inline PIVector<T> & PIVector<T>::clear() {PIINTROSPECTION_CONTAINER_UNUSED(T, piv_size); piv_size = 0; return *this;} \
|
||||
template<> inline PIVector<T> & PIVector<T>::assign(size_t new_size, const T & f) {_resizeRaw(new_size); return fill(f);}
|
||||
|
||||
|
||||
__PIVECTOR_SIMPLE_TYPE__(bool)
|
||||
__PIVECTOR_SIMPLE_TYPE__(char)
|
||||
__PIVECTOR_SIMPLE_TYPE__(uchar)
|
||||
__PIVECTOR_SIMPLE_TYPE__(short)
|
||||
__PIVECTOR_SIMPLE_TYPE__(ushort)
|
||||
__PIVECTOR_SIMPLE_TYPE__(int)
|
||||
__PIVECTOR_SIMPLE_TYPE__(uint)
|
||||
__PIVECTOR_SIMPLE_TYPE__(long)
|
||||
__PIVECTOR_SIMPLE_TYPE__(ulong)
|
||||
__PIVECTOR_SIMPLE_TYPE__(llong)
|
||||
__PIVECTOR_SIMPLE_TYPE__(ullong)
|
||||
__PIVECTOR_SIMPLE_TYPE__(float)
|
||||
__PIVECTOR_SIMPLE_TYPE__(double)
|
||||
__PIVECTOR_SIMPLE_TYPE__(ldouble)
|
||||
|
||||
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
template<typename T>
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIVector<T> & v) {s << "{"; for (size_t i = 0; i < v.size(); ++i) {s << v[i]; if (i < v.size() - 1) s << ", ";} s << "}"; return s;}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
inline PICout operator <<(PICout s, const PIVector<T> & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s << "{";
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
s << v[i];
|
||||
if (i < v.size() - 1)
|
||||
s << ", ";
|
||||
}
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
#endif // PIVECTOR_H
|
||||
307
lib/main/containers/pivector2d.h
Normal file
307
lib/main/containers/pivector2d.h
Normal file
@@ -0,0 +1,307 @@
|
||||
/*! \file pivecto2d.h
|
||||
* \brief 2D wrapper around PIVector
|
||||
*
|
||||
* This file declares PIVector
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
2D wrapper around PIVector
|
||||
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 PIVECTOR2D_H
|
||||
#define PIVECTOR2D_H
|
||||
|
||||
#include "pivector.h"
|
||||
|
||||
/*! \brief 2D array,
|
||||
* \details This class used to store 2D array of any type elements as plain vector.
|
||||
* You can read/write any element via operators [][], first dimension - row, second - column.
|
||||
* The first dimension is Row, and you can operate with Row as PIVector<T>: modify any element, assign to another Row and etc.
|
||||
* You can't add values to array, but you can modify any elements or create another PIVector2D.
|
||||
* PIVector2D has constructors from PIVector<T> and PIVector<PIVector<T> >
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
class PIVector2D {
|
||||
public:
|
||||
inline PIVector2D() {rows_ = cols_ = 0;}
|
||||
inline PIVector2D(size_t rows, size_t cols, const T & f = T()) {
|
||||
rows_ = rows;
|
||||
cols_ = cols;
|
||||
mat.resize(rows*cols, f);
|
||||
}
|
||||
inline PIVector2D(size_t rows, size_t cols, const PIVector<T> & v) {
|
||||
mat = v;
|
||||
rows_ = rows;
|
||||
cols_ = cols;
|
||||
mat.resize(rows*cols);
|
||||
}
|
||||
inline PIVector2D(const PIVector<PIVector<T> > & v) {
|
||||
rows_ = v.size();
|
||||
if (rows_) {
|
||||
cols_ = v[0].size();
|
||||
for (size_t i = 0; i < rows_; i++) {
|
||||
mat.append(v[i]);
|
||||
}
|
||||
mat.resize(rows_*cols_);
|
||||
}
|
||||
if (mat.isEmpty()) rows_ = cols_ = 0;
|
||||
}
|
||||
|
||||
inline size_t rows() const {return rows_;}
|
||||
inline size_t cols() const {return cols_;}
|
||||
inline size_t size() const {return mat.size();}
|
||||
inline ssize_t size_s() const {return mat.size_s();}
|
||||
inline size_t length() const {return mat.length();}
|
||||
inline size_t capacity() const {return mat.capacity();}
|
||||
inline bool isEmpty() const {return mat.isEmpty();}
|
||||
|
||||
class Row {
|
||||
friend class PIVector2D<T>;
|
||||
private:
|
||||
inline Row(PIVector2D<T> * p, size_t row) : p_(&(p->mat)) {st_ = p->cols_ * row; sz_ = p->cols_;}
|
||||
PIVector<T> * p_;
|
||||
size_t st_, sz_;
|
||||
public:
|
||||
inline size_t size() const {return sz_;}
|
||||
inline T & operator [](size_t index) {return (*p_)[st_ + index];}
|
||||
inline const T & operator [](size_t index) const {return (*p_)[st_ + index];}
|
||||
inline T * data(size_t index = 0) {return p_->data(st_ + index);}
|
||||
inline const T * data(size_t index = 0) const {return p_->data(st_ + index);}
|
||||
inline Row & operator =(const Row & other) {
|
||||
if (p_ == other.p_ && st_ == other.st_) return *this;
|
||||
size_t sz = piMin<size_t>(sz_, other.sz_);
|
||||
p_->_copyRaw(p_->data(st_), other.data(), sz);
|
||||
return *this;
|
||||
}
|
||||
inline Row & operator =(const PIVector<T> & other) {
|
||||
size_t sz = piMin<size_t>(sz, other.size());
|
||||
p_->_copyRaw(p_->data(st_), other.data(), sz);
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> toVector() const {return PIVector<T>(p_->data(st_), sz_);}
|
||||
};
|
||||
|
||||
class Col {
|
||||
friend class PIVector2D<T>;
|
||||
private:
|
||||
inline Col(PIVector2D<T> * p, size_t row) : p_(&(p->mat)) {step_ = p->cols_; row_ = row; sz_ = p->rows_;}
|
||||
PIVector<T> * p_;
|
||||
size_t step_, row_, sz_;
|
||||
public:
|
||||
inline size_t size() const {return sz_;}
|
||||
inline T & operator [](size_t index) {return (*p_)[index * step_ + row_];}
|
||||
inline const T & operator [](size_t index) const {return (*p_)[index * step_ + row_];}
|
||||
inline T * data(size_t index = 0) {return p_->data(index * step_ + row_);}
|
||||
inline const T * data(size_t index = 0) const {return p_->data(index * step_ + row_);}
|
||||
inline Col & operator =(const Col & other) {
|
||||
if (p_ == other.p_ && row_ == other.row_) return *this;
|
||||
size_t sz = piMin<size_t>(sz_, other.sz_);
|
||||
for (int i=0; i<sz; ++i) (*p_)[i * step_ + row_] = other[i];
|
||||
return *this;
|
||||
}
|
||||
inline Row & operator =(const PIVector<T> & other) {
|
||||
size_t sz = piMin<size_t>(sz_, other.size());
|
||||
for (int i=0; i<sz; ++i) (*p_)[i * step_ + row_] = other[i];
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> toVector() const {
|
||||
PIVector<T> ret;
|
||||
ret.reserve(sz_);
|
||||
for (size_t i=0; i<sz_; i++) ret << (*p_)[i * step_ + row_];
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
class RowConst {
|
||||
friend class PIVector2D<T>;
|
||||
private:
|
||||
inline RowConst(const PIVector2D<T> * p, size_t row) : p_(&(p->mat)) {st_ = p->cols_ * row; sz_ = p->cols_;}
|
||||
const PIVector<T> * p_;
|
||||
size_t st_, sz_;
|
||||
public:
|
||||
inline size_t size() const {return sz_;}
|
||||
inline const T & operator [](size_t index) const {return (*p_)[st_ + index];}
|
||||
inline const T * data(size_t index = 0) const {return p_->data(st_ + index);}
|
||||
inline PIVector<T> toVector() const {return PIVector<T>(p_->data(st_), sz_);}
|
||||
};
|
||||
|
||||
class ColConst {
|
||||
friend class PIVector2D<T>;
|
||||
private:
|
||||
inline ColConst(const PIVector2D<T> * p, size_t row) : p_(&(p->mat)) {step_ = p->cols_; row_ = row; sz_ = p->rows_;}
|
||||
const PIVector<T> * p_;
|
||||
size_t step_, row_, sz_;
|
||||
public:
|
||||
inline size_t size() const {return p_->rows_;}
|
||||
inline const T & operator [](size_t index) const {return (*p_)[index * step_ + row_];}
|
||||
inline const T * data(size_t index = 0) const {return p_->data(index * step_ + row_);}
|
||||
inline PIVector<T> toVector() const {
|
||||
PIVector<T> ret;
|
||||
ret.reserve(sz_);
|
||||
for (int i=0; i<size(); i++) ret << (*p_)[i * step_ + row_];
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
inline T & element(size_t row, size_t col) {return mat[row * cols_ + col];}
|
||||
inline const T & element(size_t row, size_t col) const {return mat[row * cols_ + col];}
|
||||
inline Row operator[](size_t index) {return Row(this, index);}
|
||||
inline RowConst operator[](size_t index) const {return RowConst(this, index);}
|
||||
inline T * data(size_t index = 0) {return mat.data(index);}
|
||||
inline const T * data(size_t index = 0) const {return mat.data(index);}
|
||||
|
||||
inline Row row(size_t index) {return Row(this, index);}
|
||||
inline RowConst row(size_t index) const {return RowConst(this, index);}
|
||||
inline Col col(size_t index) {return Col(this, index);}
|
||||
inline ColConst col(size_t index) const {return ColConst(this, index);}
|
||||
inline PIVector2D<T> & setRow(size_t row, const Row & other) {
|
||||
size_t sz = piMin<size_t>(cols_, other.sz_);
|
||||
mat._copyRaw(mat.data(cols_ * row), other.data(), sz);
|
||||
return *this;
|
||||
}
|
||||
inline PIVector2D<T> & setRow(size_t row, const RowConst & other) {
|
||||
size_t sz = piMin<size_t>(cols_, other.sz_);
|
||||
mat._copyRaw(mat.data(cols_ * row), other.data(), sz);
|
||||
return *this;
|
||||
}
|
||||
inline PIVector2D<T> & setRow(size_t row, const PIVector<T> & other) {
|
||||
size_t sz = piMin<size_t>(cols_, other.size());
|
||||
mat._copyRaw(mat.data(cols_ * row), other.data(), sz);
|
||||
return *this;
|
||||
}
|
||||
inline PIVector2D<T> & addRow(const Row & other) {
|
||||
if (cols_ == 0) cols_ = other.sz_;
|
||||
size_t sz = piMin<size_t>(cols_, other.sz_);
|
||||
size_t ps = mat.size();
|
||||
mat.resize(mat.size() + cols_);
|
||||
mat._copyRaw(mat.data(ps), other.data(), sz);
|
||||
rows_++;
|
||||
return *this;
|
||||
}
|
||||
inline PIVector2D<T> & addRow(const RowConst & other) {
|
||||
if (cols_ == 0) cols_ = other.sz_;
|
||||
size_t sz = piMin<size_t>(cols_, other.sz_);
|
||||
size_t ps = mat.size();
|
||||
mat.resize(mat.size() + cols_);
|
||||
mat._copyRaw(mat.data(ps), other.data(), sz);
|
||||
rows_++;
|
||||
return *this;
|
||||
}
|
||||
inline PIVector2D<T> & addRow(const PIVector<T> & other) {
|
||||
if (cols_ == 0) cols_ = other.size();
|
||||
size_t sz = piMin<size_t>(cols_, other.size());
|
||||
size_t ps = mat.size();
|
||||
mat.resize(mat.size() + cols_);
|
||||
mat._copyRaw(mat.data(ps), other.data(), sz);
|
||||
rows_++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIVector2D<T> & resize(size_t rows, size_t cols, const T & f = T()) {
|
||||
mat.resize(rows*cols_, f);
|
||||
rows_ = rows;
|
||||
int cs = (cols - cols_);
|
||||
if (cs < 0) {
|
||||
for (size_t r=0; r<rows; ++r) {
|
||||
mat.remove(r*cols_ + cols_, -cs);
|
||||
}
|
||||
}
|
||||
mat.resize(rows*cols, f);
|
||||
if (!mat.isEmpty()) {
|
||||
if (cs > 0) {
|
||||
for (size_t r=0; r<rows_; ++r) {
|
||||
for (int i=0; i<cs; ++i)
|
||||
mat.insert(r*cols + cols_, mat.take_back());
|
||||
}
|
||||
}
|
||||
}
|
||||
cols_ = cols;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PIVector<PIVector<T> > toVectors() const {
|
||||
PIVector<PIVector<T> > ret;
|
||||
for(size_t i = 0; i < rows_; ++i)
|
||||
ret << PIVector<T>(mat.data(i*cols_), cols_);
|
||||
return ret;
|
||||
}
|
||||
PIVector<T> toPlainVector() const {return mat;}
|
||||
PIVector<T> & plainVector() {return mat;}
|
||||
const PIVector<T> & plainVector() const {return mat;}
|
||||
|
||||
inline void swap(PIVector2D<T> & other) {
|
||||
mat.swap(other.mat);
|
||||
piSwap<size_t>(rows_, other.rows_);
|
||||
piSwap<size_t>(cols_, other.cols_);
|
||||
}
|
||||
|
||||
inline PIVector2D<T> & _resizeRaw(size_t r, size_t c) {
|
||||
piCout << "Error, \"resizeRaw()\" only allowed for simple type declared with __PIVECTOR_SIMPLE_TYPE__ macro!";
|
||||
assert(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void clear() {
|
||||
rows_ = cols_ = 0;
|
||||
mat.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
size_t rows_, cols_;
|
||||
PIVector<T> mat;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline PICout operator <<(PICout s, const PIVector2D<T> & v) {
|
||||
s.setControl(0, true);
|
||||
s << "{";
|
||||
for (size_t i = 0; i < v.rows(); ++i) {
|
||||
s << "{ ";
|
||||
for (size_t j = 0; j < v.cols(); ++j) {
|
||||
s << v[i][j];
|
||||
if (j < v.cols() - 1) s << ", ";
|
||||
}
|
||||
s << " }";
|
||||
if (i < v.rows() - 1) s << PICoutManipulators::NewLine ;
|
||||
}
|
||||
if (v.isEmpty()) s << "{ }";
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
#define __PIVECTOR2D_SIMPLE_TYPE__(T) \
|
||||
template<> inline PIVector2D<T> & PIVector2D<T>::_resizeRaw(size_t r, size_t c) {rows_ = r; cols_ = c; mat._resizeRaw(r*c); return *this;}
|
||||
|
||||
__PIVECTOR2D_SIMPLE_TYPE__(bool)
|
||||
__PIVECTOR2D_SIMPLE_TYPE__(char)
|
||||
__PIVECTOR2D_SIMPLE_TYPE__(uchar)
|
||||
__PIVECTOR2D_SIMPLE_TYPE__(short)
|
||||
__PIVECTOR2D_SIMPLE_TYPE__(ushort)
|
||||
__PIVECTOR2D_SIMPLE_TYPE__(int)
|
||||
__PIVECTOR2D_SIMPLE_TYPE__(uint)
|
||||
__PIVECTOR2D_SIMPLE_TYPE__(long)
|
||||
__PIVECTOR2D_SIMPLE_TYPE__(ulong)
|
||||
__PIVECTOR2D_SIMPLE_TYPE__(llong)
|
||||
__PIVECTOR2D_SIMPLE_TYPE__(ullong)
|
||||
__PIVECTOR2D_SIMPLE_TYPE__(float)
|
||||
__PIVECTOR2D_SIMPLE_TYPE__(double)
|
||||
__PIVECTOR2D_SIMPLE_TYPE__(ldouble)
|
||||
|
||||
#endif // PIVECTOR2D_H
|
||||
557
lib/main/core/pibase.h
Normal file
557
lib/main/core/pibase.h
Normal file
@@ -0,0 +1,557 @@
|
||||
/*! \file pibase.h
|
||||
* \brief Base types and functions
|
||||
*
|
||||
* This file implements first layer above the system and
|
||||
* declares some basic useful functions
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Base types and functions
|
||||
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 PIBASE_H
|
||||
#define PIBASE_H
|
||||
|
||||
#include "piversion.h"
|
||||
#include "piplatform.h"
|
||||
#include "pip_export.h"
|
||||
#include "pip_defs.h"
|
||||
#include "string.h"
|
||||
|
||||
//! Meta-information section for any entity.
|
||||
//! Parsing by \a pip_cmg and can be accessed by \a PICodeInfo.
|
||||
//! Contains sequence of key=value pairs, e.g.
|
||||
//! PIMETA(id=12345,tag="my string")
|
||||
#define PIMETA(...)
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
//! Major value of PIP version
|
||||
# define PIP_VERSION_MAJOR
|
||||
|
||||
//! Minor value of PIP version
|
||||
# define PIP_VERSION_MINOR
|
||||
|
||||
//! Revision value of PIP version
|
||||
# define PIP_VERSION_REVISION
|
||||
|
||||
//! Suffix of PIP version
|
||||
# define PIP_VERSION_SUFFIX
|
||||
|
||||
//! Version of PIP in hex - 0x##(Major)##(Minor)##(Revision)
|
||||
# define PIP_VERSION
|
||||
|
||||
//! Macro is defined when compile-time debug is enabled
|
||||
# define PIP_DEBUG
|
||||
|
||||
//! Macro is defined when host is any Windows
|
||||
# define WINDOWS
|
||||
|
||||
//! Macro is defined when host is QNX or Blackberry
|
||||
# define QNX
|
||||
|
||||
//! Macro is defined when host is Blackberry
|
||||
# define BLACKBERRY
|
||||
|
||||
//! Macro is defined when host is FreeBSD
|
||||
# define FREE_BSD
|
||||
|
||||
//! Macro is defined when host is Mac OS
|
||||
# define MAC_OS
|
||||
|
||||
//! Macro is defined when host is Android
|
||||
# define ANDROID
|
||||
|
||||
//! Macro is defined when host is any Linux
|
||||
# define LINUX
|
||||
|
||||
//! Macro is defined when compiler is GCC or MinGW
|
||||
# define CC_GCC
|
||||
|
||||
//! Macro is defined when PIP is decided that host is support language
|
||||
# define HAS_LOCALE
|
||||
|
||||
//! Macro is defined when compiler is Visual Studio
|
||||
# define CC_VC
|
||||
|
||||
//! Macro is defined when compiler is unknown
|
||||
# define CC_OTHER
|
||||
|
||||
//! Macro is defined when PIP can use "rt" library for "PITimer::ThreadRT" timers implementation
|
||||
# define PIP_TIMER_RT
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
# include <functional>
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#ifdef WINDOWS
|
||||
# ifdef CC_VC
|
||||
# define SHUT_RDWR 2
|
||||
# pragma comment(lib, "Ws2_32.lib")
|
||||
# pragma comment(lib, "Iphlpapi.lib")
|
||||
# pragma comment(lib, "Psapi.lib")
|
||||
# ifdef ARCH_BITS_32
|
||||
# define _X86_
|
||||
# else
|
||||
# define _IA64_
|
||||
# endif
|
||||
# else
|
||||
# define SHUT_RDWR SD_BOTH
|
||||
# endif
|
||||
typedef int socklen_t;
|
||||
extern long long __pi_perf_freq;
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
///# define tcdrain(fd) ioctl(fd, TCSBRK, 1)
|
||||
//inline int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;}
|
||||
//inline int mbtowc(wchar_t * w, const char * c, size_t) {*w = ((wchar_t * )&c)[0]; return 1;}
|
||||
#endif
|
||||
|
||||
#ifdef MAC_OS
|
||||
# define environ (*_NSGetEnviron())
|
||||
typedef long time_t;
|
||||
#endif
|
||||
|
||||
#ifdef LINUX
|
||||
# define environ __environ
|
||||
#endif
|
||||
|
||||
#ifdef FREE_BSD
|
||||
extern char ** environ;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CC_GCC
|
||||
# undef DEPRECATED
|
||||
# define DEPRECATED __attribute__((deprecated))
|
||||
# if CC_GCC_VERSION > 0x025F // > 2.95
|
||||
# ifdef LINUX
|
||||
# define HAS_LOCALE
|
||||
# endif
|
||||
# ifdef MAC_OS
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
|
||||
# pragma GCC diagnostic ignored "-Wc++11-extensions"
|
||||
# endif
|
||||
# endif
|
||||
# ifdef ANDROID
|
||||
# pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
# pragma GCC diagnostic ignored "-Wextra"
|
||||
# pragma GCC diagnostic ignored "-Wc++11-extensions"
|
||||
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
|
||||
//# pragma GCC diagnostic ignored "-Wliteral-suffix"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef CC_VC
|
||||
# undef DEPRECATED
|
||||
# define DEPRECATED
|
||||
# pragma warning(disable: 4018)
|
||||
# pragma warning(disable: 4061)
|
||||
# pragma warning(disable: 4100)
|
||||
# pragma warning(disable: 4239)
|
||||
# pragma warning(disable: 4242)
|
||||
# pragma warning(disable: 4244)
|
||||
# pragma warning(disable: 4251)
|
||||
# pragma warning(disable: 4365)
|
||||
# pragma warning(disable: 4512)
|
||||
# pragma warning(disable: 4668)
|
||||
# pragma warning(disable: 4710)
|
||||
# pragma warning(disable: 4800)
|
||||
# pragma warning(disable: 4820)
|
||||
# pragma warning(disable: 4986)
|
||||
# pragma warning(disable: 4996)
|
||||
# ifdef ARCH_BITS_32
|
||||
typedef long ssize_t;
|
||||
# else
|
||||
typedef long long ssize_t;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef CC_OTHER
|
||||
# undef DEPRECATED
|
||||
# define DEPRECATED
|
||||
#endif
|
||||
|
||||
|
||||
// Private data macros
|
||||
|
||||
#define PRIVATE_DECLARATION \
|
||||
struct __Private__; \
|
||||
friend struct __Private__; \
|
||||
struct __PrivateInitializer__ { \
|
||||
__PrivateInitializer__(); \
|
||||
__PrivateInitializer__(const __PrivateInitializer__ & o); \
|
||||
~__PrivateInitializer__(); \
|
||||
__PrivateInitializer__ & operator =(const __PrivateInitializer__ & o); \
|
||||
__Private__ * p; \
|
||||
}; \
|
||||
__PrivateInitializer__ __privateinitializer__;
|
||||
|
||||
#define PRIVATE_DEFINITION_START(c) \
|
||||
struct c::__Private__ {
|
||||
|
||||
#define PRIVATE_DEFINITION_END(c) \
|
||||
}; \
|
||||
c::__PrivateInitializer__::__PrivateInitializer__() {p = new c::__Private__();} \
|
||||
c::__PrivateInitializer__::__PrivateInitializer__(const c::__PrivateInitializer__ & ) {/*if (p) delete p;*/ p = new c::__Private__();} \
|
||||
c::__PrivateInitializer__::~__PrivateInitializer__() {delete p; p = 0;} \
|
||||
c::__PrivateInitializer__ & c::__PrivateInitializer__::operator =(const c::__PrivateInitializer__ & ) {if (p) delete p; p = new c::__Private__(); return *this;}
|
||||
|
||||
#define PRIVATE (__privateinitializer__.p)
|
||||
#define PRIVATEWB __privateinitializer__.p
|
||||
|
||||
#define NO_COPY_CLASS(name) \
|
||||
explicit name(const name & ); \
|
||||
void operator =(const name & );
|
||||
|
||||
#ifdef FREERTOS
|
||||
# define PIP_MIN_MSLEEP 10.
|
||||
#else
|
||||
# define PIP_MIN_MSLEEP 1.
|
||||
#endif
|
||||
|
||||
|
||||
//! Macro used for infinite loop
|
||||
#define FOREVER for (;;)
|
||||
|
||||
//! Macro used for infinite wait
|
||||
#define FOREVER_WAIT FOREVER msleep(PIP_MIN_MSLEEP);
|
||||
|
||||
//! Macro used for infinite wait
|
||||
#define WAIT_FOREVER FOREVER msleep(PIP_MIN_MSLEEP);
|
||||
|
||||
|
||||
//! global variable enabling output to piCout, default is true
|
||||
extern PIP_EXPORT bool piDebug;
|
||||
|
||||
//! global variable that set minimum real update interval
|
||||
//! for function PIInit::mountInfo(), default is 10000 ms
|
||||
extern PIP_EXPORT double piMountInfoRefreshIntervalMs;
|
||||
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned long long ullong;
|
||||
typedef long long llong;
|
||||
typedef long double ldouble;
|
||||
|
||||
/*! \brief Templated function for swap two values
|
||||
* \details Example:\n \snippet piincludes.cpp swap */
|
||||
template<typename T> inline void piSwap(T & f, T & s) {T t = f; f = s; s = t;}
|
||||
|
||||
/*! \brief Templated function for swap two values without "="
|
||||
* \details Example:\n \snippet piincludes.cpp swapBinary */
|
||||
template<typename T> inline void piSwapBinary(T & f, T & s) {
|
||||
if ((size_t*)&f == (size_t*)&s) return;
|
||||
size_t j = (sizeof(T) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(T);
|
||||
size_t i = 0;
|
||||
for (i = 0; i < j; ++i) {
|
||||
((size_t*)(&f))[i] ^= ((size_t*)(&s))[i];
|
||||
((size_t*)(&s))[i] ^= ((size_t*)(&f))[i];
|
||||
((size_t*)(&f))[i] ^= ((size_t*)(&s))[i];
|
||||
}
|
||||
for (i = bs; i < bf; ++i) {
|
||||
((uchar*)(&f))[i] ^= ((uchar*)(&s))[i];
|
||||
((uchar*)(&s))[i] ^= ((uchar*)(&f))[i];
|
||||
((uchar*)(&f))[i] ^= ((uchar*)(&s))[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void piSwapBinary(const void *& f, const void *& s) {
|
||||
if ((size_t*)f == (size_t*)s) return;
|
||||
size_t j = (sizeof(void *) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(void *);
|
||||
size_t i = 0;
|
||||
void * pf = const_cast<void*>(f), * ps = const_cast<void*>(s);
|
||||
for (i = 0; i < j; ++i) {
|
||||
((size_t*)(&pf))[i] ^= ((size_t*)(&ps))[i];
|
||||
((size_t*)(&ps))[i] ^= ((size_t*)(&pf))[i];
|
||||
((size_t*)(&pf))[i] ^= ((size_t*)(&ps))[i];
|
||||
}
|
||||
for (i = bs; i < bf; ++i) {
|
||||
((uchar*)(&pf))[i] ^= ((uchar*)(&ps))[i];
|
||||
((uchar*)(&ps))[i] ^= ((uchar*)(&pf))[i];
|
||||
((uchar*)(&pf))[i] ^= ((uchar*)(&ps))[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Function for compare two values without "=" by raw content
|
||||
* \details Example:\n \snippet piincludes.cpp compareBinary */
|
||||
inline bool piCompareBinary(const void * f, const void * s, size_t size) {
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
if (((const uchar*)f)[i] != ((const uchar*)s)[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! \brief Templated function return round of float falue
|
||||
* \details Round is the nearest integer value \n
|
||||
* There are some macros:
|
||||
* - \c piRoundf for "float"
|
||||
* - \c piRoundd for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp round */
|
||||
template<typename T> inline int piRound(const T & v) {return int(v >= T(0.) ? v + T(0.5) : v - T(0.5));}
|
||||
|
||||
/*! \brief Templated function return floor of float falue
|
||||
* \details Floor is the largest integer that is not greater than value \n
|
||||
* There are some macros:
|
||||
* - \c piFloorf for "float"
|
||||
* - \c piFloord for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp floor */
|
||||
template<typename T> inline int piFloor(const T & v) {return v < T(0) ? int(v) - 1 : int(v);}
|
||||
|
||||
/*! \brief Templated function return ceil of float falue
|
||||
* \details Ceil is the smallest integer that is not less than value \n
|
||||
* There are some macros:
|
||||
* - \c piCeilf for "float"
|
||||
* - \c piCeild for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp ceil */
|
||||
template<typename T> inline int piCeil(const T & v) {return v < T(0) ? int(v) : int(v) + 1;}
|
||||
|
||||
/*! \brief Templated function return absolute of numeric falue
|
||||
* \details Absolute is the positive or equal 0 value \n
|
||||
* There are some macros:
|
||||
* - \c piAbss for "short"
|
||||
* - \c piAbsi for "int"
|
||||
* - \c piAbsl for "long"
|
||||
* - \c piAbsll for "llong"
|
||||
* - \c piAbsf for "float"
|
||||
* - \c piAbsd for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp abs */
|
||||
template<typename T> inline T piAbs(const T & v) {return (v >= T(0) ? v : -v);}
|
||||
|
||||
/*! \brief Templated function return minimum of two values
|
||||
* \details There are some macros:
|
||||
* - \c piMins for "short"
|
||||
* - \c piMini for "int"
|
||||
* - \c piMinl for "long"
|
||||
* - \c piMinll for "llong"
|
||||
* - \c piMinf for "float"
|
||||
* - \c piMind for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp min2 */
|
||||
template<typename T> inline T piMin(const T & f, const T & s) {return ((f > s) ? s : f);}
|
||||
|
||||
/*! \brief Templated function return minimum of tree values
|
||||
* \details There are some macros:
|
||||
* - \c piMins for "short"
|
||||
* - \c piMini for "int"
|
||||
* - \c piMinl for "long"
|
||||
* - \c piMinll for "llong"
|
||||
* - \c piMinf for "float"
|
||||
* - \c piMind for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp min3 */
|
||||
template<typename T> inline T piMin(const T & f, const T & s, const T & t) {return ((f < s && f < t) ? f : ((s < t) ? s : t));}
|
||||
|
||||
/*! \brief Templated function return maximum of two values
|
||||
* \details There are some macros:
|
||||
* - \c piMaxs for "short"
|
||||
* - \c piMaxi for "int"
|
||||
* - \c piMaxl for "long"
|
||||
* - \c piMaxll for "llong"
|
||||
* - \c piMaxf for "float"
|
||||
* - \c piMaxd for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp max2 */
|
||||
template<typename T> inline T piMax(const T & f, const T & s) {return ((f < s) ? s : f);}
|
||||
|
||||
/*! \brief Templated function return maximum of tree values
|
||||
* \details There are some macros:
|
||||
* - \c piMaxs for "short"
|
||||
* - \c piMaxi for "int"
|
||||
* - \c piMaxl for "long"
|
||||
* - \c piMaxll for "llong"
|
||||
* - \c piMaxf for "float"
|
||||
* - \c piMaxd for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp max3 */
|
||||
template<typename T> inline T piMax(const T & f, const T & s, const T & t) {return ((f > s && f > t) ? f : ((s > t) ? s : t));}
|
||||
|
||||
/*! \brief Templated function return clamped value
|
||||
* \details Clamped is the not greater than "max" and not lesser than "min" value \n
|
||||
* There are some macros:
|
||||
* - \c piClamps for "short"
|
||||
* - \c piClampi for "int"
|
||||
* - \c piClampl for "long"
|
||||
* - \c piClampll for "llong"
|
||||
* - \c piClampf for "float"
|
||||
* - \c piClampd for "double"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp clamp */
|
||||
template<typename T> inline T piClamp(const T & v, const T & min, const T & max) {return (v > max ? max : (v < min ? min : v));}
|
||||
|
||||
/// Function inverse byte order in memory block
|
||||
inline void piLetobe(void * data, int size) {
|
||||
for (int i = 0; i < size / 2; i++)
|
||||
piSwap<uchar>(((uchar*)data)[size - i - 1], ((uchar*)data)[i]);
|
||||
}
|
||||
|
||||
/// \brief Templated function that inverse byte order of value "v"
|
||||
template<typename T> inline void piLetobe(T * v) {piLetobe(v, sizeof(T));}
|
||||
|
||||
/*! \brief Templated function that returns "v" with inversed byte order
|
||||
* \details This function used to convert values between little and big endian \n
|
||||
* There are some macros:
|
||||
* - \c piLetobes for "ushort"
|
||||
* - \c piLetobei for "uint"
|
||||
* - \c piLetobel for "ulong"
|
||||
* - \c piLetobell for "ullong"
|
||||
*
|
||||
* Example:
|
||||
* \snippet piincludes.cpp letobe */
|
||||
template<typename T> inline T piLetobe(const T & v) {T tv(v); piLetobe(&tv, sizeof(T)); return tv;}
|
||||
|
||||
// specialization
|
||||
template<> inline ushort piLetobe(const ushort & v) {return (v << 8) | (v >> 8);}
|
||||
template<> inline uint piLetobe(const uint & v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
|
||||
template<> inline float piLetobe(const float & v) {
|
||||
union _pletobe_f {
|
||||
_pletobe_f(const float &f_) {f = f_;}
|
||||
float f;
|
||||
uint v;
|
||||
};
|
||||
_pletobe_f a(v);
|
||||
a.v = (a.v >> 24) | ((a.v >> 8) & 0xFF00) | ((a.v << 8) & 0xFF0000) | ((a.v << 24) & 0xFF000000);
|
||||
return a.f;
|
||||
}
|
||||
|
||||
DEPRECATED inline ushort letobe_s(const ushort & v) {return (v << 8) | (v >> 8);}
|
||||
DEPRECATED inline uint letobe_i(const uint & v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
/// \deprecated \brief Use \a piLetobe() instead of this function
|
||||
ushort letobe_s(ushort v) {return (v << 8) | (v >> 8);}
|
||||
|
||||
/// \deprecated \brief Use \a piLetobe() instead of this function
|
||||
uint letobe_i(uint v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
|
||||
|
||||
#endif
|
||||
|
||||
/// \brief Generic hash function, impements murmur3/32 algorithm
|
||||
inline uint piHashData(const uchar * data, uint len, uint seed = 0) {
|
||||
if (!data || len <= 0) return 0u;
|
||||
uint h = seed;
|
||||
if (len > 3) {
|
||||
uint i = len >> 2;
|
||||
do {
|
||||
uint k;
|
||||
memcpy(&k, data, sizeof(uint));
|
||||
data += sizeof(uint);
|
||||
k *= 0xcc9e2d51;
|
||||
k = (k << 15) | (k >> 17);
|
||||
k *= 0x1b873593;
|
||||
h ^= k;
|
||||
h = (h << 13) | (h >> 19);
|
||||
h = h * 5 + 0xe6546b64;
|
||||
} while (--i);
|
||||
}
|
||||
if (len & 3) {
|
||||
uint i = len & 3;
|
||||
uint k = 0;
|
||||
do {
|
||||
k <<= 8;
|
||||
k |= data[i - 1];
|
||||
} while (--i);
|
||||
k *= 0xcc9e2d51;
|
||||
k = (k << 15) | (k >> 17);
|
||||
k *= 0x1b873593;
|
||||
h ^= k;
|
||||
}
|
||||
h ^= len;
|
||||
h ^= h >> 16;
|
||||
h *= 0x85ebca6b;
|
||||
h ^= h >> 13;
|
||||
h *= 0xc2b2ae35;
|
||||
h ^= h >> 16;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
template<typename T> inline uint piHash(const T & v) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<> inline uint piHash(const char & v) {return (uint)v;}
|
||||
template<> inline uint piHash(const uchar & v) {return (uint)v;}
|
||||
template<> inline uint piHash(const short & v) {return (uint)v;}
|
||||
template<> inline uint piHash(const ushort & v) {return (uint)v;}
|
||||
template<> inline uint piHash(const int & v) {return (uint)v;}
|
||||
template<> inline uint piHash(const uint & v) {return (uint)v;}
|
||||
template<> inline uint piHash(const llong & v) {return piHashData((const uchar *)&v, sizeof(v));}
|
||||
template<> inline uint piHash(const ullong & v) {return piHashData((const uchar *)&v, sizeof(v));}
|
||||
template<> inline uint piHash(const float & v) {return (uint)v;}
|
||||
template<> inline uint piHash(const double & v) {return piHashData((const uchar *)&v, sizeof(v));}
|
||||
template<> inline uint piHash(const ldouble & v) {return piHashData((const uchar *)&v, sizeof(v));}
|
||||
|
||||
#define piRoundf piRound<float>
|
||||
#define piRoundd piRound<double>
|
||||
#define piFloorf piFloor<float>
|
||||
#define piFloord piFloor<double>
|
||||
#define piCeilf piCeil<float>
|
||||
#define piCeild piCeil<double>
|
||||
#define piAbss piAbs<short>
|
||||
#define piAbsi piAbs<int>
|
||||
#define piAbsl piAbs<long>
|
||||
#define piAbsll piAbs<llong>
|
||||
#define piAbsf piAbs<float>
|
||||
#define piAbsd piAbs<double>
|
||||
#define piMins piMin<short>
|
||||
#define piMini piMin<int>
|
||||
#define piMinl piMin<long>
|
||||
#define piMinll piMin<llong>
|
||||
#define piMinf piMin<float>
|
||||
#define piMind piMin<double>
|
||||
#define piMaxs piMax<short>
|
||||
#define piMaxi piMax<int>
|
||||
#define piMaxl piMax<long>
|
||||
#define piMaxll piMax<llong>
|
||||
#define piMaxf piMax<float>
|
||||
#define piMaxd piMax<double>
|
||||
#define piClamps piClamp<short>
|
||||
#define piClampi piClamp<int>
|
||||
#define piClampl piClamp<long>
|
||||
#define piClampll piClamp<llong>
|
||||
#define piClampf piClamp<float>
|
||||
#define piClampd piClamp<double>
|
||||
#define piLetobes piLetobe<ushort>
|
||||
#define piLetobei piLetobe<uint>
|
||||
#define piLetobel piLetobe<ulong>
|
||||
#define piLetobell piLetobe<ullong>
|
||||
#define piLetobef piLetobe<float>
|
||||
|
||||
|
||||
#endif // PIBASE_H
|
||||
44
lib/main/core/pibitarray.cpp
Normal file
44
lib/main/core/pibitarray.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Bit array
|
||||
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 "pibitarray.h"
|
||||
#include "picout.h"
|
||||
|
||||
|
||||
PICout operator <<(PICout s, const PIBitArray & ba) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
for (uint i = 0; i < ba.bitSize(); ++i) {
|
||||
s << int(ba[i]);
|
||||
if (i % 8 == 7) s << ' ';
|
||||
}
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
std::ostream &operator <<(std::ostream & s, const PIBitArray & ba) {
|
||||
for (uint i = 0; i < ba.bitSize(); ++i) {
|
||||
s << ba[i];
|
||||
if (i % 8 == 7) s << ' ';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
112
lib/main/core/pibitarray.h
Normal file
112
lib/main/core/pibitarray.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/*! \file pibitarray.h
|
||||
* \brief Bit array
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Bit array
|
||||
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 PIBITARRAY_H
|
||||
#define PIBITARRAY_H
|
||||
|
||||
#include "pivector.h"
|
||||
|
||||
class PIP_EXPORT PIBitArray {
|
||||
friend PIByteArray & operator <<(PIByteArray & s, const PIBitArray & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & s, PIBitArray & v);
|
||||
public:
|
||||
PIBitArray(const int & size = 0) {resize(size);}
|
||||
PIBitArray(uchar val) {resize(sizeof(val) * 8); data_[0] = val;}
|
||||
PIBitArray(ushort val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
PIBitArray(uint val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
PIBitArray(ulong val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
PIBitArray(ullong val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
PIBitArray(const uchar * bytes, uint size) {resize(size * 8); memcpy(data(), bytes, size);}
|
||||
|
||||
uint bitSize() const {return size_;}
|
||||
uint byteSize() const {return bytesInBits(size_);}
|
||||
PIBitArray & resize(const uint & size) {size_ = size; data_.resize(bytesInBits(size_)); return *this;}
|
||||
|
||||
PIBitArray & clearBit(const uint & index) {data_[index / 8] &= ~(1 << (index % 8)); return *this;}
|
||||
PIBitArray & setBit(const uint & index) {data_[index / 8] |= (1 << (index % 8)); return *this;}
|
||||
PIBitArray & writeBit(const uint & index, const bool & value) {if (value) setBit(index); else clearBit(index); return *this;}
|
||||
PIBitArray & writeBit(const uint & index, const uchar & value) {return writeBit(index, value > 0);}
|
||||
|
||||
PIBitArray & push_back(const bool & value) {resize(size_ + 1); writeBit(size_ - 1, value); return *this;}
|
||||
PIBitArray & push_back(const uchar & value) {return push_back(value > 0);}
|
||||
PIBitArray & insert(const uint & index, const bool & value) {
|
||||
resize(size_ + 1);
|
||||
uint fi = byteSize() - 1, si = index / 8, ti = index % 8;
|
||||
uchar c = data_[si];
|
||||
for (uint i = fi; i > si; --i) {
|
||||
data_[i] <<= 1;
|
||||
if ((0x80 & data_[i - 1]) == 0x80) data_[i] |= 1;
|
||||
else data_[i] &= 0xFE;}
|
||||
data_[si] &= (0xFF >> (7 - ti));
|
||||
data_[si] |= ((c << 1) & (0xFF << (ti)));
|
||||
if (value) data_[si] |= (1 << ti);
|
||||
else data_[si] &= ~(1 << ti);
|
||||
return *this;}
|
||||
PIBitArray & insert(const uint & index, const uchar & value) {return insert(index, value > 0);}
|
||||
PIBitArray & push_front(const bool & value) {return insert(0, value);}
|
||||
PIBitArray & push_front(const uchar & value) {return push_front(value > 0);}
|
||||
PIBitArray & pop_back() {return resize(size_ - 1);}
|
||||
PIBitArray & pop_front() {
|
||||
if (size_ == 0) return *this;
|
||||
uint fi = byteSize() - 1;
|
||||
for (uint i = 0; i < fi; ++i) {
|
||||
data_[i] >>= 1;
|
||||
if ((1 & data_[i + 1]) == 1) data_[i] |= 0x80;
|
||||
else data_[i] &= 0x7F;}
|
||||
data_[fi] >>= 1;
|
||||
resize(size_ - 1);
|
||||
return *this;}
|
||||
PIBitArray & append(const PIBitArray & ba) {for (uint i = 0; i < ba.bitSize(); ++i) push_back(ba[i]); return *this;}
|
||||
|
||||
uchar * data() {return data_.data();}
|
||||
uchar toUChar() {if (size_ == 0) return 0; return data_[0];}
|
||||
ushort toUShort() {ushort t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
|
||||
uint toUInt() {uint t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
|
||||
ulong toULong() {ulong t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
|
||||
ullong toULLong() {ullong t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
|
||||
|
||||
bool at(const uint & index) const {return (1 & (data_[index / 8] >> (index % 8))) == 1 ? true : false;}
|
||||
bool operator [](const uint & index) const {return at(index);}
|
||||
void operator +=(const PIBitArray & ba) {append(ba);}
|
||||
bool operator ==(const PIBitArray & ba) const {if (bitSize() != ba.bitSize()) return false; for (uint i = 0; i < bitSize(); ++i) if (at(i) != ba[i]) return false; return true;}
|
||||
bool operator !=(const PIBitArray & ba) const {return !(*this == ba);}
|
||||
void operator =(const uchar & val) {resize(sizeof(val) * 8); data_[0] = val;}
|
||||
void operator =(const ushort & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
void operator =(const uint & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
void operator =(const ulong & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
void operator =(const ullong & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
|
||||
|
||||
private:
|
||||
static uint bytesInBits(const uint & bits) {return (bits + 7) / 8;}
|
||||
|
||||
PIVector<uchar> data_;
|
||||
uint size_;
|
||||
|
||||
};
|
||||
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
//std::ostream & operator <<(std::ostream & s, const PIBitArray & ba);
|
||||
#endif
|
||||
|
||||
PICout operator <<(PICout s, const PIBitArray & ba);
|
||||
|
||||
#endif // PIBITARRAY_H
|
||||
403
lib/main/core/pibytearray.cpp
Normal file
403
lib/main/core/pibytearray.cpp
Normal file
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Byte array
|
||||
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 "pibytearray.h"
|
||||
#include "pistringlist.h"
|
||||
#include <iostream>
|
||||
|
||||
/*! \class PIByteArray
|
||||
* \brief Byte array
|
||||
* \details This class based on PIDeque<uchar> and provide some handle function
|
||||
* to manipulate it.
|
||||
*
|
||||
* \section PIByteArray_sec0 Usage
|
||||
* %PIByteArray can be used to store custom data and manipulate it. There are many
|
||||
* stream operators to store/restore common types to byte array. Store operators
|
||||
* places data at the end of array, restore operators takes data from the beginning
|
||||
* of array.
|
||||
* In addition there are Base 64 convertions and checksums:
|
||||
* * plain 8-bit
|
||||
* * plain 32-bit
|
||||
*
|
||||
* One of the major usage of %PIByteArray is stream functions. You can form binary
|
||||
* packet from many types (also dynamic types, e.g. PIVector) with one line:
|
||||
* \snippet pibytearray.cpp 0
|
||||
*
|
||||
* Or you can descibe stream operator of your own type and store/restore vectors of
|
||||
* your type:
|
||||
* \snippet pibytearray.cpp 1
|
||||
*
|
||||
* For store/restore custom data blocks there is PIByteArray::RawData class. Stream
|
||||
* operators of this class simply store/restore data block to/from byte array.
|
||||
* \snippet pibytearray.cpp 2
|
||||
*
|
||||
* \section PIByteArray_sec1 Attention
|
||||
* Stream operator of %PIByteArray store byte array as vector, not simply append
|
||||
* content of byte array. This operators useful to transmit custom data as %PIByteArray
|
||||
* packed into parent byte array, e.g. to form packet from %PIByteArray.
|
||||
* To append one byte array to another use funtion \a append().
|
||||
* \snippet pibytearray.cpp 3
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
static const uchar base64Table[64] = {
|
||||
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
|
||||
0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
|
||||
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
||||
0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
|
||||
0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
|
||||
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
|
||||
0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f};
|
||||
|
||||
static const uchar base64InvTable[256] = {
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x3E, 0x0, 0x0, 0x0, 0x3F,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
|
||||
0x3C, 0x3D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6,
|
||||
0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE,
|
||||
0xF, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
0x17, 0x18, 0x19, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
|
||||
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
||||
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
|
||||
0x31, 0x32, 0x33, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
|
||||
|
||||
|
||||
struct base64HelpStruct {
|
||||
base64HelpStruct() {v = 0;}
|
||||
inline void setBytes(const uchar * r, int size = 3) {
|
||||
v = 0;
|
||||
switch (size) {
|
||||
case 3: v |= r[2];
|
||||
case 2: v |= r[1] << 8;
|
||||
case 1: v |= r[0] << 16;
|
||||
}
|
||||
}
|
||||
inline void getBytes(uchar * r) {
|
||||
r[0] = (v >> 16) & 0xFF;
|
||||
r[1] = (v >> 8) & 0xFF;
|
||||
r[2] = v & 0xFF;
|
||||
}
|
||||
inline void setAscii(const uchar * r, int size = 4) {
|
||||
v = 0;
|
||||
switch (size) {
|
||||
case 4: v |= (base64InvTable[r[3]] & 0x3F);
|
||||
case 3: v |= (base64InvTable[r[2]] & 0x3F) << 6;
|
||||
case 2: v |= (base64InvTable[r[1]] & 0x3F) << 12;
|
||||
case 1: v |= (base64InvTable[r[0]] & 0x3F) << 18;
|
||||
}
|
||||
}
|
||||
inline void getAscii(uchar * r) {
|
||||
r[0] = base64Table[(v >> 18) & 0x3F];
|
||||
r[1] = base64Table[(v >> 12) & 0x3F];
|
||||
r[2] = base64Table[(v >> 6) & 0x3F];
|
||||
r[3] = base64Table[ v & 0x3F];
|
||||
}
|
||||
uint v;
|
||||
};
|
||||
|
||||
|
||||
PIByteArray &PIByteArray::convertToBase64() {
|
||||
return *this = toBase64();
|
||||
}
|
||||
|
||||
|
||||
PIByteArray &PIByteArray::convertFromBase64() {
|
||||
return *this = fromBase64(*this);
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIByteArray::toBase64() const {
|
||||
if (isEmpty()) return PIByteArray();
|
||||
base64HelpStruct hs;
|
||||
PIByteArray ret;
|
||||
int sz = (size_s() / 3) * 3, ri = -1;
|
||||
uchar t[4];
|
||||
ret.resize(((size_s() - 1) / 3 + 1) * 4);
|
||||
for (int i = 0; i < sz; i += 3) {
|
||||
hs.setBytes(data(i));
|
||||
hs.getAscii(t);
|
||||
ret[++ri] = (t[0]);
|
||||
ret[++ri] = (t[1]);
|
||||
ret[++ri] = (t[2]);
|
||||
ret[++ri] = (t[3]);
|
||||
}
|
||||
int der = size_s() % 3;
|
||||
switch (der) {
|
||||
case 1:
|
||||
hs.setBytes(data(sz), 1);
|
||||
hs.getAscii(t);
|
||||
ret[++ri] = (t[0]);
|
||||
ret[++ri] = (t[1]);
|
||||
ret[++ri] = ('=');
|
||||
ret[++ri] = ('=');
|
||||
break;
|
||||
case 2:
|
||||
hs.setBytes(data(sz), 2);
|
||||
hs.getAscii(t);
|
||||
ret[++ri] = (t[0]);
|
||||
ret[++ri] = (t[1]);
|
||||
ret[++ri] = (t[2]);
|
||||
ret[++ri] = ('=');
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIByteArray::fromBase64(const PIByteArray & base64) {
|
||||
if (base64.isEmpty()) return PIByteArray();
|
||||
base64HelpStruct hs;
|
||||
PIByteArray ret;
|
||||
int sz = base64.size_s(), ind = -1;
|
||||
uchar t[4];
|
||||
ret.resize(sz / 4 * 3);
|
||||
for (int i = 0; i < sz; i += 4) {
|
||||
hs.setAscii(base64.data(i));
|
||||
hs.getBytes(t);
|
||||
ret[++ind] = (t[0]);
|
||||
ret[++ind] = (t[1]);
|
||||
ret[++ind] = (t[2]);
|
||||
}
|
||||
if (base64.back() == '=') ret.pop_back();
|
||||
if (sz > 1) if (base64[sz - 2] == '=') ret.pop_back();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIByteArray::fromBase64(const PIString & base64) {
|
||||
return fromBase64(base64.toByteArray());
|
||||
}
|
||||
|
||||
|
||||
PIByteArray & PIByteArray::compressRLE(uchar threshold) {
|
||||
PIByteArray t;
|
||||
uchar fb, clen, mlen = 255 - threshold;
|
||||
for (uint i = 0; i < size();) {
|
||||
fb = at(i);
|
||||
clen = 1;
|
||||
while (at(++i) == fb) {
|
||||
++clen;
|
||||
if (clen == mlen)
|
||||
break;
|
||||
}
|
||||
if (clen > 1) {
|
||||
t.push_back(threshold + clen);
|
||||
t.push_back(fb);
|
||||
continue;
|
||||
}
|
||||
if (fb >= threshold) {
|
||||
t.push_back(threshold + 1);
|
||||
t.push_back(fb);
|
||||
} else
|
||||
t.push_back(fb);
|
||||
}
|
||||
*this = t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray & PIByteArray::decompressRLE(uchar threshold) {
|
||||
PIByteArray t;
|
||||
uchar fb, clen;
|
||||
for (uint i = 0; i < size(); ++i) {
|
||||
fb = at(i);
|
||||
if (fb >= threshold) {
|
||||
clen = fb - threshold;
|
||||
fb = at(++i);
|
||||
for (uint j = 0; j < clen; ++j)
|
||||
t.push_back(fb);
|
||||
continue;
|
||||
} else
|
||||
t.push_back(fb);
|
||||
}
|
||||
*this = t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
uchar PIByteArray::checksumPlain8() const {
|
||||
uchar c = 0;
|
||||
int sz = size_s();
|
||||
for (int i = 0; i < sz; ++i)
|
||||
c += at(i);
|
||||
c = ~(c + 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
uint PIByteArray::checksumPlain32() const {
|
||||
uint c = 0;
|
||||
int sz = size_s();
|
||||
for (int i = 0; i < sz; ++i)
|
||||
c += at(i) * (i + 1);
|
||||
c = ~(c + 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
uint PIByteArray::hash() const {
|
||||
return piHashData(data(), size_s());
|
||||
}
|
||||
|
||||
|
||||
PIString PIByteArray::toString(int base) const {
|
||||
PIString ret;
|
||||
int sz = size_s();
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
if (i > 0) ret += " ";
|
||||
if (base == 2) ret += "b";
|
||||
if (base == 8) ret += "0";
|
||||
if (base == 16) ret += "0x";
|
||||
ret += PIString::fromNumber(at(i), base);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIByteArray::toHex() const {
|
||||
PIByteArray hex(size() * 2);
|
||||
uchar *hexData = hex.data();
|
||||
const uchar *d = data();
|
||||
for (int i = 0; i < size_s(); ++i) {
|
||||
int j = (d[i] >> 4) & 0xf;
|
||||
if (j <= 9) hexData[i*2] = (j + '0');
|
||||
else hexData[i*2] = (j + 'a' - 10);
|
||||
j = d[i] & 0xf;
|
||||
if (j <= 9) hexData[i*2+1] = (j + '0');
|
||||
else hexData[i*2+1] = (j + 'a' - 10);
|
||||
}
|
||||
return PIString(hex);
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIByteArray::fromUserInput(PIString str) {
|
||||
PIByteArray ret;
|
||||
if (str.trim().isEmpty()) return ret;
|
||||
str.replaceAll("\n", " ").replaceAll("\t", " ").replaceAll(" ", " ");
|
||||
PIStringList bl(str.split(" "));
|
||||
bool ok(false);
|
||||
piForeachC (PIString & b, bl) {
|
||||
int bv = b.toInt(-1, &ok);
|
||||
if (ok) ret << uchar(bv);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIByteArray::fromHex(PIString str) {
|
||||
PIByteArray hexEncoded = str.toByteArray();
|
||||
PIByteArray res((hexEncoded.size() + 1)/ 2);
|
||||
uchar *result = res.data() + res.size();
|
||||
bool odd_digit = true;
|
||||
for (int i = hexEncoded.size() - 1; i >= 0; --i) {
|
||||
int ch = hexEncoded.at(i);
|
||||
int tmp;
|
||||
if (ch >= '0' && ch <= '9') tmp = ch - '0';
|
||||
else if (ch >= 'a' && ch <= 'f') tmp = ch - 'a' + 10;
|
||||
else if (ch >= 'A' && ch <= 'F') tmp = ch - 'A' + 10;
|
||||
else continue;
|
||||
if (odd_digit) {
|
||||
--result;
|
||||
*result = tmp;
|
||||
odd_digit = false;
|
||||
} else {
|
||||
*result |= tmp << 4;
|
||||
odd_digit = true;
|
||||
}
|
||||
}
|
||||
res.remove(0, result - res.data());
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
PICout operator <<(PICout s, const PIByteArray & ba) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s << "{";
|
||||
for (uint i = 0; i < ba.size(); ++i) {
|
||||
s << ba[i];
|
||||
if (i < ba.size() - 1) s << ", ";
|
||||
}
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
std::ostream &operator <<(std::ostream & s, const PIByteArray & ba) {
|
||||
s << "{";
|
||||
for (uint i = 0; i < ba.size(); ++i) {
|
||||
s << ba[i];
|
||||
if (i < ba.size() - 1) s << ", ";
|
||||
}
|
||||
s << "}";
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
PIByteArray & operator >>(PIByteArray & s, PIByteArray & v) {
|
||||
if (s.size_s() < 4) {
|
||||
s.clear();
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
assert(s.size_s() >= 4);
|
||||
int sz = 0;
|
||||
s >> sz;
|
||||
if (sz > s.size_s()) {
|
||||
piCout << "[PIByteArray] Warning: operator >> wants too much data, discard!" << sz << s.size_s();
|
||||
s.clear();
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
v.resize(sz);
|
||||
if (sz > 0) {
|
||||
memcpy(v.data(), s.data(), v.size());
|
||||
s.remove(0, v.size());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
321
lib/main/core/pibytearray.h
Normal file
321
lib/main/core/pibytearray.h
Normal file
@@ -0,0 +1,321 @@
|
||||
/*! \file pibytearray.h
|
||||
* \brief Byte array
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Byte array
|
||||
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 PIBYTEARRAY_H
|
||||
#define PIBYTEARRAY_H
|
||||
|
||||
#include "pichar.h"
|
||||
#include "pibitarray.h"
|
||||
#include "pimap.h"
|
||||
#include "pivector2d.h"
|
||||
|
||||
__PICONTAINERS_SIMPLE_TYPE__(PIChar)
|
||||
|
||||
#define __PIBYTEARRAY_SIMPLE_TYPE__(T) \
|
||||
template<> \
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {s << int(v.size_s()); int os = s.size_s(); s.enlarge(v.size_s()*sizeof(T)); memcpy(s.data(os), v.data(), v.size_s()*sizeof(T)); return s;} \
|
||||
template<> \
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v._resizeRaw(sz); if (sz > 0) memcpy(v.data(), s.data(), sz*sizeof(T)); s.remove(0, sz*sizeof(T)); return s;} \
|
||||
template<> \
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {s << int(v.size_s()); int os = s.size_s(); s.enlarge(v.size_s()*sizeof(T)); memcpy(s.data(os), v.data(), v.size_s()*sizeof(T)); return s;} \
|
||||
template<> \
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v._resizeRaw(sz); if (sz > 0) memcpy(v.data(), s.data(), sz*sizeof(T)); s.remove(0, sz*sizeof(T)); return s;} \
|
||||
template<> \
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {s << int(v.rows()) << int(v.cols()); int os = s.size_s(); s.enlarge(v.size_s()*sizeof(T)); memcpy(s.data(os), v.data(), v.size_s()*sizeof(T)); return s;} \
|
||||
template<> \
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {assert(s.size_s() >= 8); int r, c; s >> r >> c; v._resizeRaw(r, c); int sz = r*c; if (sz > 0) memcpy(v.data(), s.data(), sz*sizeof(T)); s.remove(0, sz*sizeof(T)); return s;}
|
||||
|
||||
|
||||
class PIString;
|
||||
class PIByteArray;
|
||||
|
||||
|
||||
class PIP_EXPORT PIByteArray: public PIDeque<uchar>
|
||||
{
|
||||
public:
|
||||
|
||||
//! Constructs an empty byte array
|
||||
PIByteArray() {;}
|
||||
|
||||
//! Constructs 0-filled byte array with size "size"
|
||||
PIByteArray(const uint size) {resize(size);}
|
||||
|
||||
//! Constructs byte array from data "data" and size "size"
|
||||
PIByteArray(const void * data, const uint size): PIDeque<uchar>((const uchar*)data, size_t(size)) {}
|
||||
|
||||
//! Constructs byte array with size "size" filled by "t"
|
||||
PIByteArray(const uint size, uchar t): PIDeque<uchar>(size, t) {}
|
||||
|
||||
|
||||
//! Help struct to store/restore custom blocks of data to/from PIByteArray
|
||||
struct RawData {
|
||||
friend PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v);
|
||||
public:
|
||||
//! Constructs data block
|
||||
RawData(void * data = 0, int size = 0) {d = data; s = size;}
|
||||
RawData(const RawData & o) {d = o.d; s = o.s;}
|
||||
//! Constructs data block
|
||||
RawData(const void * data, const int size) {d = const_cast<void * >(data); s = size;}
|
||||
RawData & operator =(const RawData & o) {d = o.d; s = o.s; return *this;}
|
||||
private:
|
||||
void * d;
|
||||
int s;
|
||||
};
|
||||
|
||||
//! Return resized byte array
|
||||
PIByteArray resized(uint new_size) const {PIByteArray ret(new_size); memcpy(ret.data(), data(), new_size); return ret;}
|
||||
|
||||
//! Convert data to Base 64 and return this byte array
|
||||
PIByteArray & convertToBase64();
|
||||
|
||||
//! Convert data from Base 64 and return this byte array
|
||||
PIByteArray & convertFromBase64();
|
||||
|
||||
//! Return converted to Base 64 data
|
||||
PIByteArray toBase64() const;
|
||||
|
||||
//! Return converted from Base 64 data
|
||||
|
||||
PIByteArray & compressRLE(uchar threshold = 192);
|
||||
PIByteArray & decompressRLE(uchar threshold = 192);
|
||||
PIByteArray compressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.compressRLE(threshold); return ba;}
|
||||
PIByteArray decompressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.decompressRLE(threshold); return ba;}
|
||||
|
||||
PIString toString(int base = 16) const;
|
||||
PIString toHex() const;
|
||||
|
||||
//! Add to the end data "data" with size "size"
|
||||
PIByteArray & append(const void * data_, int size_) {uint ps = size(); enlarge(size_); memcpy(data(ps), data_, size_); return *this;}
|
||||
|
||||
//! Add to the end byte array "data"
|
||||
PIByteArray & append(const PIByteArray & data_) {uint ps = size(); enlarge(data_.size_s()); memcpy(data(ps), data_.data(), data_.size()); return *this;}
|
||||
|
||||
//! Add to the end "t"
|
||||
PIByteArray & append(uchar t) {push_back(t); return *this;}
|
||||
|
||||
//! Returns plain 8-bit checksum
|
||||
uchar checksumPlain8() const;
|
||||
|
||||
//! Returns plain 32-bit checksum
|
||||
uint checksumPlain32() const;
|
||||
|
||||
//! Returns hash
|
||||
uint hash() const;
|
||||
|
||||
void operator =(const PIDeque<uchar> & d) {resize(d.size()); memcpy(data(), d.data(), d.size());}
|
||||
|
||||
static PIByteArray fromUserInput(PIString str);
|
||||
static PIByteArray fromHex(PIString str);
|
||||
static PIByteArray fromBase64(const PIByteArray & base64);
|
||||
static PIByteArray fromBase64(const PIString & base64);
|
||||
};
|
||||
|
||||
inline bool operator <(const PIByteArray & v0, const PIByteArray & v1) {if (v0.size() == v1.size()) {for (uint i = 0; i < v0.size(); ++i) if (v0[i] != v1[i]) return v0[i] < v1[i]; return false;} return v0.size() < v1.size();}
|
||||
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
//! \relatesalso PIByteArray \brief Output to std::ostream operator
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIByteArray & ba);
|
||||
#endif
|
||||
|
||||
//! \relatesalso PIByteArray \brief Output to PICout operator
|
||||
PICout operator <<(PICout s, const PIByteArray & ba);
|
||||
|
||||
#define PBA_OPERATOR_TO int os = s.size_s(); s.enlarge(sizeof(v)); memcpy(s.data(os), &v, sizeof(v));
|
||||
|
||||
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, bool v) {s.push_back(v); return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, char v) {s.push_back(v); return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, uchar v) {s.push_back(v); return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const short v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const int v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const long & v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const llong & v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const ushort v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const uint v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const ulong & v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const ullong & v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const float v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const double & v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const ldouble & v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
template<typename T> inline PIByteArray & operator <<(PIByteArray & s, const PIFlags<T> & v) {PBA_OPERATOR_TO return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator, see \ref PIByteArray_sec1 for details
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v) {s << int(v.size_s()); int os = s.size_s(); s.enlarge(v.size_s()); if (v.size_s() > 0) memcpy(s.data(os), v.data(), v.size()); return s;}
|
||||
//! \relatesalso PIByteArray \brief Store operator, see \ref PIByteArray_sec1 for details
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) {int os = s.size_s(); s.enlarge(v.s); if (v.s > 0) memcpy(s.data(os), v.d, v.s); return s;}
|
||||
|
||||
#undef PBA_OPERATOR_TO
|
||||
#define PBA_OPERATOR_FROM memcpy((void*)(&v), s.data(), sizeof(v)); s.remove(0, sizeof(v));
|
||||
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, bool & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, char & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, uchar & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, short & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, int & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, long & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, llong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, ushort & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, uint & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, ulong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, ullong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, float & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, double & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, ldouble & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
template<typename T> inline PIByteArray & operator >>(PIByteArray & s, PIFlags<T> & v) {PBA_OPERATOR_FROM return s;}
|
||||
//! \relatesalso PIByteArray \brief Restore operator, see \ref PIByteArray_sec1 for details
|
||||
PIByteArray & operator >>(PIByteArray & s, PIByteArray & v);
|
||||
//! \relatesalso PIByteArray \brief Restore operator, see \ref PIByteArray_sec1 for details
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) {assert(s.size_s() >= v.s); if (v.s > 0) memcpy((void*)(v.d), s.data(), v.s); s.remove(0, v.s); return s;}
|
||||
|
||||
#undef PBA_OPERATOR_FROM
|
||||
|
||||
template<typename Type0, typename Type1> inline PIByteArray & operator <<(PIByteArray & s, const PIPair<Type0, Type1> & v);
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
template<typename T> inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v);
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
template<typename T> inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v);
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
template <typename Key, typename T> inline PIByteArray & operator <<(PIByteArray & s, const PIMap<Key, T> & v);
|
||||
//! Write operator to \c PIByteArray
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIChar & v) {s << v.ch; return s;}
|
||||
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
template<typename Type0, typename Type1> inline PIByteArray & operator >>(PIByteArray & s, PIPair<Type0, Type1> & v);
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
template<typename T> inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v);
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
template<typename T> inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v);
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
template <typename Key, typename T> inline PIByteArray & operator >>(PIByteArray & s, PIMap<Key, T> & v);
|
||||
//! Read operator from \c PIByteArray
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIChar & v) {s >> v.ch; return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIByteArray \brief Store operator
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIBitArray & v) {s << v.size_ << v.data_; return s;}
|
||||
template<typename Type0, typename Type1>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIPair<Type0, Type1> & v) {s << v.first << v.second; return s;}
|
||||
template<typename T>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {s << int(v.size_s()); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;}
|
||||
template<typename T>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {s << int(v.size_s()); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;}
|
||||
template <typename Key, typename T>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIMap<Key, T> & v) {
|
||||
s << int(v.pim_index.size_s());
|
||||
for (uint i = 0; i < v.size(); ++i)
|
||||
s << int(v.pim_index[i].index) << v.pim_index[i].key;
|
||||
s << v.pim_content;
|
||||
return s;
|
||||
}
|
||||
template<typename T>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {s << int(v.rows()) << int(v.cols()) << v.toPlainVector(); return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIByteArray \brief Restore operator
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIBitArray & v) {assert(s.size_s() >= 8); s >> v.size_ >> v.data_; return s;}
|
||||
template<typename Type0, typename Type1>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIPair<Type0, Type1> & v) {s >> v.first >> v.second; return s;}
|
||||
template<typename T>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
|
||||
template<typename T>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
|
||||
template <typename Key, typename T>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIMap<Key, T> & v) {
|
||||
assert(s.size_s() >= 4);
|
||||
int sz; s >> sz; v.pim_index.resize(sz);
|
||||
int ind = 0;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
s >> ind >> v.pim_index[i].key;
|
||||
v.pim_index[i].index = ind;
|
||||
}
|
||||
s >> v.pim_content;
|
||||
if (v.pim_content.size_s() != v.pim_index.size_s()) {
|
||||
piCout << "Warning: loaded invalid PIMap, clear";
|
||||
v.clear();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template<typename T>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {assert(s.size_s() >= 8); int r,c; PIVector<T> tmp; s >> r >> c >> tmp; v = PIVector2D<T>(r, c, tmp); return s;}
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const T & ) {piCout << "[PIByteArray] Warning: using undeclared operator <<!"; return s;}
|
||||
template<typename T>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, T & ) {piCout << "[PIByteArray] Warning: using undeclared operator >>!"; return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIByteArray \brief Byte arrays compare operator
|
||||
inline bool operator ==(PIByteArray & f, PIByteArray & s) {if (f.size_s() != s.size_s()) return false; for (int i = 0; i < f.size_s(); ++i) if (f[i] != s[i]) return false; return true;}
|
||||
//! \relatesalso PIByteArray \brief Byte arrays compare operator
|
||||
inline bool operator !=(PIByteArray & f, PIByteArray & s) {if (f.size_s() != s.size_s()) return true; for (int i = 0; i < f.size_s(); ++i) if (f[i] != s[i]) return true; return false;}
|
||||
|
||||
__PIBYTEARRAY_SIMPLE_TYPE__(bool)
|
||||
__PIBYTEARRAY_SIMPLE_TYPE__(char)
|
||||
__PIBYTEARRAY_SIMPLE_TYPE__(short)
|
||||
__PIBYTEARRAY_SIMPLE_TYPE__(ushort)
|
||||
__PIBYTEARRAY_SIMPLE_TYPE__(int)
|
||||
__PIBYTEARRAY_SIMPLE_TYPE__(uint)
|
||||
__PIBYTEARRAY_SIMPLE_TYPE__(long)
|
||||
__PIBYTEARRAY_SIMPLE_TYPE__(ulong)
|
||||
__PIBYTEARRAY_SIMPLE_TYPE__(llong)
|
||||
__PIBYTEARRAY_SIMPLE_TYPE__(ullong)
|
||||
__PIBYTEARRAY_SIMPLE_TYPE__(float)
|
||||
__PIBYTEARRAY_SIMPLE_TYPE__(double)
|
||||
__PIBYTEARRAY_SIMPLE_TYPE__(ldouble)
|
||||
__PIBYTEARRAY_SIMPLE_TYPE__(PIChar)
|
||||
|
||||
|
||||
template<> inline uint piHash(const PIByteArray & ba) {return ba.hash();}
|
||||
|
||||
|
||||
#endif // PIBYTEARRAY_H
|
||||
393
lib/main/core/pichar.cpp
Normal file
393
lib/main/core/pichar.cpp
Normal file
@@ -0,0 +1,393 @@
|
||||
/*! \file pichar.h
|
||||
* \brief Unicode char
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Unicode char
|
||||
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 "piincludes_p.h"
|
||||
#include "pibytearray.h"
|
||||
#ifdef PIP_ICU
|
||||
# define U_NOEXCEPT
|
||||
# include "unicode/ucnv.h"
|
||||
# include "unicode/ustring.h"
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
# include <stringapiset.h>
|
||||
# include <winnls.h>
|
||||
#endif
|
||||
char * __syslocname__ = 0;
|
||||
char * __sysoemname__ = 0;
|
||||
char * __utf8name__ = 0;
|
||||
#ifdef BLACKBERRY
|
||||
# include <ctype.h>
|
||||
#endif
|
||||
#include <wchar.h>
|
||||
#ifdef ANDROID
|
||||
# if __ANDROID_API__ < 21
|
||||
# define wctomb(s, wc) wcrtomb(s, wc, NULL)
|
||||
# define mbtowc(pwc, s, n) mbrtowc(pwc, s, n, NULL)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*! \class PIChar
|
||||
* \brief Unicode char
|
||||
* \details This class is wrapper around \c "uint".
|
||||
* There are many contructors and information functions
|
||||
*/
|
||||
|
||||
|
||||
ushort charFromCodepage(const char * c, int size, const char * codepage, int * taken = 0) {
|
||||
if (!c || size <= 0) return 0;
|
||||
if (uchar(c[0]) < 0x80) return c[0];
|
||||
int ret;
|
||||
#ifdef PIP_ICU
|
||||
UErrorCode e((UErrorCode)0);
|
||||
UConverter * cc = ucnv_open(codepage, &e);
|
||||
if (cc) {
|
||||
UChar uc(0);
|
||||
e = (UErrorCode)0;
|
||||
ret = ucnv_toUChars(cc, &uc, 1, c, size, &e);
|
||||
//printf("PIChar %d -> %d\n", c[0], uc);
|
||||
if (taken) *taken = ret;
|
||||
ucnv_close(cc);
|
||||
return ushort(uc);
|
||||
}
|
||||
#else
|
||||
# ifdef WINDOWS
|
||||
wchar_t buffer;
|
||||
ret = MultiByteToWideChar((uint)(uintptr_t)codepage, MB_ERR_INVALID_CHARS, c, size, &buffer, 1);
|
||||
if (ret <= 0) return 0;
|
||||
if (taken) *taken = ret;
|
||||
return buffer;
|
||||
# else
|
||||
wchar_t wc(0);
|
||||
mbtowc(0, 0, 0); // reset mbtowc
|
||||
ret = mbtowc(&wc, c, size);
|
||||
//printf("mbtowc = %d\n", ret);
|
||||
if (ret < 1) return 0;
|
||||
return ushort(int(wc));
|
||||
# endif
|
||||
#endif
|
||||
return ushort(c[0]);
|
||||
}
|
||||
|
||||
|
||||
int charCompare(const PIChar & f, const PIChar & s) {
|
||||
if (f.isAscii() && s.isAscii())
|
||||
return strncmp(f.toCharPtr(), s.toCharPtr(), 1);
|
||||
return
|
||||
#ifdef PIP_ICU
|
||||
u_strCompare((const UChar*)f.toWCharPtr(), 1, (const UChar*)s.toWCharPtr(), 1, FALSE);
|
||||
#else
|
||||
# ifdef WINDOWS
|
||||
CompareStringW(LOCALE_USER_DEFAULT, 0, (PCNZWCH)f.toWCharPtr(), 1, (PCNZWCH)s.toWCharPtr(), 1) - 2;
|
||||
# else
|
||||
wcsncmp((const wchar_t *)f.toWCharPtr(), (const wchar_t *)s.toWCharPtr(), 1);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool winIsCharType(const ushort * ch, int type) {
|
||||
#ifdef WINDOWS
|
||||
WORD attr = 0;
|
||||
if (GetStringTypeW(CT_CTYPE1, (LPCWCH)ch, 1, &attr) == 0) return false;
|
||||
return ((attr & type) == type);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PIChar::PIChar(const char * c, int * bytes) {
|
||||
ch = charFromCodepage(c, 4, __syslocname__, bytes);
|
||||
}
|
||||
|
||||
|
||||
PIChar PIChar::fromConsole(char c) {
|
||||
PIChar ret;
|
||||
ret.ch = charFromCodepage(&c, 1, __sysoemname__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIChar PIChar::fromSystem(char c) {
|
||||
PIChar ret;
|
||||
ret.ch = charFromCodepage(&c, 1, __syslocname__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIChar PIChar::fromUTF8(const char * c) {
|
||||
PIChar ret;
|
||||
int l = 0;
|
||||
while (c[l] != '\0') ++l;
|
||||
ret.ch = charFromCodepage(c, l, __utf8name__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::operator ==(const PIChar & o) const {
|
||||
return ch == o.ch;
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::operator >(const PIChar & o) const {
|
||||
return charCompare(*this, o) > 0;
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::operator <(const PIChar & o) const {
|
||||
return charCompare(*this, o) < 0;
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::operator >=(const PIChar & o) const {
|
||||
return charCompare(*this, o) >= 0;
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::operator <=(const PIChar & o) const {
|
||||
return charCompare(*this, o) <= 0;
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::isDigit() const {
|
||||
if (isAscii()) return isdigit(ch) != 0;
|
||||
#ifdef WINDOWS
|
||||
return winIsCharType(&ch, C1_DIGIT);
|
||||
#else
|
||||
return iswdigit(ch) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::isHex() const {
|
||||
if (isAscii()) return isxdigit(ch) != 0;
|
||||
#ifdef WINDOWS
|
||||
return winIsCharType(&ch, C1_XDIGIT);
|
||||
#else
|
||||
return iswxdigit(ch) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::isGraphical() const {
|
||||
if (isAscii()) return isgraph(ch) != 0;
|
||||
#ifdef WINDOWS
|
||||
return !winIsCharType(&ch, C1_CNTRL);
|
||||
#else
|
||||
return iswgraph(ch) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::isControl() const {
|
||||
if (isAscii()) return iscntrl(ch) != 0;
|
||||
#ifdef WINDOWS
|
||||
return winIsCharType(&ch, C1_CNTRL);
|
||||
#else
|
||||
return iswcntrl(ch) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::isLower() const {
|
||||
if (isAscii()) return islower(ch) != 0;
|
||||
#ifdef WINDOWS
|
||||
return winIsCharType(&ch, C1_LOWER);
|
||||
#else
|
||||
return iswlower(ch) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::isUpper() const {
|
||||
if (isAscii()) return isupper(ch) != 0;
|
||||
#ifdef WINDOWS
|
||||
return winIsCharType(&ch, C1_UPPER);
|
||||
#else
|
||||
return iswupper(ch) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::isPrint() const {
|
||||
if (isAscii()) return isprint(ch) != 0;
|
||||
#ifdef WINDOWS
|
||||
return !winIsCharType(&ch, C1_CNTRL);
|
||||
#else
|
||||
return iswprint(ch) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::isSpace() const {
|
||||
if (isAscii()) return isspace(ch) != 0;
|
||||
#ifdef WINDOWS
|
||||
return winIsCharType(&ch, C1_SPACE);
|
||||
#else
|
||||
return iswspace(ch) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::isAlpha() const {
|
||||
if (isAscii()) return isalpha(ch) != 0;
|
||||
#ifdef WINDOWS
|
||||
return winIsCharType(&ch, C1_ALPHA);
|
||||
#else
|
||||
return iswalpha(ch) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PIChar::isAscii() const {
|
||||
return isascii(ch) != 0;
|
||||
}
|
||||
|
||||
|
||||
const wchar_t * PIChar::toWCharPtr() const {
|
||||
return reinterpret_cast<const wchar_t * >(&ch);
|
||||
}
|
||||
|
||||
|
||||
const char * PIChar::toCharPtr() const {
|
||||
return reinterpret_cast<const char * >(&ch);
|
||||
}
|
||||
|
||||
|
||||
wchar_t PIChar::toWChar() const {
|
||||
return wchar_t(ch);
|
||||
}
|
||||
|
||||
|
||||
char PIChar::toConsole1Byte() const {
|
||||
if (ch < 0x80) return ch;
|
||||
#ifdef PIP_ICU
|
||||
UErrorCode e((UErrorCode)0);
|
||||
UConverter * cc = ucnv_open(__sysoemname__, &e);
|
||||
if (cc) {
|
||||
char uc[8];
|
||||
e = (UErrorCode)0;
|
||||
ucnv_fromUChars(cc, uc, 8, (const UChar*)(&ch), 1, &e);
|
||||
ucnv_close(cc);
|
||||
return uc[0];
|
||||
}
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
char ret[4] = {0,0,0,0};
|
||||
WideCharToMultiByte(CP_OEMCP, 0, (LPCWCH)&ch, 1, ret, 4, NULL, NULL);
|
||||
return ret[0];
|
||||
#endif
|
||||
return toAscii();
|
||||
}
|
||||
|
||||
|
||||
char PIChar::toSystem() const {
|
||||
if (ch < 0x80) return ch;
|
||||
#ifdef PIP_ICU
|
||||
UErrorCode e((UErrorCode)0);
|
||||
UConverter * cc = ucnv_open(__syslocname__, &e);
|
||||
if (cc) {
|
||||
char uc[8];
|
||||
e = (UErrorCode)0;
|
||||
ucnv_fromUChars(cc, uc, 8, (const UChar*)(&ch), 1, &e);
|
||||
ucnv_close(cc);
|
||||
return uc[0];
|
||||
}
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
char ret[4] = {0,0,0,0};
|
||||
WideCharToMultiByte(CP_ACP, 0, (LPCWCH)&ch, 1, ret, 4, NULL, NULL);
|
||||
return ret[0];
|
||||
#endif
|
||||
return toAscii();
|
||||
}
|
||||
|
||||
|
||||
PIChar PIChar::toUpper() const {
|
||||
if (isAscii()) return PIChar(toupper(ch));
|
||||
#ifdef PIP_ICU
|
||||
UChar c(0);
|
||||
UErrorCode e((UErrorCode)0);
|
||||
u_strToUpper(&c, 1, (const UChar*)(&ch), 1, 0, &e);
|
||||
return PIChar(c);
|
||||
#else
|
||||
# ifdef WINDOWS
|
||||
ushort wc = 0;
|
||||
if (LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, (LPCWSTR)&ch, 1, (LPWSTR)&wc, 1) == 1)
|
||||
return PIChar(wc);
|
||||
# endif
|
||||
#endif
|
||||
return PIChar(towupper(ch));
|
||||
}
|
||||
|
||||
|
||||
PIChar PIChar::toLower() const {
|
||||
if (isAscii()) return PIChar(tolower(ch));
|
||||
#ifdef PIP_ICU
|
||||
UChar c(0);
|
||||
UErrorCode e((UErrorCode)0);
|
||||
u_strToLower(&c, 1, (const UChar*)(&ch), 1, 0, &e);
|
||||
return PIChar(c);
|
||||
#else
|
||||
# ifdef WINDOWS
|
||||
ushort wc = 0;
|
||||
if (LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, (LPCWSTR)&ch, 1, (LPWSTR)&wc, 1) == 1)
|
||||
return PIChar(wc);
|
||||
# endif
|
||||
#endif
|
||||
return PIChar(towlower(ch));
|
||||
}
|
||||
|
||||
|
||||
PICout operator <<(PICout s, const PIChar & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
if (v.isAscii()) s << char(v.ch);
|
||||
else {
|
||||
#ifdef PIP_ICU
|
||||
UErrorCode e((UErrorCode)0);
|
||||
UConverter * cc = ucnv_open(__syslocname__, &e);
|
||||
if (cc) {
|
||||
char uc[8];
|
||||
memset(uc, 0, 8);
|
||||
e = (UErrorCode)0;
|
||||
ucnv_fromUChars(cc, uc, 8, (const UChar*)(&v.ch), 1, &e);
|
||||
ucnv_close(cc);
|
||||
s << uc;
|
||||
} else
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
s << v.toSystem();
|
||||
#else
|
||||
{
|
||||
char tc[8];
|
||||
wctomb(0, 0);
|
||||
int sz = wctomb(tc, v.ch);
|
||||
for (int b = 0; b < sz; ++b)
|
||||
s << tc[b];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
187
lib/main/core/pichar.h
Normal file
187
lib/main/core/pichar.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/*! \file pichar.h
|
||||
* \brief Unicode char
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Unicode char
|
||||
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 PICHAR_H
|
||||
#define PICHAR_H
|
||||
|
||||
#include "piincludes.h"
|
||||
|
||||
extern char * __syslocname__;
|
||||
extern char * __sysoemname__;
|
||||
extern char * __utf8name__;
|
||||
|
||||
class PIP_EXPORT PIChar
|
||||
{
|
||||
friend class PIString;
|
||||
friend PIByteArray & operator <<(PIByteArray & s, const PIChar & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & s, PIChar & v);
|
||||
friend PICout operator <<(PICout s, const PIChar & v);
|
||||
public:
|
||||
//! Contructs ascii symbol
|
||||
PIChar(const char c) {ch = c; ch &= 0xFF;}
|
||||
|
||||
//! Contructs 2-bytes symbol
|
||||
PIChar(const short c) {ch = c;}
|
||||
|
||||
//! Contructs 4-bytes symbol
|
||||
PIChar(const int c) {ch = c;}
|
||||
|
||||
//! Contructs ascii symbol
|
||||
PIChar(const uchar c) {ch = c; ch &= 0xFF;}
|
||||
|
||||
//! Contructs 2-bytes symbol
|
||||
PIChar(const ushort c) {ch = c;}
|
||||
|
||||
//! Default constructor. Contructs 4-bytes symbol
|
||||
PIChar(const uint c = 0) {ch = c;}
|
||||
|
||||
//! Contructs symbol from no more than 4 bytes of string
|
||||
PIChar(const char * c, int * bytes = 0);
|
||||
|
||||
//! Copy operator
|
||||
PIChar & operator =(const char v) {ch = v; return *this;}
|
||||
|
||||
//! Compare operator
|
||||
bool operator ==(const PIChar & o) const;
|
||||
|
||||
//! Compare operator
|
||||
bool operator !=(const PIChar & o) const {return !(o == *this);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator >(const PIChar & o) const;
|
||||
|
||||
//! Compare operator
|
||||
bool operator <(const PIChar & o) const;
|
||||
|
||||
//! Compare operator
|
||||
bool operator >=(const PIChar & o) const;
|
||||
|
||||
//! Compare operator
|
||||
bool operator <=(const PIChar & o) const;
|
||||
|
||||
//! Return \b true if symbol is digit ('0' to '9')
|
||||
bool isDigit() const;
|
||||
|
||||
//! Return \b true if symbol is HEX digit ('0' to '9', 'a' to 'f', 'A' to 'F')
|
||||
bool isHex() const;
|
||||
|
||||
//! Return \b true if symbol is drawable (without space)
|
||||
bool isGraphical() const;
|
||||
|
||||
//! Return \b true if symbol is control byte (< 32 or 127)
|
||||
bool isControl() const;
|
||||
|
||||
//! Return \b true if symbol is in lower case
|
||||
bool isLower() const;
|
||||
|
||||
//! Return \b true if symbol is in upper case
|
||||
bool isUpper() const;
|
||||
|
||||
//! Return \b true if symbol is printable (with space)
|
||||
bool isPrint() const;
|
||||
|
||||
//! Return \b true if symbol is space or tab
|
||||
bool isSpace() const;
|
||||
|
||||
//! Return \b true if symbol is alphabetical letter
|
||||
bool isAlpha() const;
|
||||
|
||||
//! Return \b true if symbol is ascii (< 128)
|
||||
bool isAscii() const;
|
||||
|
||||
const wchar_t * toWCharPtr() const;
|
||||
|
||||
//! Return as <tt>"char * "</tt> string
|
||||
const char * toCharPtr() const;
|
||||
|
||||
wchar_t toWChar() const;
|
||||
char toAscii() const {return ch % 256;}
|
||||
char toConsole1Byte() const;
|
||||
char toSystem() const;
|
||||
ushort unicode16Code() const {return ch;}
|
||||
|
||||
//! Return symbol in upper case
|
||||
PIChar toUpper() const;
|
||||
|
||||
//! Return symbol in lower case
|
||||
PIChar toLower() const;
|
||||
|
||||
static PIChar fromConsole(char c);
|
||||
static PIChar fromSystem(char c);
|
||||
static PIChar fromUTF8(const char * c);
|
||||
|
||||
private:
|
||||
ushort ch;
|
||||
|
||||
};
|
||||
|
||||
//! Output operator to \a PICout
|
||||
PICout operator <<(PICout s, const PIChar & v);
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator ==(const char v, const PIChar & c) {return (PIChar(v) == c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator >(const char v, const PIChar & c) {return (PIChar(v) > c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator <(const char v, const PIChar & c) {return (PIChar(v) < c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator >=(const char v, const PIChar & c) {return (PIChar(v) >= c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator <=(const char v, const PIChar & c) {return (PIChar(v) <= c);}
|
||||
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator ==(const char * v, const PIChar & c) {return (PIChar(v) == c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator >(const char * v, const PIChar & c) {return (PIChar(v) > c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator <(const char * v, const PIChar & c) {return (PIChar(v) < c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator >=(const char * v, const PIChar & c) {return (PIChar(v) >= c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator <=(const char * v, const PIChar & c) {return (PIChar(v) <= c);}
|
||||
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator ==(const int v, const PIChar & c) {return (PIChar(v) == c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator >(const int v, const PIChar & c) {return (PIChar(v) > c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator <(const int v, const PIChar & c) {return (PIChar(v) < c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator >=(const int v, const PIChar & c) {return (PIChar(v) >= c);}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator <=(const int v, const PIChar & c) {return (PIChar(v) <= c);}
|
||||
|
||||
#endif // PICHAR_H
|
||||
148
lib/main/core/pichunkstream.cpp
Normal file
148
lib/main/core/pichunkstream.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Binary markup serializator
|
||||
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 "pichunkstream.h"
|
||||
|
||||
/*! \class PIChunkStream
|
||||
* \brief Class for binary serialization
|
||||
*
|
||||
* \section PIChunkStream_sec0 Synopsis
|
||||
* This class provides very handly mechanism to store and restore values to and from
|
||||
* \a PIByteArray. The main advantage of using this class is that your binary data
|
||||
* become independent from order and collection of your values.
|
||||
*
|
||||
* \section PIChunkStream_sec1 Mechanism
|
||||
* %PIChunkStream works with items called "chunk". Chunk is an ID and any value that
|
||||
* can be stored and restored to \a PIByteArray with stream operators << and >>.
|
||||
* You can place chunks to stream and read chunks from stream.
|
||||
*
|
||||
* To construct %PIChunkStream for writing data use any constructor. Empty constructor
|
||||
* creates internal empty buffer that can be accessed by function \a data().
|
||||
* Non-empty constructor works with given byte array.
|
||||
*
|
||||
* To read chunks from byte array use function \a read() that returns ID of
|
||||
* next chunk. Then you can get value of this chunk with function \a getData(),
|
||||
* but you should definitely know type of this value. You can read from byte array
|
||||
* while \a atEnd() if false.
|
||||
*
|
||||
* \section PIChunkStream_ex0 Example
|
||||
* Prepare your structs to work with %PIChunkStream
|
||||
* \snippet pichunkstream.cpp struct
|
||||
* Writing to %PIChunkStream
|
||||
* \snippet pichunkstream.cpp write
|
||||
* Reading from %PIChunkStream
|
||||
* \snippet pichunkstream.cpp read
|
||||
*/
|
||||
|
||||
|
||||
void PIChunkStream::setSource(const PIByteArray & data) {
|
||||
data_ = const_cast<PIByteArray*>(&data);
|
||||
_init();
|
||||
}
|
||||
|
||||
|
||||
void PIChunkStream::setSource(PIByteArray * data) {
|
||||
data_ = (data ? data : &tmp_data);
|
||||
_init();
|
||||
}
|
||||
|
||||
|
||||
int PIChunkStream::read() {
|
||||
switch (version_) {
|
||||
case Version_1:
|
||||
(*data_) >> last_id >> last_data;
|
||||
break;
|
||||
case Version_2:
|
||||
last_id = readVInt(*data_);
|
||||
last_data.resize(readVInt(*data_));
|
||||
//piCout << last_id << last_data.size();
|
||||
(*data_) >> PIByteArray::RawData(last_data.data(), last_data.size_s());
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return last_id;
|
||||
}
|
||||
|
||||
|
||||
void PIChunkStream::readAll() {
|
||||
data_map.clear();
|
||||
while (!atEnd()) {
|
||||
read();
|
||||
data_map[last_id] = last_data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIChunkStream::~PIChunkStream() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void PIChunkStream::_init() {
|
||||
last_id = -1;
|
||||
last_data.clear();
|
||||
if (!data_->isEmpty()) {
|
||||
uchar v = data_->at(0);
|
||||
if ((v & 0x80) == 0x80) {
|
||||
v &= 0x7f;
|
||||
switch (v) {
|
||||
case 2: version_ = (uchar)Version_2; data_->pop_front(); break;
|
||||
default: version_ = Version_1; break;
|
||||
}
|
||||
} else
|
||||
version_ = Version_1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint PIChunkStream::readVInt(PIByteArray & s) {
|
||||
if (s.isEmpty()) return 0;
|
||||
uchar bytes[4]; s >> bytes[0];
|
||||
uchar abc = 0;
|
||||
for (abc = 0; abc < 3; ++abc) {
|
||||
uchar mask = (0x80 >> abc);
|
||||
if ((bytes[0] & mask) == mask) {
|
||||
bytes[0] &= (mask - 1);
|
||||
s >> bytes[abc + 1];
|
||||
} else break;
|
||||
}
|
||||
uint ret = 0;
|
||||
for (int i = 0; i <= abc; ++i) {
|
||||
ret += (bytes[i] << (8 * ((int)abc - i)));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PIChunkStream::writeVInt(PIByteArray & s, uint val) {
|
||||
if (val > 0xfffffff) return;
|
||||
if (val <= 0x7f) {
|
||||
s << uchar(val);
|
||||
return;
|
||||
}
|
||||
if (val <= 0x3fff) {
|
||||
s << uchar((val >> 8) | 0x80) << uchar(val & 0xff);
|
||||
return;
|
||||
}
|
||||
if (val <= 0x1fffff) {
|
||||
s << uchar((val >> 16) | 0xc0) << uchar((val >> 8) & 0xff) << uchar(val & 0xff);
|
||||
return;
|
||||
}
|
||||
s << uchar((val >> 24) | 0xe0) << uchar((val >> 16) & 0xff) << uchar((val >> 8) & 0xff) << uchar(val & 0xff);
|
||||
}
|
||||
137
lib/main/core/pichunkstream.h
Normal file
137
lib/main/core/pichunkstream.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/*! \file pichunkstream.h
|
||||
* \brief Binary markup serializator
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Binary markup serializator
|
||||
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 PICHUNKSTREAM_H
|
||||
#define PICHUNKSTREAM_H
|
||||
|
||||
#include "pibytearray.h"
|
||||
|
||||
|
||||
class PIP_EXPORT PIChunkStream
|
||||
{
|
||||
public:
|
||||
|
||||
//! Version of data packing. Read-access %PIChunkStream automatic detect version, but write-access
|
||||
//! %PIChunkStream by default write in new version, be careful!
|
||||
enum Version {
|
||||
Version_1 /*! First, old version */,
|
||||
Version_2 /*! Second, more optimized version */ = 2,
|
||||
};
|
||||
|
||||
//! Contructs stream for read from "data"
|
||||
PIChunkStream(const PIByteArray & data): version_(Version_2) {setSource(data);}
|
||||
|
||||
//! Contructs stream for read or write to/from "data", or empty stream for write
|
||||
PIChunkStream(PIByteArray * data = 0, Version v = Version_2): version_(v) {setSource(data);}
|
||||
|
||||
//! Contructs empty stream for write with version \"v\"
|
||||
PIChunkStream(Version v): version_(v) {setSource(0);}
|
||||
|
||||
~PIChunkStream();
|
||||
|
||||
template <typename T>
|
||||
struct Chunk {
|
||||
Chunk(int i, const T & d): id(i), data(d) {}
|
||||
int id;
|
||||
T data;
|
||||
};
|
||||
|
||||
//! Returns chunk with ID "id" and value "data" for write to stream
|
||||
template <typename T> static Chunk<T> chunk(int id, const T & data) {return Chunk<T>(id, data);}
|
||||
|
||||
//! Add data to this chunk strean with ID "id" and value "data"
|
||||
template <typename T> PIChunkStream & add(int id, const T & data) {*this << Chunk<T>(id, data); return *this;}
|
||||
|
||||
void setSource(const PIByteArray & data);
|
||||
void setSource(PIByteArray * data);
|
||||
|
||||
//! Returns internal buffer with written data
|
||||
PIByteArray data() const {return tmp_data;}
|
||||
|
||||
//! Returns if there is end of stream
|
||||
bool atEnd() const {return data_->size_s() <= 1;}
|
||||
|
||||
//! Returns stream version
|
||||
Version version() const {return (Version)version_;}
|
||||
|
||||
|
||||
//! Read one chunk from stream and returns its ID
|
||||
int read();
|
||||
|
||||
//! Read all chunks from stream
|
||||
void readAll();
|
||||
|
||||
//! Returns last readed chunk ID
|
||||
int getID() {return last_id;}
|
||||
|
||||
//! Returns value of last readed chunk
|
||||
template <typename T>
|
||||
T getData() const {T ret; PIByteArray s(last_data); s >> ret; return ret;}
|
||||
|
||||
//! Place value of last readed chunk into \"v\"
|
||||
template <typename T>
|
||||
void get(T & v) const {v = getData<T>();}
|
||||
|
||||
//! Place value of chunk with id \"id\" into \"v\". You should call \a readAll() before using this function!
|
||||
template <typename T>
|
||||
const PIChunkStream & get(int id, T & v) const {
|
||||
PIByteArray ba = data_map.value(id);
|
||||
if (!ba.isEmpty())
|
||||
ba >> v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
void _init();
|
||||
|
||||
static uint readVInt(PIByteArray & s);
|
||||
static void writeVInt(PIByteArray & s, uint val);
|
||||
|
||||
int last_id;
|
||||
uchar version_;
|
||||
PIByteArray * data_, last_data, tmp_data;
|
||||
PIMap<int, PIByteArray> data_map;
|
||||
|
||||
template <typename T> friend PIChunkStream & operator <<(PIChunkStream & s, const PIChunkStream::Chunk<T> & c);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
PIChunkStream & operator <<(PIChunkStream & s, const PIChunkStream::Chunk<T> & c) {
|
||||
PIByteArray ba;
|
||||
ba << c.data;
|
||||
switch (s.version_) {
|
||||
case PIChunkStream::Version_1:
|
||||
(*(s.data_)) << c.id << ba;
|
||||
break;
|
||||
case PIChunkStream::Version_2:
|
||||
if (s.data_->isEmpty())
|
||||
(*(s.data_)) << uchar(uchar(s.version_) | 0x80);
|
||||
PIChunkStream::writeVInt(*(s.data_), c.id);
|
||||
PIChunkStream::writeVInt(*(s.data_), ba.size());
|
||||
s.data_->append(ba);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif // PICHUNKSTREAM_H
|
||||
101
lib/main/core/picli.cpp
Normal file
101
lib/main/core/picli.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
|
||||
/*! \class PICLI
|
||||
* \brief Command-line arguments parser
|
||||
*
|
||||
* \section PICLI_sec0 Synopsis
|
||||
* This class provide handy parsing of command-line arguments. First you should add
|
||||
* arguments to PICLI with function \a addArgument(). Then you can check if there
|
||||
* is some argument in application command-line with function \a hasArgument();
|
||||
* \section PICLI_sec1 Example
|
||||
* \snippet picli.cpp main
|
||||
*/
|
||||
|
||||
|
||||
PICLI::PICLI(int argc, char * argv[]) {
|
||||
setName("CLI");
|
||||
needParse = true;
|
||||
_prefix_short = "-";
|
||||
_prefix_full = "--";
|
||||
_count_opt = 0;
|
||||
_count_mand = 0;
|
||||
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);
|
||||
piForeach (Argument & a, _args) {
|
||||
if (a.full_key == full) {
|
||||
a.found = true;
|
||||
last = &a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (cra.left(1) == _prefix_short) {
|
||||
last = 0;
|
||||
for (int j = 1; j < cra.length(); ++j) {
|
||||
bool found = false;
|
||||
piForeach (Argument & a, _args) {
|
||||
if ((a.short_key != '\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 << "[PICli] Arguments overflow, \"" << cra << "\" ignored";
|
||||
}
|
||||
if (last == 0 ? false : last->has_value) {
|
||||
last->value = cra;
|
||||
last = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
needParse = false;
|
||||
}
|
||||
101
lib/main/core/picli.h
Normal file
101
lib/main/core/picli.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/*! \file picli.h
|
||||
* \brief Command-Line parser
|
||||
*/
|
||||
/*
|
||||
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 "piobject.h"
|
||||
|
||||
class PIP_EXPORT PICLI: public PIObject
|
||||
{
|
||||
PIOBJECT_SUBCLASS(PICLI, PIObject)
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
PICLI(int argc, char * argv[]);
|
||||
|
||||
|
||||
//! Add argument with name "name", short key = name first letter, full key = name
|
||||
void addArgument(const PIString & name, bool value = false) {_args << Argument(name, name[0], name, value); needParse = true;}
|
||||
|
||||
//! Add argument with name "name", short key = "shortKey", full key = name
|
||||
void addArgument(const PIString & name, const PIChar & shortKey, bool value = false) {_args << Argument(name, shortKey, name, value); needParse = true;}
|
||||
|
||||
//! Add argument with name "name", short key = "shortKey", full key = name
|
||||
void addArgument(const PIString & name, const char * shortKey, bool value = false) {_args << Argument(name, PIChar(shortKey), name, value); needParse = true;}
|
||||
|
||||
//! Add argument with name "name", short key = "shortKey", full key = "fullKey"
|
||||
void addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value = false) {_args << Argument(name, shortKey, fullKey, value); needParse = true;}
|
||||
|
||||
//! Add argument with name "name", short key = "shortKey", full key = "fullKey"
|
||||
void addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value = false) {_args << Argument(name, PIChar(shortKey), fullKey, value); needParse = true;}
|
||||
|
||||
|
||||
//! Returns unparsed command-line argument by index "index". Index 0 is program execute command.
|
||||
PIString rawArgument(int index) {parse(); return _args_raw[index];}
|
||||
PIString mandatoryArgument(int index) {parse(); return _args_mand[index];}
|
||||
PIString optionalArgument(int index) {parse(); return _args_opt[index];}
|
||||
|
||||
//! Returns unparsed command-line arguments
|
||||
const PIStringList & rawArguments() {parse(); return _args_raw;}
|
||||
const PIStringList & mandatoryArguments() {parse(); return _args_mand;}
|
||||
const PIStringList & optionalArguments() {parse(); return _args_opt;}
|
||||
|
||||
//! Returns program execute command without arguments
|
||||
PIString programCommand() {parse(); return _args_raw.size() > 0 ? _args_raw.front() : PIString();}
|
||||
bool hasArgument(const PIString & name) {parse(); piForeach (Argument & i, _args) if (i.name == name && i.found) return true; return false;}
|
||||
PIString argumentValue(const PIString & name) {parse(); piForeach (Argument &i, _args) if (i.name == name && i.found) return i.value; return PIString();}
|
||||
PIString argumentShortKey(const PIString & name) {piForeach (Argument &i, _args) if (i.name == name) return i.short_key; return PIString();}
|
||||
PIString argumentFullKey(const PIString & name) {piForeach (Argument &i, _args) if (i.name == name) return i.full_key; return PIString();}
|
||||
|
||||
const PIString & shortKeyPrefix() const {return _prefix_short;}
|
||||
const PIString & fullKeyPrefix() const {return _prefix_full;}
|
||||
int mandatoryArgumentsCount() const {return _count_mand;}
|
||||
int optionalArgumentsCount() const {return _count_opt;}
|
||||
void setShortKeyPrefix(const PIString & prefix) {_prefix_short = prefix; needParse = true;}
|
||||
void setFullKeyPrefix(const PIString & prefix) {_prefix_full = prefix; needParse = true;}
|
||||
void setMandatoryArgumentsCount(const int count) {_count_mand = count; needParse = true;}
|
||||
void setOptionalArgumentsCount(const int count) {_count_opt = count; needParse = true;}
|
||||
|
||||
private:
|
||||
struct Argument {
|
||||
Argument() {has_value = found = false;}
|
||||
Argument(const PIString & n, const PIChar & s, const PIString & f, bool v) {name = n; short_key = s; full_key = f; has_value = v; found = false;}
|
||||
PIString name;
|
||||
PIChar short_key;
|
||||
PIString full_key;
|
||||
PIString value;
|
||||
bool has_value, found;
|
||||
};
|
||||
|
||||
void parse();
|
||||
|
||||
PIString _prefix_short, _prefix_full;
|
||||
PIStringList _args_raw, _args_mand, _args_opt;
|
||||
PISet<PIString> keys_full, keys_short;
|
||||
PIVector<Argument> _args;
|
||||
int _count_mand, _count_opt;
|
||||
bool needParse;
|
||||
|
||||
};
|
||||
|
||||
#endif // PICLI_H
|
||||
84
lib/main/core/picollection.cpp
Normal file
84
lib/main/core/picollection.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Peer - named I/O ethernet node, forming self-organized peering network
|
||||
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 "picollection.h"
|
||||
|
||||
|
||||
/** \class PICollection
|
||||
* \brief Interface to discover element groups
|
||||
* \details
|
||||
* \section PICollection_sec0 Synopsis
|
||||
* This class has only static functions so no need to create instance of the
|
||||
* %PICollection. This class provide macros to add some classes or existing
|
||||
* objects to global collection and access to them from any place of the code.
|
||||
* \snippet picollection.cpp main
|
||||
* */
|
||||
|
||||
|
||||
PIStringList PICollection::groups() {
|
||||
PIStringList sl;
|
||||
PIVector<PICollection::Group> & cg(_groups());
|
||||
piForeachC (Group & g, cg)
|
||||
sl << g.name;
|
||||
return sl;
|
||||
}
|
||||
|
||||
|
||||
PIVector<const PIObject * > PICollection::groupElements(const PIString & group) {
|
||||
PIVector<PICollection::Group> & cg(_groups());
|
||||
piForeachC (Group & g, cg)
|
||||
if (g.name == group)
|
||||
return g.elements;
|
||||
return PIVector<const PIObject * >();
|
||||
}
|
||||
|
||||
|
||||
bool PICollection::addToGroup(const PIString & group, const PIObject * element) {
|
||||
//piCout << "add to" << group << element;
|
||||
PIString n = PIStringAscii(element->className());
|
||||
PIVector<PICollection::Group> & cg(_groups());
|
||||
piForeach (Group & g, cg)
|
||||
if (g.name == group) {
|
||||
for (int i = 0; i < g.elements.size_s(); ++i)
|
||||
if (PIString(g.elements[i]->className()) == n)
|
||||
return false;
|
||||
g.elements << element;
|
||||
//piCout << "new group" << group << ", ok";
|
||||
return true;
|
||||
}
|
||||
_groups() << Group(group);
|
||||
_groups().back().elements << element;
|
||||
//piCout << "new group" << group << ", ok";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PIVector<PICollection::Group> & PICollection::_groups() {
|
||||
static PIVector<PICollection::Group> ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PICollection::CollectionAdder::CollectionAdder(const PIString & group, const PIObject * element, const PIString & name, bool own) {
|
||||
if (!element) return;
|
||||
const_cast<PIObject * >(element)->setName(name);
|
||||
bool added = PICollection::addToGroup(group, element);
|
||||
if (!added && own)
|
||||
delete element;
|
||||
}
|
||||
83
lib/main/core/picollection.h
Normal file
83
lib/main/core/picollection.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*! \file picollection.h
|
||||
* \brief Custom elements collection
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Peer - named I/O ethernet node, forming self-organized peering network
|
||||
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 PICOLLECTION_H
|
||||
#define PICOLLECTION_H
|
||||
|
||||
#include "piobject.h"
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
/** \brief Add existing element "object" in group with name "group"
|
||||
* \relatesalso PICollection
|
||||
* \details If there is no group with name "group" it will be created.
|
||||
* Only one element of the class "object" can be in group "group". If
|
||||
* this is already exists nothing be happens. \n "object" should to
|
||||
* be pointer to object based on PIObject. */
|
||||
# define ADD_TO_COLLECTION(group, object)
|
||||
|
||||
/** \brief Add new element of class "class" in group with name "group"
|
||||
* \relatesalso PICollection
|
||||
* \details If there is no group with name "group" it will be created.
|
||||
* Only one element of the class "class" can be in group "group". If
|
||||
* this is already exists nothing be happens. \n "class" should to
|
||||
* be name of the any class based on PIObject. */
|
||||
# define ADD_NEW_TO_COLLECTION(group, class)
|
||||
|
||||
#else
|
||||
# define ADD_TO_COLLECTION(group, object) static PICollection::CollectionAdder __##group##_##__LINE__##_##adder##__(#group, object, false);
|
||||
# define ADD_TO_COLLECTION_WITH_NAME(group, object, name) static PICollection::CollectionAdder __##group##_##__LINE__##_##adder##__(#group, object, #name, false);
|
||||
# define ADD_NEW_TO_COLLECTION(group, class) static PICollection::CollectionAdder __##group##_##class##_##adder##__(#group, new class(), true);
|
||||
# define ADD_NEW_TO_COLLECTION_WITH_NAME(group, class, name) static PICollection::CollectionAdder __##group##_##class##_##adder##__(#group, new class(), #name, true);
|
||||
#endif
|
||||
|
||||
class PIP_EXPORT PICollection
|
||||
{
|
||||
friend class __PICollectionInitializer;
|
||||
public:
|
||||
PICollection() {;}
|
||||
|
||||
//! \brief Returns all existing groups by their names
|
||||
static PIStringList groups();
|
||||
|
||||
//! \brief Returns all elements of group "group"
|
||||
static PIVector<const PIObject * > groupElements(const PIString & group);
|
||||
|
||||
static bool addToGroup(const PIString & group, const PIObject * element);
|
||||
|
||||
class CollectionAdder {
|
||||
public:
|
||||
CollectionAdder(const PIString & group, const PIObject * element, const PIString & name = PIString(), bool own = false);
|
||||
};
|
||||
|
||||
protected:
|
||||
struct Group {
|
||||
Group(const PIString & name_ = PIString()) {name = name_;}
|
||||
PIString name;
|
||||
PIVector<const PIObject * > elements;
|
||||
};
|
||||
|
||||
static PIVector<Group> & _groups();
|
||||
|
||||
};
|
||||
|
||||
#endif // PICOLLECTION_H
|
||||
30
lib/main/core/picoremodule.h
Normal file
30
lib/main/core/picoremodule.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef PICOREMODULE_H
|
||||
#define PICOREMODULE_H
|
||||
|
||||
#include "picollection.h"
|
||||
#include "piobject.h"
|
||||
#include "pitime.h"
|
||||
#include "picli.h"
|
||||
#include "pichunkstream.h"
|
||||
#include "pipropertystorage.h"
|
||||
|
||||
#endif // PICOREMODULE_H
|
||||
548
lib/main/core/picout.cpp
Normal file
548
lib/main/core/picout.cpp
Normal file
@@ -0,0 +1,548 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Universal output to console class
|
||||
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 "picout.h"
|
||||
#include "piconsole.h"
|
||||
#include "pibytearray.h"
|
||||
#include "pistack.h"
|
||||
#include "pistring_std.h"
|
||||
#ifdef WINDOWS
|
||||
# include <windows.h>
|
||||
# include <wincon.h>
|
||||
# define COMMON_LVB_UNDERSCORE 0x8000
|
||||
#endif
|
||||
|
||||
/*! \class PICout
|
||||
* \brief Class for formatted output similar std::cout
|
||||
*
|
||||
* \section PICout_sec0 Synopsis
|
||||
* This class provide many stream operators for output with some features.
|
||||
* Output to PICout is thread-sequential, i.e. doesn`t mixed from parallel
|
||||
* threads.
|
||||
*
|
||||
* \section PICout_sec1 Features
|
||||
* - insertion spaces between entries
|
||||
* - insertion new line at the end of output
|
||||
* - strings are quoted
|
||||
* - custom output operator can be easily written
|
||||
*
|
||||
* \section PICout_ex0 Usage
|
||||
* \snippet picout.cpp 0
|
||||
*
|
||||
* \section PICout_ex1 Writing your own output operator
|
||||
* \snippet picout.cpp own
|
||||
*/
|
||||
|
||||
|
||||
/*! \class PICout::Notifier
|
||||
* \brief Class for emit notifications of PICout
|
||||
*
|
||||
* \section PICout_sec0 Synopsis
|
||||
* This class used as PICout events emitter. When
|
||||
* PICout constructs with external PIString* buffer
|
||||
* and some id, last copy of this PICout on delete
|
||||
* emit event "finished()" on object Notifier::object().
|
||||
* Sample:
|
||||
* \snippet picout.cpp notifier
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
class NotifierObject: public PIObject {
|
||||
PIOBJECT(NotifierObject)
|
||||
public:
|
||||
NotifierObject() {}
|
||||
EVENT2(finished, int, id, PIString*, buffer)
|
||||
};
|
||||
|
||||
|
||||
|
||||
PICout::Notifier::Notifier() {
|
||||
o = new NotifierObject();
|
||||
}
|
||||
|
||||
|
||||
PICout::Notifier * PICout::Notifier::instance() {
|
||||
static PICout::Notifier * ret = new PICout::Notifier();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIObject * PICout::Notifier::object() {
|
||||
return instance()->o;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
using namespace PICoutManipulators;
|
||||
|
||||
PIMutex & PICout::__mutex__() {static PIMutex * ret = new PIMutex(); return *ret;}
|
||||
PIString & PICout::__string__() {static PIString * ret = new PIString(); return *ret;}
|
||||
|
||||
PICout::OutputDevices PICout::devs = PICout::StdOut;
|
||||
|
||||
PRIVATE_DEFINITION_START(PICout)
|
||||
PIStack<PICoutControls> cos_;
|
||||
#ifdef WINDOWS
|
||||
static void * hOut;
|
||||
static WORD dattr;
|
||||
static DWORD smode;
|
||||
#endif
|
||||
PRIVATE_DEFINITION_END(PICout)
|
||||
|
||||
#ifdef WINDOWS
|
||||
void * PICout::__Private__::hOut = 0;
|
||||
WORD PICout::__Private__::dattr = 0;
|
||||
DWORD PICout::__Private__::smode = 0;
|
||||
#endif
|
||||
|
||||
PICout::PICout(PIFlags<PICoutControl> controls): fo_(true), cc_(false), fc_(false), act_(true), cnb_(10), co_(controls) {
|
||||
init();
|
||||
}
|
||||
|
||||
PICout::PICout(PICoutControl control): fo_(true), cc_(false), fc_(false), act_(true), cnb_(10), co_(control) {
|
||||
init();
|
||||
}
|
||||
|
||||
PICout::PICout(bool active): fo_(true), cc_(false), fc_(false), act_(active), cnb_(10), co_(PICoutManipulators::DefaultControls) {
|
||||
if (act_)
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
PICout::PICout(PIString * buffer, int id, PIFlags<PICoutManipulators::PICoutControl> controls): fo_(true), cc_(false),
|
||||
fc_(false), act_(true), cnb_(10), co_(controls) {
|
||||
init();
|
||||
buffer_ = buffer;
|
||||
id_ = id;
|
||||
}
|
||||
|
||||
|
||||
PICout::PICout(const PICout & other): fo_(other.fo_), cc_(true), fc_(false), act_(other.act_), cnb_(other.cnb_), attr_(other.attr_),
|
||||
id_(other.id_), buffer_(other.buffer_), co_(other.co_) {
|
||||
}
|
||||
|
||||
|
||||
PICout::~PICout() {
|
||||
if (!act_) return;
|
||||
if (fc_) applyFormat(PICoutManipulators::Default);
|
||||
if (cc_) return;
|
||||
newLine();
|
||||
if ((co_ & NoLock) != NoLock)
|
||||
PICout::__mutex__().unlock();
|
||||
if (buffer_)
|
||||
((NotifierObject*)Notifier::object())->finished(id_, buffer_);
|
||||
}
|
||||
|
||||
|
||||
PICout PICout::operator <<(const PICoutAction v) {
|
||||
if (!act_) return *this;
|
||||
#ifdef WINDOWS
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
COORD coord;
|
||||
CONSOLE_CURSOR_INFO curinfo;
|
||||
#endif
|
||||
switch (v) {
|
||||
case PICoutManipulators::Flush:
|
||||
if (!buffer_ && isOutputDeviceActive(StdOut))
|
||||
std::cout << std::flush;
|
||||
break;
|
||||
case PICoutManipulators::Backspace:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
||||
coord = sbi.dwCursorPosition;
|
||||
coord.X = piMax<int>(0, int(coord.X) - 1);
|
||||
SetConsoleCursorPosition(__Private__::hOut, coord);
|
||||
printf(" ");
|
||||
SetConsoleCursorPosition(__Private__::hOut, coord);
|
||||
#else
|
||||
printf("\e[1D \e[1D");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::ShowCursor:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleCursorInfo(__Private__::hOut, &curinfo);
|
||||
curinfo.bVisible = true;
|
||||
SetConsoleCursorInfo(__Private__::hOut, &curinfo);
|
||||
#else
|
||||
printf("\e[?25h");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::HideCursor:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleCursorInfo(__Private__::hOut, &curinfo);
|
||||
curinfo.bVisible = false;
|
||||
SetConsoleCursorInfo(__Private__::hOut, &curinfo);
|
||||
#else
|
||||
printf("\e[?25l");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::ClearLine:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
#ifdef WINDOWS
|
||||
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
||||
coord = sbi.dwCursorPosition;
|
||||
int dx = coord.X;
|
||||
coord.X = 0;
|
||||
SetConsoleCursorPosition(__Private__::hOut, coord);
|
||||
if (dx > 0) {
|
||||
char * line = new char[dx + 1];
|
||||
memset(line, ' ', dx);
|
||||
line[dx] = 0;
|
||||
printf("%s", line);
|
||||
delete[] line;
|
||||
}
|
||||
SetConsoleCursorPosition(__Private__::hOut, coord);
|
||||
#else
|
||||
printf("\e[0G\e[K");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::ClearScreen:
|
||||
if (isOutputDeviceActive(StdOut)) {
|
||||
#ifdef WINDOWS
|
||||
/// TODO : wondows ClearScreen !!!
|
||||
#else
|
||||
printf("\e[H\e[J");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::SaveContol: saveControl(); break;
|
||||
case PICoutManipulators::RestoreControl: restoreControl(); break;
|
||||
default: break;
|
||||
};
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
#define PICOUTTOTARGET(v) { \
|
||||
if (buffer_) {\
|
||||
(*buffer_) << (v);\
|
||||
} else {\
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v);\
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() << (v);\
|
||||
}\
|
||||
}
|
||||
#define PICOUTTOTARGETS(v) { \
|
||||
if (buffer_) {\
|
||||
(*buffer_) << (v);\
|
||||
} else {\
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v).dataConsole();\
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() << (v);\
|
||||
}\
|
||||
}
|
||||
#define PINUMERICCOUT if (cnb_ == 10) PICOUTTOTARGET(v) else PICOUTTOTARGETS(PIString::fromNumber(v, cnb_))
|
||||
|
||||
|
||||
PICout PICout::operator <<(const char * v) {if (!act_) return *this; if (v[0] == '\0') return *this; space(); quote(); PICOUTTOTARGET(v) quote(); return *this;}
|
||||
|
||||
PICout PICout::operator <<(const bool v) {if (!act_) return *this; space(); if (v) PICOUTTOTARGET("true") else PICOUTTOTARGET("false") return *this;}
|
||||
|
||||
PICout PICout::operator <<(const char v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
|
||||
|
||||
PICout PICout::operator <<(const uchar v) {if (!act_) return *this; space(); if (cnb_ == 10) PICOUTTOTARGET(ushort(v)) else PICOUTTOTARGETS(PIString::fromNumber(v, cnb_)) return *this;}
|
||||
|
||||
PICout PICout::operator <<(const short int v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const ushort v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const int v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const uint v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const long v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const ulong v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const llong v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const ullong v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
|
||||
|
||||
PICout PICout::operator <<(const float v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
|
||||
|
||||
PICout PICout::operator <<(const double v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
|
||||
|
||||
PICout PICout::operator <<(const void * v) {if (!act_) return *this; space(); PICOUTTOTARGET("0x") PICOUTTOTARGETS(PIString::fromNumber(ullong(v), 16)) return *this;}
|
||||
|
||||
PICout PICout::operator <<(const PIObject * v) {
|
||||
if (!act_) return *this;
|
||||
space();
|
||||
if (v == 0) PICOUTTOTARGET("PIObject*(0x0)")
|
||||
else {
|
||||
PICOUTTOTARGET(v->className())
|
||||
PICOUTTOTARGET("*(0x")
|
||||
PICOUTTOTARGETS(PIString::fromNumber(ullong(v), 16))
|
||||
PICOUTTOTARGET(", \"")
|
||||
PICOUTTOTARGET(v->name())
|
||||
PICOUTTOTARGET("\")")
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
PICout PICout::operator <<(const PICoutSpecialChar v) {
|
||||
if (!act_) return *this;
|
||||
switch (v) {
|
||||
case Null:
|
||||
if (buffer_) {
|
||||
(*buffer_) << PIChar(0);
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << char(0);
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << PIChar(0);
|
||||
}
|
||||
break;
|
||||
case NewLine:
|
||||
if (buffer_) {
|
||||
(*buffer_) << "\n";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '\n';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\n";
|
||||
}
|
||||
fo_ = true;
|
||||
break;
|
||||
case Tab:
|
||||
if (buffer_) {
|
||||
(*buffer_) << "\t";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '\t';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\t";
|
||||
}
|
||||
break;
|
||||
case Esc:
|
||||
#ifdef CC_VC
|
||||
if (buffer_) {
|
||||
(*buffer_) << PIChar(27);
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << char(27);
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << PIChar(27);
|
||||
}
|
||||
#else
|
||||
if (buffer_) {
|
||||
(*buffer_) << "\e";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '\e';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\e";
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case Quote:
|
||||
if (buffer_) {
|
||||
(*buffer_) << "\"";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '"';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\"";
|
||||
}
|
||||
break;
|
||||
};
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::saveControl() {
|
||||
if (!act_) return *this;
|
||||
PRIVATE->cos_.push(co_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::restoreControl() {
|
||||
if (!act_) return *this;
|
||||
if (!PRIVATE->cos_.isEmpty()) {
|
||||
co_ = PRIVATE->cos_.top();
|
||||
PRIVATE->cos_.pop();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
#undef PICOUTTOTARGET
|
||||
#undef PINUMERICCOUT
|
||||
|
||||
PICout & PICout::space() {
|
||||
if (!act_) return *this;
|
||||
if (!fo_ && co_[AddSpaces]) {
|
||||
if (buffer_) {
|
||||
(*buffer_) << " ";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << ' ';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << " ";
|
||||
}
|
||||
}
|
||||
fo_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PICout & PICout::quote() {
|
||||
if (!act_) return *this;
|
||||
if (co_[AddQuotes]) {
|
||||
if (buffer_) {
|
||||
(*buffer_) << "\"";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '"';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\"";
|
||||
}
|
||||
}
|
||||
fo_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PICout & PICout::newLine() {
|
||||
if (!act_) return *this;
|
||||
if (co_[AddNewLine]) {
|
||||
if (buffer_) {
|
||||
(*buffer_) << "\n";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << std::endl;
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\n";
|
||||
}
|
||||
}
|
||||
fo_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void PICout::init() {
|
||||
#ifdef WINDOWS
|
||||
if (__Private__::hOut == 0) {
|
||||
__Private__::hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
|
||||
__Private__::dattr = sbi.wAttributes;
|
||||
}
|
||||
attr_ = __Private__::dattr;
|
||||
#endif
|
||||
buffer_ = 0;
|
||||
id_ = 0;
|
||||
if ((co_ & NoLock) != NoLock)
|
||||
PICout::__mutex__().lock();
|
||||
}
|
||||
|
||||
|
||||
void PICout::applyFormat(PICoutFormat f) {
|
||||
if (!act_) return;
|
||||
if (buffer_ || !isOutputDeviceActive(StdOut)) return;
|
||||
fc_ = true;
|
||||
#ifdef WINDOWS
|
||||
static int mask_fore = ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
static int mask_back = ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
|
||||
switch (f) {
|
||||
case Bin: case Oct: case Dec: case Hex: break;
|
||||
case PICoutManipulators::Bold: attr_ |= FOREGROUND_INTENSITY; break;
|
||||
case PICoutManipulators::Underline: attr_ |= COMMON_LVB_UNDERSCORE; break;
|
||||
case PICoutManipulators::Black: attr_ = (attr_ & mask_fore); break;
|
||||
case PICoutManipulators::Red: attr_ = (attr_ & mask_fore) | FOREGROUND_RED; break;
|
||||
case PICoutManipulators::Green: attr_ = (attr_ & mask_fore) | FOREGROUND_GREEN; break;
|
||||
case PICoutManipulators::Blue: attr_ = (attr_ & mask_fore) | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::Yellow: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN; break;
|
||||
case PICoutManipulators::Magenta: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::Cyan: attr_ = (attr_ & mask_fore) | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::White: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackBlack: attr_ = (attr_ & mask_back); break;
|
||||
case PICoutManipulators::BackRed: attr_ = (attr_ & mask_back) | BACKGROUND_RED; break;
|
||||
case PICoutManipulators::BackGreen: attr_ = (attr_ & mask_back) | BACKGROUND_GREEN; break;
|
||||
case PICoutManipulators::BackBlue: attr_ = (attr_ & mask_back) | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackYellow: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN; break;
|
||||
case PICoutManipulators::BackMagenta: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackCyan: attr_ = (attr_ & mask_back) | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::BackWhite: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
|
||||
case PICoutManipulators::Default: attr_ = __Private__::dattr; break;
|
||||
default: break;
|
||||
}
|
||||
SetConsoleTextAttribute(__Private__::hOut, attr_);
|
||||
#else
|
||||
switch (f) {
|
||||
case Bin: case Oct: case Dec: case Hex: break;
|
||||
case PICoutManipulators::Bold: printf("\e[1m"); break;
|
||||
case PICoutManipulators::Faint: printf("\e[2m"); break;
|
||||
case PICoutManipulators::Italic: printf("\e[3m"); break;
|
||||
case PICoutManipulators::Underline: printf("\e[4m"); break;
|
||||
case PICoutManipulators::Blink: printf("\e[5m"); break;
|
||||
case PICoutManipulators::Black: printf("\e[30m"); break;
|
||||
case PICoutManipulators::Red: printf("\e[31m"); break;
|
||||
case PICoutManipulators::Green: printf("\e[32m"); break;
|
||||
case PICoutManipulators::Blue: printf("\e[34m"); break;
|
||||
case PICoutManipulators::Yellow: printf("\e[33m"); break;
|
||||
case PICoutManipulators::Magenta: printf("\e[35m"); break;
|
||||
case PICoutManipulators::Cyan: printf("\e[36m"); break;
|
||||
case PICoutManipulators::White: printf("\e[37m"); break;
|
||||
case PICoutManipulators::BackBlack: printf("\e[40m"); break;
|
||||
case PICoutManipulators::BackRed: printf("\e[41m"); break;
|
||||
case PICoutManipulators::BackGreen: printf("\e[42m"); break;
|
||||
case PICoutManipulators::BackBlue: printf("\e[44m"); break;
|
||||
case PICoutManipulators::BackYellow: printf("\e[43m"); break;
|
||||
case PICoutManipulators::BackMagenta: printf("\e[45m"); break;
|
||||
case PICoutManipulators::BackCyan: printf("\e[46m"); break;
|
||||
case PICoutManipulators::BackWhite: printf("\e[47m"); break;
|
||||
case PICoutManipulators::Default: printf("\e[0m"); break;
|
||||
default: break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PICout::setBufferActive(bool on, bool clear) {
|
||||
PIMutexLocker ml(PICout::__mutex__());
|
||||
bool ret = isBufferActive();
|
||||
if (clear) PICout::__string__().clear();
|
||||
setOutputDevice(Buffer, on);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PICout::isBufferActive() {
|
||||
return isOutputDeviceActive(Buffer);
|
||||
}
|
||||
|
||||
|
||||
PIString PICout::buffer(bool clear) {
|
||||
PIMutexLocker ml(PICout::__mutex__());
|
||||
PIString ret = PICout::__string__();
|
||||
if (clear) PICout::__string__().clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PICout::clearBuffer() {
|
||||
PIMutexLocker ml(PICout::__mutex__());
|
||||
PICout::__string__().clear();
|
||||
}
|
||||
|
||||
|
||||
bool PICout::setOutputDevice(PICout::OutputDevice d, bool on) {
|
||||
bool ret = devs[d];
|
||||
devs.setFlag(d, on);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PICout::setOutputDevices(PICout::OutputDevices d) {
|
||||
devs = d;
|
||||
}
|
||||
|
||||
|
||||
bool PICout::isOutputDeviceActive(PICout::OutputDevice d) {
|
||||
return devs[d];
|
||||
}
|
||||
301
lib/main/core/picout.h
Normal file
301
lib/main/core/picout.h
Normal file
@@ -0,0 +1,301 @@
|
||||
/*! \file picout.h
|
||||
* \brief Universal output to console class
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Universal output to console class
|
||||
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 PICOUT_H
|
||||
#define PICOUT_H
|
||||
|
||||
#include "piincludes.h"
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
//! \brief Macro used for conditional (piDebug) output to PICout
|
||||
# define piCout
|
||||
|
||||
//! \relatesalso PIObject \brief Macro used for conditional (piDebug and PIObject::debug()) output to PICout for subclasses of PIObject
|
||||
# define piCoutObj
|
||||
|
||||
#else
|
||||
# define piCout PICout(piDebug)
|
||||
# define piCoutObj PICout(piDebug && debug()) << (PIStringAscii("[") + className() + PIStringAscii(" \"") + name() + PIStringAscii("\"]"))
|
||||
#endif
|
||||
|
||||
|
||||
class PIObject;
|
||||
|
||||
|
||||
//! \brief Namespace contains enums controlled PICout
|
||||
namespace PICoutManipulators {
|
||||
|
||||
//! \brief Enum contains special characters
|
||||
enum PIP_EXPORT PICoutSpecialChar {
|
||||
Null /*! Null-character, '\\0' */,
|
||||
NewLine /*! New line character, '\\n' */,
|
||||
Tab /*! Tab character, '\\t' */,
|
||||
Esc /*! Escape character, '\\e' */,
|
||||
Quote /*! Quote character, '"' */
|
||||
};
|
||||
|
||||
//! \brief Enum contains immediate action
|
||||
enum PIP_EXPORT PICoutAction {
|
||||
Flush /*! Flush the output */,
|
||||
Backspace /*! Remove last symbol */,
|
||||
ShowCursor /*! Show cursor */,
|
||||
HideCursor /*! Hide cursor */,
|
||||
ClearLine /*! Clear current line */,
|
||||
ClearScreen /*! Clear the screen */,
|
||||
SaveContol /*! Save control flags, equivalent to \a saveControl() */,
|
||||
RestoreControl /*! Restore control flags, equivalent to \a restoreControl() */
|
||||
};
|
||||
|
||||
//! \brief Enum contains control of PICout
|
||||
enum PIP_EXPORT PICoutControl {
|
||||
AddNone /*! No controls */ = 0x0,
|
||||
AddSpaces /*! Spaces will be appear after each output */ = 0x1,
|
||||
AddNewLine /*! New line will be appear after all output */ = 0x2,
|
||||
AddQuotes /*! Each string will be quoted */ = 0x4,
|
||||
DefaultControls /*! Default controls */ = AddSpaces | AddNewLine,
|
||||
AddAll /*! All controls */ = 0xFF,
|
||||
NoLock /*! Don`t use mutex for output */ = 0x100,
|
||||
};
|
||||
|
||||
//! \brief Enum contains output format
|
||||
enum PIP_EXPORT PICoutFormat {
|
||||
Bin /*! Binary representation of integers */ = 0x01,
|
||||
Oct /*! Octal representation of integers */ = 0x02,
|
||||
Dec /*! Decimal representation of integers */ = 0x04,
|
||||
Hex /*! Hexadecimal representation of integers */ = 0x08,
|
||||
Bold /*! Bold */ = 0x10,
|
||||
Faint /*! */ = 0x20,
|
||||
Italic /*! */ = 0x40,
|
||||
Underline /*! Underline */ = 0x80,
|
||||
Blink /*! Blink */ = 0x100,
|
||||
Black /*! Black font */ = 0x400,
|
||||
Red /*! Red font */ = 0x800,
|
||||
Green /*! Green font */ = 0x1000,
|
||||
Blue /*! Blue font */ = 0x2000,
|
||||
Yellow /*! Yellow font */ = 0x4000,
|
||||
Magenta /*! Magenta font */ = 0x8000,
|
||||
Cyan /*! Cyan font */ = 0x10000,
|
||||
White /*! White font */ = 0x20000,
|
||||
BackBlack /*! Black background */ = 0x40000,
|
||||
BackRed /*! Red background */ = 0x80000,
|
||||
BackGreen /*! Green background */ = 0x100000,
|
||||
BackBlue /*! Blue background */ = 0x200000,
|
||||
BackYellow /*! Yellow background */ = 0x400000,
|
||||
BackMagenta /*! Magenta background */ = 0x800000,
|
||||
BackCyan /*! Cyan background */ = 0x1000000,
|
||||
BackWhite /*! White background */ = 0x2000000,
|
||||
Default /*! Default format */ = 0x4000000
|
||||
};
|
||||
|
||||
typedef PIFlags<PICoutControl> PICoutControls;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class PIP_EXPORT PICout {
|
||||
public:
|
||||
//! Default constructor with default features (AddSpaces and AddNewLine)
|
||||
PICout(PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::DefaultControls);
|
||||
PICout(PICoutManipulators::PICoutControl control = PICoutManipulators::DefaultControls);
|
||||
|
||||
//! Construct with default features (AddSpaces and AddNewLine), but if \"active\" is false does nothing
|
||||
PICout(bool active);
|
||||
|
||||
//! Construct with external buffer and id "id". See \a Notifier for details
|
||||
PICout(PIString * buffer, int id = 0, PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces | PICoutManipulators::AddNewLine);
|
||||
|
||||
PICout(const PICout & other);
|
||||
|
||||
~PICout();
|
||||
|
||||
class Notifier {
|
||||
public:
|
||||
static Notifier * instance();
|
||||
static PIObject * object();
|
||||
private:
|
||||
Notifier();
|
||||
PIObject * o;
|
||||
};
|
||||
|
||||
//! \brief Enum contains output devices of PICout
|
||||
enum OutputDevice {
|
||||
NoDevices /** PICout is disabled */ = 0x0,
|
||||
StdOut /** Standard console output */ = 0x1,
|
||||
Buffer /** Internal buffer */ = 0x2,
|
||||
AllDevices /** All */ = 0xFFFF,
|
||||
};
|
||||
|
||||
typedef PIFlags<OutputDevice> OutputDevices;
|
||||
|
||||
//! Output operator for strings with <tt>"const char * "</tt> type
|
||||
PICout operator <<(const char * v);
|
||||
|
||||
//! Output operator for strings with <tt>"std::string"</tt> type
|
||||
//PICout operator <<(const std::string & v);
|
||||
|
||||
//! Output operator for boolean values
|
||||
PICout operator <<(const bool v);
|
||||
|
||||
//! Output operator for <tt>"char"</tt> values
|
||||
PICout operator <<(const char v);
|
||||
|
||||
//! Output operator for <tt>"unsigned char"</tt> values
|
||||
PICout operator <<(const uchar v);
|
||||
|
||||
//! Output operator for <tt>"short"</tt> values
|
||||
PICout operator <<(const short v);
|
||||
|
||||
//! Output operator for <tt>"unsigned short"</tt> values
|
||||
PICout operator <<(const ushort v);
|
||||
|
||||
//! Output operator for <tt>"int"</tt> values
|
||||
PICout operator <<(const int v);
|
||||
|
||||
//! Output operator for <tt>"unsigned int"</tt> values
|
||||
PICout operator <<(const uint v);
|
||||
|
||||
//! Output operator for <tt>"long"</tt> values
|
||||
PICout operator <<(const long v);
|
||||
|
||||
//! Output operator for <tt>"unsigned long"</tt> values
|
||||
PICout operator <<(const ulong v);
|
||||
|
||||
//! Output operator for <tt>"long long"</tt> values
|
||||
PICout operator <<(const llong v);
|
||||
|
||||
//! Output operator for <tt>"unsigned long long"</tt> values
|
||||
PICout operator <<(const ullong v);
|
||||
|
||||
//! Output operator for <tt>"float"</tt> values
|
||||
PICout operator <<(const float v);
|
||||
|
||||
//! Output operator for <tt>"double"</tt> values
|
||||
PICout operator <<(const double v);
|
||||
|
||||
//! Output operator for pointers
|
||||
PICout operator <<(const void * v);
|
||||
|
||||
//! Output operator for PIObject and ancestors
|
||||
PICout operator <<(const PIObject * v);
|
||||
|
||||
//! Output operator for \a PICoutSpecialChar values
|
||||
PICout operator <<(const PICoutManipulators::PICoutSpecialChar v);
|
||||
|
||||
//! Output operator for \a PIFlags<PICoutFormat> values
|
||||
PICout operator <<(const PIFlags<PICoutManipulators::PICoutFormat> & v) {
|
||||
if (v[PICoutManipulators::Bin]) cnb_ = 2;
|
||||
if (v[PICoutManipulators::Oct]) cnb_ = 8;
|
||||
if (v[PICoutManipulators::Dec]) cnb_ = 10;
|
||||
if (v[PICoutManipulators::Hex]) cnb_ = 16;
|
||||
if (v[PICoutManipulators::Bold]) applyFormat(PICoutManipulators::Bold);
|
||||
if (v[PICoutManipulators::Faint]) applyFormat(PICoutManipulators::Faint);
|
||||
if (v[PICoutManipulators::Italic]) applyFormat(PICoutManipulators::Italic);
|
||||
if (v[PICoutManipulators::Underline]) applyFormat(PICoutManipulators::Underline);
|
||||
if (v[PICoutManipulators::Blink]) applyFormat(PICoutManipulators::Blink);
|
||||
if (v[PICoutManipulators::Black]) applyFormat(PICoutManipulators::Black);
|
||||
if (v[PICoutManipulators::Red]) applyFormat(PICoutManipulators::Red);
|
||||
if (v[PICoutManipulators::Green]) applyFormat(PICoutManipulators::Green);
|
||||
if (v[PICoutManipulators::Blue]) applyFormat(PICoutManipulators::Blue);
|
||||
if (v[PICoutManipulators::Yellow]) applyFormat(PICoutManipulators::Yellow);
|
||||
if (v[PICoutManipulators::Magenta]) applyFormat(PICoutManipulators::Magenta);
|
||||
if (v[PICoutManipulators::Cyan]) applyFormat(PICoutManipulators::Cyan);
|
||||
if (v[PICoutManipulators::White]) applyFormat(PICoutManipulators::White);
|
||||
if (v[PICoutManipulators::BackBlack]) applyFormat(PICoutManipulators::BackBlack);
|
||||
if (v[PICoutManipulators::BackRed]) applyFormat(PICoutManipulators::BackRed);
|
||||
if (v[PICoutManipulators::BackGreen]) applyFormat(PICoutManipulators::BackGreen);
|
||||
if (v[PICoutManipulators::BackBlue]) applyFormat(PICoutManipulators::BackBlue);
|
||||
if (v[PICoutManipulators::BackYellow]) applyFormat(PICoutManipulators::BackYellow);
|
||||
if (v[PICoutManipulators::BackMagenta]) applyFormat(PICoutManipulators::BackMagenta);
|
||||
if (v[PICoutManipulators::BackCyan]) applyFormat(PICoutManipulators::BackCyan);
|
||||
if (v[PICoutManipulators::BackWhite]) applyFormat(PICoutManipulators::BackWhite);
|
||||
if (v[PICoutManipulators::Default]) applyFormat(PICoutManipulators::Default);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Output operator for \a PICoutFormat values
|
||||
PICout operator <<(const PICoutManipulators::PICoutFormat v) {
|
||||
switch (v) {
|
||||
case PICoutManipulators::Bin: cnb_ = 2; break;
|
||||
case PICoutManipulators::Oct: cnb_ = 8; break;
|
||||
case PICoutManipulators::Dec: cnb_ = 10; break;
|
||||
case PICoutManipulators::Hex: cnb_ = 16; break;
|
||||
default: applyFormat(v);
|
||||
};
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Do some action
|
||||
PICout operator <<(const PICoutManipulators::PICoutAction v);
|
||||
|
||||
//! Set control flag "c" is "on" state
|
||||
PICout & setControl(PICoutManipulators::PICoutControl c, bool on = true) {co_.setFlag(c, on); return *this;}
|
||||
|
||||
//! Set control flags "c" and if "save" exec \a saveControl()
|
||||
PICout & setControl(PICoutManipulators::PICoutControls c, bool save = false) {if (save) saveControl(); co_ = c; return *this;}
|
||||
|
||||
//! Save control flags to internal stack \sa \a restoreControl()
|
||||
PICout & saveControl();
|
||||
|
||||
//! Restore control flags from internal stack \sa \a saveControl()
|
||||
PICout & restoreControl();
|
||||
|
||||
/*! \brief Conditional put space character to output
|
||||
* \details If it is not a first output and control \a AddSpaces is set
|
||||
* space character is put \sa \a quote(), \a newLine() */
|
||||
PICout & space();
|
||||
|
||||
/*! \brief Conditional put quote character to output
|
||||
* \details If control \a AddQuotes is set
|
||||
* quote character is put \sa \a space(), \a newLine() */
|
||||
PICout & quote();
|
||||
|
||||
/*! \brief Conditional put new line character to output
|
||||
* \details If control \a AddNewLine is set
|
||||
* new line character is put \sa \a space(), \a quote() */
|
||||
PICout & newLine();
|
||||
|
||||
static bool setBufferActive(bool on, bool clear = false);
|
||||
static bool isBufferActive();
|
||||
static PIString buffer(bool clear = false);
|
||||
static void clearBuffer();
|
||||
|
||||
static bool setOutputDevice(OutputDevice d, bool on = true);
|
||||
static void setOutputDevices(OutputDevices d);
|
||||
static bool isOutputDeviceActive(OutputDevice d);
|
||||
|
||||
static PIMutex & __mutex__();
|
||||
static PIString & __string__();
|
||||
|
||||
private:
|
||||
void init();
|
||||
void applyFormat(PICoutManipulators::PICoutFormat f);
|
||||
|
||||
static OutputDevices devs;
|
||||
PRIVATE_DECLARATION
|
||||
bool fo_, cc_, fc_, act_;
|
||||
int cnb_, attr_, id_;
|
||||
PIString * buffer_;
|
||||
PICoutManipulators::PICoutControls co_;
|
||||
};
|
||||
|
||||
#endif // PICOUT_H
|
||||
137
lib/main/core/piflags.h
Normal file
137
lib/main/core/piflags.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/*! \file piflags.h
|
||||
* \brief General flags class
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
General flags class
|
||||
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 PIFLAGS_H
|
||||
#define PIFLAGS_H
|
||||
|
||||
#include "pip_export.h"
|
||||
|
||||
/*! \brief This class used as container for bit flags
|
||||
* \details PIFlags is wrapper around \c "int". There are many
|
||||
* bit-wise operators, native conversion to int and function
|
||||
* to test flag. \n Example:
|
||||
* \snippet piincludes.cpp flags
|
||||
*/
|
||||
template<typename Enum>
|
||||
class PIP_EXPORT PIFlags {
|
||||
public:
|
||||
//! Constructor with flags = 0
|
||||
PIFlags(): flags(0) {;}
|
||||
//! Constructor with flags = Enum "e"
|
||||
PIFlags(Enum e): flags(e) {;}
|
||||
//! Constructor with flags = PIFlags "f"
|
||||
PIFlags(const PIFlags & f): flags(f.flags) {;}
|
||||
//! Constructor with flags = int "i"
|
||||
PIFlags(const int i): flags(i) {;}
|
||||
//! Set flags "f" to value "on"
|
||||
PIFlags & setFlag(const PIFlags & f, bool on = true) {if (on) flags |= f.flags; else flags &= ~f.flags; return *this;}
|
||||
//! Set flag "e" to value "on"
|
||||
PIFlags & setFlag(const Enum & e, bool on = true) {if (on) flags |= e; else flags &= ~e; return *this;}
|
||||
//! Set flag "i" to value "on"
|
||||
PIFlags & setFlag(const int & i, bool on = true) {if (on) flags |= i; else flags &= ~i; return *this;}
|
||||
//! copy operator
|
||||
void operator =(const PIFlags & f) {flags = f.flags;}
|
||||
//! copy operator
|
||||
void operator =(const Enum & e) {flags = e;}
|
||||
//! copy operator
|
||||
void operator =(const int & i) {flags = i;}
|
||||
//! compare operator
|
||||
bool operator ==(const PIFlags & f) {return flags == f.flags;}
|
||||
//! compare operator
|
||||
bool operator ==(const Enum & e) {return flags == e;}
|
||||
//! compare operator
|
||||
bool operator ==(const int i) {return flags == i;}
|
||||
//! compare operator
|
||||
bool operator !=(const PIFlags & f) {return flags != f.flags;}
|
||||
//! compare operator
|
||||
bool operator !=(const Enum & e) {return flags != e;}
|
||||
//! compare operator
|
||||
bool operator !=(const int i) {return flags != i;}
|
||||
//! compare operator
|
||||
bool operator >(const PIFlags & f) {return flags > f.flags;}
|
||||
//! compare operator
|
||||
bool operator >(const Enum & e) {return flags > e;}
|
||||
//! compare operator
|
||||
bool operator >(const int i) {return flags > i;}
|
||||
//! compare operator
|
||||
bool operator <(const PIFlags & f) {return flags < f.flags;}
|
||||
//! compare operator
|
||||
bool operator <(const Enum & e) {return flags < e;}
|
||||
//! compare operator
|
||||
bool operator <(const int i) {return flags < i;}
|
||||
//! compare operator
|
||||
bool operator >=(const PIFlags & f) {return flags >= f.flags;}
|
||||
//! compare operator
|
||||
bool operator >=(const Enum & e) {return flags >= e;}
|
||||
//! compare operator
|
||||
bool operator >=(const int i) {return flags >= i;}
|
||||
//! compare operator
|
||||
bool operator <=(const PIFlags & f) {return flags <= f.flags;}
|
||||
//! compare operator
|
||||
bool operator <=(const Enum & e) {return flags <= e;}
|
||||
//! compare operator
|
||||
bool operator <=(const int i) {return flags <= i;}
|
||||
//! Bit-wise AND operator
|
||||
void operator &=(const PIFlags & f) {flags &= f.flags;}
|
||||
//! Bit-wise AND operator
|
||||
void operator &=(const Enum & e) {flags &= e;}
|
||||
//! Bit-wise AND operator
|
||||
void operator &=(const int i) {flags &= i;}
|
||||
//! Bit-wise OR operator
|
||||
void operator |=(const PIFlags & f) {flags |= f.flags;}
|
||||
//! Bit-wise OR operator
|
||||
void operator |=(const Enum & e) {flags |= e;}
|
||||
//! Bit-wise OR operator
|
||||
void operator |=(const int i) {flags |= i;}
|
||||
//! Bit-wise XOR operator
|
||||
void operator ^=(const PIFlags & f) {flags ^= f.flags;}
|
||||
//! Bit-wise XOR operator
|
||||
void operator ^=(const Enum & e) {flags ^= e;}
|
||||
//! Bit-wise XOR operator
|
||||
void operator ^=(const int i) {flags ^= i;}
|
||||
//! Bit-wise AND operator
|
||||
PIFlags operator &(PIFlags f) const {PIFlags tf(flags & f.flags); return tf;}
|
||||
//! Bit-wise AND operator
|
||||
PIFlags operator &(Enum e) const {PIFlags tf(flags & e); return tf;}
|
||||
//! Bit-wise AND operator
|
||||
PIFlags operator &(int i) const {PIFlags tf(flags & i); return tf;}
|
||||
//! Bit-wise OR operator
|
||||
PIFlags operator |(PIFlags f) const {PIFlags tf(flags | f.flags); return tf;}
|
||||
//! Bit-wise OR operator
|
||||
PIFlags operator |(Enum e) const {PIFlags tf(flags | e); return tf;}
|
||||
//! Bit-wise OR operator
|
||||
PIFlags operator |(int i) const {PIFlags tf(flags | i); return tf;}
|
||||
//! Bit-wise XOR operator
|
||||
PIFlags operator ^(PIFlags f) const {PIFlags tf(flags ^ f.flags); return tf;}
|
||||
//! Bit-wise XOR operator
|
||||
PIFlags operator ^(Enum e) const {PIFlags tf(flags ^ e); return tf;}
|
||||
//! Bit-wise XOR operator
|
||||
PIFlags operator ^(int i) const {PIFlags tf(flags ^ i); return tf;}
|
||||
//! Test flag operator
|
||||
bool operator [](Enum e) const {return (flags & e) == e;}
|
||||
//! Implicity conversion to \c int
|
||||
operator int() const {return flags;}
|
||||
private:
|
||||
int flags;
|
||||
};
|
||||
|
||||
#endif // PIFLAGS_H
|
||||
266
lib/main/core/piincludes.cpp
Normal file
266
lib/main/core/piincludes.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Global 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 distributed in the hope that 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.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "piconsole.h"
|
||||
#include "pitime.h"
|
||||
#ifndef QNX
|
||||
# include <clocale>
|
||||
#else
|
||||
# include <locale.h>
|
||||
#endif
|
||||
#ifdef MAC_OS
|
||||
//# include <mach/mach_traps.h>
|
||||
//# include <mach/mach.h>
|
||||
# include <mach/clock.h>
|
||||
//# include <crt_externs.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
bool piDebug = true;
|
||||
double piMountInfoRefreshIntervalMs = 10000.;
|
||||
|
||||
lconv * currentLocale =
|
||||
#ifdef ANDROID
|
||||
0;
|
||||
#else
|
||||
std::localeconv();
|
||||
#endif
|
||||
|
||||
#ifdef MAC_OS
|
||||
clock_serv_t __pi_mac_clock;
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS
|
||||
FILETIME __pi_ftjan1970;
|
||||
long long __pi_perf_freq = -1;
|
||||
PINtQueryTimerResolution getTimerResolutionAddr = 0;
|
||||
PINtSetTimerResolution setTimerResolutionAddr = 0;
|
||||
#endif
|
||||
|
||||
void errorClear() {
|
||||
#ifdef WINDOWS
|
||||
SetLastError(0);
|
||||
#else
|
||||
errno = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
PIString errorString() {
|
||||
#ifdef WINDOWS
|
||||
char * msg;
|
||||
int err = GetLastError();
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&msg, 0, NULL);
|
||||
return "code " + PIString::fromNumber(err) + " - " + PIString(msg);
|
||||
#else
|
||||
int e = errno;
|
||||
return PIString("code ") + PIString::fromNumber(e) + " - " + PIString(strerror(e));
|
||||
#endif
|
||||
}
|
||||
|
||||
PIString PIPVersion() {
|
||||
static PIString ret = PIStringAscii(PIP_VERSION_NAME);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*! \class PICout
|
||||
* \brief Class for formatted output similar std::cout
|
||||
*
|
||||
* \section PICout_sec0 Synopsis
|
||||
* This class provide many stream operators for output with some features.
|
||||
* Output to PICout is thread-sequential, i.e. doesn`t mixed from parallel
|
||||
* threads.
|
||||
*
|
||||
* \section PICout_sec1 Features
|
||||
* - insertion spaces between entries
|
||||
* - insertion new line at the end of output
|
||||
* - strings are quoted
|
||||
* - custom output operator can be easily written
|
||||
*
|
||||
* \section PICout_ex0 Usage
|
||||
* \snippet picout.cpp 0
|
||||
*
|
||||
* \section PICout_ex1 Writing your own output operator
|
||||
* \snippet picout.cpp own
|
||||
*/
|
||||
|
||||
|
||||
/*! \mainpage What is PIP
|
||||
* PIP - Platform-Independent Primitives - is crossplatform library for C++ developers.
|
||||
* It is wrap around STL and pure C++. This library can help developers write non-GUI
|
||||
* projects much more quickly, efficiently and customizable than on pure C++.
|
||||
* Library contains many classes, some of them are pure abstract, some classes
|
||||
* can be used as they are, some classes should be inherited to new classes.
|
||||
* PIP provide classes:
|
||||
* * direct output to console (\a PICout)
|
||||
* * containers (\a PIVector, \a PIList, \a PIMap, \a PIStack)
|
||||
* * byte array (\a PIByteArray)
|
||||
* * string (\a PIString, \a PIStringList)
|
||||
* * base object (events and handlers) (\a PIObject)
|
||||
* * multithreading
|
||||
* * thread (\a PIThread)
|
||||
* * executor (\a PIThreadPoolExecutor)
|
||||
* * blocking dequeue (\a PIBlockingDequeue)
|
||||
* * timer (\a PITimer)
|
||||
* * console (information output) (\a PIConsole)
|
||||
* * stand-alone
|
||||
* * server
|
||||
* * client
|
||||
* * I/O devices
|
||||
* * base class (\a PIIODevice)
|
||||
* * file (\a PIFile)
|
||||
* * serial port (\a PISerial)
|
||||
* * ethernet (\a PIEthernet)
|
||||
* * USB (\a PIUSB)
|
||||
* * packets extractor (\a PIPacketExtractor)
|
||||
* * binary log (\a PIBinaryLog)
|
||||
* * complex I/O point (\a PIConnection)
|
||||
* * connection quality diagnotic (\a PIDiagnostics)
|
||||
* * command-line arguments parser (\a PICLI)
|
||||
* * math evaluator (\a PIEvaluator)
|
||||
* * peering net node (\a PIPeer)
|
||||
* * process (\a PIProcess)
|
||||
* * state machine (\a PIStateMachine)
|
||||
* \n \n Basic using of PIP described at page \ref using_basic */
|
||||
|
||||
|
||||
/*! \page using_basic Getting started
|
||||
* Many novice programmers are solved many common task with system integrity: output to console,
|
||||
* keyboard buttons press detecting, working with serial ports, ethernet or files, and many other.
|
||||
* These tasks can solve this library, and code, based only on PIP will be compile and work
|
||||
* similar on many systems: Windows, any Linux, Red Hat, FreeBSD, MacOS X and QNX.
|
||||
* Typical application on PIP looks like this: \n
|
||||
\code{.cpp}
|
||||
#include <pip.h>
|
||||
|
||||
|
||||
// declare key press handler
|
||||
void key_event(char key, void * );
|
||||
|
||||
|
||||
PIConsole console(false, key_event); // don`t start now, key handler is "key_event"
|
||||
|
||||
|
||||
// some vars
|
||||
int i = 2, j = 3;
|
||||
|
||||
|
||||
// implicit key press handler
|
||||
void key_event(char key, void * ) {
|
||||
switch (key) {
|
||||
case '-':
|
||||
i--;
|
||||
break;
|
||||
case '+':
|
||||
i++;
|
||||
break;
|
||||
case '(':
|
||||
j--;
|
||||
break;
|
||||
case ')':
|
||||
j++;
|
||||
break;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
class MainClass: public PITimer {
|
||||
PIOBJECT(MainClass)
|
||||
public:
|
||||
MainClass() {}
|
||||
protected:
|
||||
void tick(void * data, int delimiter) {
|
||||
piCout << "timer tick";
|
||||
// timer tick
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
MainClass main_class;
|
||||
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
// enabling auto-detection of exit button press, by default 'Q' (shift+q)
|
||||
console.enableExitCapture();
|
||||
|
||||
// if we want to parse command-line arguments
|
||||
PICLI cli(argc, argv);
|
||||
cli.addArgument("console"); // "-c" or "--console"
|
||||
cli.addArgument("debug"); // "-d" or "--debug"
|
||||
|
||||
// enabling or disabling global debug flag
|
||||
piDebug = cli.hasArgument("debug");
|
||||
|
||||
// configure console
|
||||
console.addTab("first tab", '1');
|
||||
console.addString("PIP console", 1, PIConsole::Bold);
|
||||
console.addVariable("int var (i)", &i, 1);
|
||||
console.addVariable("int green var (j)", &j, 1, PIConsole::Green);
|
||||
console.addString("'-' - i--", 2);
|
||||
console.addString("'+' - i++", 2);
|
||||
console.addString("'(' - j--", 2);
|
||||
console.addString("')' - j++", 2);
|
||||
console.addTab("second tab", '2');
|
||||
console.addString("col 1", 1);
|
||||
console.addString("col 2", 2);
|
||||
console.addString("col 3", 3);
|
||||
console.setTab("first tab");
|
||||
|
||||
// start output to console if "console" argument exists
|
||||
if (cli.hasArgument("console"))
|
||||
console.start();
|
||||
|
||||
// start main class, e.g. 40 Hz
|
||||
main_class.start(25.);
|
||||
|
||||
// wait for 'Q' press, independently if console is started or not
|
||||
console.waitForFinish();
|
||||
|
||||
return 0;
|
||||
};
|
||||
\endcode
|
||||
* This code demonstrates simple interactive configurable program, which can be started with console
|
||||
* display or not, and with debug or not. \b MainClass is central class that also can be inherited from
|
||||
* \a PIThread and reimplement \a run() function.
|
||||
* \n Many PIP classes has events and event handlers, which can be connected one to another.
|
||||
* Details you can see at \a PIObject reference page (\ref PIObject_sec0).
|
||||
* \n To configure your program from file use \a PIConfig.
|
||||
* \n If you want more information see \ref using_advanced */
|
||||
|
||||
|
||||
/*! \page using_advanced Advanced using
|
||||
* Sorry, creativity crysis xD
|
||||
*/
|
||||
|
||||
|
||||
void piqsort(void * base, size_t num, size_t size, int (*compar)(const void *, const void *)) {
|
||||
qsort(base, num, size, compar);
|
||||
}
|
||||
|
||||
|
||||
void randomize() {
|
||||
srand(PISystemTime::current(true).nanoseconds);
|
||||
}
|
||||
|
||||
|
||||
int randomi() {
|
||||
return rand();
|
||||
}
|
||||
|
||||
56
lib/main/core/piincludes.h
Normal file
56
lib/main/core/piincludes.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Minimal PIP 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 distributed in the hope that 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 PIINCLUDES_H
|
||||
#define PIINCLUDES_H
|
||||
|
||||
#include "pibase.h"
|
||||
#include "piflags.h"
|
||||
#include <sys/types.h>
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
||||
class PIObject;
|
||||
class PIMutex;
|
||||
class PIString;
|
||||
class PIByteArray;
|
||||
class PIInit;
|
||||
class PIChar;
|
||||
class PICout;
|
||||
|
||||
struct lconv;
|
||||
|
||||
extern lconv * currentLocale;
|
||||
|
||||
/*! \fn errorString()
|
||||
* \brief Return readable error description in format "code <number> - <description>" */
|
||||
PIP_EXPORT PIString errorString();
|
||||
|
||||
PIP_EXPORT void errorClear();
|
||||
|
||||
PIP_EXPORT void piqsort(void* base, size_t num, size_t size, int (*compar)(const void*,const void*));
|
||||
|
||||
PIP_EXPORT void randomize();
|
||||
PIP_EXPORT int randomi();
|
||||
|
||||
/// Return readable version of PIP
|
||||
PIP_EXPORT PIString PIPVersion();
|
||||
|
||||
#endif // PIINCLUDES_H
|
||||
45
lib/main/core/piincludes_p.h
Normal file
45
lib/main/core/piincludes_p.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Private PIP 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/>.
|
||||
*/
|
||||
#ifndef PIINCLUDES_P_H
|
||||
#define PIINCLUDES_P_H
|
||||
|
||||
|
||||
#include "picout.h"
|
||||
#ifdef WINDOWS
|
||||
# include <stdarg.h>
|
||||
# include <windef.h>
|
||||
# include <winbase.h>
|
||||
typedef LONG(NTAPI*PINtQueryTimerResolution)(PULONG, PULONG, PULONG);
|
||||
typedef LONG(NTAPI*PINtSetTimerResolution)(ULONG, BOOLEAN, PULONG);
|
||||
#endif
|
||||
#ifdef CC_GCC
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include <cstdlib>
|
||||
#include <stdio.h>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
|
||||
#endif // PIINCLUDES_P_H
|
||||
417
lib/main/core/piinit.cpp
Normal file
417
lib/main/core/piinit.cpp
Normal file
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Initialization
|
||||
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 "piinit.h"
|
||||
#include "pitime.h"
|
||||
#include "pisignals.h"
|
||||
#include "piobject.h"
|
||||
#include "pisysteminfo.h"
|
||||
#include "piresourcesstorage.h"
|
||||
#include "pidir.h"
|
||||
#ifndef FREERTOS
|
||||
# include "piprocess.h"
|
||||
#endif
|
||||
#ifdef ESP_PLATFORM
|
||||
# include "esp_system.h"
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
# include <winsock2.h>
|
||||
extern FILETIME __pi_ftjan1970;
|
||||
extern PINtQueryTimerResolution getTimerResolutionAddr;
|
||||
extern PINtSetTimerResolution setTimerResolutionAddr;
|
||||
void __PISetTimerResolution() {
|
||||
if (setTimerResolutionAddr == NULL || getTimerResolutionAddr == NULL)
|
||||
return;
|
||||
ULONG _max(0), _min(0), _cur(0);
|
||||
//printf("getTimerResolution ...\n");
|
||||
LONG q = getTimerResolutionAddr(&_max, &_min, &_cur);
|
||||
//printf("getTimerResolution %d %lu %lu %lu\n", q, _min, _max, _cur);
|
||||
if (q == 0)
|
||||
setTimerResolutionAddr(_min, TRUE, &_cur);
|
||||
//printf("setTimerResolution %lu\n", cur);
|
||||
}
|
||||
#else
|
||||
# include <pwd.h>
|
||||
# ifndef FREERTOS
|
||||
# include <sys/utsname.h>
|
||||
# endif
|
||||
# include <pthread.h>
|
||||
# ifdef BLACKBERRY
|
||||
# include <signal.h>
|
||||
# else
|
||||
# include <csignal>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef MAC_OS
|
||||
# include <mach/mach_traps.h>
|
||||
# include <mach/mach.h>
|
||||
# include <mach/clock.h>
|
||||
extern clock_serv_t __pi_mac_clock;
|
||||
#endif
|
||||
#ifdef PIP_ICU
|
||||
# define U_NOEXCEPT
|
||||
# include <unicode/uclean.h>
|
||||
# include <unicode/ucnv.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAS_LOCALE
|
||||
static locale_t currentLocale_t = 0;
|
||||
#endif
|
||||
|
||||
PRIVATE_DEFINITION_START(PIInit)
|
||||
#ifdef WINDOWS
|
||||
HMODULE ntlib;
|
||||
ULONG prev_res;
|
||||
#endif
|
||||
bool delete_locs;
|
||||
PRIVATE_DEFINITION_END(PIInit)
|
||||
|
||||
#ifndef FREERTOS
|
||||
void __sighandler__(PISignals::Signal s) {
|
||||
//piCout << Hex << int(s);
|
||||
if (s == PISignals::StopTTYInput || s == PISignals::StopTTYOutput)
|
||||
piMSleep(10);
|
||||
if (s == PISignals::UserDefined1)
|
||||
dumpApplicationToFile(PIDir::home().path() + PIDir::separator + PIStringAscii("_PIP_DUMP_") + PIString::fromNumber(PIProcess::currentPID()));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ANDROID
|
||||
void android_thread_exit_handler(int sig) {
|
||||
pthread_exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
PIInit::PIInit() {
|
||||
file_charset = 0;
|
||||
PISystemInfo * sinfo = PISystemInfo::instance();
|
||||
sinfo->execDateTime = PIDateTime::current();
|
||||
setFileCharset("UTF-8");
|
||||
#ifndef FREERTOS
|
||||
#ifndef ANDROID
|
||||
PISignals::setSlot(__sighandler__);
|
||||
PISignals::grabSignals(PISignals::UserDefined1);
|
||||
# ifndef WINDOWS
|
||||
PISignals::grabSignals(PISignals::StopTTYInput | PISignals::StopTTYOutput);
|
||||
sigset_t ss;
|
||||
sigemptyset(&ss);
|
||||
sigaddset(&ss, SIGALRM);
|
||||
sigprocmask(SIG_BLOCK, &ss, 0);
|
||||
pthread_sigmask(SIG_BLOCK, &ss, 0);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
PIStringList ifpathes;
|
||||
ifpathes << PIStringAscii("/bin/ifconfig") << PIStringAscii("/sbin/ifconfig")
|
||||
<< PIStringAscii("/usr/bin/ifconfig") << PIStringAscii("/usr/sbin/ifconfig");
|
||||
piForeachC (PIString & i, ifpathes) {
|
||||
if (fileExists(i)) {
|
||||
sinfo->ifconfigPath = i;
|
||||
piBreak;
|
||||
}
|
||||
}
|
||||
# else
|
||||
// OS version
|
||||
DWORD dwVersion = GetVersion();
|
||||
DWORD dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
|
||||
DWORD dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
|
||||
sinfo->OS_version = PIString::fromNumber(dwMajorVersion) + "." + PIString::fromNumber(dwMinorVersion);
|
||||
|
||||
// WinSock inint
|
||||
WSADATA wsaData;
|
||||
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
|
||||
// Timers init
|
||||
SYSTEMTIME jan1970 = {1970, 1, 4, 1, 0, 0, 0, 0};
|
||||
SystemTimeToFileTime(&jan1970, &__pi_ftjan1970);
|
||||
LARGE_INTEGER pf;
|
||||
pf.QuadPart = -1;
|
||||
if (QueryPerformanceFrequency(&pf) != 0) __pi_perf_freq = pf.QuadPart;
|
||||
if (__pi_perf_freq == 0) __pi_perf_freq = -1;
|
||||
|
||||
// Sleep precision init
|
||||
PRIVATE->ntlib = LoadLibrary("ntdll.dll");
|
||||
if (PRIVATE->ntlib) {
|
||||
getTimerResolutionAddr = (PINtQueryTimerResolution)GetProcAddress(PRIVATE->ntlib, "NtQueryTimerResolution");
|
||||
setTimerResolutionAddr = (PINtSetTimerResolution)GetProcAddress(PRIVATE->ntlib, "NtSetTimerResolution");
|
||||
__PISetTimerResolution();
|
||||
}
|
||||
# endif
|
||||
# ifdef HAS_LOCALE
|
||||
//cout << "has locale" << endl;
|
||||
if (currentLocale_t != 0) {
|
||||
freelocale(currentLocale_t);
|
||||
currentLocale_t = 0;
|
||||
}
|
||||
currentLocale_t = newlocale(LC_ALL, setlocale(LC_ALL, ""), 0);
|
||||
# else
|
||||
setlocale(LC_ALL, "");
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
# endif
|
||||
#else
|
||||
struct sigaction actions;
|
||||
memset(&actions, 0, sizeof(actions));
|
||||
sigemptyset(&actions.sa_mask);
|
||||
actions.sa_flags = 0;
|
||||
actions.sa_handler = android_thread_exit_handler;
|
||||
sigaction(SIGTERM, &actions, 0);
|
||||
#endif
|
||||
PRIVATE->delete_locs = false;
|
||||
__syslocname__ = __sysoemname__ = 0;
|
||||
__utf8name__ = const_cast<char*>("UTF-8");
|
||||
#ifdef PIP_ICU
|
||||
UErrorCode e((UErrorCode)0);
|
||||
u_init(&e);
|
||||
# ifdef WINDOWS
|
||||
PRIVATE->delete_locs = true;
|
||||
CPINFOEX cpinfo;
|
||||
int l = 0;
|
||||
GetCPInfoEx(CP_OEMCP, 0, &cpinfo);
|
||||
for (l = 0; l < MAX_PATH; ++l)
|
||||
if (cpinfo.CodePageName[l] == '\0' || cpinfo.CodePageName[l] == ' ')
|
||||
break;
|
||||
__sysoemname__ = new char[256];
|
||||
memset(__sysoemname__, 0, 256);
|
||||
memcpy(__sysoemname__, "ibm-", 4);
|
||||
memcpy(&(__sysoemname__[4]), cpinfo.CodePageName, l);
|
||||
# else
|
||||
/*PIString en(getenv("LANG"));
|
||||
if (!en.isEmpty())
|
||||
en = en.mid(en.find(".") + 1);
|
||||
PIByteArray enba = en.toByteArray();
|
||||
memcpy(__syslocname__, enba.data(), enba.size_s());*/
|
||||
# endif
|
||||
//piCout << __syslocname__;
|
||||
//piCout << __sysoemname__;
|
||||
#else
|
||||
# ifdef WINDOWS
|
||||
__syslocname__ = (char *)CP_ACP;
|
||||
__sysoemname__ = (char *)CP_OEMCP;
|
||||
__utf8name__ = (char *)CP_UTF8;
|
||||
# endif
|
||||
#endif
|
||||
#ifdef MAC_OS
|
||||
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &__pi_mac_clock);
|
||||
#endif
|
||||
char cbuff[1024];
|
||||
memset(cbuff, 0, 1024);
|
||||
if (gethostname(cbuff, 1023) == 0)
|
||||
sinfo->hostname = cbuff;
|
||||
#ifdef WINDOWS
|
||||
SYSTEM_INFO sysinfo;
|
||||
GetSystemInfo(&sysinfo);
|
||||
sinfo->processorsCount = sysinfo.dwNumberOfProcessors;
|
||||
switch (sysinfo.wProcessorArchitecture) {
|
||||
case PROCESSOR_ARCHITECTURE_AMD64: sinfo->architecture = PIStringAscii("x86_64"); break;
|
||||
case PROCESSOR_ARCHITECTURE_ARM: sinfo->architecture = PIStringAscii("arm"); break;
|
||||
case PROCESSOR_ARCHITECTURE_IA64: sinfo->architecture = PIStringAscii("Intel Itanium-based"); break;
|
||||
case PROCESSOR_ARCHITECTURE_INTEL: sinfo->architecture = PIStringAscii("x86"); break;
|
||||
case PROCESSOR_ARCHITECTURE_UNKNOWN:
|
||||
default: sinfo->architecture = PIStringAscii("unknown"); break;
|
||||
}
|
||||
int argc_(0);
|
||||
wchar_t ** argv_ = CommandLineToArgvW(GetCommandLineW(), &argc_);
|
||||
if (argc_ > 0 && argv_ != 0)
|
||||
sinfo->execCommand = argv_[0];
|
||||
LocalFree(argv_);
|
||||
memset(cbuff, 0, 1024);
|
||||
ulong unlen = 1023;
|
||||
if (GetUserName(cbuff, &unlen) != 0)
|
||||
sinfo->user = cbuff;
|
||||
#else
|
||||
sinfo->processorsCount = piMaxi(1, int(sysconf(_SC_NPROCESSORS_ONLN)));
|
||||
passwd * ps = getpwuid(getuid());
|
||||
if (ps)
|
||||
sinfo->user = ps->pw_name;
|
||||
else {
|
||||
memset(cbuff, 0, 1024);
|
||||
char * l = getlogin();
|
||||
if (l)
|
||||
sinfo->user = l;
|
||||
}
|
||||
struct utsname uns;
|
||||
if (uname(&uns) == 0) {
|
||||
sinfo->OS_version = uns.release;
|
||||
sinfo->architecture = uns.machine;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#ifdef ESP_PLATFORM
|
||||
esp_chip_info_t chip_info;
|
||||
esp_chip_info(&chip_info);
|
||||
sinfo->processorsCount = chip_info.cores;
|
||||
sinfo->architecture = "Xtensa LX6";
|
||||
//printf("silicon revision %d, ", chip_info.revision);
|
||||
sinfo->OS_version = esp_get_idf_version();
|
||||
#endif
|
||||
sinfo->OS_name =
|
||||
#ifdef WINDOWS
|
||||
PIStringAscii("Windows");
|
||||
#elif defined(QNX)
|
||||
PIStringAscii("QNX");
|
||||
#elif defined(MAC_OS)
|
||||
PIStringAscii("MacOS");
|
||||
#elif defined(ANDROID)
|
||||
PIStringAscii("Android");
|
||||
#elif defined(FREE_BSD)
|
||||
PIStringAscii("FreeBSD");
|
||||
#elif defined(FREERTOS)
|
||||
PIStringAscii("FreeRTOS");
|
||||
#else
|
||||
uns.sysname;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PIInit::~PIInit() {
|
||||
if (file_charset) delete file_charset;
|
||||
file_charset = 0;
|
||||
PIResourcesStorage::instance()->clear();
|
||||
#ifdef WINDOWS
|
||||
WSACleanup();
|
||||
if (PRIVATE->ntlib) FreeLibrary(PRIVATE->ntlib);
|
||||
PRIVATE->ntlib = 0;
|
||||
#endif
|
||||
#ifdef MAC_OS
|
||||
mach_port_deallocate(mach_task_self(), __pi_mac_clock);
|
||||
#endif
|
||||
if (PRIVATE->delete_locs) {
|
||||
if (__syslocname__) delete __syslocname__;
|
||||
if (__sysoemname__) delete __sysoemname__;
|
||||
}
|
||||
#ifdef PIP_ICU
|
||||
u_cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PIInit::isBuildOptionEnabled(PIInit::BuildOption o) {
|
||||
switch (o) {
|
||||
case ICU: return
|
||||
#ifdef PIP_ICU
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
case USB: return
|
||||
#ifdef PIP_USB
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
case Crypt: return
|
||||
#ifdef PIP_CRYPT
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
case Introspection: return
|
||||
#ifdef PIP_INTROSPECTION
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
case FFTW: return
|
||||
#ifdef PIP_FFTW
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
case Compress: return
|
||||
#ifdef PIP_COMPRESS
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
case OpenCL: return
|
||||
#ifdef PIP_OPENCL
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
case Cloud: return
|
||||
#ifdef PIP_CLOUD
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
default: return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PIStringList PIInit::buildOptions() {
|
||||
PIStringList ret;
|
||||
if (isBuildOptionEnabled(ICU)) ret << "ICU";
|
||||
if (isBuildOptionEnabled(USB)) ret << "USB";
|
||||
if (isBuildOptionEnabled(Crypt)) ret << "Crypt";
|
||||
if (isBuildOptionEnabled(Introspection)) ret << "Introspection";
|
||||
if (isBuildOptionEnabled(FFTW)) ret << "FFTW";
|
||||
if (isBuildOptionEnabled(Compress)) ret << "Compress";
|
||||
if (isBuildOptionEnabled(OpenCL)) ret << "OpenCL";
|
||||
if (isBuildOptionEnabled(Cloud)) ret << "Cloud";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PIInit::setFileCharset(const char *charset) {
|
||||
if (file_charset) delete file_charset;
|
||||
file_charset = 0;
|
||||
if (charset) {
|
||||
file_charset = new char[1024];
|
||||
memset(file_charset, 0, 1024);
|
||||
strcpy(file_charset, charset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PIInit::fileExists(const PIString & p) {
|
||||
FILE * f = fopen(p.data(), "r");
|
||||
if (f == 0)
|
||||
return false;
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int __PIInit_Initializer__::count_(0);
|
||||
PIInit * __PIInit_Initializer__::__instance__(0);
|
||||
|
||||
|
||||
__PIInit_Initializer__::__PIInit_Initializer__() {
|
||||
count_++;
|
||||
if (count_ > 1) return;
|
||||
//piCout << "create PIInit";
|
||||
__instance__ = new PIInit();
|
||||
}
|
||||
|
||||
|
||||
__PIInit_Initializer__::~__PIInit_Initializer__() {
|
||||
count_--;
|
||||
if (count_ > 0) return;
|
||||
//piCout << "delete PIInit";
|
||||
if (__instance__ != 0) {
|
||||
delete __instance__;
|
||||
__instance__ = 0;
|
||||
}
|
||||
}
|
||||
73
lib/main/core/piinit.h
Normal file
73
lib/main/core/piinit.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*! \file piinit.h
|
||||
* \brief Initialization
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Initialization
|
||||
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 PIINIT_H
|
||||
#define PIINIT_H
|
||||
|
||||
#include "piincludes.h"
|
||||
|
||||
|
||||
class PIFile;
|
||||
class PIStringList;
|
||||
|
||||
|
||||
class PIP_EXPORT __PIInit_Initializer__ {
|
||||
public:
|
||||
__PIInit_Initializer__();
|
||||
~__PIInit_Initializer__();
|
||||
static int count_;
|
||||
static PIInit * __instance__;
|
||||
};
|
||||
|
||||
|
||||
class PIP_EXPORT PIInit {
|
||||
friend class __PIInit_Initializer__;
|
||||
friend class PIFile;
|
||||
public:
|
||||
~PIInit();
|
||||
|
||||
//! \brief Build options which PIP library was built
|
||||
enum BuildOption {
|
||||
ICU /*! Unicode support */ = 0x01,
|
||||
USB /*! USB support */ = 0x02,
|
||||
Crypt /*! Crypt support */ = 0x08,
|
||||
Introspection /*! Introspection */ = 0x010,
|
||||
FFTW /*! FFTW3 support */ = 0x40,
|
||||
Compress /*! Zlib compression support */ = 0x80,
|
||||
OpenCL /*! OpenCL support */ = 0x100,
|
||||
Cloud /*! Cloud transport support */ = 0x200,
|
||||
};
|
||||
static PIInit * instance() {return __PIInit_Initializer__::__instance__;}
|
||||
static bool isBuildOptionEnabled(BuildOption o);
|
||||
static PIStringList buildOptions();
|
||||
private:
|
||||
explicit PIInit();
|
||||
void setFileCharset(const char *charset);
|
||||
bool fileExists(const PIString & p);
|
||||
PRIVATE_DECLARATION
|
||||
char * file_charset;
|
||||
};
|
||||
|
||||
static __PIInit_Initializer__ __piinit_initializer__;
|
||||
|
||||
|
||||
#endif // PIINIT_H
|
||||
676
lib/main/core/piobject.cpp
Normal file
676
lib/main/core/piobject.cpp
Normal file
@@ -0,0 +1,676 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Object, base class of some PIP classes, provide EVENT -> EVENT_HANDLER mechanism
|
||||
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 "piobject.h"
|
||||
#include "pisysteminfo.h"
|
||||
#ifndef FREERTOS
|
||||
# include "pifile.h"
|
||||
#endif
|
||||
|
||||
/** \class PIObject
|
||||
* \brief This is base class for any classes which use events -> handlers mechanism.
|
||||
* \details
|
||||
* \section PIObject_sec0 Events and Event handlers
|
||||
* %PIObject provide notification mechanism similar Qt but implemented
|
||||
* on language capabilities without any special preprocessors or compilers.
|
||||
* Any class inherits PIObject should use macro \a PIOBJECT() immediate
|
||||
* after declaration to proper compile.
|
||||
*
|
||||
* Event is a some abstract event that can be raised at any time.
|
||||
* Event is a function but declared with special macro \a EVENT().
|
||||
* To raise event simply execute event function.
|
||||
*
|
||||
* Event handler is a function but declared with special macro
|
||||
* \a EVENT_HANDLER(). You can use event handlers as ordinary functions.
|
||||
*
|
||||
* Main goal of this mechanism is perform abstract connections between
|
||||
* various objects. This functionality provide macro \a CONNECT() which
|
||||
* connect some event of first object to some event handler or event of
|
||||
* second object. Each event can be connected any times to any event handlers.
|
||||
*
|
||||
* \image html events_handlers.png
|
||||
*
|
||||
* Example: \snippet piobject.cpp main
|
||||
* Result:
|
||||
\code{.cpp}
|
||||
handler B: 2 , 0.5
|
||||
handler A: event to handler
|
||||
handler A: event to event
|
||||
\endcode
|
||||
*/
|
||||
|
||||
|
||||
PIString PIObject::__MetaFunc::arguments() const {
|
||||
return types.join(",");
|
||||
}
|
||||
|
||||
|
||||
PIString PIObject::__MetaFunc::fullFormat() const {
|
||||
PIString ret = type_ret + " " + scope + "::" + func_name +"(";
|
||||
for (int i = 0; i < types.size_s(); ++i) {
|
||||
if (i > 0) ret += ", ";
|
||||
ret += types[i] + " " + names[i];
|
||||
}
|
||||
ret += ")";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIObject::PIObject(const PIString & name): _signature_(__PIOBJECT_SIGNATURE__), emitter_(0), thread_safe_(false), proc_event_queue(false) {
|
||||
setName(name);
|
||||
setDebug(true);
|
||||
mutexObjects().lock();
|
||||
objects() << this;
|
||||
mutexObjects().unlock();
|
||||
//piCout << "new" << this;
|
||||
}
|
||||
|
||||
|
||||
PIObject::~PIObject() {
|
||||
//piCout << "delete" << this;
|
||||
mutexObjects().lock();
|
||||
objects().removeAll(this);
|
||||
mutexObjects().unlock();
|
||||
piDisconnect(this);
|
||||
}
|
||||
|
||||
PIMap<PIString, PIVariant> PIObject::properties() const {
|
||||
PIMap<PIString, PIVariant> ret;
|
||||
piForeachC (PropertyHash p, properties_)
|
||||
ret[p.second.first] = p.second.second;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool PIObject::execute(const PIString & method, const PIVector<PIVariant> & vl) {
|
||||
if (method.isEmpty()) return false;
|
||||
if (!isPIObject()) {
|
||||
piCout << "Error: \"execute(" << method << ")\":" << (void*)this << "is not PIObject!";
|
||||
return false;
|
||||
}
|
||||
int ac = 0;
|
||||
__MetaFunc func;
|
||||
bool ok = findSuitableMethodV(method, vl.size_s(), ac, func);
|
||||
if (!ok)
|
||||
return false;
|
||||
callAddrV(func.addrV, toThis(), ac, vl);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIObject::executeQueued(PIObject * performer, const PIString & method, const PIVector<PIVariant> & vl) {
|
||||
if (!isPIObject()) {
|
||||
piCout << "Error: \"executeQueued(" << method << ")\": this(" << (void*)this << ") is not PIObject!";
|
||||
return false;
|
||||
}
|
||||
if (!performer->isPIObject()) {
|
||||
piCout << "Error: \"executeQueued(" << method << ")\": performer(" << (void*)performer << ") is not PIObject!";
|
||||
return false;
|
||||
}
|
||||
int ac = 0;
|
||||
__MetaFunc func;
|
||||
bool ok = findSuitableMethodV(method, vl.size_s(), ac, func);
|
||||
if (!ok)
|
||||
return false;
|
||||
performer->postQueuedEvent(__QueuedEvent(func.addrV, toThis(), this, performer, vl));
|
||||
performer->proc_event_queue = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIObject::piConnect(const PIString & src, const PIString & sig, void * dest, void * ev_h) {
|
||||
PIObject * o = findByName(src);
|
||||
if (o == 0) {
|
||||
piCout << "[PIObject] Can`t find object with name \"" << src << "\"!";
|
||||
return;
|
||||
}
|
||||
PIMutexLocker _ml(o->mutex_connect);
|
||||
PIMutexLocker _mld(((PIObject*)dest)->mutex_connect, ((PIObject*)dest) != o);
|
||||
o->connections << __Connection(ev_h, 0, sig, (PIObject*)dest, dest);
|
||||
((PIObject*)dest)->connectors << o;
|
||||
}
|
||||
|
||||
|
||||
void PIObject::piConnect(PIObject * src, const PIString & sig, const PIString & dest, void * ev_h) {
|
||||
PIObject * o = findByName(dest);
|
||||
if (o == 0) {
|
||||
piCout << "[PIObject] Can`t find object with name \"" << dest << "\"!";
|
||||
return;
|
||||
}
|
||||
PIMutexLocker _ml(src->mutex_connect);
|
||||
PIMutexLocker _mld(o->mutex_connect, src != o);
|
||||
src->connections << __Connection(ev_h, 0, sig, o, o);
|
||||
((PIObject*)o)->connectors << src;
|
||||
}
|
||||
|
||||
|
||||
void PIObject::piConnect(const PIString & src, const PIString & sig, const PIString & dest, void * ev_h) {
|
||||
PIObject * s = findByName(src);
|
||||
if (s == 0) {
|
||||
piCout << "[PIObject] Can`t find object with name \"" << src << "\"!";
|
||||
return;
|
||||
}
|
||||
PIObject * d = findByName(dest);
|
||||
if (d == 0) {
|
||||
piCout << "[PIObject] Can`t find object with name \"" << dest << "\"!";
|
||||
return;
|
||||
}
|
||||
PIMutexLocker _ml(s->mutex_connect);
|
||||
PIMutexLocker _mld(d->mutex_connect, s != d);
|
||||
s->connections << __Connection(ev_h, 0, sig, d, d);
|
||||
d->connectors << s;
|
||||
}
|
||||
|
||||
|
||||
PIStringList PIObject::scopeList() const {
|
||||
PIMutexLocker ml(__meta_mutex());
|
||||
return __meta_data()[classNameID()].scope_list;
|
||||
}
|
||||
|
||||
|
||||
PIStringList PIObject::methodsEH() const {
|
||||
PIMutexLocker ml(__meta_mutex());
|
||||
PIStringList ret;
|
||||
__MetaData & ehd(__meta_data()[classNameID()]);
|
||||
piForeachC (__EHPair & eh, ehd.eh_func)
|
||||
ret << eh.second.fullFormat();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PIObject::isMethodEHContains(const PIString & name) const {
|
||||
PIMutexLocker ml(__meta_mutex());
|
||||
__MetaData & ehd(__meta_data()[classNameID()]);
|
||||
piForeachC (__EHPair & eh, ehd.eh_func)
|
||||
if (eh.second.func_name == name)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PIString PIObject::methodEHArguments(const PIString & name) const {
|
||||
PIMutexLocker ml(__meta_mutex());
|
||||
__MetaData & ehd(__meta_data()[classNameID()]);
|
||||
piForeachC (__EHPair & eh, ehd.eh_func)
|
||||
if (eh.second.func_name == name)
|
||||
return eh.second.arguments();
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
PIString PIObject::methodEHFullFormat(const PIString & name) const {
|
||||
PIMutexLocker ml(__meta_mutex());
|
||||
__MetaData & ehd(__meta_data()[classNameID()]);
|
||||
piForeachC (__EHPair & eh, ehd.eh_func)
|
||||
if (eh.second.func_name == name)
|
||||
return eh.second.fullFormat();
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
PIString PIObject::methodEHFromAddr(const void * addr) const {
|
||||
return methodEH(addr).func_name;
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIObject::__MetaFunc> PIObject::findEH(const PIString & name) const {
|
||||
PIVector<__MetaFunc> ret;
|
||||
__MetaData & ehd(__meta_data()[classNameID()]);
|
||||
piForeachC (__EHPair & eh, ehd.eh_func)
|
||||
if (eh.second.func_name == name)
|
||||
ret << eh.second;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIObject::__MetaFunc PIObject::methodEH(const void * addr) const {
|
||||
PIMutexLocker ml(__meta_mutex());
|
||||
return __meta_data()[classNameID()].eh_func.value(addr);
|
||||
}
|
||||
|
||||
|
||||
void PIObject::piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc) {
|
||||
//piCout << "piConnect ...";
|
||||
//piCout << "piConnect" << src << (void*)(dest) << sig;
|
||||
//piCout << "piConnect" << src->className() << "->" << ((PIObject*)dest)->className();
|
||||
PIMutexLocker _ml(src->mutex_connect);
|
||||
PIMutexLocker _mld(dest_o->mutex_connect, src != dest_o);
|
||||
|
||||
src->connections << __Connection(ev_h, e_h, sig, dest_o, dest, args);
|
||||
//piCout << "piConnect" << ((PIObject*)dest) << sig << ((PIObject*)dest)->connectors.size_s() << "...";
|
||||
//piCout << "addConnector" << dest_o << src;
|
||||
dest_o->connectors << src;
|
||||
//piCout << "piConnect" << ((PIObject*)dest) << sig << ((PIObject*)dest)->connectors.size_s();
|
||||
//piCout << "piConnect ok";
|
||||
}
|
||||
|
||||
|
||||
bool PIObject::piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer) {
|
||||
if (src == 0 || dest_o == 0 || dest == 0) return false;
|
||||
if (!src->isPIObject()) {
|
||||
piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: source object is not PIObject! (" << loc << ")";
|
||||
return false;
|
||||
}
|
||||
if (!dest_o->isPIObject()) {
|
||||
piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: destination object is not PIObject! (" << loc << ")";
|
||||
return false;
|
||||
}
|
||||
PIMutexLocker ml(__meta_mutex());
|
||||
PIMutexLocker mls(src->mutex_connect);
|
||||
PIMutexLocker mld(dest_o->mutex_connect, src != dest_o);
|
||||
PIVector<__MetaFunc> m_src = src->findEH(sig), m_dest = dest_o->findEH(hname);
|
||||
if (m_src.isEmpty()) {
|
||||
piCout << "[piConnectU] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
|
||||
return false;
|
||||
}
|
||||
if (m_dest.isEmpty()) {
|
||||
piCout << "[piConnectU] Error: can`t find handler \"" << hname << "\" in class \"" << dest_o->className() << "\"! (" << loc << ")";
|
||||
return false;
|
||||
}
|
||||
void * addr_src(0), * addr_dest(0);
|
||||
int args(0);
|
||||
bool que = (performer != 0);
|
||||
piForeachC (__MetaFunc & fs, m_src) {
|
||||
if (addr_src != 0) break;
|
||||
piForeachC (__MetaFunc & fd, m_dest) {
|
||||
if (addr_src != 0) break;
|
||||
if (fs.arguments().startsWith(fd.arguments()) || fd.arguments().isEmpty()) {
|
||||
addr_src = fs.addr;
|
||||
addr_dest = que ? fd.addrV : fd.addr;
|
||||
args = fd.names.size_s();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (addr_src == 0) {
|
||||
piCout << "[piConnectU] Error: can`t find suitable pair of event \"" << sig << "\" in class \"" << src->className()
|
||||
<< "\" and handler \"" << hname << "\" in class \"" << dest_o->className() << "\"! (" << loc << ")";
|
||||
return false;
|
||||
}
|
||||
src->connections << PIObject::__Connection(addr_dest, addr_src, sig, dest_o, dest, args, performer);
|
||||
if (que) performer->proc_event_queue = true;
|
||||
dest_o->connectors << src;
|
||||
//piCout << cc << cq << _ol.size();//"connect" << src << "->" << dest_o << ", dest.connectors.size() =" << dest_o->connectors.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
bool PIObject::piConnectLS(PIObject * src, const PIString & sig, std::function<void()> * f, const char * loc) {
|
||||
if (src == 0) {
|
||||
delete f;
|
||||
return false;
|
||||
}
|
||||
if (!src->isPIObject()) {
|
||||
piCout << "[piConnectLS] \"" << sig << "\" -> [lambda] error: source object is not PIObject! (" << loc << ")";
|
||||
delete f;
|
||||
return false;
|
||||
}
|
||||
PIMutexLocker ml(__meta_mutex());
|
||||
PIMutexLocker mls(src->mutex_connect);
|
||||
//piCout << "locked";
|
||||
PIVector<__MetaFunc> m_src = src->findEH(sig);
|
||||
if (m_src.isEmpty()) {
|
||||
piCout << "[piConnectLS] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
|
||||
delete f;
|
||||
return false;
|
||||
}
|
||||
if (m_src.size() != 1) {
|
||||
piCout << "[piConnectLS] Error: can`t connect overloaded event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
|
||||
delete f;
|
||||
return false;
|
||||
}
|
||||
PIObject::__Connection conn(0, m_src[0].addr, sig);
|
||||
//piCout << "found";
|
||||
conn.functor = f;
|
||||
src->connections << conn;
|
||||
//piCout << "finished";
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void PIObject::piDisconnect(PIObject * src, const PIString & sig, PIObject * dest, void * ev_h) {
|
||||
PIMutexLocker _ml(src->mutex_connect);
|
||||
PIMutexLocker _mld(dest->mutex_connect, src != dest);
|
||||
for (int i = 0; i < src->connections.size_s(); ++i) {
|
||||
__Connection & cc(src->connections[i]);
|
||||
if (cc.event == sig && cc.dest_o == dest && cc.slot == ev_h) {
|
||||
src->connections[i].destroy();
|
||||
src->connections.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
dest->updateConnectors();
|
||||
}
|
||||
|
||||
|
||||
void PIObject::piDisconnect(PIObject * src, const PIString & sig, PIObject * dest) {
|
||||
PIMutexLocker _ml(src->mutex_connect);
|
||||
PIMutexLocker _mld(dest->mutex_connect, src != dest);
|
||||
for (int i = 0; i < src->connections.size_s(); ++i) {
|
||||
__Connection & cc(src->connections[i]);
|
||||
if (cc.event == sig && cc.dest_o == dest) {
|
||||
src->connections[i].destroy();
|
||||
src->connections.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
dest->updateConnectors();
|
||||
}
|
||||
|
||||
|
||||
void PIObject::piDisconnect(PIObject * src, const PIString & sig) {
|
||||
PIMutexLocker _ml(src->mutex_connect);
|
||||
for (int i = 0; i < src->connections.size_s(); ++i) {
|
||||
__Connection & cc(src->connections[i]);
|
||||
if (cc.event == sig) {
|
||||
PIObject * dest = cc.dest_o;
|
||||
if (!dest) {
|
||||
src->connections[i].destroy();
|
||||
src->connections.remove(i);
|
||||
i--;
|
||||
#if !defined(ANDROID) && !defined(MAC_OS) && !defined(FREERTOS)
|
||||
PIMutexLocker _mld(dest->mutex_connect, src != dest);
|
||||
#endif
|
||||
dest->updateConnectors();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIObject::piDisconnect(PIObject * src) {
|
||||
src->deleted();
|
||||
PIMutexLocker _ml(src->mutex_connect);
|
||||
PIVector<PIObject * > cv = src->connectors.toVector();
|
||||
piForeach (PIObject * o, cv) {
|
||||
//piCout << "disconnect"<< src->className()<< o->className();
|
||||
if (!o || (o == src)) continue;
|
||||
if (!o->isPIObject()) continue;
|
||||
#if !defined(ANDROID) && !defined(MAC_OS) && !defined(FREERTOS)
|
||||
PIMutexLocker _mld(o->mutex_connect, src != o);
|
||||
#endif
|
||||
PIVector<__Connection> & oc(o->connections);
|
||||
for (int i = 0; i < oc.size_s(); ++i) {
|
||||
if (oc[i].functor) continue;
|
||||
//piCout << " check" << (void*)(oc[i].dest_o) << "==" << (void*)(src);
|
||||
if (oc[i].dest_o == src) {
|
||||
oc[i].destroy();
|
||||
oc.remove(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
piForeachC (PIObject::__Connection & c, src->connections) {
|
||||
if (c.functor) continue;
|
||||
if (!c.dest_o) continue;
|
||||
if (!c.dest_o->isPIObject()) continue;
|
||||
c.dest_o->connectors.remove(src);
|
||||
}
|
||||
for (int i = 0; i < src->connections.size_s(); ++i)
|
||||
src->connections[i].destroy();
|
||||
src->connections.clear();
|
||||
}
|
||||
|
||||
|
||||
void PIObject::updateConnectors() {
|
||||
//piCout << "*** updateConnectors" << this;
|
||||
connectors.clear();
|
||||
PIMutexLocker _ml(mutexObjects());
|
||||
piForeach (PIObject * o, objects()) {
|
||||
if (o == this) continue;
|
||||
PIVector<__Connection> & oc(o->connections);
|
||||
piForeach (__Connection & c, oc)
|
||||
if (c.dest == this)
|
||||
connectors << o;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIObject::postQueuedEvent(const PIObject::__QueuedEvent & e) {
|
||||
mutex_queue.lock();
|
||||
events_queue << e;
|
||||
mutex_queue.unlock();
|
||||
}
|
||||
|
||||
|
||||
void * PIObject::toThis() const {
|
||||
//piCout << ptrOffset() << (void*)this << (void*)((char*)this - ptrOffset());
|
||||
return (void*)((char*)this - ptrOffset());
|
||||
}
|
||||
|
||||
|
||||
PIMutex & PIObject::__meta_mutex() {
|
||||
static PIMutex ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIMap<uint, PIObject::__MetaData> & PIObject::__meta_data() {
|
||||
static PIMap<uint, PIObject::__MetaData> ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PIObject::callQueuedEvents() {
|
||||
mutex_queue.lock();
|
||||
PIVector<__QueuedEvent> qe = events_queue;
|
||||
events_queue.clear();
|
||||
mutex_queue.unlock();
|
||||
piForeachC (__QueuedEvent & e, qe) {
|
||||
if (e.dest_o->thread_safe_) e.dest_o->mutex_.lock();
|
||||
e.dest_o->emitter_ = e.src;
|
||||
callAddrV(e.slot, e.dest, e.values.size_s(), e.values);
|
||||
e.dest_o->emitter_ = 0;
|
||||
if (e.dest_o->thread_safe_) e.dest_o->mutex_.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PIObject::findSuitableMethodV(const PIString & method, int args, int & ret_args, PIObject::__MetaFunc & ret) {
|
||||
PIVector<__MetaFunc> ml = findEH(method);
|
||||
if (ml.isEmpty()) {
|
||||
piCoutObj << "Error: no such method \"" << method << "\"!";
|
||||
return false;
|
||||
}
|
||||
int mfi = -1, ac = -1, mac = -1;
|
||||
for (int i = 0; i < ml.size_s(); ++i) {
|
||||
__MetaFunc & m(ml[i]);
|
||||
int j = m.names.size_s();
|
||||
if (mac < 0 || mac > j) mac = j;
|
||||
if ((j <= args) && (ac < j)) {
|
||||
ac = j;
|
||||
mfi = i;
|
||||
}
|
||||
}
|
||||
if (mfi < 0) {
|
||||
piCoutObj << "Error: no such suitable method \"" << method << "\", need at least" << mac << "arguments!";
|
||||
return false;
|
||||
}
|
||||
ret_args = ac;
|
||||
ret = ml[mfi];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PIVector<PIObject * > & PIObject::objects() {
|
||||
static PIVector<PIObject * > * ret = new PIVector<PIObject * >();
|
||||
return *ret;
|
||||
}
|
||||
|
||||
|
||||
PIMutex & PIObject::mutexObjects() {
|
||||
static PIMutex ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PIObject::callAddrV(void * slot, void * obj, int args, const PIVector<PIVariant> & vl) {
|
||||
args = piMini(args, vl.size_s());
|
||||
switch (args) {
|
||||
case 0: ((void(*)(void *))slot)(obj); break;
|
||||
case 1: ((void(*)(void * , const PIVariant & ))slot)(obj, vl[0]); break;
|
||||
case 2: ((void(*)(void * , const PIVariant & , const PIVariant & ))slot)(obj, vl[0], vl[1]); break;
|
||||
case 3: ((void(*)(void * , const PIVariant & , const PIVariant & , const PIVariant & ))slot)(obj, vl[0], vl[1], vl[2]); break;
|
||||
case 4: ((void(*)(void * , const PIVariant & , const PIVariant & , const PIVariant & , const PIVariant & ))slot)(obj, vl[0], vl[1], vl[2], vl[3]); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIString PIObject::simplifyType(const char * a) {
|
||||
PIString ret = PIStringAscii(a).trim();
|
||||
int white = -1;
|
||||
for (int i = 0; i < ret.size_s(); ++i) {
|
||||
bool iw = ret[i] == ' ' || ret[i] == '\t' || ret[i] == '\r' || ret[i] == '\n';
|
||||
//piCout << i << iw << white;
|
||||
if (white < 0) {
|
||||
if (iw) {
|
||||
white = i;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (!iw) {
|
||||
ret.replace(white, i - white, " ");
|
||||
i = white;
|
||||
white = -1;
|
||||
//piCout << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.replaceAll(" &", "&");
|
||||
ret.replaceAll(" *", "*");
|
||||
if (ret.startsWith("const ") && ret.endsWith("&"))
|
||||
ret.cutLeft(6).cutRight(1).trim();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PIObject::isPIObject(const PIObject * o) {
|
||||
if (!o) return false;
|
||||
return o->_signature_ == __PIOBJECT_SIGNATURE__;
|
||||
}
|
||||
|
||||
|
||||
void PIObject::dump(const PIString & line_prefix) const {
|
||||
//printf("dump %s \"%s\"\n", className(), name().data());
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << "class " << className() << " (" << (const void*)this << ", \"" << name() << "\") {";
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << " scope: " << scopeList().join(" -> ");
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << " properties {";
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << " count: " << properties_.size_s();
|
||||
//printf("dump %d properties\n", properties_.size());
|
||||
piForeachC (PropertyHash p, properties_)
|
||||
if (p.first != PIString("name").hash())
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << p.second.first << ": " << p.second.second;
|
||||
//printf("dump %d properties ok\n", properties_.size());
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << " }";
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << " methods {";
|
||||
__MetaData & ehd(__meta_data()[classNameID()]);
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << " count: " << ehd.eh_func.size_s();
|
||||
//printf("dump %d methods\n", ehd.eh_func.size());
|
||||
piForeachC (__EHPair & eh, ehd.eh_func) {
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << eh.second.fullFormat();
|
||||
}
|
||||
//printf("dump %d methods ok\n", ehd.eh_func.size());
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << " }";
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << " connections {";
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << " count: " << connections.size_s();
|
||||
//printf("dump %d connections\n",connections.size());
|
||||
piForeachC (__Connection & c, connections) {
|
||||
PIObject * dst = c.dest_o;
|
||||
__MetaFunc ef = methodEH(c.signal);
|
||||
PIString src(c.event);
|
||||
if (!ef.func_name.isEmpty())
|
||||
src = ef.func_name + "(" + ef.arguments() + ")";
|
||||
if (dst) {
|
||||
__MetaFunc hf = dst->methodEH(c.slot);
|
||||
if (hf.func_name.isEmpty()) hf.func_name = "[BROKEN]";
|
||||
else hf.func_name += "(" + hf.arguments() + ")";
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << src << " -> " << dst->className() << " (" << c.dest << ", \"" << dst->name() << "\")::" << hf.func_name;
|
||||
} else {
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << src << " -> " << "[lambda]";
|
||||
}
|
||||
}
|
||||
//printf("dump %d connections ok\n",connections.size());
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << " }";
|
||||
PICout(PICoutManipulators::AddNewLine) << line_prefix << "}";
|
||||
}
|
||||
|
||||
|
||||
void dumpApplication() {
|
||||
PIMutexLocker _ml(PIObject::mutexObjects());
|
||||
//printf("dump application ...\n");
|
||||
PIDateTime cd = PIDateTime::current();
|
||||
PISystemInfo * pi = PISystemInfo::instance();
|
||||
PICout(PICoutManipulators::AddNewLine) << "application {";
|
||||
PICout(PICoutManipulators::AddNewLine) << " PIP version: " << PIPVersion();
|
||||
PICout(PICoutManipulators::AddNewLine) << " OS name: \"" << pi->OS_name << "\"";
|
||||
PICout(PICoutManipulators::AddNewLine) << " OS version: \"" << pi->OS_version << "\"";
|
||||
PICout(PICoutManipulators::AddNewLine) << " processors: " << pi->processorsCount;
|
||||
PICout(PICoutManipulators::AddNewLine) << " architecture: \"" << pi->architecture << "\"";
|
||||
PICout(PICoutManipulators::AddNewLine) << " hostname: \"" << pi->hostname << "\"";
|
||||
PICout(PICoutManipulators::AddNewLine) << " username: \"" << pi->user << "\"";
|
||||
PICout(PICoutManipulators::AddNewLine) << " exec command: \"" << pi->execCommand << "\"";
|
||||
PICout(PICoutManipulators::AddNewLine) << " started: " << pi->execDateTime.toString();
|
||||
PICout(PICoutManipulators::AddNewLine) << " uptime: " << PITime::fromSystemTime(cd.toSystemTime() - pi->execDateTime.toSystemTime()).toString();
|
||||
PICout(PICoutManipulators::AddNewLine) << " PIObjects {";
|
||||
PICout(PICoutManipulators::AddNewLine) << " count: " << PIObject::objects().size_s();
|
||||
piForeachC (PIObject * o, PIObject::objects())
|
||||
o->dump(" ");
|
||||
PICout(PICoutManipulators::AddNewLine) << " }";
|
||||
PICout(PICoutManipulators::AddNewLine) << "}";
|
||||
//printf("dump application done\n");
|
||||
}
|
||||
|
||||
|
||||
#ifndef FREERTOS
|
||||
bool dumpApplicationToFile(const PIString & path) {
|
||||
PIFile f(path + "_tmp");
|
||||
f.setName("__S__DumpFile");
|
||||
f.clear();
|
||||
if (!f.open(PIIODevice::WriteOnly)) return false;
|
||||
bool ba = PICout::isBufferActive();
|
||||
PICout::setBufferActive(true, true);
|
||||
dumpApplication();
|
||||
f << PICout::buffer();
|
||||
f.close();
|
||||
PICout::setBufferActive(ba, true);
|
||||
PIFile::rename(path + "_tmp", path);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void PIObject::__MetaData::addScope(const PIString & s, uint shash) {
|
||||
if (!scope_id.contains(shash)) {
|
||||
scope_list << s;
|
||||
scope_id << shash;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIObject::__Connection::destroy() {
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
if (functor) delete functor;
|
||||
functor = nullptr;
|
||||
#endif
|
||||
}
|
||||
955
lib/main/core/piobject.h
Normal file
955
lib/main/core/piobject.h
Normal file
@@ -0,0 +1,955 @@
|
||||
/*! \file piobject.h
|
||||
* \brief Base object
|
||||
*
|
||||
* This file declare PIObject class and associated macros
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Object, base class of some PIP classes, provide EVENT -> EVENT_HANDLER mechanism
|
||||
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 PIOBJECT_H
|
||||
#define PIOBJECT_H
|
||||
|
||||
#include "piinit.h"
|
||||
#include "pivariant.h"
|
||||
#include "pimutex.h"
|
||||
#include "piset.h"
|
||||
#include "piqueue.h"
|
||||
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief you should use this macro after class declaration to use EVENT and EVENT_HANDLER and correct piCoutObj output
|
||||
#define PIOBJECT(name)
|
||||
|
||||
/// \relatesalso PIObject \brief you should use this macro after class declaration to use EVENT and EVENT_HANDLER of parent class, and \a scopeList()
|
||||
#define PIOBJECT_SUBCLASS(name, parent)
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name()
|
||||
#define EVENT_HANDLER0(ret, name) ret name()
|
||||
|
||||
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0)
|
||||
#define EVENT_HANDLER1(ret, name, type0, var0) ret name(type0 var0)
|
||||
|
||||
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1)
|
||||
#define EVENT_HANDLER2(ret, name, type0, var0, type1, var1) ret name(type0 var0, type1 var1)
|
||||
|
||||
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1, type2 var2)
|
||||
#define EVENT_HANDLER3(ret, name, type0, var0, type1, var1, type2, var2) ret name(type0 var0, type1 var1, type2 var2)
|
||||
|
||||
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1, type2 var2, type3 var3)
|
||||
#define EVENT_HANDLER4(ret, name, type0, var0, type1, var1, type2, var2, type3, var3) ret name(type0 var0, type1 var1, type2 var2, type3 var3)
|
||||
|
||||
/// \relatesalso PIObject \brief EVENT_HANDLER is synonym of EVENT_HANDLER0
|
||||
#define EVENT_HANDLER EVENT_HANDLER0
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name()
|
||||
#define EVENT_VHANDLER0(ret, name) virtual ret name()
|
||||
|
||||
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0)
|
||||
#define EVENT_VHANDLER1(ret, name, type0, var0) virtual ret name(type0 var0)
|
||||
|
||||
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1)
|
||||
#define EVENT_VHANDLER2(ret, name, type0, var0, type1, var1) virtual ret name(type0 var0, type1 var1)
|
||||
|
||||
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1, type2 var2)
|
||||
#define EVENT_VHANDLER3(ret, name, type0, var0, type1, var1, type2, var2) virtual ret name(type0 var0, type1 var1, type2 var2)
|
||||
|
||||
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3)
|
||||
#define EVENT_VHANDLER4(ret, name, type0, var0, type1, var1, type2, var2, type3, var3) virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3)
|
||||
|
||||
/// \relatesalso PIObject \brief EVENT_VHANDLER is synonym of EVENT_VHANDLER0
|
||||
#define EVENT_VHANDLER EVENT_VHANDLER0
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name();
|
||||
#define EVENT0(name) void name();
|
||||
|
||||
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0);
|
||||
#define EVENT1(name, type0, var0) void name(type0 var0);
|
||||
|
||||
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1);
|
||||
#define EVENT2(name, type0, var0, type1, var1) void name(type0 var0, type1 var1);
|
||||
|
||||
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1, type2 var2);
|
||||
#define EVENT3(name, type0, var0, type1, var1, type2, var2) void name(type0 var0, type1 var1, type2 var2);
|
||||
|
||||
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1, type2 var2, type3 var3);
|
||||
#define EVENT4(name, type0, var0, type1, var1, type2, var2, type3, var3) void name(type0 var0, type1 var1, type2 var2, type3 var3);
|
||||
|
||||
/// \relatesalso PIObject \brief EVENT is synonym of EVENT0
|
||||
#define EVENT EVENT0
|
||||
|
||||
|
||||
#define RAISE_EVENT0(src, event)
|
||||
#define RAISE_EVENT1(src, event, v0)
|
||||
#define RAISE_EVENT2(src, event, v0, v1)
|
||||
#define RAISE_EVENT3(src, event, v0, v1, v2)
|
||||
#define RAISE_EVENT4(src, event, v0, v1, v2, v3)
|
||||
#define RAISE_EVENT RAISE_EVENT0
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\". \"Event\" and \"handler\" must has equal argument lists.
|
||||
#define CONNECTU(src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\".
|
||||
/// Event handler will be executed by \"performer\". \"Event\" and \"handler\" must has equal argument lists.
|
||||
#define CONNECTU_QUEUED(src, event, dest, handler, performer)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to lambda-expression \"functor\". \"Event\" and \"functor\" must has equal argument lists.
|
||||
#define CONNECTL(src, event, functor)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
|
||||
#define CONNECT0(ret, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
|
||||
#define CONNECT1(ret, type0, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
|
||||
#define CONNECT2(ret, type0, type1, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
|
||||
#define CONNECT3(ret, type0, type1, type2, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
|
||||
#define CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief CONNECT is synonym of CONNECT0
|
||||
#define CONNECT CONNECT0
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
|
||||
#define WEAK_CONNECT0(ret, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
|
||||
#define WEAK_CONNECT1(ret, type0, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
|
||||
#define WEAK_CONNECT2(ret, type0, type1, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
|
||||
#define WEAK_CONNECT3(ret, type0, type1, type2, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
|
||||
#define WEAK_CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief WEAK_CONNECT is synonym of WEAK_CONNECT0
|
||||
#define WEAK_CONNECT WEAK_CONNECT0
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
|
||||
#define DISCONNECT0(ret, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
|
||||
#define DISCONNECT1(ret, type0, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
|
||||
#define DISCONNECT2(ret, type0, type1, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
|
||||
#define DISCONNECT3(ret, type0, type1, type2, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
|
||||
#define DISCONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
|
||||
|
||||
/// \relatesalso PIObject \brief DISCONNECT is synonym of DISCONNECT0
|
||||
#define DISCONNECT DISCONNECT0
|
||||
|
||||
|
||||
/// \relatesalso PIObject \brief Returns pointer to events handler \"handler\"
|
||||
#define HANDLER(handler)
|
||||
|
||||
|
||||
#define PIOBJECT(name)
|
||||
#define PIOBJECT_SUBCLASS(name)
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#define _PI_STR(x) #x
|
||||
#define _PI_SSTR(x) _PI_STR(x)
|
||||
#define LOCATION __FILE__ ":" _PI_SSTR(__LINE__)
|
||||
#ifdef CC_GCC
|
||||
# define __PTYPE(t) typename __PIVariantTypeInfo__<t>::PureType
|
||||
#else
|
||||
# define __PTYPE(t) __PIVariantTypeInfo__<t>::PureType
|
||||
#endif
|
||||
#define __VVALUE(t, v) v.value< __PTYPE(t) >()
|
||||
|
||||
//printf("base_init %s id=%d (%d) pid=%d (%d) ...\n", #name, id, eh.eh_func.size(), pid, ehp.eh_func.size());
|
||||
//printf("base_init %s id=%d (%d) pid=%d (%d) ok\n", #name, id, eh.eh_func.size(), pid, ehp.eh_func.size());
|
||||
//printf("parent_init %s::%s id=%d (%d) pid=%d (%d) ...\n", __classNameS().dataAscii(), #name, id, eh.eh_func.size(), pid, ehp.eh_func.size());
|
||||
//printf("parent_init %s::%s id=%d (%d) pid=%d (%d) ok\n", __classNameS().dataAscii(), #name, id, eh.eh_func.size(), pid, ehp.eh_func.size());
|
||||
|
||||
#define PIOBJECT(name) \
|
||||
protected: \
|
||||
typedef name __PIObject__; \
|
||||
public: \
|
||||
static const PIString __classNameS() {static PIString ret = PIStringAscii(#name); return ret;} \
|
||||
static uint __classNameIDS() {static uint ret = PIStringAscii(#name).hash(); return ret;} \
|
||||
virtual const char * className() const {return #name;} \
|
||||
virtual uint classNameID() const {static uint ret = PIStringAscii(#name).hash(); return ret;} \
|
||||
private: \
|
||||
virtual int ptrOffset() const {name * o = (name*)100; return int(llong((PIObject*)o) - llong(o));} \
|
||||
class __BaseInitializer__ { \
|
||||
public: \
|
||||
__BaseInitializer__() { \
|
||||
uint pid = PIObject::__classNameIDS(); \
|
||||
if (pid == 0) return; \
|
||||
uint id = __classNameIDS(); \
|
||||
PIMutexLocker ml(__meta_mutex()); \
|
||||
if (__meta_data().contains(id)) return; \
|
||||
__meta_data()[pid]; \
|
||||
__meta_data()[id]; \
|
||||
__MetaData & ehp(__meta_data()[pid]); \
|
||||
__MetaData & eh(__meta_data()[id]); \
|
||||
eh.eh_set << ehp.eh_set; \
|
||||
eh.eh_func << ehp.eh_func; \
|
||||
eh.addScope(__classNameS(), id); \
|
||||
} \
|
||||
}; \
|
||||
__BaseInitializer__ __base_init__;
|
||||
|
||||
#define PIOBJECT_PARENT(name) \
|
||||
class __ParentInitializer__ { \
|
||||
public: \
|
||||
__ParentInitializer__() { \
|
||||
uint pid = name::__classNameIDS(); \
|
||||
if (pid == 0) return; \
|
||||
uint id = __classNameIDS(); \
|
||||
PIMutexLocker ml(__meta_mutex()); \
|
||||
__MetaData & eh(__meta_data()[id]); \
|
||||
if (eh.scope_id.contains(pid)) return; \
|
||||
__MetaData ehp(__meta_data().value(pid)); \
|
||||
eh.eh_set << ehp.eh_set; \
|
||||
eh.eh_func << ehp.eh_func; \
|
||||
eh.scope_id = ehp.scope_id; \
|
||||
eh.scope_list = ehp.scope_list; \
|
||||
eh.addScope(__classNameS(), id); \
|
||||
} \
|
||||
}; \
|
||||
__ParentInitializer__ __parent_init__; \
|
||||
public: \
|
||||
virtual const char * parentClassName() const {return #name;} \
|
||||
typedef name __Parent__; \
|
||||
private:
|
||||
|
||||
#define PIOBJECT_SUBCLASS(name, parent) PIOBJECT(name) PIOBJECT_PARENT(parent)
|
||||
|
||||
|
||||
#define EH_INIT0(ret, name) \
|
||||
class __##name##0_Initializer__ { \
|
||||
public: \
|
||||
__##name##0_Initializer__() { \
|
||||
PIMutexLocker ml(__meta_mutex()); \
|
||||
__MetaData & eh(__meta_data()[__classNameIDS()]); \
|
||||
void * fp = (void*)(ret(*)(void*))__stat_eh_##name##__; \
|
||||
void * fpV = fp; \
|
||||
if (eh.eh_set[fp]) return; \
|
||||
eh.eh_set << fp; \
|
||||
__MetaFunc & f(eh.eh_func[fp]); \
|
||||
f.scope = __classNameS(); \
|
||||
f.func_name = PIStringAscii(#name); \
|
||||
f.addr = fp; \
|
||||
f.addrV = fpV; \
|
||||
f.type_ret = PIStringAscii(#ret); \
|
||||
} \
|
||||
}; \
|
||||
__##name##0_Initializer__ __##name##0_init__; \
|
||||
|
||||
#define EH_INIT1(ret, name, a0, n0) \
|
||||
class __##name##1##n0##_Initializer__ { \
|
||||
public: \
|
||||
__##name##1##n0##_Initializer__() { \
|
||||
PIMutexLocker ml(__meta_mutex()); \
|
||||
__MetaData & eh(__meta_data()[__classNameIDS()]); \
|
||||
void * fp = (void*)(ret(*)(void*, a0))__stat_eh_##name##__; \
|
||||
void * fpV = (void*)(ret(*)(void*, const PIVariant &))__stat_eh_v_##name##__; \
|
||||
if (eh.eh_set[fp]) return; \
|
||||
eh.eh_set << fp; \
|
||||
__MetaFunc & f(eh.eh_func[fp]); \
|
||||
f.scope = __classNameS(); \
|
||||
f.func_name = PIStringAscii(#name); \
|
||||
f.addr = fp; \
|
||||
f.addrV = fpV; \
|
||||
f.type_ret = PIStringAscii(#ret); \
|
||||
f.types << PIObject::simplifyType(#a0); \
|
||||
f.names << PIStringAscii(#n0); \
|
||||
} \
|
||||
}; \
|
||||
__##name##1##n0##_Initializer__ __##name##1##n0##_init__; \
|
||||
|
||||
#define EH_INIT2(ret, name, a0, n0, a1, n1) \
|
||||
class __##name##2##n0##n1##_Initializer__ { \
|
||||
public: \
|
||||
__##name##2##n0##n1##_Initializer__() { \
|
||||
PIMutexLocker ml(__meta_mutex()); \
|
||||
__MetaData & eh(__meta_data()[__classNameIDS()]); \
|
||||
void * fp = (void*)(ret(*)(void*, a0, a1))__stat_eh_##name##__; \
|
||||
void * fpV = (void*)(ret(*)(void*, const PIVariant &, const PIVariant &))__stat_eh_v_##name##__; \
|
||||
if (eh.eh_set[fp]) return; \
|
||||
eh.eh_set << fp; \
|
||||
__MetaFunc & f(eh.eh_func[fp]); \
|
||||
f.scope = __classNameS(); \
|
||||
f.func_name = PIStringAscii(#name); \
|
||||
f.addr = fp; \
|
||||
f.addrV = fpV; \
|
||||
f.type_ret = PIStringAscii(#ret); \
|
||||
f.types << PIObject::simplifyType(#a0) << PIObject::simplifyType(#a1); \
|
||||
f.names << PIStringAscii(#n0) << PIStringAscii(#n1); \
|
||||
} \
|
||||
}; \
|
||||
__##name##2##n0##n1##_Initializer__ __##name##2##n0##n1##_init__; \
|
||||
|
||||
#define EH_INIT3(ret, name, a0, n0, a1, n1, a2, n2) \
|
||||
class __##name##3##n0##n1##n2##_Initializer__ { \
|
||||
public: \
|
||||
__##name##3##n0##n1##n2##_Initializer__() { \
|
||||
PIMutexLocker ml(__meta_mutex()); \
|
||||
__MetaData & eh(__meta_data()[__classNameIDS()]); \
|
||||
void * fp = (void*)(ret(*)(void*, a0, a1, a2))__stat_eh_##name##__; \
|
||||
void * fpV = (void*)(ret(*)(void*, const PIVariant &, const PIVariant &, const PIVariant &))__stat_eh_v_##name##__; \
|
||||
if (eh.eh_set[fp]) return; \
|
||||
eh.eh_set << fp; \
|
||||
__MetaFunc & f(eh.eh_func[fp]); \
|
||||
f.scope = __classNameS(); \
|
||||
f.func_name = PIStringAscii(#name); \
|
||||
f.addr = fp; \
|
||||
f.addrV = fpV; \
|
||||
f.type_ret = PIStringAscii(#ret); \
|
||||
f.types << PIObject::simplifyType(#a0) << PIObject::simplifyType(#a1) << PIObject::simplifyType(#a2); \
|
||||
f.names << PIStringAscii(#n0) << PIStringAscii(#n1) << PIStringAscii(#n2); \
|
||||
} \
|
||||
}; \
|
||||
__##name##3##n0##n1##n2##_Initializer__ __##name##3##n0##n1##n2##_init__; \
|
||||
|
||||
#define EH_INIT4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \
|
||||
class __##name##4##n0##n1##n2##n3##_Initializer__ { \
|
||||
public: \
|
||||
__##name##4##n0##n1##n2##n3##_Initializer__() { \
|
||||
PIMutexLocker ml(__meta_mutex()); \
|
||||
__MetaData & eh(__meta_data()[__classNameIDS()]); \
|
||||
void * fp = (void*)(ret(*)(void*, a0, a1, a2, a3))__stat_eh_##name##__; \
|
||||
void * fpV = (void*)(ret(*)(void*, const PIVariant &, const PIVariant &, const PIVariant &, const PIVariant &))__stat_eh_v_##name##__; \
|
||||
if (eh.eh_set[fp]) return; \
|
||||
eh.eh_set << fp; \
|
||||
__MetaFunc & f(eh.eh_func[fp]); \
|
||||
f.scope = __classNameS(); \
|
||||
f.func_name = PIStringAscii(#name); \
|
||||
f.addr = fp; \
|
||||
f.addrV = fpV; \
|
||||
f.type_ret = PIStringAscii(#ret); \
|
||||
f.types << PIObject::simplifyType(#a0) << PIObject::simplifyType(#a1) << PIObject::simplifyType(#a2) << PIObject::simplifyType(#a3); \
|
||||
f.names << PIStringAscii(#n0) << PIStringAscii(#n1) << PIStringAscii(#n2) << PIStringAscii(#n3); \
|
||||
} \
|
||||
}; \
|
||||
__##name##4##n0##n1##n2##n3##_Initializer__ __##name##4##n0##n1##n2##n3##_init__; \
|
||||
|
||||
|
||||
#define EVENT_HANDLER0(ret, name) \
|
||||
EH_INIT0(ret, name) \
|
||||
static ret __stat_eh_##name##__(void * __o__) {return ((__PIObject__*)__o__)->name();} \
|
||||
ret name()
|
||||
|
||||
#define EVENT_HANDLER1(ret, name, a0, n0) \
|
||||
EH_INIT1(ret, name, a0, n0) \
|
||||
static ret __stat_eh_##name##__(void * __o__, a0 n0) {return ((__PIObject__*)__o__)->name(n0);} \
|
||||
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0) { \
|
||||
__PTYPE(a0) tv0 = __VVALUE(a0, v0); \
|
||||
return ((__PIObject__*)__o__)->name(tv0);} \
|
||||
ret name(a0 n0)
|
||||
|
||||
#define EVENT_HANDLER2(ret, name, a0, n0, a1, n1) \
|
||||
EH_INIT2(ret, name, a0, n0, a1, n1) \
|
||||
static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1) {return ((__PIObject__*)__o__)->name(n0, n1);} \
|
||||
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1) { \
|
||||
__PTYPE(a0) tv0 = __VVALUE(a0, v0); \
|
||||
__PTYPE(a1) tv1 = __VVALUE(a1, v1); \
|
||||
return ((__PIObject__*)__o__)->name(tv0, tv1);} \
|
||||
ret name(a0 n0, a1 n1)
|
||||
|
||||
#define EVENT_HANDLER3(ret, name, a0, n0, a1, n1, a2, n2) \
|
||||
EH_INIT3(ret, name, a0, n0, a1, n1, a2, n2) \
|
||||
static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1, a2 n2) {return ((__PIObject__*)__o__)->name(n0, n1, n2);} \
|
||||
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) { \
|
||||
__PTYPE(a0) tv0 = __VVALUE(a0, v0); \
|
||||
__PTYPE(a1) tv1 = __VVALUE(a1, v1); \
|
||||
__PTYPE(a2) tv2 = __VVALUE(a2, v2); \
|
||||
return ((__PIObject__*)__o__)->name(tv0, tv1, tv2);} \
|
||||
ret name(a0 n0, a1 n1, a2 n2)
|
||||
|
||||
#define EVENT_HANDLER4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \
|
||||
EH_INIT4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \
|
||||
static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1, a2 n2, a3 n3) {return ((__PIObject__*)__o__)->name(n0, n1, n2, n3);} \
|
||||
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) { \
|
||||
__PTYPE(a0) tv0 = __VVALUE(a0, v0); \
|
||||
__PTYPE(a1) tv1 = __VVALUE(a1, v1); \
|
||||
__PTYPE(a2) tv2 = __VVALUE(a2, v2); \
|
||||
__PTYPE(a3) tv3 = __VVALUE(a3, v3); \
|
||||
return ((__PIObject__*)__o__)->name(tv0, tv1, tv2, tv3);} \
|
||||
ret name(a0 n0, a1 n1, a2 n2, a3 n3)
|
||||
|
||||
#define EVENT_HANDLER EVENT_HANDLER0
|
||||
|
||||
|
||||
#define EVENT_VHANDLER0(ret, name) \
|
||||
EH_INIT0(ret, name) \
|
||||
static ret __stat_eh_##name##__(void * __o__) {return ((__PIObject__*)__o__)->name();} \
|
||||
virtual ret name()
|
||||
|
||||
#define EVENT_VHANDLER1(ret, name, a0, n0) \
|
||||
EH_INIT1(ret, name, a0, n0) \
|
||||
static ret __stat_eh_##name##__(void * __o__, a0 n0) {return ((__PIObject__*)__o__)->name(n0);} \
|
||||
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0) {return ((__PIObject__*)__o__)->name(__VVALUE(a0, v0));} \
|
||||
virtual ret name(a0 n0)
|
||||
|
||||
#define EVENT_VHANDLER2(ret, name, a0, n0, a1, n1) \
|
||||
EH_INIT2(ret, name, a0, n0, a1, n1) \
|
||||
static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1) {return ((__PIObject__*)__o__)->name(n0, n1);} \
|
||||
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1) {return ((__PIObject__*)__o__)->name(__VVALUE(a0, v0), __VVALUE(a1, v1));} \
|
||||
virtual ret name(a0 n0, a1 n1)
|
||||
|
||||
#define EVENT_VHANDLER3(ret, name, a0, n0, a1, n1, a2, n2) \
|
||||
EH_INIT3(ret, name, a0, n0, a1, n1, a2, n2) \
|
||||
static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1, a2 n2) {return ((__PIObject__*)__o__)->name(n0, n1, n2);} \
|
||||
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return ((__PIObject__*)__o__)->name(__VVALUE(a0, v0), __VVALUE(a1, v1), __VVALUE(a2, v2));} \
|
||||
virtual ret name(a0 n0, a1 n1, a2 n2)
|
||||
|
||||
#define EVENT_VHANDLER4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \
|
||||
EH_INIT4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \
|
||||
static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1, a2 n2, a3 n3) {return ((__PIObject__*)__o__)->name(n0, n1, n2, n3);} \
|
||||
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return ((__PIObject__*)__o__)->name(__VVALUE(a0, v0), __VVALUE(a1, v1), __VVALUE(a2, v2), __VVALUE(a3, v3));} \
|
||||
virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3)
|
||||
|
||||
#define EVENT_VHANDLER EVENT_VHANDLER0
|
||||
|
||||
|
||||
#define EVENT0(name) EVENT_HANDLER0(void, name) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid);}
|
||||
#define EVENT1(name, a0, n0) EVENT_HANDLER1(void, name, a0, n0) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid, n0);}
|
||||
#define EVENT2(name, a0, n0, a1, n1) EVENT_HANDLER2(void, name, a0, n0, a1, n1) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid, n0, n1);}
|
||||
#define EVENT3(name, a0, n0, a1, n1, a2, n2) EVENT_HANDLER3(void, name, a0, n0, a1, n1, a2, n2) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid, n0, n1, n2);}
|
||||
#define EVENT4(name, a0, n0, a1, n1, a2, n2, a3, n3) EVENT_HANDLER4(void, name, a0, n0, a1, n1, a2, n2, a3, n3) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid, n0, n1, n2, n3);}
|
||||
#define EVENT EVENT0
|
||||
|
||||
#define RAISE_EVENT0(src, event) (src)->event();
|
||||
#define RAISE_EVENT1(src, event, v0) (src)->event(v0);
|
||||
#define RAISE_EVENT2(src, event, v0, v1) (src)->event(v0, v1);
|
||||
#define RAISE_EVENT3(src, event, v0, v1, v2) (src)->event(v0, v1, v2);
|
||||
#define RAISE_EVENT4(src, event, v0, v1, v2, v3) (src)->event(v0, v1, v2, v3);
|
||||
#define RAISE_EVENT RAISE_EVENT0
|
||||
|
||||
#define CONNECTU(src, event, dest, handler) PIObject::piConnectU(src, PIStringAscii(#event), dest, dest, PIStringAscii(#handler), LOCATION);
|
||||
#define CONNECTU_QUEUED(src, event, dest, handler, performer) PIObject::piConnectU(src, PIStringAscii(#event), dest, dest, PIStringAscii(#handler), LOCATION, performer);
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
# define CONNECTL(src, event, functor) PIObject::piConnectLS(src, PIStringAscii(#event), PIObject::__newFunctor(&(src)->__stat_eh_##event##__, functor), LOCATION);
|
||||
#endif
|
||||
|
||||
#define CONNECT0(ret, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*))(&(src)->__stat_eh_##event##__), 0, LOCATION);
|
||||
#define CONNECT1(ret, a0, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0))(&(src)->__stat_eh_##event##__), 1, LOCATION);
|
||||
#define CONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1))(&(src)->__stat_eh_##event##__), 2, LOCATION);
|
||||
#define CONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1, a2))(&(src)->__stat_eh_##event##__), 3, LOCATION);
|
||||
#define CONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1, a2, a3))(&(src)->__stat_eh_##event##__), 4, LOCATION);
|
||||
#define CONNECT CONNECT0
|
||||
|
||||
#define WEAK_CONNECT0(ret, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__), 0, 0, LOCATION);
|
||||
#define WEAK_CONNECT1(ret, a0, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__), 0, 1, LOCATION);
|
||||
#define WEAK_CONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__), 0, 2, LOCATION);
|
||||
#define WEAK_CONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__), 0, 3, LOCATION);
|
||||
#define WEAK_CONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__), 0, 4, LOCATION);
|
||||
#define WEAK_CONNECT WEAK_CONNECT0
|
||||
|
||||
#define DISCONNECT0(ret, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__));
|
||||
#define DISCONNECT1(ret, a0, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__));
|
||||
#define DISCONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__));
|
||||
#define DISCONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__));
|
||||
#define DISCONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__));
|
||||
#define DISCONNECT DISCONNECT0
|
||||
|
||||
#define HANDLER(handler) __stat_eh_##handler##__
|
||||
|
||||
#define __PIOBJECT_SIGNATURE__ 0xabcdbadc
|
||||
|
||||
#endif
|
||||
|
||||
typedef void (*Handler)(void * );
|
||||
|
||||
class PIP_EXPORT PIObject {
|
||||
friend class PIObjectManager;
|
||||
friend void dumpApplication();
|
||||
typedef PIObject __PIObject__;
|
||||
typedef void __Parent__;
|
||||
friend class PIIntrospection;
|
||||
public:
|
||||
|
||||
//! Contructs PIObject with name "name"
|
||||
explicit PIObject(const PIString & name = PIString());
|
||||
|
||||
virtual ~PIObject();
|
||||
|
||||
private:
|
||||
explicit PIObject(const PIObject & );
|
||||
void operator =(const PIObject & );
|
||||
|
||||
uint _signature_;
|
||||
|
||||
public:
|
||||
|
||||
//! Returns object name
|
||||
PIString name() const {return property(PIStringAscii("name")).toString();}
|
||||
|
||||
//! Returns object class name
|
||||
virtual const char * className() const {return "PIObject";}
|
||||
|
||||
virtual uint classNameID() const {static uint ret = PIStringAscii("PIObject").hash(); return ret;}
|
||||
|
||||
static const PIString __classNameS() {return PIStringAscii("PIObject");}
|
||||
static uint __classNameIDS() {static uint ret = PIStringAscii("PIObject").hash(); return ret;}
|
||||
|
||||
//! Returns parent object class name
|
||||
virtual const char * parentClassName() const {return "";}
|
||||
|
||||
|
||||
//! Return if debug of this object is active
|
||||
bool debug() const {return property(PIStringAscii("debug")).toBool();}
|
||||
|
||||
|
||||
//! Set object name
|
||||
void setName(const PIString & name) {setProperty(PIStringAscii("name"), name);}
|
||||
void setName(const char * name) {setName(PIStringAscii(name));}
|
||||
|
||||
//! Set object debug active
|
||||
void setDebug(bool debug) {setProperty(PIStringAscii("debug"), debug);}
|
||||
|
||||
//! Returns properties of the object
|
||||
PIMap<PIString, PIVariant> properties() const;
|
||||
|
||||
//! Returns properties count of the object
|
||||
int propertiesCount() const {return properties_.size_s();}
|
||||
|
||||
//! Returns property with name "name"
|
||||
PIVariant property(const PIString & name) const {return properties_.value(name.hash(), Property(PIString(), PIVariant())).second;}
|
||||
PIVariant property(const char * name) const {return property(PIStringAscii(name));}
|
||||
|
||||
//! Set property with name "name" to "value". If there is no such property in object it will be added
|
||||
void setProperty(const PIString & name, const PIVariant & value) {properties_[name.hash()] = Property(name, value); propertyChanged(name);}
|
||||
void setProperty(const char * name, const PIVariant & value) {setProperty(PIStringAscii(name), value);}
|
||||
|
||||
//! Returns if property with name "name" exists
|
||||
bool isPropertyExists(const PIString & name) const {return properties_.contains(name.hash());}
|
||||
bool isPropertyExists(const char * name) const {return isPropertyExists(PIStringAscii(name));}
|
||||
|
||||
void setThreadSafe(bool yes) {thread_safe_ = yes;}
|
||||
bool isThreadSafe() const {return thread_safe_;}
|
||||
|
||||
bool execute(const PIString & method, const PIVector<PIVariant> & vl);
|
||||
bool execute(const PIString & method) {return execute(method, PIVector<PIVariant>());}
|
||||
bool execute(const PIString & method, const PIVariant & v0) {return execute(method, PIVector<PIVariant>() << v0);}
|
||||
bool execute(const PIString & method, const PIVariant & v0, const PIVariant & v1) {return execute(method, PIVector<PIVariant>() << v0 << v1);}
|
||||
bool execute(const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return execute(method, PIVector<PIVariant>() << v0 << v1 << v2);}
|
||||
bool execute(const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return execute(method, PIVector<PIVariant>() << v0 << v1 << v2 << v3);}
|
||||
|
||||
bool executeQueued(PIObject * performer, const PIString & method, const PIVector<PIVariant> & vl);
|
||||
bool executeQueued(PIObject * performer, const PIString & method) {return executeQueued(performer, method, PIVector<PIVariant>());}
|
||||
bool executeQueued(PIObject * performer, const PIString & method, const PIVariant & v0) {return executeQueued(performer, method, PIVector<PIVariant>() << v0);}
|
||||
bool executeQueued(PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1) {return executeQueued(performer, method, PIVector<PIVariant>() << v0 << v1);}
|
||||
bool executeQueued(PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return executeQueued(performer, method, PIVector<PIVariant>() << v0 << v1 << v2);}
|
||||
bool executeQueued(PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return executeQueued(performer, method, PIVector<PIVariant>() << v0 << v1 << v2 << v3);}
|
||||
|
||||
static bool execute(PIObject * o, const PIString & method, const PIVector<PIVariant> & vl) {return o->execute(method, vl);}
|
||||
static bool execute(PIObject * o, const PIString & method) {return execute(o, method, PIVector<PIVariant>());}
|
||||
static bool execute(PIObject * o, const PIString & method, const PIVariant & v0) {return execute(o, method, PIVector<PIVariant>() << v0);}
|
||||
static bool execute(PIObject * o, const PIString & method, const PIVariant & v0, const PIVariant & v1) {return execute(o, method, PIVector<PIVariant>() << v0 << v1);}
|
||||
static bool execute(PIObject * o, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return execute(o, method, PIVector<PIVariant>() << v0 << v1 << v2);}
|
||||
static bool execute(PIObject * o, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return execute(o, method, PIVector<PIVariant>() << v0 << v1 << v2 << v3);}
|
||||
|
||||
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVector<PIVariant> & vl) {return o->executeQueued(performer, method, vl);}
|
||||
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method) {return executeQueued(o, performer, method, PIVector<PIVariant>());}
|
||||
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVariant & v0) {return executeQueued(o, performer, method, PIVector<PIVariant>() << v0);}
|
||||
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1) {return executeQueued(o, performer, method, PIVector<PIVariant>() << v0 << v1);}
|
||||
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return executeQueued(o, performer, method, PIVector<PIVariant>() << v0 << v1 << v2);}
|
||||
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return executeQueued(o, performer, method, PIVector<PIVariant>() << v0 << v1 << v2 << v3);}
|
||||
|
||||
void dump(const PIString & line_prefix = PIString()) const;
|
||||
|
||||
|
||||
PIStringList scopeList() const;
|
||||
PIStringList methodsEH() const;
|
||||
bool isMethodEHContains(const PIString & name) const;
|
||||
PIString methodEHArguments(const PIString & name) const;
|
||||
PIString methodEHFullFormat(const PIString & name) const;
|
||||
PIString methodEHFromAddr(const void * addr) const;
|
||||
|
||||
// / Direct connect
|
||||
static void piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc);
|
||||
static bool piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer = 0);
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
static bool piConnectLS(PIObject * src, const PIString & sig, std::function<void()> * f, const char * loc);
|
||||
template <typename INPUT, typename... TYPES>
|
||||
static std::function<void()> * __newFunctor(void(*stat_handler)(void*,TYPES...), INPUT functor) {
|
||||
return (std::function<void()>*)(new std::function<void(TYPES...)>(functor));
|
||||
}
|
||||
#endif
|
||||
|
||||
// / Through names and mixed
|
||||
static void piConnect(const PIString & src, const PIString & sig, void * dest, void * ev_h);
|
||||
static void piConnect(PIObject * src, const PIString & sig, const PIString & dest, void * ev_h);
|
||||
static void piConnect(const PIString & src, const PIString & sig, const PIString & dest, void * ev_h);
|
||||
|
||||
|
||||
static void piDisconnect(PIObject * src, const PIString & sig, PIObject * dest, void * ev_h);
|
||||
static void piDisconnect(PIObject * src, const PIString & sig, PIObject * dest);
|
||||
|
||||
//! Disconnect object "src" from all connections with event name "sig"
|
||||
static void piDisconnect(PIObject * src, const PIString & sig);
|
||||
|
||||
//! Disconnect object "src" from all connections, i.e. all connections where object "src" is emitter
|
||||
static void piDisconnect(PIObject * src);
|
||||
|
||||
// / Raise events
|
||||
static void raiseEvent(PIObject * sender, const uint eventID) {
|
||||
for (int j = 0; j < sender->connections.size_s(); ++j) {
|
||||
__Connection i(sender->connections[j]);
|
||||
if (i.eventID != eventID) continue;
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
if (i.functor) {
|
||||
(*(i.functor))();
|
||||
} else {
|
||||
#endif
|
||||
if (i.performer) {
|
||||
i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender));
|
||||
} else {
|
||||
bool ts = sender->thread_safe_;
|
||||
if (ts) i.dest_o->mutex_.lock();
|
||||
i.dest_o->emitter_ = sender;
|
||||
((void( *)(void * ))i.slot)(i.dest);
|
||||
if (i.dest_o->isPIObject()) {
|
||||
i.dest_o->emitter_ = 0;
|
||||
if (ts) i.dest_o->mutex_.unlock();
|
||||
}
|
||||
}
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
}
|
||||
#endif
|
||||
if (!sender->isPIObject()) break;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T0>
|
||||
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0()) {
|
||||
for (int j = 0; j < sender->connections.size_s(); ++j) {
|
||||
__Connection i(sender->connections[j]);
|
||||
if (i.eventID != eventID) continue;
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
if (i.functor) {
|
||||
(*((std::function<void(T0)>*)i.functor))(v0);
|
||||
} else {
|
||||
#endif
|
||||
if (i.performer) {
|
||||
PIVector<PIVariant> vl;
|
||||
if (i.args_count > 0) vl << PIVariant::fromValue(v0);
|
||||
i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender, vl));
|
||||
} else {
|
||||
bool ts = sender->thread_safe_;
|
||||
if (ts) i.dest_o->mutex_.lock();
|
||||
i.dest_o->emitter_ = sender;
|
||||
if (i.args_count == 0) ((void(*)(void *))i.slot)(i.dest);
|
||||
else ((void(*)(void * , T0))i.slot)(i.dest, v0);
|
||||
if (i.dest_o->isPIObject()) {
|
||||
i.dest_o->emitter_ = 0;
|
||||
if (ts) i.dest_o->mutex_.unlock();
|
||||
}
|
||||
}
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
}
|
||||
#endif
|
||||
if (!sender->isPIObject()) break;
|
||||
}
|
||||
}
|
||||
template <typename T0, typename T1>
|
||||
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1()) {
|
||||
for (int j = 0; j < sender->connections.size_s(); ++j) {
|
||||
__Connection i(sender->connections[j]);
|
||||
if (i.eventID != eventID) continue;
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
if (i.functor) {
|
||||
(*((std::function<void(T0, T1)>*)i.functor))(v0, v1);
|
||||
} else {
|
||||
#endif
|
||||
if (i.performer) {
|
||||
PIVector<PIVariant> vl;
|
||||
if (i.args_count > 0) vl << PIVariant::fromValue(v0);
|
||||
if (i.args_count > 1) vl << PIVariant::fromValue(v1);
|
||||
i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender, vl));
|
||||
} else {
|
||||
bool ts = sender->thread_safe_;
|
||||
if (ts) i.dest_o->mutex_.lock();
|
||||
i.dest_o->emitter_ = sender;
|
||||
switch (i.args_count) {
|
||||
case 0: ((void(*)(void *))i.slot)(i.dest); break;
|
||||
case 1: ((void(*)(void * , T0))i.slot)(i.dest, v0); break;
|
||||
default: ((void(*)(void * , T0, T1))i.slot)(i.dest, v0, v1); break;
|
||||
}
|
||||
if (i.dest_o->isPIObject()) {
|
||||
i.dest_o->emitter_ = 0;
|
||||
if (ts) i.dest_o->mutex_.unlock();
|
||||
}
|
||||
}
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
}
|
||||
#endif
|
||||
if (!sender->isPIObject()) break;
|
||||
}
|
||||
}
|
||||
template <typename T0, typename T1, typename T2>
|
||||
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2()) {
|
||||
for (int j = 0; j < sender->connections.size_s(); ++j) {
|
||||
__Connection i(sender->connections[j]);
|
||||
if (i.eventID != eventID) continue;
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
if (i.functor) {
|
||||
(*((std::function<void(T0, T1, T2)>*)i.functor))(v0, v1, v2);
|
||||
} else {
|
||||
#endif
|
||||
if (i.performer) {
|
||||
PIVector<PIVariant> vl;
|
||||
if (i.args_count > 0) vl << PIVariant::fromValue(v0);
|
||||
if (i.args_count > 1) vl << PIVariant::fromValue(v1);
|
||||
if (i.args_count > 2) vl << PIVariant::fromValue(v2);
|
||||
i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender, vl));
|
||||
} else {
|
||||
bool ts = sender->thread_safe_;
|
||||
if (ts) i.dest_o->mutex_.lock();
|
||||
i.dest_o->emitter_ = sender;
|
||||
switch (i.args_count) {
|
||||
case 0: ((void(*)(void *))i.slot)(i.dest); break;
|
||||
case 1: ((void(*)(void * , T0))i.slot)(i.dest, v0); break;
|
||||
case 2: ((void(*)(void * , T0, T1))i.slot)(i.dest, v0, v1); break;
|
||||
default: ((void(*)(void * , T0, T1, T2))i.slot)(i.dest, v0, v1, v2); break;
|
||||
}
|
||||
if (i.dest_o->isPIObject()) {
|
||||
i.dest_o->emitter_ = 0;
|
||||
if (ts) i.dest_o->mutex_.unlock();
|
||||
}
|
||||
}
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
}
|
||||
#endif
|
||||
if (!sender->isPIObject()) break;
|
||||
}
|
||||
}
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2(), const T3 & v3 = T3()) {
|
||||
for (int j = 0; j < sender->connections.size_s(); ++j) {
|
||||
__Connection i(sender->connections[j]);
|
||||
if (i.eventID != eventID) continue;
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
if (i.functor) {
|
||||
(*((std::function<void(T0, T1, T2, T3)>*)i.functor))(v0, v1, v2, v3);
|
||||
} else {
|
||||
#endif
|
||||
if (i.performer) {
|
||||
PIVector<PIVariant> vl;
|
||||
if (i.args_count > 0) vl << PIVariant::fromValue(v0);
|
||||
if (i.args_count > 1) vl << PIVariant::fromValue(v1);
|
||||
if (i.args_count > 2) vl << PIVariant::fromValue(v2);
|
||||
if (i.args_count > 3) vl << PIVariant::fromValue(v3);
|
||||
i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender, vl));
|
||||
} else {
|
||||
bool ts = sender->thread_safe_;
|
||||
if (ts) i.dest_o->mutex_.lock();
|
||||
i.dest_o->emitter_ = sender;
|
||||
switch (i.args_count) {
|
||||
case 0: ((void(*)(void *))i.slot)(i.dest); break;
|
||||
case 1: ((void(*)(void * , T0))i.slot)(i.dest, v0); break;
|
||||
case 2: ((void(*)(void * , T0, T1))i.slot)(i.dest, v0, v1); break;
|
||||
case 3: ((void(*)(void * , T0, T1, T2))i.slot)(i.dest, v0, v1, v2); break;
|
||||
default: ((void(*)(void * , T0, T1, T2, T3))i.slot)(i.dest, v0, v1, v2, v3); break;
|
||||
}
|
||||
if (i.dest_o->isPIObject()) {
|
||||
i.dest_o->emitter_ = 0;
|
||||
if (ts) i.dest_o->mutex_.unlock();
|
||||
}
|
||||
}
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
}
|
||||
#endif
|
||||
if (!sender->isPIObject()) break;
|
||||
}
|
||||
}
|
||||
|
||||
//! Returns PIObject* with name "name" or 0, if there is no object found
|
||||
static PIObject * findByName(const PIString & name) {
|
||||
PIMutexLocker _ml(mutexObjects());
|
||||
piForeach (PIObject * i, PIObject::objects()) {
|
||||
if (i->name() != name) continue;
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool isPIObject() const {return isPIObject(this);}
|
||||
template<typename T>
|
||||
bool isTypeOf() const {
|
||||
if (!isPIObject()) return false;
|
||||
return scopeList().contains(T::__classNameS());
|
||||
}
|
||||
template<typename T>
|
||||
T * cast() const {
|
||||
if (!isTypeOf<T>()) return (T*)0;
|
||||
return (T*)this;
|
||||
}
|
||||
|
||||
static bool isPIObject(const PIObject * o);
|
||||
static bool isPIObject(const void * o) {return isPIObject((PIObject*)o);}
|
||||
template<typename T>
|
||||
static bool isTypeOf(const PIObject * o) {return o->isTypeOf<T>();}
|
||||
template<typename T>
|
||||
static bool isTypeOf(const void * o) {return isTypeOf<T>((PIObject*)o);}
|
||||
static PIString simplifyType(const char * a);
|
||||
|
||||
struct __MetaFunc {
|
||||
__MetaFunc(): addr(0), addrV(0) {;}
|
||||
bool isNull() const {return addr == 0;}
|
||||
PIString arguments() const;
|
||||
PIString fullFormat() const;
|
||||
void * addr;
|
||||
void * addrV;
|
||||
PIString func_name;
|
||||
PIString type_ret;
|
||||
PIString scope;
|
||||
PIStringList types;
|
||||
PIStringList names;
|
||||
};
|
||||
struct __MetaData {
|
||||
__MetaData() {scope_list << PIStringAscii("PIObject"); scope_id << PIStringAscii("PIObject").hash();}
|
||||
void addScope(const PIString & s, uint shash);
|
||||
PIStringList scope_list;
|
||||
PISet<uint> scope_id;
|
||||
PISet<const void * > eh_set;
|
||||
PIMap<const void * , __MetaFunc> eh_func;
|
||||
};
|
||||
typedef PIPair<const void * , __MetaFunc> __EHPair;
|
||||
|
||||
static PIMutex & __meta_mutex();
|
||||
static PIMap<uint, __MetaData> & __meta_data(); // [hash(classname)]=__MetaData
|
||||
|
||||
//! \brief Execute all posted events from CONNECTU_QUEUED connections
|
||||
void callQueuedEvents();
|
||||
|
||||
//! \brief Check if any CONNECTU_QUEUED connections to this object and execute them.
|
||||
//! \details This function is more optimized than \a callQueuedEvents() for objects that doesn`t
|
||||
//! appears as \"performer\" target at CONNECTU_QUEUED
|
||||
bool maybeCallQueuedEvents() {if (proc_event_queue) callQueuedEvents(); return proc_event_queue;}
|
||||
|
||||
protected:
|
||||
|
||||
//! Returns PIObject* which has raised an event. This value is correct only in definition of some event handler
|
||||
PIObject * emitter() const {return emitter_;}
|
||||
|
||||
//! Virtual function executes after property with name "name" has been changed
|
||||
virtual void propertyChanged(const PIString & name) {}
|
||||
|
||||
EVENT(deleted)
|
||||
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
/** \fn void deleted()
|
||||
* \brief Raise before object delete
|
||||
* \note This event raised from destructor, so use only emitter() value,
|
||||
* don`t try to cast deleted object to some subclass! */
|
||||
|
||||
//! \}
|
||||
|
||||
private:
|
||||
struct __Connection {
|
||||
__Connection(void * sl = 0, void * si = 0, const PIString & e = PIString(), PIObject * d_o = 0, void * d = 0, int ac = 0, PIObject * p = 0) {
|
||||
slot = sl;
|
||||
signal = si;
|
||||
event = e;
|
||||
eventID = e.hash();
|
||||
dest_o = d_o;
|
||||
dest = d;
|
||||
args_count = ac;
|
||||
performer = p;
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
functor = 0;
|
||||
#endif
|
||||
}
|
||||
void destroy();
|
||||
void * slot;
|
||||
void * signal;
|
||||
#ifdef PIP_CXX11_SUPPORT
|
||||
std::function<void()> * functor;
|
||||
#endif
|
||||
PIString event;
|
||||
uint eventID;
|
||||
PIObject * dest_o;
|
||||
PIObject * performer;
|
||||
void * dest;
|
||||
int args_count;
|
||||
};
|
||||
struct __QueuedEvent {
|
||||
__QueuedEvent(void * sl = 0, void * d = 0, PIObject * d_o = 0, PIObject * s = 0, const PIVector<PIVariant> & v = PIVector<PIVariant>()) {
|
||||
slot = sl;
|
||||
dest = d;
|
||||
dest_o = d_o;
|
||||
src = s;
|
||||
values = v;
|
||||
}
|
||||
void * slot;
|
||||
void * dest;
|
||||
PIObject * dest_o;
|
||||
PIObject * src;
|
||||
PIVector<PIVariant> values;
|
||||
};
|
||||
typedef PIPair<PIString, PIVariant> Property;
|
||||
typedef PIPair<uint, PIPair<PIString, PIVariant> > PropertyHash;
|
||||
|
||||
bool findSuitableMethodV(const PIString & method, int args, int & ret_args, __MetaFunc & ret);
|
||||
PIVector<__MetaFunc> findEH(const PIString & name) const;
|
||||
__MetaFunc methodEH(const void * addr) const;
|
||||
void updateConnectors();
|
||||
void postQueuedEvent(const __QueuedEvent & e);
|
||||
void * toThis() const;
|
||||
virtual int ptrOffset() const {return 0;}
|
||||
|
||||
static PIVector<PIObject * > & objects();
|
||||
static PIMutex & mutexObjects();
|
||||
static void callAddrV(void * slot, void * obj, int args, const PIVector<PIVariant> & vl);
|
||||
|
||||
|
||||
PIVector<__Connection> connections;
|
||||
PIMap<uint, PIPair<PIString, PIVariant> > properties_;
|
||||
PISet<PIObject * > connectors;
|
||||
PIVector<__QueuedEvent> events_queue;
|
||||
PIMutex mutex_, mutex_connect, mutex_queue;
|
||||
PIObject * emitter_;
|
||||
bool thread_safe_, proc_event_queue;
|
||||
|
||||
};
|
||||
|
||||
|
||||
void dumpApplication();
|
||||
bool dumpApplicationToFile(const PIString & path);
|
||||
|
||||
#endif // PIOBJECT_H
|
||||
133
lib/main/core/pipropertystorage.cpp
Normal file
133
lib/main/core/pipropertystorage.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Storage of properties for GUI usage
|
||||
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 "pipropertystorage.h"
|
||||
|
||||
|
||||
bool PIPropertyStorage::isPropertyExists(const PIString & _name) const {
|
||||
for (uint i = 0; i < props.size(); ++i)
|
||||
if (props[i].name == _name)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void PIPropertyStorage::addProperty(const PIPropertyStorage::Property & p) {
|
||||
for (uint i = 0; i < props.size(); ++i)
|
||||
if (props[i].name == p.name) {
|
||||
props[i] = p;
|
||||
return;
|
||||
}
|
||||
props << p;
|
||||
}
|
||||
|
||||
|
||||
void PIPropertyStorage::removeProperty(const PIString & _name) {
|
||||
for (uint i = 0; i < props.size(); ++i)
|
||||
if (props[i].name == _name) {
|
||||
props.remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIPropertyStorage::removePropertiesByFlag(int flag) {
|
||||
for (int i = 0; i < props.size_s(); ++i)
|
||||
if ((props[i].flags & flag) == flag) {
|
||||
props.remove(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIPropertyStorage::updateProperties(const PIVector<PIPropertyStorage::Property> & properties_, int flag_ignore) {
|
||||
PIMap<PIString, PIVariant> values;
|
||||
piForeachC(Property & p, props)
|
||||
if (((p.flags & flag_ignore) != flag_ignore) || (flag_ignore == 0))
|
||||
values[p.name] = p.value;
|
||||
props = properties_;
|
||||
for (uint i = 0; i < props.size(); ++i) {
|
||||
Property & p(props[i]);
|
||||
if (values.contains(p.name)) {
|
||||
PIVariant pv = values[p.name];
|
||||
if (pv.type() == p.value.type())
|
||||
p.value = pv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIPropertyStorage::Property PIPropertyStorage::propertyByName(const PIString & name) const {
|
||||
piForeachC(Property & p, props)
|
||||
if (p.name == name)
|
||||
return p;
|
||||
return Property();
|
||||
}
|
||||
|
||||
|
||||
PIVariant PIPropertyStorage::propertyValueByName(const PIString & name) const {
|
||||
piForeachC(Property & p, props)
|
||||
if (p.name == name)
|
||||
return p.value;
|
||||
return PIVariant();
|
||||
}
|
||||
|
||||
|
||||
void PIPropertyStorage::setPropertyValue(const PIString & name, const PIVariant & value) {
|
||||
for (uint i = 0; i < props.size(); ++i)
|
||||
if (props[i].name == name) {
|
||||
props[i].value = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIPropertyStorage::setPropertyComment(const PIString & name, const PIString & comment) {
|
||||
for (uint i = 0; i < props.size(); ++i)
|
||||
if (props[i].name == name) {
|
||||
props[i].comment = comment;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIPropertyStorage::setPropertyFlags(const PIString & name, int flags) {
|
||||
for (uint i = 0; i < props.size(); ++i)
|
||||
if (props[i].name == name) {
|
||||
props[i].flags = flags;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIPropertyStorage::Property & PIPropertyStorage::operator[](const PIString & name) {
|
||||
piForeach (Property & p, props)
|
||||
if (p.name == name)
|
||||
return p;
|
||||
addProperty(name, "");
|
||||
return props.back();
|
||||
}
|
||||
|
||||
|
||||
const PIPropertyStorage::Property PIPropertyStorage::operator[](const PIString & name) const {
|
||||
piForeachC (Property & p, props)
|
||||
if (p.name == name)
|
||||
return p;
|
||||
return Property();
|
||||
}
|
||||
172
lib/main/core/pipropertystorage.h
Normal file
172
lib/main/core/pipropertystorage.h
Normal file
@@ -0,0 +1,172 @@
|
||||
/*! \file pipropertystorage.h
|
||||
* \brief Storage of properties for GUI usage
|
||||
*
|
||||
* This file declare PIPropertyStorage
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Storage of properties for GUI usage
|
||||
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 PIPROPERTYSTORAGE_H
|
||||
#define PIPROPERTYSTORAGE_H
|
||||
|
||||
#include "pivariant.h"
|
||||
|
||||
/**
|
||||
* @brief Key-value storage, based on PIVector with PIPropertyStorage::Property elements. Each element in vector
|
||||
* contains unique name and you can identify property by name with propertyValueByName(), propertyByName().
|
||||
* You can add property using addProperty(const Property&), addProperty(const PIString&, const PIVariant&, const PIString&, int).
|
||||
*/
|
||||
class PIPropertyStorage {
|
||||
public:
|
||||
PIPropertyStorage() {}
|
||||
|
||||
/**
|
||||
* @brief PIPropertyStorage element.
|
||||
*/
|
||||
struct Property {
|
||||
Property(const PIString & n = PIString(), const PIString & c = PIString(), const PIVariant & v = PIVariant(), int f = 0):
|
||||
name(n), comment(c), value(v), flags(f) {}
|
||||
|
||||
bool toBool() const {return value.toBool();}
|
||||
int toInt() const {return value.toInt();}
|
||||
float toFloat() const {return value.toFloat();}
|
||||
double toDouble() const {return value.toDouble();}
|
||||
PIString toString() const {return value.toString();}
|
||||
|
||||
/*! Uniqueue id of property */
|
||||
PIString name;
|
||||
|
||||
/*! Optional description of property */
|
||||
PIString comment;
|
||||
|
||||
/*! Custom value of property */
|
||||
PIVariant value;
|
||||
|
||||
/*! Abstract flags which may be used for user needs */
|
||||
int flags;
|
||||
};
|
||||
|
||||
PIPropertyStorage(const PIVector<Property> & pl) {props = pl;}
|
||||
|
||||
typedef PIVector<Property>::const_iterator const_iterator;
|
||||
typedef PIVector<Property>::iterator iterator;
|
||||
typedef Property value_type;
|
||||
|
||||
iterator begin() {return props.begin();}
|
||||
const_iterator begin() const {return props.begin();}
|
||||
iterator end() {return props.end();}
|
||||
const_iterator end() const {return props.end();}
|
||||
|
||||
int length() const {return props.length();}
|
||||
int size() const {return props.size();}
|
||||
bool isEmpty() const {return props.isEmpty();}
|
||||
Property & front() {return props.front();}
|
||||
const Property & front() const {return props.front();}
|
||||
Property & back() {return props.back();}
|
||||
const Property & back() const {return props.back();}
|
||||
void removeAt(int i) {props.remove(i);}
|
||||
void clear() {props.clear();}
|
||||
|
||||
PIPropertyStorage copy() const {return PIPropertyStorage(*this);}
|
||||
int propertiesCount() const {return props.size();}
|
||||
PIVector<Property> & properties() {return props;}
|
||||
const PIVector<Property> & properties() const {return props;}
|
||||
const PIPropertyStorage & propertyStorage() const {return *this;}
|
||||
bool isPropertyExists(const PIString & _name) const;
|
||||
void clearProperties() {props.clear();}
|
||||
|
||||
/**
|
||||
* @brief Add property if name isn't present in storage, otherwrise update existing property with same name.
|
||||
*
|
||||
* @param p to copy in storage
|
||||
*/
|
||||
void addProperty(const Property & p);
|
||||
|
||||
/**
|
||||
* @brief First of all construct Property with method params. After then add property if name isn't present
|
||||
* in storage, otherwrise update existing property with same name.
|
||||
*/
|
||||
void addProperty(const PIString & _name, const PIVariant & _def_value, const PIString & _comment = PIString(), int _flags = 0) {addProperty(Property(_name, _comment, _def_value, _flags));}
|
||||
void removeProperty(const PIString & _name);
|
||||
void removePropertiesByFlag(int flag);
|
||||
void updateProperties(const PIVector<Property> & properties_, int flag_ignore = 0);
|
||||
|
||||
/**
|
||||
* @brief Search property by name and return it.
|
||||
*
|
||||
* @param name of property
|
||||
* @return property value or default constructed Property
|
||||
*/
|
||||
Property propertyByName(const PIString & name) const;
|
||||
|
||||
/**
|
||||
* @brief Search property by name and return property value.
|
||||
*
|
||||
* @param name of property
|
||||
* @return property value or invalid PIVariant if name unknown
|
||||
*/
|
||||
PIVariant propertyValueByName(const PIString & name) const;
|
||||
|
||||
/**
|
||||
* @brief Set value of property with specific name if name is present in storage.
|
||||
*
|
||||
* @param name of property to set value
|
||||
* @param value to set
|
||||
*/
|
||||
void setPropertyValue(const PIString & name, const PIVariant & value);
|
||||
|
||||
/**
|
||||
* @brief Set comment of property with specific name if name is present in storage.
|
||||
*
|
||||
* @param name of property to set comment
|
||||
* @param comment to set
|
||||
*/
|
||||
void setPropertyComment(const PIString & name, const PIString & comment);
|
||||
|
||||
/**
|
||||
* @brief Set flags of property with specific name if name is present in storage.
|
||||
*
|
||||
* @param name of property to set flags
|
||||
* @param flags to set
|
||||
*/
|
||||
void setPropertyFlags(const PIString & name, int flags);
|
||||
|
||||
PIPropertyStorage & operator <<(const PIPropertyStorage::Property & p) {props << p; return *this;}
|
||||
PIPropertyStorage & operator <<(const PIVector<Property> & p) {props << p; return *this;}
|
||||
PIPropertyStorage & operator <<(const PIPropertyStorage & p) {props << p.props; return *this;}
|
||||
Property & operator[](int i) {return props[i];}
|
||||
const Property & operator[](int i) const {return props[i];}
|
||||
Property & operator[](const PIString & name);
|
||||
const Property operator[](const PIString & name) const;
|
||||
|
||||
static Property parsePropertyLine(PIString l);
|
||||
|
||||
protected:
|
||||
PIVector<Property> props;
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIPropertyStorage::Property & v) {s << v.name << v.value << v.comment << v.flags; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIPropertyStorage::Property & v) {s >> v.name >> v.value >> v.comment >> v.flags; return s;}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIPropertyStorage & v) {s << v.properties(); return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIPropertyStorage & v) {s >> v.properties(); return s;}
|
||||
|
||||
#endif // PIPROPERTYSTORAGE_H
|
||||
1225
lib/main/core/pistring.cpp
Normal file
1225
lib/main/core/pistring.cpp
Normal file
@@ -0,0 +1,1225 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
String
|
||||
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 "piincludes_p.h"
|
||||
#include "pistring.h"
|
||||
#include "pistringlist.h"
|
||||
#ifdef PIP_ICU
|
||||
# define U_NOEXCEPT
|
||||
# include "unicode/ucnv.h"
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
# include <stringapiset.h>
|
||||
#endif
|
||||
#include <wchar.h>
|
||||
#ifdef ANDROID
|
||||
# if __ANDROID_API__ < 21
|
||||
# define wctomb(s, wc) wcrtomb(s, wc, NULL)
|
||||
# define mbtowc(pwc, s, n) mbrtowc(pwc, s, n, NULL)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*! \class PIString
|
||||
* \brief String class
|
||||
* \details PIP use this class for use string information.
|
||||
*
|
||||
* \section PIString_sec0 Synopsis
|
||||
* This class based on \a PIVector to store information.
|
||||
* String is a sequence of \a PIChar and can contain multibyte
|
||||
* symbols. Therefore real memory size of string is symbols count * 4.
|
||||
* String can be constucted from many types of data and can be converted
|
||||
* to many types. There are man operators and handly functions to use
|
||||
* string as you wish.
|
||||
*
|
||||
* \section PIString_sec1 To/from data convertions
|
||||
* Most common constructor is \a PIString(const char * str), where "str"
|
||||
* is null-terminated string, e.g. \c "string". This is 7 chars with last char = 0.
|
||||
* Also you can constructs \a PIString from single \a PIChar, \a PIByteArray,
|
||||
* other \a PIString or sequency of the same characters with custom length.\n \n
|
||||
* This class has implicit conversions to <tt>const char * </tt> and
|
||||
* \c std::string. Also there are functions to make same convertions:
|
||||
* * \a data() - to <tt>const char * </tt>,
|
||||
* * \a stdString() - to \c std::string,
|
||||
* * \a toByteArray() - to \a PIByteArray.
|
||||
*
|
||||
* \section PIString_sec2 Numeric operations
|
||||
* You can get symbolic representation of any numeric value with function
|
||||
* \a setNumber(any integer value, int base = 10, bool * ok = 0). Default
|
||||
* arguments are set for decimal base system, but you can choose any system
|
||||
* from 2 to 40. There are the same static functions \a fromNumber(), that
|
||||
* returns \a PIString. \n
|
||||
* Also there is function \a setReadableSize() which is set human-readable
|
||||
* size in bytes, Kb, Mb, Gb or Pb. Static analog is \a readableSize().
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*! \fn int versionCompare(const PIString & v0, const PIString & v1, int components = 6)
|
||||
* \relatesalso PIString
|
||||
* \brief Compare two version strings in free notation and returns 0, -1 or 1
|
||||
* \details This function parse version to number codes and labels. Then it
|
||||
* compare no more than "components" codes. If there is no difference, compare
|
||||
* labels. Each label has corresponding integer value, so
|
||||
* "prealpha" < "alpha" < "prebeta" < "beta" < "rcN" < "" < "rN".
|
||||
* Example:
|
||||
* \code
|
||||
* piCout << versionCompare("1.0.0_rc2-999", "1.0.1_rc2-999"); // -1
|
||||
* piCout << versionCompare("1.0.0", "0.9.2"); // 1
|
||||
* piCout << versionCompare("1.0.0_r1", "1.0.0"); // 1
|
||||
* piCout << versionCompare("1.0.0_r1", "1.0.0", 3); // 0
|
||||
* piCout << versionCompare("1.0.0_r1", "1.0.0", 3); // 0
|
||||
* piCout << versionCompare(".2-alpha", "0.2_alpha"); // 0
|
||||
* piCout << versionCompare("1_prebeta", "1.0_alpha"); // 1
|
||||
* \endcode
|
||||
* \return
|
||||
* * 0 - equal
|
||||
* * 1 - v0 > v1
|
||||
* * -1 - v0 < v1
|
||||
*
|
||||
*
|
||||
* \fn PIString versionNormalize(const PIString & v)
|
||||
* \relatesalso PIString
|
||||
* \brief Converts version string in free notation to classic view
|
||||
* \details Parse version as described in \a versionCompare() and
|
||||
* returns classic view of codes and labels: major.minor.revision[-build][_label].
|
||||
* Example:
|
||||
* \code
|
||||
* piCout << versionNormalize(""); // 0.0.0
|
||||
* piCout << versionNormalize("1"); // 1.0.0
|
||||
* piCout << versionNormalize("1.2"); // 1.2.0
|
||||
* piCout << versionNormalize("1.2.3"); // 1.2.3
|
||||
* piCout << versionNormalize("1.2+rc1.99"); // 1.2.99_rc1
|
||||
* piCout << versionNormalize("1.2-alpha"); // 1.2.0_alpha
|
||||
* piCout << versionNormalize("1..4_rc2-999"); // 1.0.4-999_rc2
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
const char PIString::toBaseN[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^'};
|
||||
const int PIString::fromBaseN[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
|
||||
|
||||
const float PIString::ElideLeft = 0.f;
|
||||
const float PIString::ElideCenter = .5f;
|
||||
const float PIString::ElideRight = 1.f;
|
||||
|
||||
|
||||
#ifndef CC_VC
|
||||
# define pisprintf(f, v) char ch[256]; memset(ch, 0, 256); sprintf(ch, f, v);
|
||||
#else
|
||||
# define pisprintf(f, v) char ch[256]; memset(ch, 0, 256); sprintf_s(ch, 256, f, v);
|
||||
#endif
|
||||
#ifdef ANDROID
|
||||
//int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;}
|
||||
#endif
|
||||
PIString PIString::itos(const int num) {pisprintf("%d", num); return PIString(ch);}
|
||||
PIString PIString::ltos(const long num) {pisprintf("%ld", num); return PIString(ch);}
|
||||
PIString PIString::lltos(const llong num) {pisprintf("%lld", num); return PIString(ch);}
|
||||
PIString PIString::uitos(const uint num) {pisprintf("%u", num); return PIString(ch);}
|
||||
PIString PIString::ultos(const ulong num) {pisprintf("%lu", num); return PIString(ch);}
|
||||
PIString PIString::ulltos(const ullong num) {pisprintf("%llu", num); return PIString(ch);}
|
||||
PIString PIString::ftos(const float num, char format, int precision) {
|
||||
char f[8] = "%.";
|
||||
int wr = sprintf(&(f[2]), "%d", precision);
|
||||
f[2 + wr] = format;
|
||||
f[3 + wr] = 0;
|
||||
pisprintf(f, num);
|
||||
return PIString(ch);
|
||||
}
|
||||
PIString PIString::dtos(const double num, char format, int precision) {
|
||||
char f[8] = "%.";
|
||||
int wr = sprintf(&(f[2]), "%d", precision);
|
||||
f[2 + wr] = format;
|
||||
f[3 + wr] = 0;
|
||||
pisprintf(f, num);
|
||||
return PIString(ch);
|
||||
}
|
||||
#undef pisprintf
|
||||
|
||||
|
||||
|
||||
PIString PIString::fromNumberBaseS(const llong value, int base, bool * ok) {
|
||||
if (value == 0LL) return PIString("0");
|
||||
if (base < 2 || base > 40) {if (ok != 0) *ok = false; return PIString();}
|
||||
if (ok != 0) *ok = true;
|
||||
if (base == 10) return lltos(value);
|
||||
PIString ret;
|
||||
llong v = value < 0 ? -value : value, cn;
|
||||
int b = base;
|
||||
while (v >= llong(base)) {
|
||||
cn = v % b;
|
||||
v /= b;
|
||||
//cout << int(cn) << ", " << int(v) << endl;
|
||||
ret.push_front(PIChar(toBaseN[cn]));
|
||||
}
|
||||
if (v > 0) ret.push_front(PIChar(toBaseN[v]));
|
||||
if (value < 0) ret.push_front('-');
|
||||
return ret;
|
||||
}
|
||||
|
||||
PIString PIString::fromNumberBaseU(const ullong value, int base, bool * ok) {
|
||||
if (value == 0ULL) return PIString("0");
|
||||
if (base < 2 || base > 40) {if (ok != 0) *ok = false; return PIString();}
|
||||
if (ok != 0) *ok = true;
|
||||
if (base == 10) return ulltos(value);
|
||||
PIString ret;
|
||||
ullong v = value, cn;
|
||||
int b = base;
|
||||
while (v >= ullong(base)) {
|
||||
cn = v % b;
|
||||
v /= b;
|
||||
//cout << int(cn) << ", " << int(v) << endl;
|
||||
ret.push_front(PIChar(toBaseN[cn]));
|
||||
}
|
||||
if (v > 0) ret.push_front(PIChar(toBaseN[v]));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
llong PIString::toNumberBase(const PIString & value, int base, bool * ok) {
|
||||
PIString v = value.trimmed();
|
||||
if (base < 0) {
|
||||
int ind = v.find("0x");
|
||||
if (ind == 0 || ind == 1) {v.remove(ind, 2); base = 16;}
|
||||
else base = 10;
|
||||
} else
|
||||
if (base < 2 || base > 40) {if (ok != 0) *ok = false; return 0;}
|
||||
if (ok) *ok = true;
|
||||
PIVector<int> digits;
|
||||
llong ret = 0, m = 1;
|
||||
bool neg = false;
|
||||
int cs;
|
||||
for (int i = 0; i < v.size_s(); ++i) {
|
||||
if (v[i] == PIChar('-')) {neg = !neg; continue;}
|
||||
cs = fromBaseN[int(v[i].toAscii())];
|
||||
if (cs < 0 || cs >= base) {
|
||||
if (ok) *ok = false;
|
||||
break;
|
||||
}
|
||||
digits << cs;
|
||||
}
|
||||
for (int i = digits.size_s() - 1; i >= 0; --i) {
|
||||
ret += digits[i] * m;
|
||||
m *= base;
|
||||
}
|
||||
if (neg) ret = -ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PIString::appendFromChars(const char * c, int s, const char * codepage) {
|
||||
if (s <= 0) return;
|
||||
int sz;
|
||||
#ifdef PIP_ICU
|
||||
UErrorCode e((UErrorCode)0);
|
||||
UConverter * cc = ucnv_open(codepage, &e);
|
||||
if (cc) {
|
||||
UChar * ucs = new UChar[s];
|
||||
memset(ucs, 0, s * sizeof(UChar));
|
||||
e = (UErrorCode)0;
|
||||
int sz = ucnv_toUChars(cc, ucs, s, c, s, &e);
|
||||
//printf("appendFromChars %d -> %d\n", s, sz);
|
||||
//printf("PIString %d -> %d\n", c[0], ucs[0]);
|
||||
for (int i = 0; i < sz; ++i)
|
||||
push_back(PIChar(ucs[i]));
|
||||
delete[] ucs;
|
||||
ucnv_close(cc);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
# ifdef WINDOWS
|
||||
sz = MultiByteToWideChar((uint)(uintptr_t)codepage, MB_ERR_INVALID_CHARS, c, s, 0, 0);
|
||||
if (sz <= 0) return;
|
||||
wchar_t * buffer = new wchar_t[sz];
|
||||
MultiByteToWideChar((uint)(uintptr_t)codepage, MB_ERR_INVALID_CHARS, c, s, buffer, sz);
|
||||
for (int i = 0; i < sz; ++i)
|
||||
push_back(PIChar((ushort)buffer[i]));
|
||||
delete[] buffer;
|
||||
return;
|
||||
//printf("request %d\n", sz);
|
||||
# else
|
||||
wchar_t wc;
|
||||
mbtowc(0,0,0); // reset mbtowc
|
||||
//qDebug() << "FromChars ...";
|
||||
while (s>0) {
|
||||
//qDebug() << "0" << s;
|
||||
sz = mbtowc(&wc, c, s);
|
||||
//qDebug() << "1" << sz;
|
||||
if (sz < 1) break;
|
||||
push_back(PIChar(int(wc)));
|
||||
c += sz; s -= sz;
|
||||
//qDebug() << "2" << c;
|
||||
}
|
||||
//qDebug() << "FromChars done" << size();
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::fromConsole(const char * s) {
|
||||
int l = 0;
|
||||
while (s[l] != '\0') ++l;
|
||||
PIString ret;
|
||||
if (l > 0) ret.appendFromChars(s, l, __sysoemname__);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::fromSystem(const char * s) {
|
||||
int l = 0;
|
||||
while (s[l] != '\0') ++l;
|
||||
PIString ret;
|
||||
if (l > 0) ret.appendFromChars(s, l, __syslocname__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::fromUTF8(const char * s) {
|
||||
int l = 0;
|
||||
while (s[l] != '\0') ++l;
|
||||
PIString ret;
|
||||
if (l > 0) ret.appendFromChars(s, l, __utf8name__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::fromUTF8(const PIByteArray & ba) {
|
||||
PIString ret;
|
||||
if (ba.isEmpty()) return ret;
|
||||
ret.appendFromChars((const char*)ba.data(), ba.size(), __utf8name__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::fromAscii(const char * s) {
|
||||
PIString ret;
|
||||
int l = 0;
|
||||
while (s[l] != '\0') {
|
||||
ret.push_back(PIChar(short(s[l])));
|
||||
++l;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::fromCodepage(const char * s, const char * c) {
|
||||
int l = 0;
|
||||
while (s[l] != '\0') ++l;
|
||||
PIString ret;
|
||||
if (l > 0) ret.appendFromChars(s, l
|
||||
#ifdef PIP_ICU
|
||||
, c
|
||||
#else
|
||||
# ifdef WINDOWS
|
||||
, __utf8name__
|
||||
# endif
|
||||
#endif
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::readableSize(llong bytes) {
|
||||
PIString s;
|
||||
s.setReadableSize(bytes);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
void PIString::buildData(const char * cp) const {
|
||||
data_.clear();
|
||||
int sz = 0;
|
||||
#ifdef PIP_ICU
|
||||
UErrorCode e((UErrorCode)0);
|
||||
UConverter * cc = ucnv_open(cp, &e);
|
||||
if (cc) {
|
||||
char uc[8];
|
||||
for (int i = 0; i < size_s(); ++i) {
|
||||
if (at(i).isAscii())
|
||||
data_.push_back(uchar(at(i).unicode16Code()));
|
||||
else {
|
||||
e = (UErrorCode)0;
|
||||
sz = ucnv_fromUChars(cc, uc, 8, (const UChar*)(PIDeque<PIChar>::data(i)), 1, &e);
|
||||
for (int j = 0; j < sz; ++j)
|
||||
data_.push_back(uc[j]);
|
||||
}
|
||||
}
|
||||
ucnv_close(cc);
|
||||
data_.push_back('\0');
|
||||
return;
|
||||
}
|
||||
#else
|
||||
# ifdef WINDOWS
|
||||
sz = WideCharToMultiByte((uint)(uintptr_t)cp, 0, (LPCWCH)PIDeque<PIChar>::data(), PIDeque<PIChar>::size_s(), 0, 0, NULL, NULL);
|
||||
//printf("WideCharToMultiByte %d %d\n", (uint)(uintptr_t)cp, sz);
|
||||
if (sz <= 0) {
|
||||
//printf("WideCharToMultiByte erro %d\n", GetLastError());
|
||||
data_.push_back(uchar('\0'));
|
||||
return;
|
||||
}
|
||||
data_.resize(sz);
|
||||
WideCharToMultiByte((uint)(uintptr_t)cp, 0, (LPCWCH)PIDeque<PIChar>::data(), PIDeque<PIChar>::size_s(), (LPSTR)data_.data(), data_.size_s(), NULL, NULL);
|
||||
data_.push_back(uchar('\0'));
|
||||
return;
|
||||
# else
|
||||
wchar_t wc;
|
||||
char tc[8];
|
||||
wctomb(0, 0);
|
||||
for (int i = 0; i < size_s(); ++i) {
|
||||
if (at(i).isAscii()) {
|
||||
data_.push_back(uchar(at(i).toAscii()));
|
||||
continue;
|
||||
}
|
||||
wc = at(i).toWChar();
|
||||
sz = wctomb(tc, wc);
|
||||
for (int b = 0; b < sz; ++b)
|
||||
data_.push_back(uchar(tc[b]));
|
||||
}
|
||||
data_.push_back(uchar('\0'));
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIString::trimsubstr(int &st, int &fn) const {
|
||||
for (int i = 0; i < length(); ++i)
|
||||
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12) && at(i) != uchar(0))
|
||||
{st = i; break;}
|
||||
if (st < 0) return;
|
||||
for (int i = length() - 1; i >= 0; --i)
|
||||
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12) && at(i) != uchar(0))
|
||||
{fn = i; break;}
|
||||
}
|
||||
|
||||
|
||||
const char * PIString::dataConsole() const {
|
||||
buildData(__sysoemname__ );
|
||||
return (const char *)(data_.data());
|
||||
}
|
||||
|
||||
|
||||
const char * PIString::dataUTF8() const {
|
||||
buildData(__utf8name__);
|
||||
return (const char *)(data_.data());
|
||||
}
|
||||
|
||||
|
||||
const char * PIString::dataAscii() const {
|
||||
data_.clear();
|
||||
for (int i = 0; i < size_s(); ++i)
|
||||
data_.push_back(uchar(at(i).ch));
|
||||
data_.push_back(uchar('\0'));
|
||||
return (const char *)data_.data();
|
||||
}
|
||||
|
||||
|
||||
uint PIString::hash() const {
|
||||
return piHashData((const uchar*)PIDeque<PIChar>::data(), size() * sizeof(PIChar));
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIString::toUTF8() const {
|
||||
if (isEmpty()) return data_.resized(0);
|
||||
buildData(__utf8name__);
|
||||
return data_.resized(data_.size_s() - 1);
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIString::toCharset(const char * c) const {
|
||||
if (isEmpty()) return data_.resized(0);
|
||||
buildData(
|
||||
#ifdef PIP_ICU
|
||||
c
|
||||
#else
|
||||
# ifdef WINDOWS
|
||||
__utf8name__
|
||||
# endif
|
||||
#endif
|
||||
);
|
||||
return data_.resized(data_.size_s() - 1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::operator +=(const char * str) {
|
||||
if (!str) return *this;
|
||||
int l = 0;
|
||||
while (str[l] != '\0') ++l;
|
||||
appendFromChars(str, l, __syslocname__);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::operator +=(const wchar_t * str) {
|
||||
if (!str) return *this;
|
||||
int i = -1;
|
||||
while (str[++i])
|
||||
push_back(PIChar(ushort(str[i])));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::operator +=(const PIString & str) {
|
||||
*((PIDeque<PIChar>*)this) << *((PIDeque<PIChar>*)&str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool PIString::operator ==(const PIString & str) const {
|
||||
uint l = str.size();
|
||||
if (size() != l) return false;
|
||||
for (uint i = 0; i < l; ++i)
|
||||
if (str[i] != at(i))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIString::operator !=(const PIString & str) const {
|
||||
uint l = str.size();
|
||||
if (size() != l) return true;
|
||||
for (uint i = 0; i < l; ++i)
|
||||
if (str[i] != at(i))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PIString::operator <(const PIString & str) const {
|
||||
uint l = str.size();
|
||||
if (size() < l) return true;
|
||||
if (size() > l) return false;
|
||||
for (uint i = 0; i < l; ++i) {
|
||||
if (at(i) == str[i]) continue;
|
||||
if (at(i) < str[i]) return true;
|
||||
else return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PIString::operator >(const PIString & str) const {
|
||||
uint l = str.size();
|
||||
if (size() < l) return false;
|
||||
if (size() > l) return true;
|
||||
for (uint i = 0; i < l; ++i) {
|
||||
if (at(i) == str[i]) continue;
|
||||
if (at(i) < str[i]) return false;
|
||||
else return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::mid(const int start, const int len) const {
|
||||
//PIString str;
|
||||
int s = start, l = len;
|
||||
if (l == 0 || s >= length()) return PIString();
|
||||
if (s < 0) {
|
||||
l += s;
|
||||
s = 0;
|
||||
}
|
||||
if (l < 0) {
|
||||
return PIString(&(at(s)), size_s() - s);
|
||||
} else {
|
||||
if (l > length() - s)
|
||||
l = length() - s;
|
||||
return PIString(&(at(s)), l);
|
||||
}
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::cutMid(const int start, const int len) {
|
||||
int s = start, l = len;
|
||||
if (l == 0) return *this;
|
||||
if (s < 0) {
|
||||
l += s;
|
||||
s = 0;
|
||||
}
|
||||
if (l < 0)
|
||||
remove(s, size() - s);
|
||||
else {
|
||||
if (l > length() - s)
|
||||
l = length() - s;
|
||||
remove(s, l);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::trim() {
|
||||
int st = -1, fn = 0;
|
||||
trimsubstr(st, fn);
|
||||
if (st < 0) {
|
||||
clear();
|
||||
return *this;
|
||||
}
|
||||
if (fn < size_s() - 1) cutRight(size_s() - fn - 1);
|
||||
if (st > 0) cutLeft(st);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::trimmed() const {
|
||||
int st = -1, fn = 0;
|
||||
trimsubstr(st, fn);
|
||||
if (st < 0) return PIString();
|
||||
return mid(st, fn - st + 1);
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::replace(int from, int count, const PIString & with) {
|
||||
if (count < length() - from) remove(from, count);
|
||||
else remove(from, length() - from);
|
||||
uint c = with.length();
|
||||
for (uint i = 0; i < c; ++i) insert(from + i, with[i]);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::replace(const PIString & what, const PIString & with, bool * ok) {
|
||||
//piCout << "replace" << what << with;
|
||||
if (what.isEmpty()) {
|
||||
if (ok != 0) *ok = false;
|
||||
return *this;
|
||||
}
|
||||
int s = find(what);
|
||||
if (s >= 0) replace(s, what.length(), with);
|
||||
if (ok != 0) *ok = (s >= 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::replaceAll(const PIString & what, const PIString & with) {
|
||||
if (what.isEmpty() || what == with) return *this;
|
||||
bool ok = true;
|
||||
while (ok) replace(what, with, &ok);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::insert(int index, const PIString & str) {
|
||||
PIDeque<PIChar>::insert(index, *((const PIDeque<PIChar>*)&str));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::elide(int size, float pos) {
|
||||
if (length() <= size) return *this;
|
||||
if (length() <= 2) {
|
||||
fill(".");
|
||||
return *this;
|
||||
}
|
||||
pos = piClampf(pos, 0.f, 1.f);
|
||||
int ns = size - 2;
|
||||
int ls = piRoundf(ns * pos);
|
||||
remove(ls, length() - ns);
|
||||
insert(ls, "..");
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIStringList PIString::split(const PIString & delim) const {
|
||||
PIStringList sl;
|
||||
if (isEmpty() || delim.isEmpty()) return sl;
|
||||
PIString ts(*this);
|
||||
int ci = ts.find(delim);
|
||||
while (ci >= 0) {
|
||||
sl << ts.left(ci);
|
||||
ts.cutLeft(ci + delim.length());
|
||||
ci = ts.find(delim);
|
||||
}
|
||||
if (ts.length() > 0) sl << ts;
|
||||
return sl;
|
||||
}
|
||||
|
||||
|
||||
int PIString::find(const char str, const int start) const {
|
||||
for (int i = start; i < length(); ++i)
|
||||
if (at(i) == str)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int PIString::find(const PIString & str, const int start) const {
|
||||
int l = str.length();
|
||||
for (int i = start; i < length() - l + 1; ++i)
|
||||
if (mid(i, l) == str)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int PIString::findLast(const char str, const int start) const {
|
||||
for (int i = length() - 1; i >= start; --i)
|
||||
if (at(i) == str)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int PIString::findLast(const PIString & str, const int start) const {
|
||||
int l = str.length();
|
||||
for (int i = length() - l; i >= start; --i)
|
||||
if (mid(i, l) == str)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int PIString::findWord(const PIString & word, const int start) const {
|
||||
int f = start - 1, tl = length(), wl = word.length();
|
||||
while ((f = find(word, f + 1)) >= 0) {
|
||||
bool ok = true;
|
||||
PIChar c;
|
||||
if (f > 0) {c = (*this)[f - 1]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) {ok = false; continue;}}
|
||||
if (f + wl < tl) {c = (*this)[f + wl]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) {ok = false; continue;}}
|
||||
if (ok) return f;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int PIString::findCWord(const PIString & word, const int start) const {
|
||||
int f = start - 1, tl = length(), wl = word.length();
|
||||
while ((f = find(word, f + 1)) >= 0) {
|
||||
bool ok = true;
|
||||
PIChar c;
|
||||
if (f > 0) {c = (*this)[f - 1]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r' || (c != '_' && !c.isAlpha() && !c.isDigit()))) {ok = false; continue;}}
|
||||
if (f + wl < tl) {c = (*this)[f + wl]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r' || (c != '_' && !c.isAlpha() && !c.isDigit()))) {ok = false; continue;}}
|
||||
if (ok) return f;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int PIString::findRange(const PIChar & start, const PIChar & end, const PIChar & shield, const int start_index, int * len) const {
|
||||
if (len) *len = 0;
|
||||
bool trim_ = (start != ' ' && start != '\t' && start != '\n' && start != '\r'), eq = (start == end);
|
||||
int sz = size_s(), ls = -1, le = -1, cnt = 0;
|
||||
for (int i = start_index; i < sz; ++i) {
|
||||
PIChar c = at(i);
|
||||
if (c == shield) {++i; continue;}
|
||||
if (trim_) {
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
|
||||
continue;
|
||||
trim_ = false;
|
||||
}
|
||||
if (eq) {
|
||||
if (c == start) {
|
||||
if (cnt == 0) ls = i;
|
||||
else {le = i; cnt = 0; break;}
|
||||
cnt++;
|
||||
}
|
||||
} else {
|
||||
if (c == start) {
|
||||
if (cnt == 0) ls = i;
|
||||
cnt++;
|
||||
}
|
||||
if (c == end) {
|
||||
cnt--;
|
||||
if (cnt == 0) le = i;
|
||||
}
|
||||
}
|
||||
if (cnt <= 0) break;
|
||||
}
|
||||
//piCout << ls << le << cnt;
|
||||
if (le < ls || ls < 0 || le < 0 || cnt != 0) return -1;
|
||||
if (len) *len = le - ls - 1;
|
||||
return ls + 1;
|
||||
}
|
||||
|
||||
|
||||
int PIString::findAny(const PIString & str, const int start) const {
|
||||
for (int i = start; i < length(); ++i)
|
||||
if (str.contains(at(i)))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int PIString::findAnyLast(const PIString & str, const int start) const {
|
||||
for (int i = length() - 1; i >= start; --i)
|
||||
if (str.contains(at(i)))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int PIString::entries(const PIChar & c) const {
|
||||
int sz = size_s(), ret = 0;
|
||||
for (int i = 0; i < sz; ++i)
|
||||
if (at(i) == c) ++ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PIString::startsWith(const PIString & str) const {
|
||||
if (size() < str.size()) return false;
|
||||
return str == left(str.size());
|
||||
}
|
||||
|
||||
|
||||
bool PIString::endsWith(const PIString & str) const {
|
||||
if (size() < str.size()) return false;
|
||||
return str == right(str.size());
|
||||
}
|
||||
|
||||
|
||||
bool PIString::toBool() const {
|
||||
PIString s(*this);
|
||||
s = s.trimmed().toLowerCase();
|
||||
if ( atof(s.toNativeDecimalPoints().data()) > 0. || s == "true" || s == "yes" || s == "on" || s == "ok") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::takeSymbol() {
|
||||
PIString ret;
|
||||
int sz = size_s(), ss = -1;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
PIChar c = at(i);
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
|
||||
continue;
|
||||
ss = i;
|
||||
break;
|
||||
}
|
||||
if (ss < 0) return ret;
|
||||
ret = mid(ss, 1);
|
||||
cutLeft(ss + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::takeWord() {
|
||||
int sz = size_s(), ws = -1, we = -1;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
PIChar c = at(i);
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
||||
if (we < 0 && ws >= 0) {
|
||||
we = i;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (ws < 0) ws = i;
|
||||
if (we >= 0) break;
|
||||
}
|
||||
}
|
||||
PIString ret = mid(ws, we - ws);
|
||||
cutLeft(we < 0 ? sz : we);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::takeCWord() {
|
||||
PIString ret;
|
||||
int sz = size_s(), ws = -1, we = -1;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
PIChar c = at(i);
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
||||
if (we < 0 && ws >= 0) {
|
||||
we = i;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (ws < 0) {
|
||||
if (c.isAlpha() || c == '_')
|
||||
ws = i;
|
||||
else
|
||||
return ret;
|
||||
} else {
|
||||
if (!c.isAlpha() && !c.isDigit() && c != '_') {
|
||||
we = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (we >= 0) break;
|
||||
}
|
||||
}
|
||||
ret = mid(ws, we - ws);
|
||||
cutLeft(we < 0 ? sz : we);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::takeLine() {
|
||||
int sz = size_s(), le = -1;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
PIChar c = at(i);
|
||||
if (c == '\n') {
|
||||
le = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
PIString ret = left(le);
|
||||
if (!ret.isEmpty())
|
||||
if (ret.back() == '\r')
|
||||
ret.cutRight(1);
|
||||
cutLeft(le < 0 ? sz : le + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::takeNumber() {
|
||||
PIString ret;
|
||||
int sz = size_s(), ls = -1, le = -1, phase = 0;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
if (phase > 7) break;
|
||||
PIChar c = at(i);
|
||||
//piCout << "char " << c << "phase" << phase;
|
||||
switch (phase) {
|
||||
case 0: // trim
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
|
||||
continue;
|
||||
phase = 7;
|
||||
case 7: // sign
|
||||
if (c == '-' || c == '+') {ls = i; phase = 1; break;}
|
||||
case 1: // search start
|
||||
if (c >= '0' && c <= '9') {le = i; if (ls < 0) ls = i; phase = 2; break;}
|
||||
if (c == '.') {le = i; if (ls < 0) ls = i; phase = 3; break;}
|
||||
phase = 9;
|
||||
break;
|
||||
case 2: // integer
|
||||
if (c == '.') {le = i; phase = 3; break;}
|
||||
if (c == 'e' || c == 'E') {le = i; phase = 4; break;}
|
||||
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || c == 'x') {le = i; break;}
|
||||
phase = 6;
|
||||
break;
|
||||
case 3: // point
|
||||
if (c == 'e' || c == 'E') {le = i; phase = 4; break;}
|
||||
if (c >= '0' && c <= '9') {le = i; break;}
|
||||
phase = 6;
|
||||
break;
|
||||
case 4: // exp
|
||||
if ((c >= '0' && c <= '9') || c == '-' || c == '+') {le = i; phase = 5; break;}
|
||||
phase = 6;
|
||||
break;
|
||||
case 5: // power
|
||||
if (c >= '0' && c <= '9') {le = i; break;}
|
||||
phase = 6;
|
||||
break;
|
||||
case 6: // suffix
|
||||
if (c == 'f' || c == 's' || c == 'u' || c == 'l' || c == 'L') {le = i; break;}
|
||||
phase = 9;
|
||||
break;
|
||||
}
|
||||
if (phase == 6) {
|
||||
if (c == 'f' || c == 's' || c == 'u' || c == 'l' || c == 'L') le = i;
|
||||
else phase = 9;
|
||||
}
|
||||
}
|
||||
//piCout << ls << le;
|
||||
if (le < ls) return ret;
|
||||
ret = mid(ls, le - ls + 1);
|
||||
cutLeft(le + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::takeRange(const PIChar & start, const PIChar & end, const PIChar & shield) {
|
||||
PIString ret;
|
||||
bool trim_ = (start != ' ' && start != '\t' && start != '\n' && start != '\r'), eq = (start == end);
|
||||
int sz = size_s(), ls = -1, le = -1, cnt = 0;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
PIChar c = at(i);
|
||||
if (c == shield) {++i; continue;}
|
||||
if (trim_) {
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
|
||||
continue;
|
||||
trim_ = false;
|
||||
}
|
||||
if (eq) {
|
||||
if (c == start) {
|
||||
if (cnt == 0) ls = i;
|
||||
else {le = i; cnt = 0; break;}
|
||||
cnt++;
|
||||
}
|
||||
} else {
|
||||
if (c == start) {
|
||||
if (cnt == 0) ls = i;
|
||||
cnt++;
|
||||
}
|
||||
if (c == end) {
|
||||
cnt--;
|
||||
if (cnt == 0) le = i;
|
||||
}
|
||||
}
|
||||
if (cnt <= 0) break;
|
||||
}
|
||||
//piCout << ls << le << cnt;
|
||||
if (le < ls || ls < 0 || le < 0 || cnt != 0) return ret;
|
||||
ret = mid(ls + 1, le - ls - 1);
|
||||
cutLeft(le + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::inBrackets(const PIChar &start, const PIChar &end) const {
|
||||
int slen = length();
|
||||
int st = -1, bcnt = 0;
|
||||
PIChar cc;
|
||||
for (int i = 0; i < slen; i++) {
|
||||
cc = at(i);
|
||||
if (cc == start) {
|
||||
if (bcnt == 0) st = i;
|
||||
bcnt++;
|
||||
}
|
||||
if (cc == end && st >= 0) {
|
||||
bcnt--;
|
||||
if (bcnt == 0) return mid(st+1, i-st-1);
|
||||
}
|
||||
}
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::toUpperCase() const {
|
||||
PIString str(*this);
|
||||
int l = str.size();
|
||||
for (int i = 0; i < l; ++i) str[i] = str[i].toUpper();
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::toLowerCase() const {
|
||||
PIString str(*this);
|
||||
int l = str.size();
|
||||
for (int i = 0; i < l; ++i) str[i] = str[i].toLower();
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::toNativeDecimalPoints() const {
|
||||
#ifdef HAS_LOCALE
|
||||
PIString s(*this);
|
||||
if (currentLocale == 0) return s;
|
||||
return s.replaceAll(".", currentLocale->decimal_point).replaceAll(",", currentLocale->decimal_point);
|
||||
#else
|
||||
return PIString(*this).replaceAll(",", ".");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
char PIString::toChar() const {
|
||||
PIString s(toNativeDecimalPoints());
|
||||
char v;
|
||||
sscanf(s.data(), "%c", &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
float PIString::toFloat() const {
|
||||
return (float)atof(toNativeDecimalPoints().data());
|
||||
}
|
||||
|
||||
|
||||
double PIString::toDouble() const {
|
||||
return atof(toNativeDecimalPoints().data());
|
||||
}
|
||||
|
||||
|
||||
ldouble PIString::toLDouble() const {
|
||||
return atof(toNativeDecimalPoints().data());
|
||||
}
|
||||
|
||||
|
||||
PIString & PIString::setReadableSize(llong bytes) {
|
||||
clear();
|
||||
if (bytes < 1024) {*this += (PIString::fromNumber(bytes) + " B"); return *this;}
|
||||
double fres = bytes / 1024.;
|
||||
llong res = bytes / 1024;
|
||||
fres -= res;
|
||||
if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " kB"); return *this;}
|
||||
fres = res / 1024.;
|
||||
res /= 1024;
|
||||
fres -= res;
|
||||
if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " MB"); return *this;}
|
||||
fres = res / 1024.;
|
||||
res /= 1024;
|
||||
fres -= res;
|
||||
if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " GB"); return *this;}
|
||||
fres = res / 1024.;
|
||||
res /= 1024;
|
||||
fres -= res;
|
||||
if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " TB"); return *this;}
|
||||
fres = res / 1024.;
|
||||
res /= 1024;
|
||||
fres -= res;
|
||||
*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " PB");
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline char chrUpr(char c) {
|
||||
if (c >= 'a' && c <= 'z') return c + 'A' - 'a';
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
inline char chrLwr(char c) {
|
||||
if (c >= 'A' && c <= 'Z') return c + 'a' - 'A';
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const static PIString _versionDelims_ = PIStringAscii("._-+");
|
||||
|
||||
|
||||
void parseVersion(PIString s, PIVector<int> & codes, PIStringList & strs) {
|
||||
s.trim();
|
||||
if (s.isEmpty()) {
|
||||
codes.resize(3, 0);
|
||||
return;
|
||||
}
|
||||
int mccnt = 2 - s.entries('.');
|
||||
if (mccnt > 0) {
|
||||
int ind = s.findLast(".") + 1;
|
||||
while (!_versionDelims_.contains(s[ind])) {
|
||||
++ind;
|
||||
if (ind > s.size_s() - 1)
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < mccnt; ++i)
|
||||
s.insert(ind, ".0");
|
||||
}
|
||||
PIStringList comps;
|
||||
while (!s.isEmpty()) {
|
||||
int ind = s.findAny(_versionDelims_);
|
||||
if (ind >= 0) {
|
||||
comps << s.takeLeft(ind);
|
||||
s.cutLeft(1).trim();
|
||||
} else {
|
||||
comps << s;
|
||||
s.clear();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < comps.size_s(); ++i) {
|
||||
if (comps[i].isEmpty())
|
||||
comps[i] = "0";
|
||||
bool ok = false;
|
||||
int val = comps[i].toInt(-1, &ok);
|
||||
if (ok) {
|
||||
codes << val;
|
||||
} else {
|
||||
strs << comps[i];
|
||||
}
|
||||
}
|
||||
//piCout << codes << strs;
|
||||
}
|
||||
|
||||
|
||||
int versionLabelValue(PIString s) {
|
||||
int ret = -10000;
|
||||
if (s.isEmpty()) return 0;
|
||||
if (s.startsWith("pre")) {
|
||||
s.cutLeft(3);
|
||||
ret -= 1;
|
||||
}
|
||||
if (s.startsWith("rc")) {
|
||||
s.cutLeft(2);
|
||||
ret += s.toInt();
|
||||
}
|
||||
if (s.startsWith("r")) {
|
||||
s.cutLeft(1);
|
||||
ret += 10000 + s.toInt();
|
||||
}
|
||||
if (s == "alpha") ret -= 4;
|
||||
if (s == "beta" ) ret -= 2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int versionCompare(const PIString & v0, const PIString & v1, int components) {
|
||||
PIStringList strs[2]; PIVector<int> codes[2];
|
||||
parseVersion(v0.toLowerCase(), codes[0], strs[0]);
|
||||
parseVersion(v1.toLowerCase(), codes[1], strs[1]);
|
||||
//piCout << codes[0] << strs[0];
|
||||
int mc = piMaxi(codes[0].size_s(), codes[1].size_s());
|
||||
if (codes[0].size_s() < mc) codes[0].resize(mc, 0);
|
||||
if (codes[1].size_s() < mc) codes[1].resize(mc, 0);
|
||||
mc = piMaxi(strs[0].size_s(), strs[1].size_s());
|
||||
if (strs[0].size_s() < mc) strs[0].resize(mc, "");
|
||||
if (strs[1].size_s() < mc) strs[1].resize(mc, "");
|
||||
int comps = piMini(components, codes[0].size_s(), codes[1].size_s());
|
||||
if (comps < 1) return (v0 == v1 ? 0 : (v0 > v1 ? 1 : -1));
|
||||
for (int c = 0; c < comps; ++c) {
|
||||
if (codes[0][c] > codes[1][c]) return 1;
|
||||
if (codes[0][c] < codes[1][c]) return -1;
|
||||
}
|
||||
mc = piClampi(mc, 0, components - comps);
|
||||
for (int c = 0; c < mc; ++c) {
|
||||
int lv0 = versionLabelValue(strs[0][c]);
|
||||
int lv1 = versionLabelValue(strs[1][c]);
|
||||
if (lv0 > lv1) return 1;
|
||||
if (lv0 < lv1) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PIString versionNormalize(const PIString & v) {
|
||||
PIStringList strs; PIVector<int> codes;
|
||||
parseVersion(v.toLowerCase(), codes, strs);
|
||||
PIString ret;
|
||||
for (int i = 0; i < codes.size_s(); ++i) {
|
||||
if (i > 0) {
|
||||
if (i < 3) ret += ".";
|
||||
else ret += "-";
|
||||
}
|
||||
ret += PIString::fromNumber(codes[i]);
|
||||
}
|
||||
for (int i = 0; i < strs.size_s(); ++i) {
|
||||
ret += "_";
|
||||
ret += strs[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PICout operator <<(PICout s, const PIString & v) {
|
||||
s.space();
|
||||
s.quote();
|
||||
s.setControl(0, true);
|
||||
s << v.data();
|
||||
s.restoreControl();
|
||||
s.quote();
|
||||
return s;
|
||||
}
|
||||
|
||||
774
lib/main/core/pistring.h
Normal file
774
lib/main/core/pistring.h
Normal file
@@ -0,0 +1,774 @@
|
||||
/*! \file pistring.h
|
||||
* \brief String
|
||||
*
|
||||
* This file declare string and string list classes
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
String
|
||||
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 PISTRING_H
|
||||
#define PISTRING_H
|
||||
|
||||
#include "pibytearray.h"
|
||||
|
||||
#define PIStringAscii PIString::fromAscii
|
||||
|
||||
|
||||
class PIStringList;
|
||||
|
||||
class PIP_EXPORT PIString: public PIDeque<PIChar>
|
||||
{
|
||||
friend PIByteArray & operator >>(PIByteArray & s, PIString & v);
|
||||
public:
|
||||
//! Contructs an empty string
|
||||
PIString(): PIDeque<PIChar>() {}
|
||||
|
||||
static const float ElideLeft ;
|
||||
static const float ElideCenter;
|
||||
static const float ElideRight ;
|
||||
|
||||
PIString & operator +=(const PIChar & c) {push_back(c); return *this;}
|
||||
PIString & operator +=(const char * str);
|
||||
PIString & operator +=(const wchar_t * str);
|
||||
PIString & operator +=(const PIByteArray & ba) {appendFromChars((const char * )ba.data(), ba.size_s(), __utf8name__); return *this;}
|
||||
PIString & operator +=(const PIString & str);
|
||||
|
||||
PIString(const PIString & o): PIDeque<PIChar>() {*this += o;}
|
||||
|
||||
|
||||
//! Contructs string with single symbol "c"
|
||||
PIString(const PIChar & c): PIDeque<PIChar>() {*this += c;}
|
||||
PIString(const char c): PIDeque<PIChar>() {*this += PIChar(c);}
|
||||
|
||||
/*! \brief Contructs string from c-string "str"
|
||||
* \details "str" should be null-terminated\n
|
||||
* Example: \snippet pistring.cpp PIString(char * ) */
|
||||
PIString(const char * str): PIDeque<PIChar>() {*this += str;}
|
||||
|
||||
/*! \brief Contructs string from \c wchar_t c-string "str"
|
||||
* \details "str" should be null-terminated\n
|
||||
* Example: \snippet pistring.cpp PIString(wchar_t * ) */
|
||||
PIString(const wchar_t * str): PIDeque<PIChar>() {*this += str;}
|
||||
|
||||
//! Contructs string from byte array "ba"
|
||||
PIString(const PIByteArray & ba): PIDeque<PIChar>() {*this += ba;}
|
||||
|
||||
//! \brief Contructs string from "len" characters of buffer "str"
|
||||
PIString(const PIChar * str, const int len): PIDeque<PIChar>(str, size_t(len)) {}
|
||||
|
||||
/*! \brief Contructs string from "len" characters of buffer "str"
|
||||
* \details Example: \snippet pistring.cpp PIString(char * , int) */
|
||||
PIString(const char * str, const int len): PIDeque<PIChar>() {appendFromChars(str, len);}
|
||||
|
||||
/*! \brief Contructs string as sequence of characters "c" of buffer with length "len"
|
||||
* \details Example: \snippet pistring.cpp PIString(int, char) */
|
||||
PIString(const int len, const char c): PIDeque<PIChar>() {for (int i = 0; i < len; ++i) push_back(c);}
|
||||
|
||||
/*! \brief Contructs string as sequence of symbols "c" of buffer with length "len"
|
||||
* \details Example: \snippet pistring.cpp PIString(int, PIChar) */
|
||||
PIString(const int len, const PIChar & c): PIDeque<PIChar>() {for (int i = 0; i < len; ++i) push_back(c);}
|
||||
|
||||
~PIString() {}
|
||||
|
||||
|
||||
PIString & operator =(const PIString & o) {if (this == &o) return *this; clear(); *this += o; return *this;}
|
||||
|
||||
/*! \brief Return c-string representation of string
|
||||
* \details Converts content of string to c-string and return
|
||||
* pointer to first char. This buffer is valid until new convertion
|
||||
* or execution \a data() or \a toByteArray().\n
|
||||
* Example: \snippet pistring.cpp PIString::char* */
|
||||
operator const char*() {return data();}
|
||||
|
||||
//! Return symbol at index "pos"
|
||||
PIChar operator [](const int pos) const {return at(pos);}
|
||||
|
||||
//! Return reference to symbol at index "pos"
|
||||
PIChar & operator [](const int pos) {return at(pos);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator ==(const PIString & str) const;
|
||||
|
||||
//! Compare operator
|
||||
bool operator ==(const PIChar c) const {return *this == PIString(c);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator ==(const char * str) const {return *this == PIString(str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator !=(const PIString & str) const;
|
||||
|
||||
//! Compare operator
|
||||
bool operator !=(const PIChar c) const {return *this != PIString(c);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator !=(const char * str) const {return *this != PIString(str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator <(const PIString & str) const;
|
||||
|
||||
//! Compare operator
|
||||
bool operator <(const PIChar c) const {return *this < PIString(c);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator <(const char * str) const {return *this < PIString(str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator >(const PIString & str) const;
|
||||
|
||||
//! Compare operator
|
||||
bool operator >(const PIChar c) const {return *this > PIString(c);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator >(const char * str) const {return *this > PIString(str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator <=(const PIString & str) const {return !(*this > str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator <=(const PIChar c) const {return *this <= PIString(c);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator <=(const char * str) const {return *this <= PIString(str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator >=(const PIString & str) const {return !(*this < str);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator >=(const PIChar c) const {return *this >= PIString(c);}
|
||||
|
||||
//! Compare operator
|
||||
bool operator >=(const char * str) const {return *this >= PIString(str);}
|
||||
|
||||
/*! \brief Append string "str" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(PIString) */
|
||||
PIString & operator <<(const PIString & str) {*this += str; return *this;}
|
||||
|
||||
/*! \brief Append symbol "c" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(PIChar) */
|
||||
PIString & operator <<(const PIChar & c) {*this += c; return *this;}
|
||||
|
||||
/*! \brief Append c-string "str" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(char * ) */
|
||||
PIString & operator <<(const char * str) {*this += str; return *this;}
|
||||
|
||||
/*! \brief Append \c wchar_t c-string "str" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(wchar_t * ) */
|
||||
PIString & operator <<(const wchar_t * str) {*this += str; return *this;}
|
||||
|
||||
/*! \brief Append string representation of "num" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(int) */
|
||||
PIString & operator <<(const int & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
PIString & operator <<(const uint & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
/*! \brief Append string representation of "num" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(int) */
|
||||
PIString & operator <<(const short & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
PIString & operator <<(const ushort & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
/*! \brief Append string representation of "num" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(int) */
|
||||
PIString & operator <<(const long & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
PIString & operator <<(const ulong & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
PIString & operator <<(const llong & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
PIString & operator <<(const ullong & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
/*! \brief Append string representation of "num" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(int) */
|
||||
PIString & operator <<(const float & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
/*! \brief Append string representation of "num" at the end of string
|
||||
* \details Example: \snippet pistring.cpp PIString::<<(int) */
|
||||
PIString & operator <<(const double & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
|
||||
//! \brief Insert string "str" at the begin of string
|
||||
PIString & prepend(const PIString & str) {insert(0, str); return *this;}
|
||||
|
||||
//! \brief Insert string "str" at the end of string
|
||||
PIString & append(const PIString & str) {*this += str; return *this;}
|
||||
|
||||
|
||||
/*! \brief Return part of string from symbol at index "start" and maximum length "len"
|
||||
* \details All variants demonstrated in example: \snippet pistring.cpp PIString::mid
|
||||
* \sa \a left(), \a right() */
|
||||
PIString mid(const int start, const int len = -1) const;
|
||||
|
||||
/*! \brief Return sub-string of string from symbol at index "start" and maximum length "len" */
|
||||
PIString subString(const int start, const int len = -1) const {return mid(start, len);}
|
||||
|
||||
/*! \brief Return part of string from left and maximum length "len"
|
||||
* \details Example: \snippet pistring.cpp PIString::left
|
||||
* \sa \a mid(), \a right() */
|
||||
PIString left(const int len) const {return len <= 0 ? PIString() : mid(0, len);}
|
||||
|
||||
/*! \brief Return part of string from right and maximum length "len"
|
||||
* \details Example: \snippet pistring.cpp PIString::right
|
||||
* \sa \a mid(), \a left() */
|
||||
PIString right(const int len) const {return len <= 0 ? PIString() : mid(size() - len, len);}
|
||||
|
||||
/*! \brief Remove part of string from symbol as index "start" and maximum length "len"
|
||||
* and return this string
|
||||
* \details All variants demonstrated in example: \snippet pistring.cpp PIString::cutMid
|
||||
* \sa \a cutLeft(), \a cutRight() */
|
||||
PIString & cutMid(const int start, const int len);
|
||||
|
||||
/*! \brief Remove part of string from left and maximum length "len" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::cutLeft
|
||||
* \sa \a cutMid(), \a cutRight() */
|
||||
PIString & cutLeft(const int len) {return len <= 0 ? *this : cutMid(0, len);}
|
||||
|
||||
/*! \brief Remove part of string from right and maximum length "len" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::cutRight
|
||||
* \sa \a cutMid(), \a cutLeft() */
|
||||
PIString & cutRight(const int len) {return len <= 0 ? *this : cutMid(size() - len, len);}
|
||||
|
||||
/*! \brief Remove spaces at the start and at the end of string and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::trim
|
||||
* \sa \a trimmed() */
|
||||
PIString & trim();
|
||||
|
||||
/*! \brief Return copy of this string without spaces at the start and at the end
|
||||
* \details Example: \snippet pistring.cpp PIString::trimmed
|
||||
* \sa \a trim() */
|
||||
PIString trimmed() const;
|
||||
|
||||
/*! \brief Replace part of string from index "from" and maximum length "len"
|
||||
* with string "with" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::replace_0
|
||||
* \sa \a replaced(), \a replaceAll() */
|
||||
PIString & replace(const int from, const int count, const PIString & with);
|
||||
|
||||
/*! \brief Replace part copy of this string from index "from" and maximum length "len"
|
||||
* with string "with" and return copied string
|
||||
* \details Example: \snippet pistring.cpp PIString::replaced_0
|
||||
* \sa \a replace(), \a replaceAll() */
|
||||
PIString replaced(const int from, const int count, const PIString & with) const {PIString str(*this); str.replace(from, count, with); return str;}
|
||||
|
||||
/*! \brief Replace first founded substring "what" with string "with" and return this string
|
||||
* \details If "ok" is not null, it set to "true" if something was replaced\n
|
||||
* Example: \snippet pistring.cpp PIString::replace_1
|
||||
* \sa \a replaced(), \a replaceAll() */
|
||||
PIString & replace(const PIString & what, const PIString & with, bool * ok = 0);
|
||||
|
||||
/*! \brief Replace first founded substring "what" with string "with" and return copied string
|
||||
* \details If "ok" is not null, it set to "true" if something was replaced\n
|
||||
* Example: \snippet pistring.cpp PIString::replaced_1
|
||||
* \sa \a replaced(), \a replaceAll() */
|
||||
PIString replaced(const PIString & what, const PIString & with, bool * ok = 0) const {PIString str(*this); str.replace(what, with, ok); return str;}
|
||||
|
||||
/*! \brief Replace all founded substrings "what" with strings "with" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::replaceAll
|
||||
* \sa \a replace(), \a replaced() */
|
||||
PIString & replaceAll(const PIString & what, const PIString & with);
|
||||
PIString replaceAll(const PIString & what, const PIString & with) const {PIString str(*this); str.replaceAll(what, with); return str;}
|
||||
|
||||
/*! \brief Repeat content of string "times" times and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::repeat */
|
||||
PIString & repeat(int times) {PIString ss(*this); times--; piForTimes (times) *this += ss; return *this;}
|
||||
|
||||
/*! \brief Returns repeated "times" times string
|
||||
* \details Example: \snippet pistring.cpp PIString::repeated */
|
||||
PIString repeated(int times) const {PIString ss(*this); return ss.repeat(times);}
|
||||
|
||||
/*! \brief Insert symbol "c" after index "index" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::insert_0 */
|
||||
PIString & insert(const int index, const PIChar & c) {PIDeque<PIChar>::insert(index, c); return *this;}
|
||||
|
||||
/*! \brief Insert symbol "c" after index "index" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::insert_1 */
|
||||
PIString & insert(const int index, const char & c) {return insert(index, PIChar(c));}
|
||||
|
||||
/*! \brief Insert string "str" after index "index" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::insert_2 */
|
||||
PIString & insert(const int index, const PIString & str);
|
||||
|
||||
/*! \brief Insert string "str" after index "index" and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::insert_2 */
|
||||
PIString & insert(const int index, const char * c) {return insert(index, PIString(c));}
|
||||
|
||||
/*! \brief Enlarge string to length "len" by addition sequence of symbols
|
||||
* "c" at the end of string, and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::expandRightTo
|
||||
* \sa \a expandLeftTo() */
|
||||
PIString & expandRightTo(const int len, const PIChar & c) {if (len > length()) resize(len, c); return *this;}
|
||||
|
||||
/*! \brief Enlarge string to length "len" by addition sequence of symbols
|
||||
* "c" at the beginning of string, and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::expandLeftTo
|
||||
* \sa \a expandRightTo() */
|
||||
PIString & expandLeftTo(const int len, const PIChar & c) {if (len > length()) insert(0, PIString(len - length(), c)); return *this;}
|
||||
|
||||
/*! \brief Add "c" symbols at the beginning and end of the string, and return this string
|
||||
* \sa \a quoted() */
|
||||
PIString & quote(PIChar c = PIChar('"')) {insert(0, c); *this += c; return *this;}
|
||||
|
||||
/*! \brief Return quoted copy of this string
|
||||
* \sa \a quote() */
|
||||
PIString quoted(PIChar c = PIChar('"')) {return PIString(*this).quote(c);}
|
||||
|
||||
/*! \brief Reverse string and return this string
|
||||
* \details Example: \snippet pistring.cpp PIString::reverse
|
||||
* \sa \a reversed() */
|
||||
PIString & reverse() {PIString str(*this); clear(); piForeachR (const PIChar & c, str) push_back(c); return *this;}
|
||||
|
||||
/*! \brief Reverse copy of this string and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::reversed
|
||||
* \sa \a reverse() */
|
||||
PIString reversed() const {PIString str(*this); str.reverse(); return str;}
|
||||
|
||||
/*! \brief Elide string to maximum size \"size\" and return this string
|
||||
* \sa \a elided() */
|
||||
PIString & elide(int size, float pos = ElideCenter);
|
||||
|
||||
/*! \brief Elide copy of this string to maximum size \"size\" and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::elided
|
||||
* \sa \a elide() */
|
||||
PIString elided(int size, float pos = ElideCenter) const {PIString str(*this); str.elide(size, pos); return str;}
|
||||
|
||||
|
||||
/*! \brief Take a part of string from symbol at index "start" and maximum length "len" and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeMid
|
||||
* \sa \a takeLeft, \a takeRight() */
|
||||
PIString takeMid(const int start, const int len = -1) {PIString ret(mid(start, len)); cutMid(start, len); return ret;}
|
||||
|
||||
/*! \brief Take a part from the begin of string with maximum length "len" and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeLeft
|
||||
* \sa \a takeMid(), \a takeRight() */
|
||||
PIString takeLeft(const int len) {PIString ret(left(len)); cutLeft(len); return ret;}
|
||||
|
||||
/*! \brief Take a part from the end of string with maximum length "len" and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeRight
|
||||
* \sa \a takeMid(), \a takeLeft() */
|
||||
PIString takeRight(const int len) {PIString ret(right(len)); cutRight(len); return ret;}
|
||||
|
||||
/*! \brief Take a symbol from the begin of this string and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeSymbol
|
||||
* \sa \a takeWord(), \a takeCWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
|
||||
PIString takeSymbol();
|
||||
|
||||
/*! \brief Take a word from the begin of this string and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeWord
|
||||
* \sa \a takeSymbol(), \a takeCWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
|
||||
PIString takeWord();
|
||||
|
||||
/*! \brief Take a word with letters, numbers and '_' symbols from the
|
||||
* begin of this string and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeCWord
|
||||
* \sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
|
||||
PIString takeCWord();
|
||||
|
||||
/*! \brief Take a line from the begin of this string and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeLine
|
||||
* \sa \a takeSymbol(), \a takeWord(), \a takeCWord(), \a takeNumber(), \a takeRange() */
|
||||
PIString takeLine();
|
||||
|
||||
/*! \brief Take a number with C-format from the begin of this string and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::takeNumber
|
||||
* \sa \a takeSymbol(), \a takeWord(), \a takeCWord(), \a takeLine(), \a takeRange() */
|
||||
PIString takeNumber();
|
||||
|
||||
/*! \brief Take a range between "start" and "end" symbols from the begin of this
|
||||
* string and return it.
|
||||
* \details "Shield" symbol prevent analysis of the next symbol.
|
||||
* Example: \snippet pistring.cpp PIString::takeRange
|
||||
* \sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeNumber() */
|
||||
PIString takeRange(const PIChar & start, const PIChar & end, const PIChar & shield = '\\');
|
||||
|
||||
|
||||
/*! \brief Return a string in brackets "start" and "end" symbols from the begin of this
|
||||
* string and return it.
|
||||
* \details Example: string = "a(b(c)d)e"; inBrackets('(', ')') = "b(c)d"; */
|
||||
PIString inBrackets(const PIChar & start, const PIChar & end) const;
|
||||
|
||||
/*! \brief Return real bytes count of this string
|
||||
* \details It`s equivalent length of char sequence
|
||||
* returned by function \a data() - 1, without terminating null-char \n
|
||||
* Example: \snippet pistring.cpp PIString::lengthAscii
|
||||
* \sa \a data() */
|
||||
int lengthAscii() const {buildData(__syslocname__); return data_.size_s() - 1;}
|
||||
|
||||
/*! \brief Return \c char * representation of this string in system codepage
|
||||
* \details This function fill buffer by sequence
|
||||
* of chars. Minimum length of this buffer is count
|
||||
* of symbols. Returned \c char * is valid until next
|
||||
* execution of this function.\n
|
||||
* Example: \snippet pistring.cpp PIString::data
|
||||
* \sa \a dataConsole(), \a dataUTF8() */
|
||||
const char * data() const {buildData(__syslocname__); return (const char *)(data_.data());}
|
||||
|
||||
/*! \brief Return \c char * representation of this string in terminal codepage
|
||||
* \details This function fill buffer by sequence
|
||||
* of chars. Minimum length of this buffer is count
|
||||
* of symbols. Returned \c char * is valid until next
|
||||
* execution of this function.\n
|
||||
* \sa \a data(), \a dataUTF8() */
|
||||
const char * dataConsole() const;
|
||||
|
||||
/*! \brief Return \c char * representation of this string in UTF-8
|
||||
* \details This function fill buffer by sequence
|
||||
* of chars. Minimum length of this buffer is count
|
||||
* of symbols. Returned \c char * is valid until next
|
||||
* execution of this function.\n
|
||||
* \sa \a data(), \a dataConsole() */
|
||||
const char * dataUTF8() const;
|
||||
|
||||
/*! \brief Return \c char * representation of this string in ASCII
|
||||
* \details This function fill buffer by sequence
|
||||
* of chars. Minimum length of this buffer is count
|
||||
* of symbols. Returned \c char * is valid until next
|
||||
* execution of this function.\n */
|
||||
const char * dataAscii() const;
|
||||
|
||||
//! Returns hash
|
||||
uint hash() const;
|
||||
|
||||
//! \brief Return \a PIByteArray contains \a data() of this string without terminating null-char
|
||||
PIByteArray toByteArray() const {buildData(__utf8name__); return data_.resized(data_.size_s() - 1);}
|
||||
|
||||
//! \brief Return \a PIByteArray contains UTF-8 \a data() of this string without terminating null-char
|
||||
PIByteArray toUTF8() const;
|
||||
|
||||
//! \brief Return \a PIByteArray contains custom charset representation of this string without terminating null-char
|
||||
PIByteArray toCharset(const char * c) const;
|
||||
|
||||
/*! \brief Split string with delimiter "delim" to \a PIStringList and return it
|
||||
* \details Example: \snippet pistring.cpp PIString::split */
|
||||
PIStringList split(const PIString & delim) const;
|
||||
|
||||
|
||||
//! \brief Convert each symbol in copyed string to upper case and return it
|
||||
PIString toUpperCase() const;
|
||||
|
||||
//! \brief Convert each symbol in copyed string to lower case and return it
|
||||
PIString toLowerCase() const;
|
||||
|
||||
PIString toNativeDecimalPoints() const;
|
||||
|
||||
|
||||
//! \brief Returns if string contains "str"
|
||||
bool contains(const char str) const {return contains(PIString(str));}
|
||||
|
||||
//! \brief Returns if string contains "str"
|
||||
bool contains(const PIChar str) const {return contains(PIString(str));}
|
||||
|
||||
//! \brief Returns if string contains "str"
|
||||
bool contains(const char * str) const {return contains(PIString(str));}
|
||||
|
||||
//! \brief Returns if string contains "str"
|
||||
bool contains(const PIString & str) const {return find(str) >= 0;}
|
||||
|
||||
|
||||
//! \brief Search substring "str" from symbol at index "start" and return first occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::find
|
||||
int find(const char str, const int start = 0) const;
|
||||
|
||||
//! \brief Search substring "str" from symbol at index "start" and return first occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::find
|
||||
int find(const PIString & str, const int start = 0) const;
|
||||
|
||||
//! \brief Search substring "str" from symbol at index "start" and return first occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::find
|
||||
int find(const char * str, const int start = 0) const {return find(PIString(str), start);}
|
||||
|
||||
//! \brief Search substring "str" from symbol at index "start" and return last occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::findLast
|
||||
int findLast(const char str, const int start = 0) const;
|
||||
|
||||
//! \brief Search substring "str" from symbol at index "start" and return last occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::findLast
|
||||
int findLast(const PIString & str, const int start = 0) const;
|
||||
|
||||
//! \brief Search substring "str" from symbol at index "start" and return last occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::findLast
|
||||
int findLast(const char * str, const int start = 0) const {return findLast(PIString(str), start);}
|
||||
|
||||
//! \brief Search word "word" from symbol at index "start" and return first occur position.
|
||||
//! \details Example: \snippet pistring.cpp PIString::findWord
|
||||
int findWord(const PIString & word, const int start = 0) const;
|
||||
|
||||
//! \brief Search C-style word "word" from symbol at index "start" and return first occur position.
|
||||
//! \details Example: \snippet pistring.cpp PIString::findCWord
|
||||
int findCWord(const PIString & word, const int start = 0) const;
|
||||
|
||||
//! \brief Search range between "start" and "end" symbols at index "start_index" and return first occur position.
|
||||
//! \details Example: \snippet pistring.cpp PIString::findRange
|
||||
int findRange(const PIChar & start, const PIChar & end, const PIChar & shield = '\\', const int start_index = 0, int * len = 0) const;
|
||||
|
||||
//! \brief Search any symbol of "str" from symbol at index "start" and return first occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::findAny
|
||||
int findAny(const PIString & str, const int start = 0) const;
|
||||
|
||||
//! \brief Search any symbol of "str" from symbol at index "start" and return first occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::findAny
|
||||
int findAny(const char * str, const int start = 0) const {return findAny(PIString(str), start);}
|
||||
|
||||
//! \brief Search any symbol of "str" from symbol at index "start" and return last occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::findAnyLast
|
||||
int findAnyLast(const PIString & str, const int start = 0) const;
|
||||
|
||||
//! \brief Search any symbol of "str" from symbol at index "start" and return last occur position
|
||||
//! \details Example: \snippet pistring.cpp PIString::findAnyLast
|
||||
int findAnyLast(const char * str, const int start = 0) const {return findAnyLast(PIString(str), start);}
|
||||
|
||||
//! \brief Returns number of occurrences of symbol "c"
|
||||
int entries(const PIChar & c) const;
|
||||
|
||||
//! \brief Returns number of occurrences of symbol "c"
|
||||
int entries(char c) const {return entries(PIChar(c));}
|
||||
|
||||
//! \brief Return if string starts with "str"
|
||||
bool startsWith(const PIString & str) const;
|
||||
|
||||
//! \brief Return if string ends with "str"
|
||||
bool endsWith(const PIString & str) const;
|
||||
|
||||
//! \brief Return symbols length of string
|
||||
int length() const {return size();}
|
||||
|
||||
//! \brief Return \c true if string is empty, i.e. length = 0
|
||||
bool isEmpty() const {return (size() == 0 || *this == "");}
|
||||
|
||||
|
||||
//! \brief Return \c true if string equal "true", "yes", "on" or positive not null numeric value
|
||||
bool toBool() const;
|
||||
|
||||
//! \brief Return \c char numeric value of string
|
||||
char toChar() const;
|
||||
|
||||
//! \brief Return \c short numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
short toShort(int base = -1, bool * ok = 0) const {return short(toNumberBase(*this, base, ok));}
|
||||
|
||||
//! \brief Return \c ushort numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
ushort toUShort(int base = -1, bool * ok = 0) const {return ushort(toNumberBase(*this, base, ok));}
|
||||
|
||||
//! \brief Return \c int numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
int toInt(int base = -1, bool * ok = 0) const {return int(toNumberBase(*this, base, ok));}
|
||||
|
||||
//! \brief Return \c uint numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
uint toUInt(int base = -1, bool * ok = 0) const {return uint(toNumberBase(*this, base, ok));}
|
||||
|
||||
//! \brief Return \c long numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
long toLong(int base = -1, bool * ok = 0) const {return long(toNumberBase(*this, base, ok));}
|
||||
|
||||
//! \brief Return \c ulong numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
ulong toULong(int base = -1, bool * ok = 0) const {return ulong(toNumberBase(*this, base, ok));}
|
||||
|
||||
//! \brief Return \c llong numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
llong toLLong(int base = -1, bool * ok = 0) const {return toNumberBase(*this, base, ok);}
|
||||
|
||||
//! \brief Return \c ullong numeric value of string in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::toNumber
|
||||
ullong toULLong(int base = -1, bool * ok = 0) const {return ullong(toNumberBase(*this, base, ok));}
|
||||
|
||||
//! \brief Return \c float numeric value of string
|
||||
//! \details Example: \snippet pistring.cpp PIString::toFloat
|
||||
float toFloat() const;
|
||||
|
||||
//! \brief Return \c double numeric value of string
|
||||
//! \details Example: \snippet pistring.cpp PIString::toFloat
|
||||
double toDouble() const;
|
||||
|
||||
//! \brief Return \c ldouble numeric value of string
|
||||
//! \details Example: \snippet pistring.cpp PIString::toFloat
|
||||
ldouble toLDouble() const;
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const short value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const ushort value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const int value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const uint value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const long value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const ulong value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const llong & value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setNumber
|
||||
PIString & setNumber(const ullong & value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setFloat
|
||||
PIString & setNumber(const float value, char format = 'f', int precision = 8) {clear(); *this += PIString::fromNumber(value, format, precision); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setFloat
|
||||
PIString & setNumber(const double & value, char format = 'f', int precision = 8) {clear(); *this += PIString::fromNumber(value, format, precision); return *this;}
|
||||
|
||||
//! \brief Set string content to numeric representation of "value"
|
||||
//! \details Example: \snippet pistring.cpp PIString::setFloat
|
||||
PIString & setNumber(const ldouble & value, char format = 'f', int precision = 8) {clear(); *this += PIString::fromNumber(value, format, precision); return *this;}
|
||||
|
||||
//! \brief Set string content to human readable size in B/kB/MB/GB/TB
|
||||
//! \details Example: \snippet pistring.cpp PIString::setReadableSize
|
||||
PIString & setReadableSize(llong bytes);
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const short value, int base = 10, bool * ok = 0) {return fromNumberBaseS(llong(value), base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const ushort value, int base = 10, bool * ok = 0) {return fromNumberBaseU(ullong(value), base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const int value, int base = 10, bool * ok = 0) {return fromNumberBaseS(llong(value), base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const uint value, int base = 10, bool * ok = 0) {return fromNumberBaseU(ullong(value), base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const long value, int base = 10, bool * ok = 0) {return fromNumberBaseS(llong(value), base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const ulong value, int base = 10, bool * ok = 0) {return fromNumberBaseU(ullong(value), base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const llong & value, int base = 10, bool * ok = 0) {return fromNumberBaseS(value, base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value" in base "base"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromNumber
|
||||
static PIString fromNumber(const ullong & value, int base = 10, bool * ok = 0) {return fromNumberBaseU(value, base, ok);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromFloat
|
||||
static PIString fromNumber(const float value, char format = 'f', int precision = 8) {return ftos(value, format, precision);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromFloat
|
||||
static PIString fromNumber(const double & value, char format = 'f', int precision = 8) {return dtos(value, format, precision);}
|
||||
|
||||
//! \brief Return string contains numeric representation of "value"
|
||||
//! \details Example: \snippet pistring.cpp PIString::fromFloat
|
||||
static PIString fromNumber(const ldouble & value, char format = 'f', int precision = 8) {return dtos(value, format, precision);}
|
||||
|
||||
//! \brief Return "true" or "false"
|
||||
static PIString fromBool(const bool value) {return PIString(value ? "true" : "false");}
|
||||
|
||||
//! \brief Return string constructed from terminal codepage
|
||||
static PIString fromConsole(const char * s);
|
||||
|
||||
//! \brief Return string constructed from system codepage
|
||||
static PIString fromSystem(const char * s);
|
||||
|
||||
//! \brief Return string constructed from UTF-8
|
||||
static PIString fromUTF8(const char * s);
|
||||
|
||||
//! \brief Return string constructed from UTF-8
|
||||
static PIString fromUTF8(const PIByteArray &ba);
|
||||
|
||||
//! \brief Return string constructed from ASCII
|
||||
static PIString fromAscii(const char * s);
|
||||
|
||||
//! \brief Return string constructed from "c" codepage
|
||||
static PIString fromCodepage(const char * s, const char * c);
|
||||
|
||||
//! \brief Return string contains human readable size in B/kB/MB/GB/TB
|
||||
//! \details Example: \snippet pistring.cpp PIString::readableSize
|
||||
static PIString readableSize(llong bytes);
|
||||
|
||||
PIString & removeAll(char v) {replaceAll(v, ""); return *this;}
|
||||
PIString & removeAll(const PIString & v) {replaceAll(v, ""); return *this;}
|
||||
|
||||
private:
|
||||
static const char toBaseN[];
|
||||
static const int fromBaseN[];
|
||||
|
||||
static PIString itos(const int num);
|
||||
static PIString ltos(const long num);
|
||||
static PIString lltos(const llong num);
|
||||
static PIString uitos(const uint num);
|
||||
static PIString ultos(const ulong num);
|
||||
static PIString ulltos(const ullong num);
|
||||
static PIString ftos(const float num, char format = 'f', int precision = 8);
|
||||
static PIString dtos(const double num, char format = 'f', int precision = 8);
|
||||
static PIString fromNumberBaseS(const llong value, int base = 10, bool * ok = 0);
|
||||
static PIString fromNumberBaseU(const ullong value, int base = 10, bool * ok = 0);
|
||||
static llong toNumberBase(const PIString & value, int base = -1, bool * ok = 0);
|
||||
void appendFromChars(const char * c, int s, const char * cp = __syslocname__);
|
||||
void buildData(const char * cp = __syslocname__) const;
|
||||
void trimsubstr(int &st, int &fn) const;
|
||||
mutable PIByteArray data_;
|
||||
};
|
||||
|
||||
|
||||
//! \relatesalso PIString \relatesalso PICout \brief Output operator to PICout
|
||||
PIP_EXPORT PICout operator <<(PICout s, const PIString & v);
|
||||
|
||||
|
||||
//! \relatesalso PIString \relatesalso PIByteArray \brief Output operator to PIByteArray
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIString & v) {s << *(PIDeque<PIChar>*)&v; return s;}
|
||||
|
||||
//! \relatesalso PIString \relatesalso PIByteArray \brief Input operator from PIByteArray
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIString & v) {v.clear(); s >> *(PIDeque<PIChar>*)&v; return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIString \brief Return concatenated string
|
||||
inline PIString operator +(const PIString & str, const PIString & f) {PIString s(str); s += f; return s;}
|
||||
|
||||
//! \relatesalso PIString \brief Return concatenated string
|
||||
inline PIString operator +(const PIString & f, const char * str) {PIString s(f); s += str; return s;}
|
||||
|
||||
//! \relatesalso PIString \brief Return concatenated string
|
||||
inline PIString operator +(const char * str, const PIString & f) {return PIString(str) + f;}
|
||||
|
||||
inline char chrUpr(char c);
|
||||
inline char chrLwr(char c);
|
||||
|
||||
|
||||
int versionCompare(const PIString & v0, const PIString & v1, int components = 6);
|
||||
|
||||
PIString versionNormalize(const PIString & v);
|
||||
|
||||
|
||||
|
||||
template<> inline uint piHash(const PIString & s) {return s.hash();}
|
||||
|
||||
#endif // PISTRING_H
|
||||
100
lib/main/core/pistring_std.h
Normal file
100
lib/main/core/pistring_std.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*! \file pistring.h
|
||||
* \brief String
|
||||
*
|
||||
* This file declare std operators and string conversions
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
STD for PIString
|
||||
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 PISTRING_STD_H
|
||||
#define PISTRING_STD_H
|
||||
#include <string>
|
||||
#ifdef QNX
|
||||
typedef std::basic_string<wchar_t> wstring;
|
||||
#endif
|
||||
|
||||
#include "pistringlist.h"
|
||||
|
||||
|
||||
inline std::string PIString2StdString(const PIString & v) {
|
||||
std::string s;
|
||||
uint wc;
|
||||
uchar tc;
|
||||
if (v.size() > 0) {
|
||||
for (int i = 0; i < v.length(); ++i) {
|
||||
wc = uint(v.at(i).unicode16Code());
|
||||
while (tc = wc & 0xFF, tc) {
|
||||
s.push_back(char(tc));
|
||||
wc >>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
inline PIString StdString2PIString(const std::string & v) {
|
||||
return PIString(v.c_str(), v.length());
|
||||
}
|
||||
|
||||
#ifdef HAS_LOCALE
|
||||
inline std::wstring PIString2StdWString(const PIString & v) {
|
||||
std::wstring s;
|
||||
for (int i = 0; i < v.length(); ++i)
|
||||
s.push_back(v.at(i).toWChar());
|
||||
return s;
|
||||
}
|
||||
|
||||
inline PIString StdWString2PIString(const std::wstring & v) {
|
||||
PIString s;
|
||||
uint l = v.size();
|
||||
for (uint i = 0; i < l; ++i) s.push_back(v[i]);
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//! \relatesalso PIChar \brief Output operator to \c std::ostream
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIChar & v) {s << v.toCharPtr(); return s;}
|
||||
|
||||
//! \relatesalso PIString \brief Return concatenated string
|
||||
inline PIString operator +(const PIString & f, const std::string & str) {PIString s(f); s += StdString2PIString(str); return s;}
|
||||
|
||||
//! \relatesalso PIString \brief Return concatenated string
|
||||
inline PIString operator +(const std::string & str, const PIString & f) {return StdString2PIString(str) + f;}
|
||||
|
||||
|
||||
//! \relatesalso PIString \brief Output operator to std::ostream (cout)
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIString & v) {for (int i = 0; i < v.length(); ++i) s << v[i]; return s;}
|
||||
|
||||
//! \relatesalso PIString \brief Input operator from std::istream (cin)
|
||||
inline std::istream & operator >>(std::istream & s, PIString & v) {std::string ss; s >> ss; v = StdString2PIString(ss); return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIStringList \brief Output operator to std::ostream (cout)
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIStringList & v) {
|
||||
s << PIChar("{");
|
||||
for (uint i = 0; i < v.size(); ++i) {
|
||||
s << PIChar("\"") << v[i] << PIChar("\"");
|
||||
if (i < v.size() - 1) s << PIStringAscii(", ");
|
||||
}
|
||||
s << PIChar("}");
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif // PISTRING_STD_H
|
||||
42
lib/main/core/pistringlist.cpp
Normal file
42
lib/main/core/pistringlist.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Strings array class
|
||||
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 "pistringlist.h"
|
||||
|
||||
|
||||
PIStringList& PIStringList::removeDuplicates() {
|
||||
PIStringList l;
|
||||
PIString s;
|
||||
bool ae;
|
||||
for (int i = 0; i < size_s(); ++i) {
|
||||
ae = false;
|
||||
s = at(i);
|
||||
for (int j = 0; j < l.size_s(); ++j) {
|
||||
if (s != l[j]) continue;
|
||||
ae = true; break;
|
||||
}
|
||||
if (!ae) {
|
||||
l << s;
|
||||
continue;
|
||||
}
|
||||
remove(i);
|
||||
--i;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
100
lib/main/core/pistringlist.h
Normal file
100
lib/main/core/pistringlist.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*! \brief Strings array class
|
||||
* \details This class is based on \a PIDeque<PIString> and
|
||||
* expand it functionality. */
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Strings array class
|
||||
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 PISTRINGLIST_H
|
||||
#define PISTRINGLIST_H
|
||||
|
||||
#include "pistring.h"
|
||||
|
||||
|
||||
class PIP_EXPORT PIStringList: public PIDeque<PIString>
|
||||
{
|
||||
public:
|
||||
|
||||
//! Contructs empty strings list
|
||||
PIStringList() {;}
|
||||
|
||||
~PIStringList() {;}
|
||||
|
||||
//! Contructs strings list with one string "str"
|
||||
PIStringList(const PIString & str) {push_back(str);}
|
||||
|
||||
//! Contructs empty strings list with strings "s0" and "s1"
|
||||
PIStringList(const PIString & s0, const PIString & s1) {push_back(s0); push_back(s1);}
|
||||
|
||||
//! Contructs empty strings list with strings "s0", "s1" and "s2"
|
||||
PIStringList(const PIString & s0, const PIString & s1, const PIString & s2) {push_back(s0); push_back(s1); push_back(s2);}
|
||||
|
||||
//! Contructs empty strings list with strings "s0", "s1", "s2" and "s3"
|
||||
PIStringList(const PIString & s0, const PIString & s1, const PIString & s2, const PIString & s3) {push_back(s0); push_back(s1); push_back(s2); push_back(s3);}
|
||||
|
||||
PIStringList(const PIStringList & o): PIDeque<PIString>() {resize(o.size()); for (uint i = 0; i < size(); ++i) (*this)[i] = o[i];}
|
||||
PIStringList(const PIVector<PIString> & o): PIDeque<PIString>() {resize(o.size()); for (uint i = 0; i < size(); ++i) (*this)[i] = o[i];}
|
||||
PIStringList(const PIDeque<PIString> & o): PIDeque<PIString>() {resize(o.size()); for (uint i = 0; i < size(); ++i) (*this)[i] = o[i];}
|
||||
|
||||
|
||||
//! \brief Join all strings in one with delimiter "delim" and return it
|
||||
//! \details Example: \snippet pistring.cpp PIStringList::join
|
||||
PIString join(const PIString & delim) const {PIString s; for (uint i = 0; i < size(); ++i) {s += at(i); if (i < size() - 1) s += delim;} return s;}
|
||||
|
||||
//! \brief Remove all strings equal "value" and return this
|
||||
//! \details Example: \snippet pistring.cpp PIStringList::removeStrings
|
||||
PIStringList & removeStrings(const PIString & value) {for (uint i = 0; i < size(); ++i) {if (at(i) == value) {remove(i); --i;}} return *this;}
|
||||
|
||||
PIStringList & remove(uint num) {PIDeque<PIString>::remove(num); return *this;}
|
||||
PIStringList & remove(uint num, uint count) {PIDeque<PIString>::remove(num, count); return *this;}
|
||||
|
||||
//! \brief Remove duplicated strings and return this
|
||||
//! \details Example: \snippet pistring.cpp PIStringList::removeDuplicates
|
||||
PIStringList & removeDuplicates();
|
||||
|
||||
//! \brief Trim all strings
|
||||
//! \details Example: \snippet pistring.cpp PIStringList::trim
|
||||
PIStringList & trim() {for (uint i = 0; i < size(); ++i) at(i).trim(); return *this;}
|
||||
|
||||
//! Return sum of lengths of all strings
|
||||
uint contentSize() {uint s = 0; for (uint i = 0; i < size(); ++i) s += at(i).size(); return s;}
|
||||
|
||||
//! Compare operator
|
||||
bool operator ==(const PIStringList & o) const {if (size() != o.size()) return false; for (size_t i = 0; i < size(); ++i) if (o[i] != (*this)[i]) return false; return true;}
|
||||
|
||||
//! Compare operator
|
||||
bool operator !=(const PIStringList & o) const {return !(o == (*this));}
|
||||
|
||||
PIStringList & operator =(const PIStringList & o) {PIDeque<PIString>::operator=(o); return *this;}
|
||||
|
||||
PIStringList & operator <<(const PIString & str) {append(str); return *this;}
|
||||
PIStringList & operator <<(const PIStringList & sl) {append(sl); return *this;}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//! \relatesalso PIStringList \relatesalso PIByteArray \brief Output operator to PIByteArray
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIStringList & v) {s << int(v.size_s()); for (int i = 0; i < v.size_s(); ++i) s << v[i]; return s;}
|
||||
|
||||
//! \relatesalso PIStringList \relatesalso PIByteArray \brief Input operator from PIByteArray
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIStringList & v) {int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
|
||||
|
||||
//! \relatesalso PIStringList \relatesalso PICout \brief Output operator to PICout
|
||||
inline PICout operator <<(PICout s, const PIStringList & v) {s.space(); s.setControl(0, true); s << "{"; for (uint i = 0; i < v.size(); ++i) {s << "\"" << v[i] << "\""; if (i < v.size() - 1) s << ", ";} s << "}"; s.restoreControl(); return s;}
|
||||
|
||||
#endif // PISTRINGLIST_H
|
||||
474
lib/main/core/pitime.cpp
Normal file
474
lib/main/core/pitime.cpp
Normal file
@@ -0,0 +1,474 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Timer
|
||||
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 "pitime.h"
|
||||
#include "pisystemtests.h"
|
||||
#ifdef WINDOWS
|
||||
extern FILETIME __pi_ftjan1970;
|
||||
long long __PIQueryPerformanceCounter() {LARGE_INTEGER li; QueryPerformanceCounter(&li); return li.QuadPart;}
|
||||
#endif
|
||||
#ifdef MAC_OS
|
||||
//# include <mach/mach_traps.h>
|
||||
//# include <mach/mach.h>
|
||||
# include <mach/clock.h>
|
||||
//# include <crt_externs.h>
|
||||
extern clock_serv_t __pi_mac_clock;
|
||||
#endif
|
||||
#ifdef FREERTOS
|
||||
# include "freertos/FreeRTOS.h"
|
||||
# include "freertos/task.h"
|
||||
#endif
|
||||
|
||||
/*! \class PISystemTime
|
||||
* \brief System time
|
||||
*
|
||||
* \section PISystemTime_sec0 Synopsis
|
||||
* This class provide arithmetic functions for POSIX system time.
|
||||
* This time represents as seconds and nanosecons in integer formats.
|
||||
* You can take current system time with function \a PISystemTime::current(),
|
||||
* compare times, sum or subtract two times, convert time to/from
|
||||
* seconds, milliseconds, microseconds or nanoseconds.
|
||||
* \section PISystemTime_sec1 Example
|
||||
* \snippet pitimer.cpp system_time
|
||||
*/
|
||||
|
||||
|
||||
/*! \class PITimeMeasurer
|
||||
* \brief Time measurements
|
||||
*
|
||||
* \section PITimeMeasurer_sec0 Synopsis
|
||||
* Function \a reset() set time mark to current
|
||||
* system time, then functions double elapsed_*() returns time elapsed from this mark.
|
||||
* These functions can returns nano-, micro-, milli- and seconds with suffixes "n", "u", "m"
|
||||
* and "s"
|
||||
*/
|
||||
|
||||
|
||||
void piUSleep(int usecs) {
|
||||
if (usecs <= 0) return;
|
||||
#ifdef WINDOWS
|
||||
//printf("Sleep %d\n", usecs / 1000);
|
||||
if (usecs > 0) Sleep(usecs / 1000);
|
||||
//printf("Sleep end");
|
||||
#else
|
||||
# ifdef FREERTOS
|
||||
vTaskDelay(usecs / 1000 / portTICK_PERIOD_MS);
|
||||
# else
|
||||
usecs -= PISystemTests::usleep_offset_us;
|
||||
if (usecs > 0) usleep(usecs);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool operator ==(const PITime & t0, const PITime & t1) {
|
||||
return (t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds);
|
||||
}
|
||||
|
||||
|
||||
bool operator <(const PITime & t0, const PITime & t1) {
|
||||
if (t0.hours == t1.hours) {
|
||||
if (t0.minutes == t1.minutes) {
|
||||
return t0.seconds < t1.seconds;
|
||||
} else return t0.minutes < t1.minutes;
|
||||
} else return t0.hours < t1.hours;
|
||||
}
|
||||
|
||||
|
||||
bool operator >(const PITime & t0, const PITime & t1) {
|
||||
if (t0.hours == t1.hours) {
|
||||
if (t0.minutes == t1.minutes) {
|
||||
return t0.seconds > t1.seconds;
|
||||
} else return t0.minutes > t1.minutes;
|
||||
} else return t0.hours > t1.hours;
|
||||
}
|
||||
|
||||
bool operator ==(const PIDate & t0, const PIDate & t1) {
|
||||
return (t0.year == t1.year && t0.month == t1.month && t0.day == t1.day);
|
||||
}
|
||||
|
||||
|
||||
bool operator <(const PIDate & t0, const PIDate & t1) {
|
||||
if (t0.year == t1.year) {
|
||||
if (t0.month == t1.month) {
|
||||
return t0.day < t1.day;
|
||||
} else return t0.month < t1.month;
|
||||
} else return t0.year < t1.year;
|
||||
}
|
||||
|
||||
|
||||
bool operator >(const PIDate & t0, const PIDate & t1) {
|
||||
if (t0.year == t1.year) {
|
||||
if (t0.month == t1.month) {
|
||||
return t0.day > t1.day;
|
||||
} else return t0.month > t1.month;
|
||||
} else return t0.year > t1.year;
|
||||
}
|
||||
|
||||
bool operator ==(const PIDateTime & t0, const PIDateTime & t1) {
|
||||
return (t0.year == t1.year && t0.month == t1.month && t0.day == t1.day &&
|
||||
t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds);
|
||||
}
|
||||
|
||||
|
||||
bool operator <(const PIDateTime & t0, const PIDateTime & t1) {
|
||||
if (t0.year == t1.year) {
|
||||
if (t0.month == t1.month) {
|
||||
if (t0.day == t1.day) {
|
||||
if (t0.hours == t1.hours) {
|
||||
if (t0.minutes == t1.minutes) {
|
||||
return t0.seconds < t1.seconds;
|
||||
} else return t0.minutes < t1.minutes;
|
||||
} else return t0.hours < t1.hours;
|
||||
} else return t0.day < t1.day;
|
||||
} else return t0.month < t1.month;
|
||||
} else return t0.year < t1.year;
|
||||
}
|
||||
|
||||
|
||||
bool operator >(const PIDateTime & t0, const PIDateTime & t1) {
|
||||
if (t0.year == t1.year) {
|
||||
if (t0.month == t1.month) {
|
||||
if (t0.day == t1.day) {
|
||||
if (t0.hours == t1.hours) {
|
||||
if (t0.minutes == t1.minutes) {
|
||||
return t0.seconds > t1.seconds;
|
||||
} else return t0.minutes > t1.minutes;
|
||||
} else return t0.hours > t1.hours;
|
||||
} else return t0.day > t1.day;
|
||||
} else return t0.month > t1.month;
|
||||
} else return t0.year > t1.year;
|
||||
}
|
||||
|
||||
|
||||
PISystemTime PITime::toSystemTime() const {
|
||||
return PISystemTime((hours * 60. + minutes) * 60. + seconds, milliseconds * 1000.);
|
||||
}
|
||||
|
||||
|
||||
PITime PITime::current() {
|
||||
time_t rt = ::time(0);
|
||||
tm * pt = localtime(&rt);
|
||||
PITime t;
|
||||
t.seconds = pt->tm_sec;
|
||||
t.minutes = pt->tm_min;
|
||||
t.hours = pt->tm_hour;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
PITime PITime::fromSystemTime(const PISystemTime & st) {
|
||||
double s = st.toSeconds();
|
||||
int v = s;
|
||||
PITime ret;
|
||||
ret.milliseconds = (s - v) * 1000;
|
||||
ret.seconds = v % 60; v = (v - ret.seconds) / 60;
|
||||
ret.minutes = v % 60; v = (v - ret.minutes) / 60;
|
||||
ret.hours = v;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIDate PIDate::current() {
|
||||
time_t rt = ::time(0);
|
||||
tm * pt = localtime(&rt);
|
||||
PIDate d;
|
||||
d.day = pt->tm_mday;
|
||||
d.month = pt->tm_mon + 1;
|
||||
d.year = pt->tm_year + 1900;
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
PIDateTime PIDateTime::current() {
|
||||
time_t rt = ::time(0);
|
||||
tm * pt = localtime(&rt);
|
||||
PIDateTime dt;
|
||||
dt.milliseconds = 0;
|
||||
dt.seconds = pt->tm_sec;
|
||||
dt.minutes = pt->tm_min;
|
||||
dt.hours = pt->tm_hour;
|
||||
dt.day = pt->tm_mday;
|
||||
dt.month = pt->tm_mon + 1;
|
||||
dt.year = pt->tm_year + 1900;
|
||||
return dt;
|
||||
}
|
||||
|
||||
|
||||
PISystemTime PISystemTime::abs() const {
|
||||
if (seconds < 0)
|
||||
return PISystemTime(piAbsl(seconds) - 1, 1000000000l - piAbsl(nanoseconds));
|
||||
else
|
||||
return PISystemTime(piAbsl(seconds), piAbsl(nanoseconds));
|
||||
}
|
||||
|
||||
|
||||
PISystemTime PISystemTime::current(bool precise_but_not_system) {
|
||||
#ifdef WINDOWS
|
||||
if (precise_but_not_system) {
|
||||
llong qpc(0);
|
||||
if (__pi_perf_freq > 0) {
|
||||
qpc = __PIQueryPerformanceCounter();
|
||||
return PISystemTime::fromSeconds(qpc / double(__pi_perf_freq));
|
||||
}
|
||||
return PISystemTime();
|
||||
} else {
|
||||
FILETIME ft, sft;
|
||||
# if (_WIN32_WINNT >= 0x0602)
|
||||
GetSystemTimePreciseAsFileTime(&ft);
|
||||
# else
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
# endif
|
||||
sft.dwHighDateTime = ft.dwHighDateTime - __pi_ftjan1970.dwHighDateTime;
|
||||
if (ft.dwLowDateTime < __pi_ftjan1970.dwLowDateTime) {
|
||||
sft.dwLowDateTime = ft.dwLowDateTime + (0xFFFFFFFF - __pi_ftjan1970.dwLowDateTime);
|
||||
sft.dwHighDateTime--;
|
||||
} else
|
||||
sft.dwLowDateTime = ft.dwLowDateTime - __pi_ftjan1970.dwLowDateTime;
|
||||
ullong lt = ullong(sft.dwHighDateTime) * 0x100000000U + ullong(sft.dwLowDateTime);
|
||||
return PISystemTime(lt / 10000000U, (lt % 10000000U) * 100U);
|
||||
}
|
||||
#else
|
||||
# ifdef MAC_OS
|
||||
mach_timespec_t t_cur;
|
||||
clock_get_time(__pi_mac_clock, &t_cur);
|
||||
# else
|
||||
# ifdef FREERTOS
|
||||
timespec t_cur;
|
||||
timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
gettimeofday(&tv, NULL);
|
||||
t_cur.tv_sec = tv.tv_sec;
|
||||
t_cur.tv_nsec = tv.tv_usec * 1000;
|
||||
# else
|
||||
timespec t_cur;
|
||||
clock_gettime(0, &t_cur);
|
||||
# endif
|
||||
# endif
|
||||
return PISystemTime(t_cur.tv_sec, t_cur.tv_nsec);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PIString PITime::toString(const PIString & format) const {
|
||||
PIString ts = format;
|
||||
ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0'));
|
||||
ts.replace("h", PIString::fromNumber(hours));
|
||||
ts.replace("mm", PIString::fromNumber(minutes).expandLeftTo(2, '0'));
|
||||
ts.replace("m", PIString::fromNumber(minutes));
|
||||
ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0'));
|
||||
ts.replace("s", PIString::fromNumber(seconds));
|
||||
ts.replace("zzz", PIString::fromNumber(milliseconds).expandLeftTo(3, '0'));
|
||||
ts.replace("zz", PIString::fromNumber(milliseconds).expandLeftTo(2, '0'));
|
||||
ts.replace("z", PIString::fromNumber(milliseconds));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
PIString PIDate::toString(const PIString & format) const {
|
||||
PIString ts = format;
|
||||
ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0'));
|
||||
ts.replace("yy", PIString::fromNumber(year).right(2));
|
||||
ts.replace("y", PIString::fromNumber(year).right(1));
|
||||
ts.replace("MM", PIString::fromNumber(month).expandLeftTo(2, '0'));
|
||||
ts.replace("M", PIString::fromNumber(month));
|
||||
ts.replace("dd", PIString::fromNumber(day).expandLeftTo(2, '0'));
|
||||
ts.replace("d", PIString::fromNumber(day));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
PIString PIDateTime::toString(const PIString & format) const {
|
||||
PIString ts = format;
|
||||
ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0'));
|
||||
ts.replace("yy", PIString::fromNumber(year).right(2));
|
||||
ts.replace("y", PIString::fromNumber(year).right(1));
|
||||
ts.replace("MM", PIString::fromNumber(month).expandLeftTo(2, '0'));
|
||||
ts.replace("M", PIString::fromNumber(month));
|
||||
ts.replace("dd", PIString::fromNumber(day).expandLeftTo(2, '0'));
|
||||
ts.replace("d", PIString::fromNumber(day));
|
||||
ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0'));
|
||||
ts.replace("h", PIString::fromNumber(hours));
|
||||
ts.replace("mm", PIString::fromNumber(minutes).expandLeftTo(2, '0'));
|
||||
ts.replace("m", PIString::fromNumber(minutes));
|
||||
ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0'));
|
||||
ts.replace("s", PIString::fromNumber(seconds));
|
||||
ts.replace("zzz", PIString::fromNumber(milliseconds).expandLeftTo(3, '0'));
|
||||
ts.replace("zz", PIString::fromNumber(milliseconds).expandLeftTo(2, '0'));
|
||||
ts.replace("z", PIString::fromNumber(milliseconds));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
time_t PIDateTime::toSecondSinceEpoch() const {
|
||||
tm pt;
|
||||
memset(&pt, 0, sizeof(pt));
|
||||
pt.tm_sec = seconds;
|
||||
pt.tm_min = minutes;
|
||||
pt.tm_hour = hours;
|
||||
pt.tm_mday = day;
|
||||
pt.tm_mon = month - 1;
|
||||
#ifdef WINDOWS
|
||||
pt.tm_year = piMaxi(year - 1900, 70);
|
||||
#else
|
||||
pt.tm_year = piMaxi(year - 1900, 0);
|
||||
#endif
|
||||
return mktime(&pt);
|
||||
}
|
||||
|
||||
|
||||
PIDateTime PIDateTime::fromSecondSinceEpoch(const time_t sec) {
|
||||
tm * pt = localtime(&sec);
|
||||
PIDateTime dt;
|
||||
dt.seconds = pt->tm_sec;
|
||||
dt.minutes = pt->tm_min;
|
||||
dt.hours = pt->tm_hour;
|
||||
dt.day = pt->tm_mday;
|
||||
dt.month = pt->tm_mon + 1;
|
||||
dt.year = pt->tm_year + 1900;
|
||||
return dt;
|
||||
|
||||
}
|
||||
|
||||
|
||||
PIString time2string(const PITime & time, const PIString & format) {
|
||||
PIString ts = format;
|
||||
ts.replace("hh", PIString::fromNumber(time.hours).expandLeftTo(2, '0'));
|
||||
ts.replace("h", PIString::fromNumber(time.hours));
|
||||
ts.replace("mm", PIString::fromNumber(time.minutes).expandLeftTo(2, '0'));
|
||||
ts.replace("m", PIString::fromNumber(time.minutes));
|
||||
ts.replace("ss", PIString::fromNumber(time.seconds).expandLeftTo(2, '0'));
|
||||
ts.replace("s", PIString::fromNumber(time.seconds));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
PIString date2string(const PIDate & date, const PIString & format) {
|
||||
PIString ts = format;
|
||||
ts.replace("yyyy", PIString::fromNumber(date.year).expandLeftTo(4, '0'));
|
||||
ts.replace("yy", PIString::fromNumber(date.year).right(2));
|
||||
ts.replace("y", PIString::fromNumber(date.year).right(1));
|
||||
ts.replace("MM", PIString::fromNumber(date.month).expandLeftTo(2, '0'));
|
||||
ts.replace("M", PIString::fromNumber(date.month));
|
||||
ts.replace("dd", PIString::fromNumber(date.day).expandLeftTo(2, '0'));
|
||||
ts.replace("d", PIString::fromNumber(date.day));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
PIString datetime2string(const PIDateTime & date, const PIString & format) {
|
||||
PIString ts = format;
|
||||
ts.replace("hh", PIString::fromNumber(date.hours).expandLeftTo(2, '0'));
|
||||
ts.replace("h", PIString::fromNumber(date.hours));
|
||||
ts.replace("mm", PIString::fromNumber(date.minutes).expandLeftTo(2, '0'));
|
||||
ts.replace("m", PIString::fromNumber(date.minutes));
|
||||
ts.replace("ss", PIString::fromNumber(date.seconds).expandLeftTo(2, '0'));
|
||||
ts.replace("s", PIString::fromNumber(date.seconds));
|
||||
ts.replace("yyyy", PIString::fromNumber(date.year).expandLeftTo(4, '0'));
|
||||
ts.replace("yy", PIString::fromNumber(date.year).right(2));
|
||||
ts.replace("y", PIString::fromNumber(date.year).right(1));
|
||||
ts.replace("MM", PIString::fromNumber(date.month).expandLeftTo(2, '0'));
|
||||
ts.replace("M", PIString::fromNumber(date.month));
|
||||
ts.replace("dd", PIString::fromNumber(date.day).expandLeftTo(2, '0'));
|
||||
ts.replace("d", PIString::fromNumber(date.day));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PITimeMeasurer::PITimeMeasurer() {
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
double PITimeMeasurer::elapsed_n() const {
|
||||
return (PISystemTime::current(true) - t_st).toNanoseconds() - PISystemTests::time_elapsed_ns;
|
||||
}
|
||||
|
||||
|
||||
double PITimeMeasurer::elapsed_u() const {
|
||||
return (PISystemTime::current(true) - t_st).toMicroseconds() - PISystemTests::time_elapsed_ns / 1.E+3;
|
||||
}
|
||||
|
||||
|
||||
double PITimeMeasurer::elapsed_m() const {
|
||||
return (PISystemTime::current(true) - t_st).toMilliseconds() - PISystemTests::time_elapsed_ns / 1.E+6;
|
||||
}
|
||||
|
||||
|
||||
double PITimeMeasurer::elapsed_s() const {
|
||||
return (PISystemTime::current(true) - t_st).toSeconds() - PISystemTests::time_elapsed_ns / 1.E+9;
|
||||
}
|
||||
|
||||
|
||||
PISystemTime PITimeMeasurer::elapsed() const {
|
||||
return (PISystemTime::current(true) - t_st);
|
||||
}
|
||||
|
||||
|
||||
PICout operator <<(PICout s, const PITime & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s << "PITime(" << v.hours << ":";
|
||||
s << PIString::fromNumber(v.minutes).expandLeftTo(2, '0') << ":";
|
||||
s << PIString::fromNumber(v.seconds).expandLeftTo(2, '0') << ":";
|
||||
s << PIString::fromNumber(v.milliseconds).expandLeftTo(3, '0') << ")";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
PICout operator <<(PICout s, const PIDate & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s << "PIDate(" << v.day << "-";
|
||||
s << PIString::fromNumber(v.month).expandLeftTo(2, '0') << "-";
|
||||
s << v.year << ")";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
PICout operator <<(PICout s, const PIDateTime & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s << "PIDateTime(";
|
||||
s << v.day << "-";
|
||||
s << PIString::fromNumber(v.month).expandLeftTo(2, '0') << "-";
|
||||
s << v.year << " ";
|
||||
s << v.hours << ":";
|
||||
s << PIString::fromNumber(v.minutes).expandLeftTo(2, '0') << ":";
|
||||
s << PIString::fromNumber(v.seconds).expandLeftTo(2, '0') << ":";
|
||||
s << PIString::fromNumber(v.milliseconds).expandLeftTo(3, '0') << ")";
|
||||
s.restoreControl();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
#ifdef WINDOWS
|
||||
void msleep(int msecs) {Sleep(msecs);}
|
||||
#else
|
||||
# ifdef FREERTOS
|
||||
void msleep(int msecs) {vTaskDelay(msecs / portTICK_PERIOD_MS);}
|
||||
# else
|
||||
void msleep(int msecs) {usleep(msecs * 1000);}
|
||||
# endif
|
||||
#endif
|
||||
333
lib/main/core/pitime.h
Normal file
333
lib/main/core/pitime.h
Normal file
@@ -0,0 +1,333 @@
|
||||
/*! \file pitime.h
|
||||
* \brief Time structs
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Time 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 distributed in the hope that 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 PITIME_H
|
||||
#define PITIME_H
|
||||
|
||||
|
||||
#include "pistring.h"
|
||||
#include <ctime>
|
||||
#ifdef QNX
|
||||
# include <time.h>
|
||||
#endif
|
||||
//! \brief Sleep for "msecs" milliseconds
|
||||
PIP_EXPORT void msleep(int msecs);
|
||||
|
||||
/*! \brief Precise sleep for "usecs" microseconds
|
||||
* \details This function consider \c "usleep" offset
|
||||
* on QNX/Linux/Mac, which is calculated with
|
||||
* \a pip_sys_test program. If there is correct
|
||||
* offset value in system config, this function
|
||||
* wait \b exactly "usecs" microseconds. */
|
||||
PIP_EXPORT void piUSleep(int usecs); // on !Windows consider constant "usleep" offset
|
||||
|
||||
/*! \brief Precise sleep for "msecs" milliseconds
|
||||
* \details This function exec \a piUSleep (msecs * 1000). */
|
||||
inline void piMSleep(double msecs) {piUSleep(int(msecs * 1000.));} // on !Windows consider constant "usleep" offset
|
||||
|
||||
/*! \brief Precise sleep for "secs" seconds
|
||||
* \details This function exec \a piUSleep (msecs * 1000000). */
|
||||
inline void piSleep(double secs) {piUSleep(int(secs * 1000000.));} // on !Windows consider constant "usleep" offset
|
||||
|
||||
|
||||
|
||||
|
||||
class PIP_EXPORT PISystemTime {
|
||||
public:
|
||||
|
||||
//! Contructs system time with s = ns = 0
|
||||
PISystemTime() {seconds = nanoseconds = 0;}
|
||||
|
||||
//! Contructs system time with s = "s" and ns = "ns"
|
||||
PISystemTime(int s, int ns) {seconds = s; nanoseconds = ns; checkOverflows();}
|
||||
|
||||
//! Contructs system time from another
|
||||
PISystemTime(const PISystemTime & t) {seconds = t.seconds; nanoseconds = t.nanoseconds;}
|
||||
|
||||
//! Returns stored system time value in seconds
|
||||
double toSeconds() const {return double(seconds) + nanoseconds / 1.e+9;}
|
||||
|
||||
//! Returns stored system time value in milliseconds
|
||||
double toMilliseconds() const {return seconds * 1.e+3 + nanoseconds / 1.e+6;}
|
||||
|
||||
//! Returns stored system time value in microseconds
|
||||
double toMicroseconds() const {return seconds * 1.e+6 + nanoseconds / 1.e+3;}
|
||||
|
||||
//! Returns stored system time value in nanoseconds
|
||||
double toNanoseconds() const {return seconds * 1.e+9 + double(nanoseconds);}
|
||||
|
||||
|
||||
//! Add to stored system time "v" seconds
|
||||
PISystemTime & addSeconds(double v) {*this += fromSeconds(v); return *this;}
|
||||
|
||||
//! Add to stored system time "v" milliseconds
|
||||
PISystemTime & addMilliseconds(double v) {*this += fromMilliseconds(v); return *this;}
|
||||
|
||||
//! Add to stored system time "v" microseconds
|
||||
PISystemTime & addMicroseconds(double v) {*this += fromMicroseconds(v); return *this;}
|
||||
|
||||
//! Add to stored system time "v" nanoseconds
|
||||
PISystemTime & addNanoseconds(double v) {*this += fromNanoseconds(v); return *this;}
|
||||
|
||||
|
||||
//! Sleep for stored value. \warning Use this function to sleep for difference of system times or constructs system time.
|
||||
//! If you call this function on system time returned with \a PISystemTime::current() thread will be sleep almost forever.
|
||||
void sleep() {piUSleep(piFloord(toMicroseconds()));} // wait self value, useful to wait some dT = (t1 - t0)
|
||||
|
||||
|
||||
//! Returns copy of this system time with absolutely values of s and ns
|
||||
PISystemTime abs() const;
|
||||
|
||||
//! Returns sum of this system time with "t"
|
||||
PISystemTime operator +(const PISystemTime & t) const {PISystemTime tt(*this); tt.seconds += t.seconds; tt.nanoseconds += t.nanoseconds; tt.checkOverflows(); return tt;}
|
||||
|
||||
//! Returns difference between this system time and "t"
|
||||
PISystemTime operator -(const PISystemTime & t) const {PISystemTime tt(*this); tt.seconds -= t.seconds; tt.nanoseconds -= t.nanoseconds; tt.checkOverflows(); return tt;}
|
||||
|
||||
//! Returns multiplication between this system time and "t"
|
||||
PISystemTime operator *(const double & v) const {return fromMilliseconds(toMilliseconds() * v);}
|
||||
|
||||
//! Returns division between this system time and "t"
|
||||
PISystemTime operator /(const double & v) const {return fromMilliseconds(toMilliseconds() / v);}
|
||||
|
||||
//! Add to stored value system time "t"
|
||||
PISystemTime & operator +=(const PISystemTime & t) {seconds += t.seconds; nanoseconds += t.nanoseconds; checkOverflows(); return *this;}
|
||||
|
||||
//! Subtract from stored value system time "t"
|
||||
PISystemTime & operator -=(const PISystemTime & t) {seconds -= t.seconds; nanoseconds -= t.nanoseconds; checkOverflows(); return *this;}
|
||||
|
||||
//! Multiply stored value system time by "v"
|
||||
PISystemTime & operator *=(const double & v) {*this = fromMilliseconds(toMilliseconds() * v); return *this;}
|
||||
|
||||
//! Divide stored value system time by "v"
|
||||
PISystemTime & operator /=(const double & v) {*this = fromMilliseconds(toMilliseconds() / v); return *this;}
|
||||
|
||||
|
||||
//! Compare system times
|
||||
bool operator ==(const PISystemTime & t) const {return ((seconds == t.seconds) && (nanoseconds == t.nanoseconds));}
|
||||
|
||||
//! Compare system times
|
||||
bool operator !=(const PISystemTime & t) const {return ((seconds != t.seconds) || (nanoseconds != t.nanoseconds));}
|
||||
|
||||
//! Compare system times
|
||||
bool operator >(const PISystemTime & t) const {if (seconds == t.seconds) return nanoseconds > t.nanoseconds; return seconds > t.seconds;}
|
||||
|
||||
//! Compare system times
|
||||
bool operator <(const PISystemTime & t) const {if (seconds == t.seconds) return nanoseconds < t.nanoseconds; return seconds < t.seconds;}
|
||||
|
||||
//! Compare system times
|
||||
bool operator >=(const PISystemTime & t) const {if (seconds == t.seconds) return nanoseconds >= t.nanoseconds; return seconds >= t.seconds;}
|
||||
|
||||
//! Compare system times
|
||||
bool operator <=(const PISystemTime & t) const {if (seconds == t.seconds) return nanoseconds <= t.nanoseconds; return seconds <= t.seconds;}
|
||||
|
||||
|
||||
//! Contructs system time from seconds "v"
|
||||
static PISystemTime fromSeconds(double v) {int s = piFloord(v); return PISystemTime(s, int((v - s) * 1000000000.));}
|
||||
|
||||
//! Contructs system time from milliseconds "v"
|
||||
static PISystemTime fromMilliseconds(double v) {int s = piFloord(v / 1000.); return PISystemTime(s, int((v / 1000. - s) * 1000000000.));}
|
||||
|
||||
//! Contructs system time from microseconds "v"
|
||||
static PISystemTime fromMicroseconds(double v) {int s = piFloord(v / 1000000.); return PISystemTime(s, int((v / 1000000. - s) * 1000000000.));}
|
||||
|
||||
//! Contructs system time from nanoseconds "v"
|
||||
static PISystemTime fromNanoseconds(double v) {int s = piFloord(v / 1000000000.); return PISystemTime(s, int((v / 1000000000. - s) * 1000000000.));}
|
||||
|
||||
//! Returns current system time
|
||||
static PISystemTime current(bool precise_but_not_system = false);
|
||||
|
||||
//! Seconds of stored system time
|
||||
int seconds;
|
||||
|
||||
//! Nanoseconds of stored system time
|
||||
int nanoseconds;
|
||||
|
||||
private:
|
||||
void checkOverflows() {while (nanoseconds >= 1000000000) {nanoseconds -= 1000000000; seconds++;} while (nanoseconds < 0) {nanoseconds += 1000000000; seconds--;}}
|
||||
|
||||
};
|
||||
|
||||
//! \relatesalso PICout \relatesalso PICout \brief Output operator to PICout
|
||||
inline PICout operator <<(PICout s, const PISystemTime & v) {s.space(); s.setControl(0, true); s << "(" << v.seconds << " s, " << v.nanoseconds << " ns)"; s.restoreControl(); return s;}
|
||||
|
||||
//! \relatesalso PISystemTime \relatesalso PIByteArray \brief Output operator to PIByteArray
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PISystemTime & v) {s << v.seconds << v.nanoseconds; return s;}
|
||||
|
||||
//! \relatesalso PISystemTime \relatesalso PIByteArray \brief Input operator from PIByteArray
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PISystemTime & v) {s >> v.seconds >> v.nanoseconds; return s;}
|
||||
|
||||
|
||||
|
||||
|
||||
struct PIP_EXPORT PITime {
|
||||
PITime(int hours_ = 0, int minutes_ = 0, int seconds_ = 0, int milliseconds_ = 0): hours(hours_), minutes(minutes_), seconds(seconds_), milliseconds(milliseconds_) {;}
|
||||
int hours;
|
||||
int minutes;
|
||||
int seconds;
|
||||
int milliseconds;
|
||||
PIString toString(const PIString & format = "h:mm:ss") const;
|
||||
PISystemTime toSystemTime() const;
|
||||
static PITime current();
|
||||
static PITime fromSystemTime(const PISystemTime & st);
|
||||
};
|
||||
|
||||
PIP_EXPORT bool operator ==(const PITime & t0, const PITime & t1);
|
||||
PIP_EXPORT bool operator <(const PITime & t0, const PITime & t1);
|
||||
PIP_EXPORT bool operator >(const PITime & t0, const PITime & t1);
|
||||
inline bool operator !=(const PITime & t0, const PITime & t1) {return !(t0 == t1);}
|
||||
inline bool operator <=(const PITime & t0, const PITime & t1) {return !(t0 > t1);}
|
||||
inline bool operator >=(const PITime & t0, const PITime & t1) {return !(t0 < t1);}
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PITime & v) {s << v.hours << v.minutes << v.seconds << v.milliseconds; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PITime & v) {s >> v.hours >> v.minutes >> v.seconds >> v.milliseconds; return s;}
|
||||
|
||||
//! \relatesalso PICout \relatesalso PICout \brief Output operator to PICout
|
||||
PIP_EXPORT PICout operator <<(PICout s, const PITime & v);
|
||||
|
||||
|
||||
|
||||
|
||||
struct PIP_EXPORT PIDate {
|
||||
PIDate(int year_ = 0, int month_ = 0, int day_ = 0): year(year_), month(month_), day(day_) {;}
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
PIString toString(const PIString & format = "d.MM.yyyy") const;
|
||||
static PIDate current();
|
||||
};
|
||||
|
||||
PIP_EXPORT bool operator ==(const PIDate & t0, const PIDate & t1);
|
||||
PIP_EXPORT bool operator <(const PIDate & t0, const PIDate & t1);
|
||||
PIP_EXPORT bool operator >(const PIDate & t0, const PIDate & t1);
|
||||
inline bool operator !=(const PIDate & t0, const PIDate & t1) {return !(t0 == t1);}
|
||||
inline bool operator <=(const PIDate & t0, const PIDate & t1) {return !(t0 > t1);}
|
||||
inline bool operator >=(const PIDate & t0, const PIDate & t1) {return !(t0 < t1);}
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIDate & v) {s << v.year << v.month << v.day; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIDate & v) {s >> v.year >> v.month >> v.day; return s;}
|
||||
|
||||
//! \relatesalso PICout \relatesalso PICout \brief Output operator to PICout
|
||||
PIP_EXPORT PICout operator <<(PICout s, const PIDate & v);
|
||||
|
||||
|
||||
|
||||
|
||||
struct PIP_EXPORT PIDateTime {
|
||||
PIDateTime() {year = month = day = hours = minutes = seconds = milliseconds = 0;}
|
||||
PIDateTime(const PITime & time) {year = month = day = 0; hours = time.hours; minutes = time.minutes; seconds = time.seconds; milliseconds = time.milliseconds;}
|
||||
PIDateTime(const PIDate & date) {year = date.year; month = date.month; day = date.day; hours = minutes = seconds = milliseconds = 0;}
|
||||
PIDateTime(const PIDate & date, const PITime & time) {year = date.year; month = date.month; day = date.day; hours = time.hours; minutes = time.minutes; seconds = time.seconds; milliseconds = time.milliseconds;}
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
int hours;
|
||||
int minutes;
|
||||
int seconds;
|
||||
int milliseconds;
|
||||
PIDateTime normalized() const {return PIDateTime::fromSecondSinceEpoch(toSecondSinceEpoch());}
|
||||
void normalize() {*this = normalized();}
|
||||
PIString toString(const PIString & format = "h:mm:ss d.MM.yyyy") const;
|
||||
time_t toSecondSinceEpoch() const;
|
||||
PISystemTime toSystemTime() const {return PISystemTime(int(toSecondSinceEpoch()), milliseconds * 1000000);}
|
||||
PIDate date() const {return PIDate(year, month, day);}
|
||||
PITime time() const {return PITime(hours, minutes, seconds, milliseconds);}
|
||||
void setDate(const PIDate & d) {year = d.year; month = d.month; day = d.day;}
|
||||
void setTime(const PITime & t) {hours = t.hours; minutes = t.minutes; seconds = t.seconds; milliseconds = t.milliseconds;}
|
||||
void operator +=(const PIDateTime & d1) {year += d1.year; month += d1.month; day += d1.day; hours += d1.hours; minutes += d1.minutes; seconds += d1.seconds; normalize();}
|
||||
void operator -=(const PIDateTime & d1) {year -= d1.year; month -= d1.month; day -= d1.day; hours -= d1.hours; minutes -= d1.minutes; seconds -= d1.seconds; normalize();}
|
||||
static PIDateTime fromSecondSinceEpoch(const time_t sec);
|
||||
static PIDateTime fromSystemTime(const PISystemTime & st) {PIDateTime dt = fromSecondSinceEpoch(st.seconds); dt.milliseconds = piClampi(st.nanoseconds / 1000000, 0, 999); return dt;}
|
||||
static PIDateTime current();
|
||||
};
|
||||
|
||||
inline PIDateTime operator +(const PIDateTime & d0, const PIDateTime & d1) {PIDateTime td = d0; td += d1; return td.normalized();}
|
||||
inline PIDateTime operator -(const PIDateTime & d0, const PIDateTime & d1) {PIDateTime td = d0; td -= d1; return td.normalized();}
|
||||
PIP_EXPORT bool operator ==(const PIDateTime & t0, const PIDateTime & t1);
|
||||
PIP_EXPORT bool operator <(const PIDateTime & t0, const PIDateTime & t1);
|
||||
PIP_EXPORT bool operator >(const PIDateTime & t0, const PIDateTime & t1);
|
||||
inline bool operator !=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 == t1);}
|
||||
inline bool operator <=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 > t1);}
|
||||
inline bool operator >=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 < t1);}
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIDateTime & v) {s << v.year << v.month << v.day << v.hours << v.minutes << v.seconds << v.milliseconds; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIDateTime & v) {s >> v.year >> v.month >> v.day >> v.hours >> v.minutes >> v.seconds >> v.milliseconds; return s;}
|
||||
|
||||
//! \relatesalso PICout \relatesalso PICout \brief Output operator to PICout
|
||||
PIP_EXPORT PICout operator <<(PICout s, const PIDateTime & v);
|
||||
|
||||
|
||||
|
||||
|
||||
class PIP_EXPORT PITimeMeasurer {
|
||||
public:
|
||||
PITimeMeasurer();
|
||||
|
||||
/** \brief Set internal time mark to current system time
|
||||
* \details This function used for set start time mark. Later
|
||||
* you can find out elapsed time from this time mark to any
|
||||
* moment of time with \a elapsed_s(), \a elapsed_m(),
|
||||
* \a elapsed_u() or \a elapsed_n() functions.
|
||||
* \sa \a elapsed_s(), \a elapsed_m(), \a elapsed_u(), \a elapsed_n() */
|
||||
void reset() {t_st = PISystemTime::current(true);}
|
||||
|
||||
//! \brief Returns nanoseconds elapsed from last \a reset() execution or from timer measurer creation.
|
||||
double elapsed_n() const;
|
||||
|
||||
//! \brief Returns microseconds elapsed from last \a reset() execution or from timer measurer creation.
|
||||
double elapsed_u() const;
|
||||
|
||||
//! \brief Returns milliseconds elapsed from last \a reset() execution or from timer measurer creation.
|
||||
double elapsed_m() const;
|
||||
|
||||
//! \brief Returns seconds elapsed from last \a reset() execution or from timer measurer creation.
|
||||
double elapsed_s() const;
|
||||
|
||||
//! \brief Returns PISystemTime elapsed from last \a reset() execution or from timer measurer creation.
|
||||
PISystemTime elapsed() const;
|
||||
|
||||
double reset_time_n() const {return t_st.toNanoseconds();}
|
||||
double reset_time_u() const {return t_st.toMicroseconds();}
|
||||
double reset_time_m() const {return t_st.toMilliseconds();}
|
||||
double reset_time_s() const {return t_st.toSeconds();}
|
||||
|
||||
//! \brief Returns time mark of last \a reset() execution or timer measurer creation.
|
||||
PISystemTime reset_time() {return t_st;}
|
||||
|
||||
//! \brief Returns nanoseconds representation of current system time.
|
||||
static double elapsed_system_n() {return PISystemTime::current(true).toNanoseconds();}
|
||||
|
||||
//! \brief Returns microseconds representation of current system time.
|
||||
static double elapsed_system_u() {return PISystemTime::current(true).toMicroseconds();}
|
||||
|
||||
//! \brief Returns milliseconds representation of current system time.
|
||||
static double elapsed_system_m() {return PISystemTime::current(true).toMilliseconds();}
|
||||
|
||||
//! \brief Returns seconds representation of current system time.
|
||||
static double elapsed_system_s() {return PISystemTime::current(true).toSeconds();}
|
||||
|
||||
//! \brief Returns time mark of current system time.
|
||||
static PISystemTime elapsed_system() {return PISystemTime::current(true);}
|
||||
|
||||
private:
|
||||
PISystemTime t_st, t_cur;
|
||||
|
||||
};
|
||||
|
||||
#endif // PITIME_H
|
||||
87
lib/main/core/pitime_win.h
Normal file
87
lib/main/core/pitime_win.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*! \file pitime_win.h
|
||||
* \brief PITime conversions for Windows
|
||||
*
|
||||
* This file declare time conversions for Windows
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
PITime conversions for Windows
|
||||
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 PITIME_WIN_H
|
||||
#define PITIME_WIN_H
|
||||
|
||||
#include "pibase.h"
|
||||
#ifdef WINDOWS
|
||||
|
||||
#include "pitime.h"
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
inline PISystemTime FILETIME2PISystemTime(const FILETIME &t) {
|
||||
PISystemTime st;
|
||||
ullong lt = ullong(t.dwHighDateTime) * 0x100000000U + ullong(t.dwLowDateTime);
|
||||
st.seconds = lt / 10000000U;
|
||||
st.nanoseconds = (lt % 10000000U) * 100U;
|
||||
return st;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline PIDateTime SYSTEMTIME2PIDateTime(const SYSTEMTIME &t) {
|
||||
PIDateTime dt;
|
||||
dt.year = t.wYear;
|
||||
dt.month = t.wMonth;
|
||||
dt.day = t.wDay;
|
||||
dt.hours = t.wHour;
|
||||
dt.minutes = t.wMinute;
|
||||
dt.seconds = t.wSecond;
|
||||
dt.milliseconds = t.wMilliseconds;
|
||||
return dt;
|
||||
}
|
||||
|
||||
inline PIDateTime FILETIME2PIDateTime(const FILETIME &t) {
|
||||
FILETIME lt;
|
||||
SYSTEMTIME st;
|
||||
FileTimeToLocalFileTime(&t, <);
|
||||
FileTimeToSystemTime(<, &st);
|
||||
return SYSTEMTIME2PIDateTime(st);
|
||||
}
|
||||
|
||||
inline SYSTEMTIME PIDateTime2SYSTEMTIME(const PIDateTime &dt) {
|
||||
SYSTEMTIME st;
|
||||
st.wYear = dt.year;
|
||||
st.wMonth = dt.month;
|
||||
st.wDay = dt.day;
|
||||
st.wHour = dt.hours;
|
||||
st.wMinute = dt.minutes;
|
||||
st.wSecond = dt.seconds;
|
||||
st.wMilliseconds = dt.milliseconds;
|
||||
return st;
|
||||
}
|
||||
|
||||
inline FILETIME PIDateTime2FILETIME(const PIDateTime &dt) {
|
||||
FILETIME lt, ret;
|
||||
SYSTEMTIME st = PIDateTime2SYSTEMTIME(dt);
|
||||
SystemTimeToFileTime(&st, <);
|
||||
LocalFileTimeToFileTime(<, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // WINDOWS
|
||||
#endif // PITIME_WIN_H
|
||||
620
lib/main/core/pivariant.cpp
Normal file
620
lib/main/core/pivariant.cpp
Normal file
@@ -0,0 +1,620 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Variant type
|
||||
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 "pivariant.h"
|
||||
|
||||
|
||||
/** \class PIVariant
|
||||
* \brief Variant type
|
||||
* \details
|
||||
* \section PIVariant_sec0 Synopsis
|
||||
* This class provides general type that can contains all standard types, some
|
||||
* PIP types or custom type. In case of standard types this class also provides
|
||||
* convertions between them.
|
||||
*
|
||||
* \section PIVariant_sec1 Usage
|
||||
* %PIVariant useful if you want pass many variables with different types in
|
||||
* single array, e.g.:
|
||||
* \code{cpp}
|
||||
* PIVector<PIVariant> array;
|
||||
* array << PIVariant(10) << PIVariant(1.61) << PIVariant(true) << PIVariant("0xFF");
|
||||
* piCout << array;
|
||||
* piForeachC (PIVariant & i, array)
|
||||
* piCout << i.toInt();
|
||||
* \endcode
|
||||
* Result:
|
||||
* \code{cpp}
|
||||
* {PIVariant(Int, 10), PIVariant(Double, 1,61), PIVariant(Bool, true), PIVariant(String, 0xFF)}
|
||||
* 10
|
||||
* 1
|
||||
* 1
|
||||
* 255
|
||||
* \endcode
|
||||
* */
|
||||
|
||||
#ifdef CUSTOM_PIVARIANT
|
||||
PIMap<PIString, __PIVariantInfo__ * > * __PIVariantInfoStorage__::map = 0;
|
||||
#endif
|
||||
|
||||
|
||||
PIVariant::PIVariant() {
|
||||
_type = PIVariant::pivInvalid;
|
||||
_info = 0;
|
||||
}
|
||||
|
||||
|
||||
PIVariant::PIVariant(const PIVariant &v) {
|
||||
_type = v._type;
|
||||
_content = v._content;
|
||||
#ifdef CUSTOM_PIVARIANT
|
||||
_info = v._info;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIVariant::setValueFromString(const PIString & v) {
|
||||
switch (_type) {
|
||||
case PIVariant::pivBool: {setValue(v.toBool());} break;
|
||||
case PIVariant::pivChar: {setValue(v.toChar());} break;
|
||||
case PIVariant::pivUChar: {setValue((uchar)v.toChar());} break;
|
||||
case PIVariant::pivShort: {setValue(v.toShort());} break;
|
||||
case PIVariant::pivUShort: {setValue(v.toUShort());} break;
|
||||
case PIVariant::pivInt: {setValue(v.toInt());} break;
|
||||
case PIVariant::pivUInt: {setValue(v.toUInt());} break;
|
||||
case PIVariant::pivLLong: {setValue(v.toLLong());} break;
|
||||
case PIVariant::pivULLong: {setValue(v.toULLong());} break;
|
||||
case PIVariant::pivFloat: {setValue(v.toFloat());} break;
|
||||
case PIVariant::pivDouble: {setValue(v.toDouble());} break;
|
||||
case PIVariant::pivLDouble: {setValue(v.toLDouble());} break;
|
||||
case PIVariant::pivTime: {} break; // TODO
|
||||
case PIVariant::pivDate: {} break; // TODO
|
||||
case PIVariant::pivDateTime: {} break; // TODO
|
||||
case PIVariant::pivString: {setValue(v);} break;
|
||||
case PIVariant::pivStringList: {setValue(v.split("%|%"));} break;
|
||||
case PIVariant::pivEnum: {PIVariantTypes::Enum r = toEnum(); r.selectName(v); setValue(r);} break;
|
||||
case PIVariant::pivFile: {PIVariantTypes::File r = toFile(); r.file = v; setValue(r);} break;
|
||||
case PIVariant::pivDir: {PIVariantTypes::Dir r = toDir(); r.dir = v; setValue(r);} break;
|
||||
case PIVariant::pivColor: {setValue(PIVariantTypes::Color(v.mid(1).toUInt(16)));} break;
|
||||
case PIVariant::pivIODevice: {setValue(PIVariantTypes::IODevice());} break; // TODO
|
||||
case PIVariant::pivCustom: {} break; // TODO;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIVariant & PIVariant::operator =(const PIVariant & v) {
|
||||
_type = v._type;
|
||||
_content = v._content;
|
||||
#ifdef CUSTOM_PIVARIANT
|
||||
_info = v._info;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool PIVariant::operator ==(const PIVariant & v) const {
|
||||
return (_type == v._type) && (_content == v._content);
|
||||
}
|
||||
|
||||
|
||||
PIVariant::Type PIVariant::typeFromName(const PIString & tname) {
|
||||
PIString s = tname.trimmed().toLowerCase().replaceAll(" ", "");
|
||||
if (s == "bool" || s == "boolean") return PIVariant::pivBool;
|
||||
if (s == "char" || s == "sbyte") return PIVariant::pivChar;
|
||||
if (s == "short" || s == "shortint" || s == "signedshort" || s == "signedshortint" || s == "sword") return PIVariant::pivShort;
|
||||
if (s == "int" || s == "signed" || s == "signedint") return PIVariant::pivInt;
|
||||
if (s == "long" || s == "longint" || s == "signedlong" || s == "signedlongint" || s == "sdword") return PIVariant::pivInt;
|
||||
if (s == "llong" || s == "longlong" || s == "longlongint" || s == "signedlonglong" || s == "signedlonglongint" || s == "sqword") return PIVariant::pivLLong;
|
||||
if (s == "uchar" || s == "byte") return PIVariant::pivUChar;
|
||||
if (s == "ushort" || s == "unsignedshort" || s == "unsignedshortint" || s == "word") return PIVariant::pivUShort;
|
||||
if (s == "uint" || s == "unsigned" || s == "unsignedint") return PIVariant::pivUInt;
|
||||
if (s == "ulong" || s == "unsignedlong" || s == "unsignedlongint" || s == "dword") return PIVariant::pivUInt;
|
||||
if (s == "ullong" || s == "unsignedlonglong" || s == "unsignedlonglongint" || s == "qword") return PIVariant::pivULLong;
|
||||
if (s == "float") return PIVariant::pivFloat;
|
||||
if (s == "double" || s == "real") return PIVariant::pivDouble;
|
||||
if (s == "ldouble" || s == "longdouble") return PIVariant::pivLDouble;
|
||||
if (s == "complexd" || s == "complex<double>") return PIVariant::pivComplexd;
|
||||
if (s == "complexld" || s == "complex<ldouble>" || s == "complex<longdouble>") return PIVariant::pivComplexld;
|
||||
if (s == "pibitarray" || s == "bitarray") return PIVariant::pivBitArray;
|
||||
if (s == "pibytearray" || s == "bytearray" || s == "vector<uchar>" || s == "pivector<uchar>" || s == "vector<unsignedchar>" || s == "pivector<unsignedchar>" ||
|
||||
s == "vector<char>" || s == "pivector<char>") return PIVariant::pivByteArray;
|
||||
if (s == "pistring" || s == "string") return PIVariant::pivString;
|
||||
if (s == "pistringlist" || s == "stringlist" || s == "vector<string>" || s == "vector<pistring>" || s == "pivector<string>" || s == "pivector<pistring>") return PIVariant::pivStringList;
|
||||
if (s == "pitime" || s == "time") return PIVariant::pivTime;
|
||||
if (s == "pidate" || s == "date") return PIVariant::pivDate;
|
||||
if (s == "pidatetime" || s == "datetime") return PIVariant::pivDateTime;
|
||||
if (s == "pisystemtime" || s == "systemtime") return PIVariant::pivSystemTime;
|
||||
if (s == "enum") return PIVariant::pivEnum;
|
||||
if (s == "file" || s == "path") return PIVariant::pivFile;
|
||||
if (s == "dir" || s == "directory") return PIVariant::pivDir;
|
||||
if (s == "color") return PIVariant::pivColor;
|
||||
if (s == "point") return PIVariant::pivPoint;
|
||||
if (s == "rect") return PIVariant::pivRect;
|
||||
if (s == "vector") return PIVariant::pivMathVector;
|
||||
if (s == "matrix") return PIVariant::pivMathMatrix;
|
||||
return PIVariant::pivInvalid;
|
||||
}
|
||||
|
||||
|
||||
PIString PIVariant::typeName() const {
|
||||
#ifdef CUSTOM_PIVARIANT
|
||||
if ((_type == pivCustom) && _info)
|
||||
return _info->typeName;
|
||||
#endif
|
||||
return typeName(_type);
|
||||
}
|
||||
|
||||
|
||||
PIString PIVariant::typeName(PIVariant::Type type) {
|
||||
switch (type) {
|
||||
case PIVariant::pivBool: return "Bool";
|
||||
case PIVariant::pivChar: return "Char";
|
||||
case PIVariant::pivUChar: return "UChar";
|
||||
case PIVariant::pivShort: return "Short";
|
||||
case PIVariant::pivUShort: return "UShort";
|
||||
case PIVariant::pivInt: return "Int";
|
||||
case PIVariant::pivUInt: return "UInt";
|
||||
case PIVariant::pivLLong: return "LLong";
|
||||
case PIVariant::pivULLong: return "ULLong";
|
||||
case PIVariant::pivFloat: return "Float";
|
||||
case PIVariant::pivDouble: return "Double";
|
||||
case PIVariant::pivLDouble: return "LDouble";
|
||||
case PIVariant::pivComplexd: return "Complexd";
|
||||
case PIVariant::pivComplexld: return "Complexld";
|
||||
case PIVariant::pivBitArray: return "BitArray";
|
||||
case PIVariant::pivByteArray: return "ByteArray";
|
||||
case PIVariant::pivString: return "String";
|
||||
case PIVariant::pivStringList: return "StringList";
|
||||
case PIVariant::pivTime: return "Time";
|
||||
case PIVariant::pivDate: return "Date";
|
||||
case PIVariant::pivDateTime: return "DateTime";
|
||||
case PIVariant::pivSystemTime: return "SystemTime";
|
||||
case PIVariant::pivEnum: return "Enum";
|
||||
case PIVariant::pivFile: return "File";
|
||||
case PIVariant::pivDir: return "Dir";
|
||||
case PIVariant::pivColor: return "Color";
|
||||
case PIVariant::pivPoint: return "Point";
|
||||
case PIVariant::pivRect: return "Rect";
|
||||
case PIVariant::pivMathVector: return "Vector";
|
||||
case PIVariant::pivMathMatrix: return "Matrix";
|
||||
case PIVariant::pivCustom: return "Custom";
|
||||
default: break;
|
||||
}
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as boolean
|
||||
* \details In case of numeric types returns \b true if value != 0. \n
|
||||
* In case of String type returns \a PIString::toBool(). \n
|
||||
* In case of StringList type returns \b false if string list is empty,
|
||||
* otherwise returns \a PIString::toBool() of first string. \n
|
||||
* In case of other types returns \b false. */
|
||||
bool PIVariant::toBool() const {
|
||||
PIByteArray ba(_content);
|
||||
switch (_type) {
|
||||
case PIVariant::pivBool: {bool r; ba >> r; return r;}
|
||||
case PIVariant::pivChar: {char r; ba >> r; return r != 0;}
|
||||
case PIVariant::pivUChar: {uchar r; ba >> r; return r != 0;}
|
||||
case PIVariant::pivShort: {short r; ba >> r; return r != 0;}
|
||||
case PIVariant::pivUShort: {ushort r; ba >> r; return r != 0;}
|
||||
case PIVariant::pivInt: {int r; ba >> r; return r != 0;}
|
||||
case PIVariant::pivUInt: {uint r; ba >> r; return r != 0;}
|
||||
case PIVariant::pivLLong: {llong r; ba >> r; return r != 0;}
|
||||
case PIVariant::pivULLong: {ullong r; ba >> r; return r != 0;}
|
||||
case PIVariant::pivFloat: {float r; ba >> r; return r > 0.f;}
|
||||
case PIVariant::pivDouble: {double r; ba >> r; return r > 0.;}
|
||||
case PIVariant::pivLDouble: {ldouble r; ba >> r; return r > 0.;}
|
||||
case PIVariant::pivString: {PIString r; ba >> r; return r.toBool();}
|
||||
case PIVariant::pivStringList: {PIStringList r; ba >> r; if (r.isEmpty()) return false; return r.front().toBool();}
|
||||
case PIVariant::pivCustom: return getAsValue<bool>(*this);
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** \brief Returns variant content as int
|
||||
* \details In case of numeric types returns integer value. \n
|
||||
* In case of String type returns \a PIString::toInt(). \n
|
||||
* In case of StringList type returns \b 0 if string list is empty,
|
||||
* otherwise returns \a PIString::toInt() of first string. \n
|
||||
* In case of other types returns \b 0. */
|
||||
int PIVariant::toInt() const {
|
||||
PIByteArray ba(_content);
|
||||
switch (_type) {
|
||||
case PIVariant::pivBool: {bool r; ba >> r; return r;}
|
||||
case PIVariant::pivChar: {char r; ba >> r; return r;}
|
||||
case PIVariant::pivUChar: {uchar r; ba >> r; return r;}
|
||||
case PIVariant::pivShort: {short r; ba >> r; return r;}
|
||||
case PIVariant::pivUShort: {ushort r; ba >> r; return r;}
|
||||
case PIVariant::pivInt: {int r; ba >> r; return r;}
|
||||
case PIVariant::pivUInt: {uint r; ba >> r; return r;}
|
||||
case PIVariant::pivLLong: {llong r; ba >> r; return r;}
|
||||
case PIVariant::pivULLong: {ullong r; ba >> r; return r;}
|
||||
case PIVariant::pivFloat: {float r; ba >> r; return r;}
|
||||
case PIVariant::pivDouble: {double r; ba >> r; return r;}
|
||||
case PIVariant::pivLDouble: {ldouble r; ba >> r; return r;}
|
||||
case PIVariant::pivString: {PIString r; ba >> r; return r.toInt();}
|
||||
case PIVariant::pivStringList: {PIStringList r; ba >> r; if (r.isEmpty()) return 0; return r.front().toInt();}
|
||||
case PIVariant::pivEnum: {PIVariantTypes::Enum r; ba >> r; return r.selectedValue();}
|
||||
case PIVariant::pivColor: {PIVariantTypes::Color r; ba >> r; return (int)r.rgba;}
|
||||
case PIVariant::pivCustom: return getAsValue<int>(*this);
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as long long
|
||||
* \details In case of numeric types returns integer value. \n
|
||||
* In case of String type returns \a PIString::toLLong(). \n
|
||||
* In case of StringList type returns \b 0L if string list is empty,
|
||||
* otherwise returns \a PIString::toLLong() of first string. \n
|
||||
* In case of other types returns \b 0L. */
|
||||
llong PIVariant::toLLong() const {
|
||||
PIByteArray ba(_content);
|
||||
switch (_type) {
|
||||
case PIVariant::pivBool: {bool r; ba >> r; return r;}
|
||||
case PIVariant::pivChar: {char r; ba >> r; return r;}
|
||||
case PIVariant::pivUChar: {uchar r; ba >> r; return r;}
|
||||
case PIVariant::pivShort: {short r; ba >> r; return r;}
|
||||
case PIVariant::pivUShort: {ushort r; ba >> r; return r;}
|
||||
case PIVariant::pivInt: {int r; ba >> r; return r;}
|
||||
case PIVariant::pivUInt: {uint r; ba >> r; return r;}
|
||||
case PIVariant::pivLLong: {llong r; ba >> r; return r;}
|
||||
case PIVariant::pivULLong: {ullong r; ba >> r; return r;}
|
||||
case PIVariant::pivFloat: {float r; ba >> r; return r;}
|
||||
case PIVariant::pivDouble: {double r; ba >> r; return r;}
|
||||
case PIVariant::pivLDouble: {ldouble r; ba >> r; return r;}
|
||||
case PIVariant::pivString: {PIString r; ba >> r; return r.toLLong();}
|
||||
case PIVariant::pivStringList: {PIStringList r; ba >> r; if (r.isEmpty()) return 0L; return r.front().toLLong();}
|
||||
case PIVariant::pivEnum: {PIVariantTypes::Enum r; ba >> r; return llong(r.selectedValue());}
|
||||
case PIVariant::pivCustom: return getAsValue<llong>(*this);
|
||||
default: break;
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as float
|
||||
* \details In case of numeric types returns float value. \n
|
||||
* In case of String type returns \a PIString::toFloat(). \n
|
||||
* In case of StringList type returns \b 0.f if string list is empty,
|
||||
* otherwise returns \a PIString::toFloat() of first string. \n
|
||||
* In case of other types returns \b 0.f. */
|
||||
float PIVariant::toFloat() const {
|
||||
PIByteArray ba(_content);
|
||||
switch (_type) {
|
||||
case PIVariant::pivBool: {bool r; ba >> r; return r;}
|
||||
case PIVariant::pivChar: {char r; ba >> r; return r;}
|
||||
case PIVariant::pivUChar: {uchar r; ba >> r; return r;}
|
||||
case PIVariant::pivShort: {short r; ba >> r; return r;}
|
||||
case PIVariant::pivUShort: {ushort r; ba >> r; return r;}
|
||||
case PIVariant::pivInt: {int r; ba >> r; return r;}
|
||||
case PIVariant::pivUInt: {uint r; ba >> r; return r;}
|
||||
case PIVariant::pivLLong: {llong r; ba >> r; return r;}
|
||||
case PIVariant::pivULLong: {ullong r; ba >> r; return r;}
|
||||
case PIVariant::pivFloat: {float r; ba >> r; return r;}
|
||||
case PIVariant::pivDouble: {double r; ba >> r; return r;}
|
||||
case PIVariant::pivLDouble: {ldouble r; ba >> r; return r;}
|
||||
case PIVariant::pivString: {PIString r; ba >> r; return r.toFloat();}
|
||||
case PIVariant::pivStringList: {PIStringList r; ba >> r; if (r.isEmpty()) return 0.f; return r.front().toFloat();}
|
||||
case PIVariant::pivEnum: {PIVariantTypes::Enum r; ba >> r; return float(r.selectedValue());}
|
||||
case PIVariant::pivCustom: return getAsValue<float>(*this);
|
||||
default: break;
|
||||
}
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as double
|
||||
* \details In case of numeric types returns double value. \n
|
||||
* In case of String type returns \a PIString::toDouble(). \n
|
||||
* In case of StringList type returns \b 0. if string list is empty,
|
||||
* otherwise returns \a PIString::toDouble() of first string. \n
|
||||
* In case of other types returns \b 0.. */
|
||||
double PIVariant::toDouble() const {
|
||||
PIByteArray ba(_content);
|
||||
switch (_type) {
|
||||
case PIVariant::pivBool: {bool r; ba >> r; return r;}
|
||||
case PIVariant::pivChar: {char r; ba >> r; return r;}
|
||||
case PIVariant::pivUChar: {uchar r; ba >> r; return r;}
|
||||
case PIVariant::pivShort: {short r; ba >> r; return r;}
|
||||
case PIVariant::pivUShort: {ushort r; ba >> r; return r;}
|
||||
case PIVariant::pivInt: {int r; ba >> r; return r;}
|
||||
case PIVariant::pivUInt: {uint r; ba >> r; return r;}
|
||||
case PIVariant::pivLLong: {llong r; ba >> r; return r;}
|
||||
case PIVariant::pivULLong: {ullong r; ba >> r; return r;}
|
||||
case PIVariant::pivFloat: {float r; ba >> r; return r;}
|
||||
case PIVariant::pivDouble: {double r; ba >> r; return r;}
|
||||
case PIVariant::pivLDouble: {ldouble r; ba >> r; return r;}
|
||||
case PIVariant::pivString: {PIString r; ba >> r; return r.toDouble();}
|
||||
case PIVariant::pivStringList: {PIStringList r; ba >> r; if (r.isEmpty()) return 0.; return r.front().toDouble();}
|
||||
case PIVariant::pivEnum: {PIVariantTypes::Enum r; ba >> r; return double(r.selectedValue());}
|
||||
case PIVariant::pivCustom: return getAsValue<double>(*this);
|
||||
default: break;
|
||||
}
|
||||
return 0.;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as long double
|
||||
* \details In case of numeric types returns long double value. \n
|
||||
* In case of String type returns \a PIString::toLDouble(). \n
|
||||
* In case of StringList type returns \b 0. if string list is empty,
|
||||
* otherwise returns \a PIString::toLDouble() of first string. \n
|
||||
* In case of other types returns \b 0.. */
|
||||
ldouble PIVariant::toLDouble() const {
|
||||
PIByteArray ba(_content);
|
||||
switch (_type) {
|
||||
case PIVariant::pivBool: {bool r; ba >> r; return r;}
|
||||
case PIVariant::pivChar: {char r; ba >> r; return r;}
|
||||
case PIVariant::pivUChar: {uchar r; ba >> r; return r;}
|
||||
case PIVariant::pivShort: {short r; ba >> r; return r;}
|
||||
case PIVariant::pivUShort: {ushort r; ba >> r; return r;}
|
||||
case PIVariant::pivInt: {int r; ba >> r; return r;}
|
||||
case PIVariant::pivUInt: {uint r; ba >> r; return r;}
|
||||
case PIVariant::pivLLong: {llong r; ba >> r; return r;}
|
||||
case PIVariant::pivULLong: {ullong r; ba >> r; return r;}
|
||||
case PIVariant::pivFloat: {float r; ba >> r; return r;}
|
||||
case PIVariant::pivDouble: {double r; ba >> r; return r;}
|
||||
case PIVariant::pivLDouble: {ldouble r; ba >> r; return r;}
|
||||
case PIVariant::pivString: {PIString r; ba >> r; return r.toLDouble();}
|
||||
case PIVariant::pivStringList: {PIStringList r; ba >> r; if (r.isEmpty()) return 0.; return r.front().toLDouble();}
|
||||
case PIVariant::pivEnum: {PIVariantTypes::Enum r; ba >> r; return ldouble(r.selectedValue());}
|
||||
case PIVariant::pivCustom: return getAsValue<float>(*this);
|
||||
default: break;
|
||||
}
|
||||
return 0.;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as time
|
||||
* \details In case of Time type returns time value. \n
|
||||
* In case of DateTime type returns time part of value. \n
|
||||
* In case of other types returns \a PITime(). */
|
||||
PITime PIVariant::toTime() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivTime) {PITime r; ba >> r; return r;}
|
||||
if (_type == PIVariant::pivDateTime) {PIDateTime r; ba >> r; return r.time();}
|
||||
if (_type == PIVariant::pivCustom) {return getAsValue<PITime>(*this);}
|
||||
return PITime();
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as date
|
||||
* \details In case of Date type returns date value. \n
|
||||
* In case of DateTime type returns date part of value. \n
|
||||
* In case of other types returns \a PIDate(). */
|
||||
PIDate PIVariant::toDate() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivDate) {PIDate r; ba >> r; return r;}
|
||||
if (_type == PIVariant::pivDateTime) {PIDateTime r; ba >> r; return r.date();}
|
||||
if (_type == PIVariant::pivCustom) {return getAsValue<PIDate>(*this);}
|
||||
return PIDate();
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as date and time
|
||||
* \details In case of Time type returns time value with null date. \n
|
||||
* In case of Date type returns date value with null time. \n
|
||||
* In case of DateTime type returns date and time. \n
|
||||
* In case of other types returns \a PIDateTime(). */
|
||||
PIDateTime PIVariant::toDateTime() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivTime) {PITime r; ba >> r; return PIDateTime(r);}
|
||||
if (_type == PIVariant::pivDate) {PIDate r; ba >> r; return PIDateTime(r);}
|
||||
if (_type == PIVariant::pivDateTime) {PIDateTime r; ba >> r; return r;}
|
||||
if (_type == PIVariant::pivCustom) {return getAsValue<PIDateTime>(*this);}
|
||||
return PIDateTime();
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as system time
|
||||
* \details In case of SystemTime type returns system time. \n
|
||||
* In case of other types returns \a PISystemTime::fromSeconds() from
|
||||
* double value of variant content. */
|
||||
PISystemTime PIVariant::toSystemTime() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivSystemTime) {PISystemTime r; ba >> r; return r;}
|
||||
if (_type == PIVariant::pivCustom) {return getAsValue<PISystemTime>(*this);}
|
||||
return PISystemTime::fromSeconds(toDouble());
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as string
|
||||
* \details In case of numeric types returns \a PIString::fromNumber(). \n
|
||||
* In case of String type returns string value. \n
|
||||
* In case of StringList type returns joined string ("(" + PIStringList::join("; ") + ")"). \n
|
||||
* In case of BitArray or ByteArray types returns number of bits/bytes. \n
|
||||
* In case of Time, Date or DateTime types returns toString() of this values. \n
|
||||
* In case of SystemTime types returns second and nanoseconds of time
|
||||
* ("(PISystemTime::seconds s, PISystemTime::nanoseconds ns)"). \n
|
||||
* In case of other types returns \b "". */
|
||||
PIString PIVariant::toString() const {
|
||||
PIByteArray ba(_content);
|
||||
switch (_type) {
|
||||
case PIVariant::pivBool: {bool r; ba >> r; return PIString::fromNumber(r);}
|
||||
case PIVariant::pivChar: {char r; ba >> r; return PIString::fromNumber(r);}
|
||||
case PIVariant::pivUChar: {uchar r; ba >> r; return PIString::fromNumber(r);}
|
||||
case PIVariant::pivShort: {short r; ba >> r; return PIString::fromNumber(r);}
|
||||
case PIVariant::pivUShort: {ushort r; ba >> r; return PIString::fromNumber(r);}
|
||||
case PIVariant::pivInt: {int r; ba >> r; return PIString::fromNumber(r);}
|
||||
case PIVariant::pivUInt: {uint r; ba >> r; return PIString::fromNumber(r);}
|
||||
case PIVariant::pivLLong: {llong r; ba >> r; return PIString::fromNumber(r);}
|
||||
case PIVariant::pivULLong: {ullong r; ba >> r; return PIString::fromNumber(r);}
|
||||
case PIVariant::pivFloat: {float r; ba >> r; return PIString::fromNumber(r);}
|
||||
case PIVariant::pivDouble: {double r; ba >> r; return PIString::fromNumber(r);}
|
||||
case PIVariant::pivLDouble: {ldouble r; ba >> r; return PIString::fromNumber(r);}
|
||||
case PIVariant::pivTime: {PITime r; ba >> r; return r.toString();}
|
||||
case PIVariant::pivDate: {PIDate r; ba >> r; return r.toString();}
|
||||
case PIVariant::pivDateTime: {PIDateTime r; ba >> r; return r.toString();}
|
||||
case PIVariant::pivString: {PIString r; ba >> r; return r;}
|
||||
case PIVariant::pivStringList: {PIStringList r; ba >> r; if (r.isEmpty()) return PIString(); return r.join(";");}
|
||||
case PIVariant::pivEnum: {PIVariantTypes::Enum r; ba >> r; return r.selectedName();}
|
||||
case PIVariant::pivFile: {PIVariantTypes::File r; ba >> r; return r.file;}
|
||||
case PIVariant::pivDir: {PIVariantTypes::Dir r; ba >> r; return r.dir;}
|
||||
case PIVariant::pivColor: {PIVariantTypes::Color r; ba >> r; return "#" + PIString::fromNumber(r.rgba, 16);}
|
||||
case PIVariant::pivIODevice: {PIVariantTypes::IODevice r; ba >> r; return "IODevice";} // TODO
|
||||
case PIVariant::pivCustom: return getAsValue<PIString>(*this);
|
||||
default: break;
|
||||
}
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as strings list
|
||||
* \details In case of StringList type returns strings list value. \n
|
||||
* In case of other types returns \a PIStringList with one string value of variant content. */
|
||||
PIStringList PIVariant::toStringList() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivStringList) {PIStringList r; ba >> r; return r;}
|
||||
if (_type == PIVariant::pivEnum) {PIVariantTypes::Enum r; ba >> r; return r.names();}
|
||||
if (_type == PIVariant::pivCustom) {return getAsValue<PIStringList>(*this);}
|
||||
return PIStringList(toString());
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as bit array
|
||||
* \details In case of BitArray type returns bit array value. \n
|
||||
* In case of other types returns \a PIBitArray from \a toLLong() value. */
|
||||
PIBitArray PIVariant::toBitArray() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivBitArray) {PIBitArray r; ba >> r; return r;}
|
||||
if (_type == PIVariant::pivCustom) {return getAsValue<PIBitArray>(*this);}
|
||||
return PIBitArray(ullong(toLLong()));
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as byte array
|
||||
* \details In case of ByteArray type returns byte array value. \n
|
||||
* In case of other types returns empty \a PIByteArray. */
|
||||
PIByteArray PIVariant::toByteArray() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivByteArray) {PIByteArray r; ba >> r; return r;}
|
||||
if (_type == PIVariant::pivCustom) {return getAsValue<PIByteArray>(*this);}
|
||||
return PIByteArray();
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as enum
|
||||
* \details In case of Enum type returns enum value. \n
|
||||
* In case of String returns Enum with one member. \n
|
||||
* In case of StringList returns Enum with corresponding members. \n
|
||||
* In case of other types returns empty Enum. */
|
||||
PIVariantTypes::Enum PIVariant::toEnum() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivEnum) {PIVariantTypes::Enum r; ba >> r; return r;}
|
||||
if (_type == PIVariant::pivString) {PIString v; ba >> v; PIVariantTypes::Enum r; r << v; return r;}
|
||||
if (_type == PIVariant::pivStringList) {PIStringList v; ba >> v; PIVariantTypes::Enum r; r << v; return r;}
|
||||
if (_type == PIVariant::pivCustom) {return getAsValue<PIVariantTypes::Enum>(*this);}
|
||||
return PIVariantTypes::Enum();
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as file
|
||||
* \details In case of File type returns file value. \n
|
||||
* In case of String returns File with string value path. \n
|
||||
* In case of other types returns empty File. */
|
||||
PIVariantTypes::File PIVariant::toFile() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivFile) {PIVariantTypes::File r; ba >> r; return r;}
|
||||
if (_type == PIVariant::pivString) {PIString v; ba >> v; PIVariantTypes::File r; r.file = v; return r;}
|
||||
if (_type == PIVariant::pivCustom) {return getAsValue<PIVariantTypes::File>(*this);}
|
||||
return PIVariantTypes::File();
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as dir
|
||||
* \details In case of Dir type returns dir value. \n
|
||||
* In case of String returns Dir with string value path. \n
|
||||
* In case of other types returns empty Dir. */
|
||||
PIVariantTypes::Dir PIVariant::toDir() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivDir) {PIVariantTypes::Dir r; ba >> r; return r;}
|
||||
if (_type == PIVariant::pivString) {PIString v; ba >> v; PIVariantTypes::Dir r; r.dir = v; return r;}
|
||||
if (_type == PIVariant::pivCustom) {return getAsValue<PIVariantTypes::Dir>(*this);}
|
||||
return PIVariantTypes::Dir();
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as color
|
||||
* \details In case of Color type returns color value. \n
|
||||
* In case of int returns color with int value. \n
|
||||
* In case of other types returns empty Color. */
|
||||
PIVariantTypes::Color PIVariant::toColor() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivColor) {PIVariantTypes::Color r; ba >> r; return r;}
|
||||
if (_type == PIVariant::pivInt) {int v; ba >> v; return PIVariantTypes::Color(v);}
|
||||
if (_type == PIVariant::pivCustom) {return getAsValue<PIVariantTypes::Color>(*this);}
|
||||
return PIVariantTypes::Color();
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as IODevice
|
||||
* \details In case of IODevice type returns IODevice value. \n
|
||||
* In case of other types returns empty IODevice. */
|
||||
PIVariantTypes::IODevice PIVariant::toIODevice() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivIODevice) {PIVariantTypes::IODevice r; ba >> r; return r;}
|
||||
return PIVariantTypes::IODevice();
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as point
|
||||
* \details In case of PIPointd type returns point value. \n
|
||||
* In case of other types returns empty PIPointd. */
|
||||
PIPointd PIVariant::toPoint() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivPoint) {PIPointd r; ba >> r; return r;}
|
||||
return PIPointd();
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as rect
|
||||
* \details In case of PIRectd type returns rect value. \n
|
||||
* In case of other types returns empty PIRectd. */
|
||||
PIRectd PIVariant::toRect() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivRect) {PIRectd r; ba >> r; return r;}
|
||||
return PIRectd();
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as math vector
|
||||
* \details In case of PIMathVectord type returns rect value. \n
|
||||
* In case of other types returns empty PIMathVectord. */
|
||||
PIMathVectord PIVariant::toMathVector() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivMathVector) {PIMathVectord r; ba >> r; return r;}
|
||||
return PIMathVectord();
|
||||
}
|
||||
|
||||
|
||||
/** \brief Returns variant content as math matrix
|
||||
* \details In case of PIMathMatrixd type returns rect value. \n
|
||||
* In case of other types returns empty PIMathMatrixd. */
|
||||
PIMathMatrixd PIVariant::toMathMatrix() const {
|
||||
PIByteArray ba(_content);
|
||||
if (_type == PIVariant::pivMathMatrix) {PIMathMatrixd r; ba >> r; return r;}
|
||||
return PIMathMatrixd();
|
||||
}
|
||||
|
||||
787
lib/main/core/pivariant.h
Normal file
787
lib/main/core/pivariant.h
Normal file
@@ -0,0 +1,787 @@
|
||||
/*! \file pivariant.h
|
||||
* \brief Variant type
|
||||
*
|
||||
* This file declares PIVariant
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Variant type
|
||||
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 PIVARIANT_H
|
||||
#define PIVARIANT_H
|
||||
|
||||
#include "pivarianttypes.h"
|
||||
#include "pitime.h"
|
||||
#include "pigeometry.h"
|
||||
#include "pimathmatrix.h"
|
||||
|
||||
|
||||
#ifndef QNX
|
||||
# define CUSTOM_PIVARIANT
|
||||
#endif
|
||||
|
||||
#ifdef CUSTOM_PIVARIANT
|
||||
|
||||
|
||||
template<typename T>
|
||||
class PIP_EXPORT __PIVariantFunctions__ {
|
||||
public:
|
||||
static PIString typeNameHelper() {return PIStringAscii("");}
|
||||
|
||||
static bool isSimpleHelper() {return false;}
|
||||
template<typename C> static PIByteArray castHelper(PIByteArray ba) {return PIByteArray();}
|
||||
template<typename C> static C castVariant(const T & v) {return C();}
|
||||
};
|
||||
|
||||
struct PIP_EXPORT __PIVariantInfo__ {
|
||||
__PIVariantInfo__() {
|
||||
simple = false;
|
||||
}
|
||||
typedef PIByteArray(*castHelperFunc)(PIByteArray);
|
||||
PIMap<PIString, castHelperFunc> cast;
|
||||
PIString typeName;
|
||||
bool simple;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct PIP_EXPORT __PIVariantTypeInfo__ {
|
||||
typedef T PureType;
|
||||
typedef const T ConstPureType;
|
||||
typedef T * PointerType;
|
||||
typedef const T * ConstPointerType;
|
||||
typedef T & ReferenceType;
|
||||
typedef const T & ConstReferenceType;
|
||||
};
|
||||
|
||||
#define __TYPEINFO_SINGLE(PT, T) \
|
||||
template<> struct __PIVariantTypeInfo__<T> { \
|
||||
typedef PT PureType; \
|
||||
typedef const PT ConstPureType; \
|
||||
typedef PT * PointerType; \
|
||||
typedef const PT * ConstPointerType; \
|
||||
typedef PT & ReferenceType; \
|
||||
typedef const PT & ConstReferenceType; \
|
||||
};
|
||||
|
||||
#define REGISTER_VARIANT_TYPEINFO(T) \
|
||||
__TYPEINFO_SINGLE(T, T &) \
|
||||
__TYPEINFO_SINGLE(T, const T) \
|
||||
__TYPEINFO_SINGLE(T, const T &)
|
||||
|
||||
|
||||
class PIP_EXPORT __PIVariantInfoStorage__ {
|
||||
public:
|
||||
__PIVariantInfoStorage__() {if (!map) map = new PIMap<PIString, __PIVariantInfo__ * >();}
|
||||
static __PIVariantInfoStorage__ * get() {static __PIVariantInfoStorage__ * r = new __PIVariantInfoStorage__(); return r;}
|
||||
static PIMap<PIString, __PIVariantInfo__ * > * map;
|
||||
};
|
||||
|
||||
|
||||
#define REGISTER_VARIANT_H(classname) \
|
||||
template<> inline PIString __PIVariantFunctions__< classname >::typeNameHelper() {static PIString tn = PIStringAscii(#classname); return tn;} \
|
||||
REGISTER_VARIANT_TYPEINFO(classname)
|
||||
|
||||
#define REGISTER_NS_VARIANT_H(ns, classname) \
|
||||
template<> inline PIString __PIVariantFunctions__< ns::classname >::typeNameHelper() {static PIString tn = PIStringAscii(#ns"::"#classname); return tn;} \
|
||||
REGISTER_VARIANT_TYPEINFO(ns::classname)
|
||||
|
||||
#define REGISTER_VARIANT_CPP(classname) \
|
||||
template <typename T> \
|
||||
class PIP_EXPORT __##classname##_PIVariantInitializer__ { \
|
||||
public: \
|
||||
__##classname##_PIVariantInitializer__(const PIString & name) { \
|
||||
if (__PIVariantInfoStorage__::get()->map->contains(name)) \
|
||||
return; \
|
||||
__PIVariantInfo__ * vi = new __PIVariantInfo__(); \
|
||||
vi->typeName = name; \
|
||||
(*(__PIVariantInfoStorage__::get()->map))[name] = vi; \
|
||||
} \
|
||||
};
|
||||
|
||||
#define REGISTER_NS_VARIANT_CPP(ns, classname) \
|
||||
template <typename T> \
|
||||
class PIP_EXPORT __##ns##classname##_PIVariantInitializer__ { \
|
||||
public: \
|
||||
__##ns##classname##_PIVariantInitializer__(const PIString & name) { \
|
||||
if (__PIVariantInfoStorage__::get()->map->contains(name)) \
|
||||
return; \
|
||||
__PIVariantInfo__ * vi = new __PIVariantInfo__(); \
|
||||
vi->typeName = name; \
|
||||
(*(__PIVariantInfoStorage__::get()->map))[name] = vi; \
|
||||
} \
|
||||
};
|
||||
|
||||
#define INIT_VARIANT(classname) \
|
||||
__##classname##_PIVariantInitializer__< classname > __##classname##_pivariant_initializer__(#classname);
|
||||
|
||||
#define INIT_NS_VARIANT(ns, classname) \
|
||||
__##ns##classname##_PIVariantInitializer__< ns::classname > __##ns##classname##_pivariant_initializer__(#ns"::"#classname);
|
||||
|
||||
#define REGISTER_VARIANT(classname) \
|
||||
REGISTER_VARIANT_H(classname) \
|
||||
REGISTER_VARIANT_CPP(classname) \
|
||||
static INIT_VARIANT(classname)
|
||||
|
||||
#define REGISTER_NS_VARIANT(ns, classname) \
|
||||
REGISTER_NS_VARIANT_H(ns, classname) \
|
||||
REGISTER_NS_VARIANT_CPP(ns, classname) \
|
||||
static INIT_NS_VARIANT(ns, classname)
|
||||
|
||||
|
||||
#define REGISTER_VARIANT_CAST_H(classname_from, classname_to) \
|
||||
template<> template<> inline \
|
||||
classname_to __PIVariantFunctions__<classname_from>::castVariant<classname_to>(const classname_from & v);
|
||||
|
||||
#define REGISTER_VARIANT_CAST_CPP(classname_from, classname_to) \
|
||||
template<> template<> inline \
|
||||
PIByteArray __PIVariantFunctions__<classname_from>::castHelper<classname_to>(PIByteArray v) { \
|
||||
classname_from f; v >> f; \
|
||||
classname_to t = __PIVariantFunctions__<classname_from>::castVariant<classname_to>(f); \
|
||||
PIByteArray ret; ret << t; \
|
||||
return ret;} \
|
||||
template <typename T, typename C> \
|
||||
class PIP_EXPORT __##classname_from##_##classname_to##_PIVariantCastInitializer__ { \
|
||||
public: \
|
||||
__##classname_from##_##classname_to##_PIVariantCastInitializer__(const PIString & name, const PIString & cname) { \
|
||||
__PIVariantInfo__ * vi(__PIVariantInfoStorage__::get()->map->value(name, 0)); \
|
||||
if (!vi) { \
|
||||
piCout << "Warning! Using REGISTER_VARIANT_CAST("#classname_from", "#classname_to") before REGISTER_VARIANT("#classname_from"), ignore."; \
|
||||
return; \
|
||||
} \
|
||||
vi->cast[cname] = __PIVariantFunctions__<classname_from>::castHelper<classname_to>; \
|
||||
} \
|
||||
}; \
|
||||
static __##classname_from##_##classname_to##_PIVariantCastInitializer__< classname_from, classname_to > __##classname_from##_##classname_to##_pivariant_cast_initializer__(#classname_from, #classname_to); \
|
||||
template<> template<> \
|
||||
classname_to __PIVariantFunctions__<classname_from>::castVariant<classname_to>(const classname_from & v)
|
||||
|
||||
#define REGISTER_VARIANT_CAST(classname_from, classname_to) \
|
||||
REGISTER_VARIANT_CAST_H(classname_from, classname_to) \
|
||||
REGISTER_VARIANT_CAST_CPP(classname_from, classname_to)
|
||||
|
||||
|
||||
#define REGISTER_VARIANT_CAST_SIMPLE(classname_from, classname_to) REGISTER_VARIANT_CAST(classname_from, classname_to) {return classname_to(v);}
|
||||
#define REGISTER_VARIANT_CAST_SIMPLE_H(classname_from, classname_to) REGISTER_VARIANT_CAST_H(classname_from, classname_to)
|
||||
#define REGISTER_VARIANT_CAST_SIMPLE_CPP(classname_from, classname_to) REGISTER_VARIANT_CAST_CPP(classname_from, classname_to) {return classname_to(v);}
|
||||
|
||||
#else
|
||||
|
||||
#define REGISTER_VARIANT_TYPEINFO(classname)
|
||||
#define REGISTER_VARIANT_H(classname)
|
||||
#define REGISTER_VARIANT_CPP(classname)
|
||||
#define INIT_VARIANT(classname)
|
||||
#define REGISTER_VARIANT(classname)
|
||||
#define REGISTER_NS_VARIANT_H(ns, classname)
|
||||
#define REGISTER_NS_VARIANT_CPP(ns, classname)
|
||||
#define INIT_NS_VARIANT(ns, classname)
|
||||
#define REGISTER_NS_VARIANT(ns, classname)
|
||||
#define REGISTER_VARIANT_CAST_H(classname_from, classname_to)
|
||||
#define REGISTER_VARIANT_CAST_CPP(classname_from, classname_to)
|
||||
#define REGISTER_VARIANT_CAST(classname_from, classname_to)
|
||||
#define REGISTER_VARIANT_CAST_SIMPLE(classname_from, classname_to)
|
||||
#define REGISTER_VARIANT_CAST_SIMPLE_H(classname_from, classname_to)
|
||||
#define REGISTER_VARIANT_CAST_SIMPLE_CPP(classname_from, classname_to)
|
||||
|
||||
#endif
|
||||
|
||||
class PIP_EXPORT PIVariant {
|
||||
friend PICout operator <<(PICout s, const PIVariant & v);
|
||||
friend PIByteArray & operator <<(PIByteArray & s, const PIVariant & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & s, PIVariant & v);
|
||||
public:
|
||||
|
||||
//! Type of %PIVariant content
|
||||
enum PIP_EXPORT Type {
|
||||
pivInvalid /** Invalid type , default type of empty contructor */ = 0 ,
|
||||
pivBool /** bool */ ,
|
||||
pivChar /** char */ ,
|
||||
pivUChar /** uchar */ ,
|
||||
pivShort /** short */ ,
|
||||
pivUShort /** ushort */ ,
|
||||
pivInt /** int */ ,
|
||||
pivUInt /** uint */ ,
|
||||
pivLLong /** llong */ ,
|
||||
pivULLong /** ullong */ ,
|
||||
pivFloat /** float */ ,
|
||||
pivDouble /** double */ ,
|
||||
pivLDouble /** ldouble */ ,
|
||||
pivComplexd /** complexd */ ,
|
||||
pivComplexld /** complexld */ ,
|
||||
pivBitArray /** PIBitArray */ ,
|
||||
pivByteArray /** PIByteArray */ ,
|
||||
pivString /** PIString */ ,
|
||||
pivStringList /** PIStringList */ ,
|
||||
pivTime /** PITime */ ,
|
||||
pivDate /** PIDate */ ,
|
||||
pivDateTime /** PIDateTime */ ,
|
||||
pivSystemTime /** PISystemTime */ ,
|
||||
pivEnum /** PIVariantTypes::Enum */ ,
|
||||
pivFile /** PIVariantTypes::File */ ,
|
||||
pivDir /** PIVariantTypes::Dir */ ,
|
||||
pivColor /** PIVariantTypes::Color */ ,
|
||||
pivPoint /** PIPoint */ ,
|
||||
pivRect /** PIRect */ ,
|
||||
pivIODevice /** PIVariantTypes::IODevice */ ,
|
||||
pivMathVector /** PIMathVectord */ ,
|
||||
pivMathMatrix /** PIMathMatrixd */ ,
|
||||
pivCustom /** Custom */ = 0xFF
|
||||
};
|
||||
|
||||
//! Empty constructor, \a type() will be set to \a Invalid
|
||||
PIVariant();
|
||||
|
||||
PIVariant(const PIVariant & v);
|
||||
|
||||
//! Constructs variant from string
|
||||
PIVariant(const char * v) {initType(PIString(v));}
|
||||
|
||||
//! Constructs variant from boolean
|
||||
PIVariant(const bool v) {initType(v);}
|
||||
|
||||
//! Constructs variant from char
|
||||
PIVariant(const char v) {initType(v);}
|
||||
|
||||
//! Constructs variant from integer
|
||||
PIVariant(const uchar v) {initType(v);}
|
||||
|
||||
//! Constructs variant from integer
|
||||
PIVariant(const short v) {initType(v);}
|
||||
|
||||
//! Constructs variant from integer
|
||||
PIVariant(const ushort v) {initType(v);}
|
||||
|
||||
//! Constructs variant from integer
|
||||
PIVariant(const int & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from integer
|
||||
PIVariant(const uint & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from integer
|
||||
PIVariant(const llong & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from integer
|
||||
PIVariant(const ullong & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from float
|
||||
PIVariant(const float & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from double
|
||||
PIVariant(const double & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from long double
|
||||
PIVariant(const ldouble & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from bit array
|
||||
PIVariant(const PIBitArray & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from byte array
|
||||
PIVariant(const PIByteArray & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from string
|
||||
PIVariant(const PIString & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from strings list
|
||||
PIVariant(const PIStringList & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from time
|
||||
PIVariant(const PITime & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from date
|
||||
PIVariant(const PIDate & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from date and time
|
||||
PIVariant(const PIDateTime & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from system time
|
||||
PIVariant(const PISystemTime & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from enum
|
||||
PIVariant(const PIVariantTypes::Enum & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from file
|
||||
PIVariant(const PIVariantTypes::File & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from dir
|
||||
PIVariant(const PIVariantTypes::Dir & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from color
|
||||
PIVariant(const PIVariantTypes::Color & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from IODevice
|
||||
PIVariant(const PIVariantTypes::IODevice & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from point
|
||||
PIVariant(const PIPointd & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from rect
|
||||
PIVariant(const PIRectd & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from MathVector
|
||||
PIVariant(const PIMathVectord & v) {initType(v);}
|
||||
|
||||
//! Constructs variant from MathMatrix
|
||||
PIVariant(const PIMathMatrixd & v) {initType(v);}
|
||||
|
||||
|
||||
//! Set variant content and type to string
|
||||
void setValue(const char * v) {setValue(PIString(v));}
|
||||
|
||||
//! Set variant content and type to boolean
|
||||
void setValue(const bool v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to char
|
||||
void setValue(const char v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to integer
|
||||
void setValue(const uchar v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to integer
|
||||
void setValue(const short v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to integer
|
||||
void setValue(const ushort v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to integer
|
||||
void setValue(const int & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to integer
|
||||
void setValue(const uint & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to integer
|
||||
void setValue(const llong & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to integer
|
||||
void setValue(const ullong & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to float
|
||||
void setValue(const float & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to double
|
||||
void setValue(const double & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to long double
|
||||
void setValue(const ldouble & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to bit array
|
||||
void setValue(const PIBitArray & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to byte array
|
||||
void setValue(const PIByteArray & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to string
|
||||
void setValue(const PIString & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to strings list
|
||||
void setValue(const PIStringList & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to time
|
||||
void setValue(const PITime & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to date
|
||||
void setValue(const PIDate & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to date and time
|
||||
void setValue(const PIDateTime & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to system time
|
||||
void setValue(const PISystemTime & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to enum
|
||||
void setValue(const PIVariantTypes::Enum & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to file
|
||||
void setValue(const PIVariantTypes::File & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to dir
|
||||
void setValue(const PIVariantTypes::Dir & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to color
|
||||
void setValue(const PIVariantTypes::Color & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to IODevice
|
||||
void setValue(const PIVariantTypes::IODevice & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to point
|
||||
void setValue(const PIPointd & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to rect
|
||||
void setValue(const PIRectd & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to math vector
|
||||
void setValue(const PIMathVectord & v) {initType(v);}
|
||||
|
||||
//! Set variant content and type to math matrix
|
||||
void setValue(const PIMathMatrixd & v) {initType(v);}
|
||||
|
||||
|
||||
//! Set current value from string without change type
|
||||
void setValueFromString(const PIString & v);
|
||||
|
||||
|
||||
bool toBool() const;
|
||||
int toInt() const;
|
||||
llong toLLong() const;
|
||||
float toFloat() const;
|
||||
double toDouble() const;
|
||||
ldouble toLDouble() const;
|
||||
PITime toTime() const;
|
||||
PIDate toDate() const;
|
||||
PIDateTime toDateTime() const;
|
||||
PISystemTime toSystemTime() const;
|
||||
PIString toString() const;
|
||||
PIStringList toStringList() const;
|
||||
PIBitArray toBitArray() const;
|
||||
PIByteArray toByteArray() const;
|
||||
PIVariantTypes::Enum toEnum() const;
|
||||
PIVariantTypes::File toFile() const;
|
||||
PIVariantTypes::Dir toDir() const;
|
||||
PIVariantTypes::Color toColor() const;
|
||||
PIVariantTypes::IODevice toIODevice() const;
|
||||
PIPointd toPoint() const;
|
||||
PIRectd toRect() const;
|
||||
PIMathVectord toMathVector() const;
|
||||
PIMathMatrixd toMathMatrix() const;
|
||||
|
||||
|
||||
/** \brief Returns variant content as custom type
|
||||
* \details In case of known types this function equivalent \a to<Type> function. \n
|
||||
* Otherwise returns content as type T. */
|
||||
template<typename T>
|
||||
T value() const {return getAsValue<T>(*this);}
|
||||
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIVariant & v);
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const char * v) {setValue(PIString(v)); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const bool v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const char v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const uchar v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const short v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const ushort v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const int & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const uint & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const llong & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const ullong & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const float & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const double & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const ldouble & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIBitArray & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIByteArray & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIString & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIStringList & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PITime & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIDate & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIDateTime & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PISystemTime & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIVariantTypes::Enum & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIVariantTypes::File & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIVariantTypes::Dir & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIVariantTypes::Color & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIVariantTypes::IODevice & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIPointd & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIRectd & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIMathVectord & v) {setValue(v); return *this;}
|
||||
//! Assign operator
|
||||
PIVariant & operator =(const PIMathMatrixd & v) {setValue(v); return *this;}
|
||||
|
||||
|
||||
//! Compare operator
|
||||
bool operator ==(const PIVariant & v) const;
|
||||
//! Compare operator
|
||||
bool operator !=(const PIVariant & v) const {return !(*this == v);}
|
||||
|
||||
|
||||
//! Returns type of variant content
|
||||
PIVariant::Type type() const {return _type;}
|
||||
|
||||
//! Returns type name of variant content
|
||||
PIString typeName() const;
|
||||
|
||||
|
||||
//! Returns \b true if type is not Invalid
|
||||
bool isValid() const {return _type != PIVariant::pivInvalid;}
|
||||
|
||||
|
||||
/** \brief Returns new variant from custom type
|
||||
* \details In case of known types this function equivalent \a PIVariant(T) constructors. \n
|
||||
* Otherwise returns variant with content \a v and type Custom. */
|
||||
template <typename T>
|
||||
static PIVariant fromValue(const T & v) {
|
||||
PIVariant ret;
|
||||
ret.initType<T>(v);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PIVariant fromValue(const PIByteArray & c, const PIString & type) {
|
||||
PIVariant ret;
|
||||
PIVariant::Type t = typeFromName(type);
|
||||
if (t == pivInvalid) {
|
||||
#ifdef CUSTOM_PIVARIANT
|
||||
ret._info = __PIVariantInfoStorage__::get()->map->value(type, 0);
|
||||
if (ret._info) {
|
||||
t = pivCustom;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
piCout << "Can`t initialize PIVariant from unregistered type \"" << type << "\"!";
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret._type = t;
|
||||
ret._content = c;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//! Returns type from name
|
||||
static PIVariant::Type typeFromName(const PIString & tname);
|
||||
|
||||
//! Returns type name
|
||||
static PIString typeName(PIVariant::Type type);
|
||||
|
||||
private:
|
||||
void destroy() {_content.clear();}
|
||||
template <typename T> inline static Type getType() {return pivCustom;}
|
||||
template <typename T> inline void initType(const T & v) {
|
||||
_content.clear();
|
||||
_content << v;
|
||||
_type = getType<T>();
|
||||
#ifdef CUSTOM_PIVARIANT
|
||||
if (_type == pivCustom) {
|
||||
_info = __PIVariantInfoStorage__::get()->map->value(__PIVariantFunctions__<T>::typeNameHelper(), 0);
|
||||
if (!_info)
|
||||
piCout << "Can`t initialize PIVariant from unregistered type!";
|
||||
} else
|
||||
_info = 0;
|
||||
#endif
|
||||
}
|
||||
template<typename T> inline static T getAsValue(const PIVariant & v) {
|
||||
#ifdef CUSTOM_PIVARIANT
|
||||
if (v._content.isEmpty() || !v._info) return T();
|
||||
PIString cn = __PIVariantFunctions__<T>::typeNameHelper();
|
||||
//piCout << "gav" << cn;
|
||||
PIByteArray ba;
|
||||
if (cn == v._info->typeName) {
|
||||
ba = v._content;
|
||||
} else {
|
||||
__PIVariantInfo__::castHelperFunc cf = v._info->cast.value(cn);
|
||||
//piCout << "gav cast" << cf;
|
||||
if (!cf) return T();
|
||||
ba = cf(v._content);
|
||||
}
|
||||
T ret; ba >> ret;
|
||||
return ret;
|
||||
#else
|
||||
return T();
|
||||
#endif
|
||||
}
|
||||
|
||||
PIByteArray _content;
|
||||
PIVariant::Type _type;
|
||||
#ifdef CUSTOM_PIVARIANT
|
||||
__PIVariantInfo__ * _info;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
template<> inline bool PIVariant::value() const {return toBool();}
|
||||
template<> inline char PIVariant::value() const {return (char)toInt();}
|
||||
template<> inline uchar PIVariant::value() const {return (uchar)toInt();}
|
||||
template<> inline short PIVariant::value() const {return (short)toInt();}
|
||||
template<> inline ushort PIVariant::value() const {return (ushort)toInt();}
|
||||
template<> inline int PIVariant::value() const {return toInt();}
|
||||
template<> inline uint PIVariant::value() const {return (uint)toInt();}
|
||||
template<> inline llong PIVariant::value() const {return toLLong();}
|
||||
template<> inline ullong PIVariant::value() const {return (ullong)toLLong();}
|
||||
template<> inline float PIVariant::value() const {return toFloat();}
|
||||
template<> inline double PIVariant::value() const {return toDouble();}
|
||||
template<> inline ldouble PIVariant::value() const {return toLDouble();}
|
||||
template<> inline void* PIVariant::value() const {return (void*)toLLong();}
|
||||
template<> inline const char* PIVariant::value() const {return toString().data();}
|
||||
template<> inline PITime PIVariant::value() const {return toTime();}
|
||||
template<> inline PIDate PIVariant::value() const {return toDate();}
|
||||
template<> inline PIDateTime PIVariant::value() const {return toDateTime();}
|
||||
template<> inline PIString PIVariant::value() const {return toString();}
|
||||
template<> inline PIStringList PIVariant::value() const {return toStringList();}
|
||||
template<> inline PIBitArray PIVariant::value() const {return toBitArray();}
|
||||
template<> inline PIByteArray PIVariant::value() const {return toByteArray();}
|
||||
template<> inline PIVariantTypes::Enum PIVariant::value() const {return toEnum();}
|
||||
template<> inline PIVariantTypes::File PIVariant::value() const {return toFile();}
|
||||
template<> inline PIVariantTypes::Dir PIVariant::value() const {return toDir();}
|
||||
template<> inline PIVariantTypes::Color PIVariant::value() const {return toColor();}
|
||||
template<> inline PIVariantTypes::IODevice PIVariant::value() const {return toIODevice();}
|
||||
template<> inline PIPointd PIVariant::value() const {return toPoint();}
|
||||
template<> inline PIRectd PIVariant::value() const {return toRect();}
|
||||
|
||||
template<> inline PIVariant PIVariant::fromValue(const bool & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const char & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const uchar & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const short & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const ushort & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const int & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const uint & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const llong & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const ullong & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const float & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const double & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const ldouble & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIBitArray & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIByteArray & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIString & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIStringList & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PITime & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIDate & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIDateTime & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PISystemTime & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::Enum & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::File & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::Dir & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::Color & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::IODevice & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIPointd & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIRectd & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIMathVectord & v) {return PIVariant(v);}
|
||||
template<> inline PIVariant PIVariant::fromValue(const PIMathMatrixd & v) {return PIVariant(v);}
|
||||
|
||||
template<> inline PIVariant::Type PIVariant::getType<bool>() {return PIVariant::pivBool;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<char>() {return PIVariant::pivChar;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<uchar>() {return PIVariant::pivUChar;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<short>() {return PIVariant::pivShort;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<ushort>() {return PIVariant::pivUShort;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<int>() {return PIVariant::pivInt;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<uint>() {return PIVariant::pivUInt;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<llong>() {return PIVariant::pivLLong;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<ullong>() {return PIVariant::pivULLong;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<float>() {return PIVariant::pivFloat;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<double>() {return PIVariant::pivDouble;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<ldouble>() {return PIVariant::pivLDouble;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIBitArray>() {return PIVariant::pivBitArray;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIByteArray>() {return PIVariant::pivByteArray;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIString>() {return PIVariant::pivString;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIStringList>() {return PIVariant::pivStringList;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PITime>() {return PIVariant::pivTime;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIDate>() {return PIVariant::pivDate;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIDateTime>() {return PIVariant::pivDateTime;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PISystemTime>() {return PIVariant::pivSystemTime;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::Enum>() {return PIVariant::pivEnum;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::File>() {return PIVariant::pivFile;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::Dir>() {return PIVariant::pivDir;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::Color>() {return PIVariant::pivColor;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::IODevice>() {return PIVariant::pivIODevice;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIPointd>() {return PIVariant::pivPoint;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIRectd>() {return PIVariant::pivRect;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIMathVectord>() {return PIVariant::pivMathVector;}
|
||||
template<> inline PIVariant::Type PIVariant::getType<PIMathMatrixd>() {return PIVariant::pivMathMatrix;}
|
||||
|
||||
REGISTER_VARIANT(bool)
|
||||
REGISTER_VARIANT(char)
|
||||
REGISTER_VARIANT(uchar)
|
||||
REGISTER_VARIANT(short)
|
||||
REGISTER_VARIANT(ushort)
|
||||
REGISTER_VARIANT(int)
|
||||
REGISTER_VARIANT(uint)
|
||||
REGISTER_VARIANT(llong)
|
||||
REGISTER_VARIANT(ullong)
|
||||
REGISTER_VARIANT(float)
|
||||
REGISTER_VARIANT(double)
|
||||
REGISTER_VARIANT(ldouble)
|
||||
REGISTER_VARIANT(PIBitArray)
|
||||
REGISTER_VARIANT(PIByteArray)
|
||||
REGISTER_VARIANT(PIString)
|
||||
REGISTER_VARIANT(PIStringList)
|
||||
REGISTER_VARIANT(PITime)
|
||||
REGISTER_VARIANT(PIDate)
|
||||
REGISTER_VARIANT(PIDateTime)
|
||||
REGISTER_VARIANT(PISystemTime)
|
||||
REGISTER_NS_VARIANT(PIVariantTypes, Enum)
|
||||
REGISTER_NS_VARIANT(PIVariantTypes, File)
|
||||
REGISTER_NS_VARIANT(PIVariantTypes, Dir)
|
||||
REGISTER_NS_VARIANT(PIVariantTypes, Color)
|
||||
REGISTER_NS_VARIANT(PIVariantTypes, IODevice)
|
||||
REGISTER_VARIANT(PIPointd)
|
||||
REGISTER_VARIANT(PIRectd)
|
||||
REGISTER_VARIANT(PIMathVectord)
|
||||
REGISTER_VARIANT(PIMathMatrixd)
|
||||
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVariant & v) {
|
||||
s << v._content << int(v._type);
|
||||
if (v._type == PIVariant::pivCustom) {
|
||||
#ifdef CUSTOM_PIVARIANT
|
||||
if (v._info) {
|
||||
s << v._info->typeName;
|
||||
} else {
|
||||
s << PIStringAscii("");
|
||||
}
|
||||
#else
|
||||
s << PIStringAscii("");
|
||||
#endif
|
||||
}
|
||||
return s;
|
||||
}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVariant & v) {
|
||||
int t(0);
|
||||
s >> v._content >> t;
|
||||
v._type = (PIVariant::Type)t;
|
||||
if (v._type == PIVariant::pivCustom) {
|
||||
PIString tn;
|
||||
s >> tn;
|
||||
#ifdef CUSTOM_PIVARIANT
|
||||
PIByteArray vc = v._content;
|
||||
v = PIVariant::fromValue(vc, tn);
|
||||
#endif
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
inline PICout operator <<(PICout s, const PIVariant & v) {
|
||||
s.space(); s.setControl(0, true);
|
||||
s << "PIVariant(" << v.typeName() << ", " << v.toString() << ")";
|
||||
s.restoreControl(); return s;
|
||||
}
|
||||
|
||||
|
||||
#endif // PIVARIANT_H
|
||||
152
lib/main/core/pivarianttypes.cpp
Normal file
152
lib/main/core/pivarianttypes.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Variant types
|
||||
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 "pivarianttypes.h"
|
||||
#include "pipropertystorage.h"
|
||||
#include "piiodevice.h"
|
||||
|
||||
|
||||
int PIVariantTypes::Enum::selectedValue() const {
|
||||
piForeachC (Enumerator & e, enum_list)
|
||||
if (e.name == selected)
|
||||
return e.value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool PIVariantTypes::Enum::selectValue(int v) {
|
||||
piForeachC (Enumerator & e, enum_list)
|
||||
if (e.value == v) {
|
||||
selected = e.name;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PIVariantTypes::Enum::selectName(const PIString & n) {
|
||||
piForeachC (Enumerator & e, enum_list)
|
||||
if (e.name == n) {
|
||||
selected = e.name;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int PIVariantTypes::Enum::value(const PIString & n) const {
|
||||
piForeachC (Enumerator & e, enum_list)
|
||||
if (e.name == n)
|
||||
return e.value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PIString PIVariantTypes::Enum::name(int v) const {
|
||||
piForeachC (Enumerator & e, enum_list)
|
||||
if (e.value == v)
|
||||
return e.name;
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
PIVector<int> PIVariantTypes::Enum::values() const {
|
||||
PIVector<int> ret;
|
||||
piForeachC (Enumerator & e, enum_list)
|
||||
ret << e.value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIStringList PIVariantTypes::Enum::names() const {
|
||||
PIStringList ret;
|
||||
piForeachC (Enumerator & e, enum_list)
|
||||
ret << e.name;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PIVariantTypes::IODevice::IODevice() {
|
||||
mode = PIIODevice::ReadWrite;
|
||||
options = 0;
|
||||
}
|
||||
|
||||
|
||||
void PIVariantTypes::IODevice::set(const PIPropertyStorage & ps) {
|
||||
props.clear();
|
||||
props << ps;
|
||||
}
|
||||
|
||||
|
||||
PIPropertyStorage PIVariantTypes::IODevice::get() const {
|
||||
PIPropertyStorage ret;
|
||||
PIByteArray ba = props;
|
||||
if (!ba.isEmpty()) ba >> ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIVariantTypes::IODevice::toPICout() const {
|
||||
PIString s;
|
||||
s << "IODevice(" << prefix << ", mode=";
|
||||
int rwc = 0;
|
||||
if (mode & 1) {s << "r"; ++rwc;}
|
||||
if (mode & 2) {s << "w"; ++rwc;}
|
||||
if (rwc == 1) s << "o";
|
||||
s << ", flags=";
|
||||
if (options != 0) {
|
||||
if (((PIIODevice::DeviceOptions)options)[PIIODevice::BlockingRead])
|
||||
s << " br";
|
||||
if (((PIIODevice::DeviceOptions)options)[PIIODevice::BlockingWrite])
|
||||
s << " bw";
|
||||
}
|
||||
PIPropertyStorage ps = get();
|
||||
piForeachC (PIPropertyStorage::Property & p, ps) {
|
||||
s << ", " << p.name << "=\"" << p.value.toString() << "\"";
|
||||
}
|
||||
s << ")";
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PIVariantTypes::Enum & PIVariantTypes::Enum::operator <<(const PIVariantTypes::Enumerator & v) {
|
||||
enum_list << v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIVariantTypes::Enum & PIVariantTypes::Enum::operator <<(const PIString & v) {
|
||||
if (enum_list.isEmpty()) {
|
||||
enum_list << Enumerator(0, v);
|
||||
} else {
|
||||
enum_list << Enumerator(enum_list.back().value+1, v);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIVariantTypes::Enum & PIVariantTypes::Enum::operator <<(const PIStringList & v) {
|
||||
piForeachC (PIString & s, v)
|
||||
(*this) << s;
|
||||
return *this;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user