version 1.22.0

source tree changed
detached PIConsole and PIScreen* in "pip_console" library
This commit is contained in:
2020-06-28 00:18:24 +03:00
parent 5de62b1c83
commit 42925122cb
231 changed files with 22981 additions and 22948 deletions

View 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() {
}

View 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
View 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() {
}

View 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;
}

View 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;
}

View 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

View 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
}

View 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);
}

View 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());
}

View 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());
}

View 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);
}

View 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
View 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
View 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;
}

View 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() {
}

View 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;
}
}
}

View 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();
}
}

View 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
View 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
View 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
View 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
View 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
View 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

View 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();
}

View 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
}

View 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.;
}

View 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 ()

View 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

View 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

View 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

View 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

View 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

View 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
View 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

View 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

View 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;
}

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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
}
}

View 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
View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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"
* */

View 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

View 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

View 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
View 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

View 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

View 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
View 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

View 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

View 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

View 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
View 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

View 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
View 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

View 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
View 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
View 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
View 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

View 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);
}

View 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
View 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
View 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

View 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;
}

View 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

View 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
View 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
View 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
View 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

View 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();
}

View 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

View 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
View 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
View 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
View 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
View 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

View 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();
}

View 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
View 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
View 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

View 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

View 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;
}

View 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
View 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
View 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

View 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, &lt);
FileTimeToSystemTime(&lt, &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, &lt);
LocalFileTimeToFileTime(&lt, &ret);
return ret;
}
#endif // WINDOWS
#endif // PITIME_WIN_H

620
lib/main/core/pivariant.cpp Normal file
View 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
View 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

View 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