Merge branch 'master' into pisteampackerconfig

# Conflicts:
#	libs/client_server/piclientserver_server.cpp
#	libs/crypt/picrypt.cpp
#	libs/io_utils/pistreampacker.cpp
#	main.cpp
This commit is contained in:
2024-11-16 14:34:34 +03:00
83 changed files with 3583 additions and 848 deletions

View File

@@ -20,6 +20,7 @@
#include "piclientserver_client.h"
#include "piethernet.h"
#include "pitranslator.h"
PIClientServer::Server::Server() {
@@ -29,13 +30,13 @@ PIClientServer::Server::Server() {
CONNECTL(tcp_server, newConnection, [this](PIEthernet * c) {
PIMutexLocker guard(clients_mutex);
if (clients.size_s() >= max_clients) {
piCout << "Server::newConnection overflow clients count";
piCout << "Server::newConnection overflow clients count"_tr("PIClientServer");
delete c;
return;
}
auto sc = client_factory();
if (!sc) {
piCout << "ClientFactory returns nullptr!";
piCout << "ClientFactory returns nullptr!"_tr("PIClientServer");
return;
}
sc->createForServer(this, c);

View File

@@ -20,6 +20,7 @@
#include "picloudclient.h"
#include "picloudtcp.h"
#include "pitranslator.h"
PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() {
@@ -174,7 +175,7 @@ void PICloudClient::_readed(PIByteArray & ba) {
if (is_connected) {
mutex_buff.lock();
if (buff.size_s() > threadedReadBufferSize()) {
piCoutObj << "Error: buffer overflow, drop" << ba.size() << "bytes";
piCoutObj << "Error: buffer overflow, drop %1 bytes"_tr("PICloud").arg(ba.size());
mutex_buff.unlock();
return;
}

View File

@@ -20,6 +20,7 @@
#include "picloudserver.h"
#include "piliterals_time.h"
#include "pitranslator.h"
PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() {
@@ -226,7 +227,7 @@ void PICloudServer::Client::pushBuffer(const PIByteArray & ba) {
if (!is_connected) return;
mutex_buff.lock();
if (buff.size_s() > threadedReadBufferSize()) {
piCoutObj << "Error: buffer overflow, drop" << ba.size() << "bytes";
piCoutObj << "Error: buffer overflow, drop %1 bytes"_tr("PICloud").arg(ba.size());
mutex_buff.unlock();
return;
}
@@ -247,7 +248,7 @@ void PICloudServer::_readed(PIByteArray & ba) {
Client * oc = index_clients.value(id, nullptr);
clients_mutex.unlock();
if (oc) {
piCoutObj << "Warning: reject client with duplicated ID";
piCoutObj << "Warning: reject client with duplicated ID"_tr("PICloud");
tcp.sendDisconnected(id);
} else {
Client * c = new Client(this, id);

View File

@@ -23,6 +23,7 @@
#include "picrypt.h"
#include "piethernet.h"
#include "pistreampacker.h"
#include "pitranslator.h"
const char hash_cloud_key[] = "_picloud_";
@@ -95,7 +96,7 @@ int PICloud::TCP::sendData(const PIByteArray & data) {
PIByteArray ba;
ba << header;
ba.append(data);
// piCout << "[PICloud::TCP] sendData" << ba.toHex();
// piCout << "[PICloud::TCP] sendData" << ba.toHex();
mutex_send.lock();
streampacker->send(ba);
mutex_send.unlock();
@@ -135,7 +136,7 @@ PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteA
ba >> hdr;
if (hdr.version != header.version) {
piCout << "[PICloud]"
<< "invalid PICloud::TCP version!";
<< "Invalid PICloud::TCP version!"_tr("PICloud");
return ret;
}
ret.first = (Type)hdr.type;

View File

@@ -18,6 +18,8 @@
*/
#include "picompress.h"
#include "pitranslator.h"
#ifdef PIP_COMPRESS
# ifdef ESP_PLATFORM
# include "esp32/rom/miniz.h"
@@ -39,7 +41,7 @@ PIByteArray piCompress(const PIByteArray & ba, int level) {
ret = compress2(zba.data(), &sz, ba.data(), ba.size(), level);
if (ret != Z_OK) {
piCout << "[PICompress]"
<< "Error: invalid input or not enought memory";
<< "Error: invalid input or not enought memory"_tr("PICompress");
return ba;
}
zba.resize(sz);
@@ -47,7 +49,7 @@ PIByteArray piCompress(const PIByteArray & ba, int level) {
return zba;
#else
piCout << "[PICompress]"
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library"_tr("PICompress");
#endif
return ba;
}
@@ -58,7 +60,7 @@ PIByteArray piDecompress(const PIByteArray & zba) {
ullong sz = 0;
if (zba.size() < sizeof(ullong)) {
piCout << "[PICompress]"
<< "Error: invalid input";
<< "Error: invalid input"_tr("PICompress");
return zba;
}
PIByteArray ba(zba.data(zba.size() - sizeof(ullong)), sizeof(ullong));
@@ -69,13 +71,13 @@ PIByteArray piDecompress(const PIByteArray & zba) {
ret = uncompress(ba.data(), &s, zba.data(), zba.size());
if (ret != Z_OK) {
piCout << "[PICompress]"
<< "Error: invalid input or not enought memory";
<< "Error: invalid input or not enought memory"_tr("PICompress");
return zba;
}
return ba;
#else
piCout << "[PICompress]"
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library"_tr("PICompress");
#endif
return zba;
}

View File

@@ -19,8 +19,13 @@
#include "picrypt.h"
#include "pitranslator.h"
#ifdef PIP_CRYPT
#include <sodium.h>
#define PICRYPT_DISABLED_WARNING \
piCout << "[PICrypt]" \
<< "Warning: PICrypt is disabled, to enable install sodium library and rebuild pip"_tr("PICrypt");
namespace {
constexpr char hash_def_key[] = "_picrypt_\0\0\0\0\0\0\0";
constexpr int hash_def_key_size = 9;
@@ -29,7 +34,7 @@ constexpr int hash_def_key_size = 9;
PICrypt::PICrypt() {
if (!init()) {
piCout << "[PICrypt]"
<< "Error while initialize sodium!";
<< "Error while initialize sodium!"_tr("PICrypt");
}
nonce_.resize(crypto_secretbox_NONCEBYTES);
key_.resize(crypto_secretbox_KEYBYTES);
@@ -181,10 +186,10 @@ ullong PICrypt::shorthash(const PIString & s, PIByteArray key) {
}
if (crypto_shorthash_BYTES != sizeof(hash))
piCout << "[PICrypt]"
<< "internal error: bad hash size";
<< "internal error: bad hash size"_tr("PICrypt");
if (key.size() != crypto_shorthash_KEYBYTES) {
piCout << "[PICrypt]"
<< "invalid key size" << key.size() << ", shoud be" << crypto_shorthash_KEYBYTES << ", filled zeros";
<< "invalid key size %1, should be %2, filled with zeros"_tr("PICrypt").arg(key.size()).arg(crypto_shorthash_KEYBYTES);
key.resize(crypto_shorthash_KEYBYTES, 0);
}
PIByteArray in(s.data(), s.size());

View File

@@ -24,6 +24,7 @@
#define PIFFT_P_H
#include "picout.h"
#include "pimathcomplex.h"
#include "pivector.h"
#if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq)
# include "fftw3.h"
@@ -41,7 +42,7 @@ 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";
// piCout << "[PIFFTW]" << "Warning: PIFFTW is disabled, to enable install libfftw3-dev library and build pip with -DFFTW=1";
// #endif
p_makeThreadSafe();
}

View File

@@ -0,0 +1,346 @@
#include "microhttpd_server_p.h"
#include "piliterals_string.h"
#include "piliterals_time.h"
#include <microhttpd.h>
// clang-format off
#ifdef QNX
# include <arpa/inet.h>
# include <sys/socket.h>
# include <sys/types.h>
# ifdef BLACKBERRY
# include <netinet/in.h>
# else
# include <sys/dcmd_io-net.h>
# endif
#else
# ifdef WINDOWS
# include <io.h>
# include <winsock2.h>
# include <ws2tcpip.h>
# else
# include <netinet/in.h>
# include <sys/socket.h>
# ifdef LWIP
# include <lwip/sockets.h>
# endif
# endif
#endif
// clang-format on
struct MicrohttpdServerConnection {
bool ready();
int send_reply(const MicrohttpdServer::Reply & r);
int send_error();
bool done = false;
MicrohttpdServer::Method method = MicrohttpdServer::Method::Unknown;
PIString path;
PIByteArray body;
PIMap<PIString, PIString> headers, args, post;
MHD_Connection * connection = nullptr;
MicrohttpdServer * server = nullptr;
MHD_PostProcessor * postprocessor = nullptr;
};
bool MicrohttpdServerConnection::ready() {
if (!server) return false;
if (done) return true;
done = true;
MicrohttpdServer::Reply rep;
if (method == MicrohttpdServer::Method::Get) {
if (path == "/favicon.ico"_a) {
// piCout << "send favicon" << server->favicon.size() << "bytes";
rep.setBody(server->favicon);
send_reply(rep);
return true;
}
}
// piCout << "ready" << (int)method << path;
MicrohttpdServer::Request req;
req.method = method;
req.path = path;
req.body = body;
req.headers = headers;
req.args = args;
rep.setCode(MHD_HTTP_BAD_REQUEST);
if (server->callback) rep = server->callback(req);
rep.addFixedHeaders();
send_reply(rep);
return true;
}
int MicrohttpdServerConnection::send_reply(const MicrohttpdServer::Reply & r) {
MHD_Response * response = MHD_create_response_from_buffer(r.body.size(), (void *)r.body.data(), MHD_RESPMEM_MUST_COPY);
if (!response) {
// piCout << "null response" << r.body.size() << (void *)r.body.data();
return MHD_NO;
}
auto it = r.headers.makeIterator();
while (it.next())
MHD_add_response_header(response, it.key().dataAscii(), it.value().dataUTF8());
// piCout << "status" << r.code;
int ret = MHD_queue_response(connection, r.code, response);
MHD_destroy_response(response);
return ret;
}
int MicrohttpdServerConnection::send_error() {
return MHD_queue_response(connection, MHD_HTTP_BAD_REQUEST, MHD_create_response_from_buffer(0, nullptr, MHD_RESPMEM_MUST_COPY));
}
void log_callback(void * cls, const char * fmt, va_list ap) {
MicrohttpdServer * server = (MicrohttpdServer *)cls;
piCout << "log" << server;
if (!server) return;
char buffer[1024];
memset(buffer, 0, 1024);
std::vsnprintf(buffer, 1024, fmt, ap);
piCout << buffer;
}
int iterate_post(void * conn_cls,
MHD_ValueKind kind,
const char * key,
const char * filename,
const char * content_type,
const char * transfer_encoding,
const char * data,
uint64_t off,
size_t size) {
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)conn_cls;
if (!conn) return MHD_NO;
conn->post[PIString::fromUTF8(key)] = PIString::fromUTF8(data);
return MHD_YES;
}
void request_completed(void * cls, MHD_Connection * connection, void ** con_cls, MHD_RequestTerminationCode toe) {
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
// piCout << "request_completed" << conn << conn->headers << conn->post << '"' << conn->body << '"';
if (!conn) return;
if (conn->method == MicrohttpdServer::Method::Post && conn->postprocessor) MHD_destroy_post_processor(conn->postprocessor);
conn->ready();
piDeleteSafety(conn);
}
int header_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
if (!conn) return MHD_NO;
conn->headers[PIString::fromUTF8(key)] = PIString::fromUTF8(value);
return MHD_YES;
}
int args_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
if (!conn) return MHD_NO;
conn->args[PIString::fromUTF8(key)] = PIString::fromUTF8(value);
return MHD_YES;
}
int answer_to_connection(void * cls,
MHD_Connection * connection,
const char * url,
const char * method,
const char * version,
const char * upload_data,
size_t * upload_data_size,
void ** con_cls) {
MicrohttpdServer * server = (MicrohttpdServer *)cls;
MicrohttpdServer::Method m = MicrohttpdServer::Method::Unknown;
if (0 == strcmp(method, "GET"))
m = MicrohttpdServer::Method::Get;
else if (0 == strcmp(method, "POST"))
m = MicrohttpdServer::Method::Post;
else if (0 == strcmp(method, "HEAD"))
m = MicrohttpdServer::Method::Head;
else if (0 == strcmp(method, "PUT"))
m = MicrohttpdServer::Method::Put;
else if (0 == strcmp(method, "DELETE"))
m = MicrohttpdServer::Method::Delete;
else if (0 == strcmp(method, "CONNECT"))
m = MicrohttpdServer::Method::Connect;
else if (0 == strcmp(method, "OPTIONS"))
m = MicrohttpdServer::Method::Options;
else if (0 == strcmp(method, "TRACE"))
m = MicrohttpdServer::Method::Trace;
else if (0 == strcmp(method, "PATCH"))
m = MicrohttpdServer::Method::Patch;
if (m == MicrohttpdServer::Method::Unknown) {
piCout << "[MicrohttpdServer]"
<< "Warning:"
<< "Unknown method!";
return MHD_NO;
}
// piCout << "answer" << url << method << server;
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
if (!conn) {
conn = new MicrohttpdServerConnection();
conn->connection = connection;
conn->server = server;
conn->path = PIString::fromUTF8(url);
conn->method = m;
MHD_get_connection_values(connection, MHD_HEADER_KIND, (MHD_KeyValueIterator)header_iterate, *con_cls);
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, (MHD_KeyValueIterator)args_iterate, *con_cls);
if (m == MicrohttpdServer::Method::Post) {
// qDebug() << "new POST" << *upload_data_size;
conn->postprocessor = MHD_create_post_processor(connection, 65536, (MHD_PostDataIterator)iterate_post, (void *)conn);
}
return MHD_YES;
}
switch (m) {
case MicrohttpdServer::Method::Get:
if (!conn->ready()) return conn->send_error();
return MHD_YES;
case MicrohttpdServer::Method::Post:
// qDebug() << "add POST" << *upload_data_size << PIString::fromUtf8(upload_data, *upload_data_size);
if (*upload_data_size) {
conn->body.append(upload_data, *upload_data_size);
if (conn->postprocessor) MHD_post_process(conn->postprocessor, upload_data, *upload_data_size);
*upload_data_size = 0;
return MHD_YES;
} else {
// qDebug() << "answer ok";
if (!conn->ready()) return conn->send_error();
return MHD_YES;
}
break;
default: break;
}
return conn->send_error();
}
PRIVATE_DEFINITION_START(MicrohttpdServer)
MHD_Daemon * daemon;
PRIVATE_DEFINITION_END(MicrohttpdServer)
MicrohttpdServer::MicrohttpdServer() {
PRIVATE->daemon = nullptr;
opts[Option::ConnectionLimit] = FD_SETSIZE - 4;
opts[Option::ConnectionTimeout] = 0_s;
}
MicrohttpdServer::~MicrohttpdServer() {
stop();
}
void MicrohttpdServer::setOption(Option o, PIVariant v) {
opts[o] = std::move(v);
}
void MicrohttpdServer::setFavicon(const PIByteArray & im) {
favicon = im;
}
bool MicrohttpdServer::listen(PINetworkAddress addr) {
stop();
uint flags = 0;
#if MHD_VERSION <= 0x00095100
flags |= MHD_USE_POLL_INTERNALLY;
#else
flags |= MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD;
#endif
if (opts.value(Option::HTTPSEnabled).toBool()) flags |= MHD_USE_TLS;
mem_key = opts.value(Option::HTTPSMemKey).toByteArray();
if (mem_key.isNotEmpty()) mem_key.append(0);
mem_cert = opts.value(Option::HTTPSMemCert).toByteArray();
if (mem_cert.isNotEmpty()) mem_cert.append(0);
key_pass = opts.value(Option::HTTPSKeyPassword).toByteArray();
if (key_pass.isNotEmpty()) key_pass.append(0);
sockaddr_in sa_addr;
memset(&sa_addr, 0, sizeof(sa_addr));
sa_addr.sin_port = htons(addr.port());
sa_addr.sin_addr.s_addr = addr.ip();
sa_addr.sin_family = AF_INET;
PIVector<MHD_OptionItem> options;
options.append({MHD_OPTION_EXTERNAL_LOGGER, (intptr_t)log_callback, this});
options.append({MHD_OPTION_NOTIFY_COMPLETED, (intptr_t)request_completed, nullptr});
options.append({MHD_OPTION_CONNECTION_LIMIT, opts.value(Option::ConnectionLimit).toInt(), nullptr});
options.append({MHD_OPTION_CONNECTION_TIMEOUT, piRound(opts.value(Option::ConnectionTimeout).toSystemTime().toSeconds()), nullptr});
options.append({MHD_OPTION_SOCK_ADDR, 0, &sa_addr});
if (opts.value(Option::HTTPSEnabled).toBool()) {
options.append({MHD_OPTION_HTTPS_MEM_KEY, 0, mem_key.data()});
options.append({MHD_OPTION_HTTPS_MEM_CERT, 0, mem_cert.data()});
options.append({MHD_OPTION_HTTPS_KEY_PASSWORD, 0, key_pass.data()});
}
options.append({MHD_OPTION_END, 0, nullptr});
PRIVATE->daemon = MHD_start_daemon(flags,
addr.port(),
nullptr,
nullptr,
(MHD_AccessHandlerCallback)answer_to_connection,
this,
MHD_OPTION_ARRAY,
options.data(),
MHD_OPTION_END);
return isListen();
}
bool MicrohttpdServer::isListen() const {
return PRIVATE->daemon;
}
void MicrohttpdServer::stop() {
if (PRIVATE->daemon) {
MHD_stop_daemon(PRIVATE->daemon);
PRIVATE->daemon = nullptr;
}
}
void MicrohttpdServer::Reply::addHeader(const PIString & header, const PIString & value) {
headers[header] = value;
}
void MicrohttpdServer::Reply::removeHeader(const PIString & header) {
headers.remove(header);
}
void MicrohttpdServer::Reply::setBody(const PIByteArray & b) {
body = b;
}
void MicrohttpdServer::Reply::setCode(int c) {
code = c;
}
void MicrohttpdServer::Reply::addFixedHeaders() {
if (!headers.contains(MHD_HTTP_HEADER_CONTENT_TYPE)) {
if (body.isNotEmpty()) {
if (body.startsWith(PIByteArray::fromAscii("<!DOCTYPE html>")))
addHeader(MHD_HTTP_HEADER_CONTENT_TYPE, "text/html; charset=utf-8");
else if (body[0] == '[' || body[0] == '{')
addHeader(MHD_HTTP_HEADER_CONTENT_TYPE, "application/json; charset=utf-8");
}
}
addHeader(MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*");
}

View File

@@ -0,0 +1,49 @@
#include "pihttpserver.h"
#include "piliterals_string.h"
PIHTTPServer::PIHTTPServer() {
setRequestCallback([this](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
MicrohttpdServer::Reply rep;
rep.setCode(404);
auto in_path = r.path.split("/");
in_path.removeAll("");
auto it = functions.makeReverseIterator();
while (it.next()) {
if (it.value().function) {
if (it.value().match(in_path)) {
rep = it.value().function(r);
break;
}
}
}
auto hit = reply_headers.makeIterator();
while (hit.next())
rep.addHeader(hit.key(), hit.value());
return rep;
});
}
PIHTTPServer::~PIHTTPServer() {
stop();
}
void PIHTTPServer::registerPath(const PIString & path, RequestFunction functor) {
auto & ep(functions[path]);
ep.path = path.split("/");
ep.function = functor;
ep.path.removeAll("");
}
bool PIHTTPServer::Endpoint::match(const PIStringList & in_path) const {
if (in_path.size() != path.size()) return false;
for (int i = 0; i < path.size_s(); ++i) {
if (path[i] == "*"_a) continue;
if (path[i] != in_path[i]) return false;
}
return true;
}

View File

@@ -18,6 +18,8 @@
*/
#include "piethutilbase.h"
#include "pitranslator.h"
#ifdef PIP_CRYPT
# include "picrypt.h"
#endif
@@ -85,7 +87,8 @@ void PIEthUtilBase::createCryptKey(const PIString & k) {
_key = PICrypt::hash("sodium_bug");
_key = PICrypt::hash(k);
#else
piCout << "[PIEthUtilBase] PICrypt wasn`t built!";
piCout << "[PIEthUtilBase]"
<< "PICrypt wasn`t built!"_tr("PIEthUtilBase");
#endif
_crypt = true;
}

View File

@@ -24,6 +24,7 @@
#include "pistreampacker.h"
#include "piiodevice.h"
#include "pitranslator.h"
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
@@ -164,7 +165,7 @@ void PIStreamPacker::assignDevice(PIIODevice * dev) {
return;
}
if (!dev->infoFlags()[PIIODevice::Reliable]) {
piCoutObj << "Warning! Not recommended to use with non-reliable" << dev;
piCoutObj << "Warning! Not recommended to use with non-reliable device"_tr("PIStreamPacker") << dev;
}
CONNECT2(void, const uchar *, ssize_t, dev, threadedReadEvent, this, received);
CONNECT1(void, PIByteArray, this, sendRequest, dev, write);

View File

@@ -52,7 +52,9 @@
#define PIAPPLICATIONMODULE_H
#include "picli.h"
#include "pilog.h"
#include "pisingleapplication.h"
#include "pisystemmonitor.h"
#include "pitranslator.h"
#endif

View File

@@ -20,6 +20,7 @@
#include "picli.h"
#include "pisysteminfo.h"
#include "pitranslator.h"
//! \class PICLI picli.h
@@ -116,7 +117,7 @@ void PICLI::parse() {
_args_opt << cra;
continue;
}
piCoutObj << "Arguments overflow, \"" << cra << "\" ignored";
piCoutObj << "Arguments overflow, \"%1\" ignored"_tr("PICLI").arg(cra);
}
if (last == 0 ? false : last->has_value) {
last->value = cra;

View File

@@ -30,44 +30,10 @@
//! \~english \section PILog_sec0 Synopsis
//! \~russian \section PILog_sec0 Краткий обзор
//! \~english
//! This class provide handy parsing of command-line arguments. First you should add
//! arguments to %PICLI with function \a addArgument(). Then you can check if there
//! is some argument in application command-line with function \a hasArgument(),
//! or obtain argument value by \a argumentValue().
//! This class provides log with optional file and console output.
//!
//! \~russian
//! Этот класс предоставляет удобный механизм для разбора аргументов командной строки.
//! Сперва необходимо добавить аргументы в %PICLI с помощью методов \a addArgument().
//! Далее можно проверять аргументы на наличие в командной строке методом \a hasArgument(),
//! а также получать их значения при помощи \a argumentValue().
//!
//! \~english \section PICLI_sec1 Example
//! \~russian \section PICLI_sec1 Пример
//! \~\code
//! int main(int argc, char ** argv) {
//! PICLI cli(argc, argv);
//! cli.addArgument("console");
//! cli.addArgument("debug");
//! cli.addArgument("Value", "v", "value", true);
//! if (cli.hasArgument("console"))
//! piCout << "console active";
//! if (cli.hasArgument("debug"))
//! piCout << "debug active";
//! piCout << "Value =" << cli.argumentValue("Value");
//! return 0;
//! }
//! \endcode
//!
//! \~english These executions are similar:
//! \~russian Эти вызовы будут идентичны:
//!
//! \~\code
//! a.out -cd -v 10
//! a.out --value 10 -dc
//! a.out -c -v 10 -d
//! a.out --console -d -v 10
//! a.out --debug -c --value 10
//! \endcode
//! Этот класс предоставляет лог с опциональным выводом в файл и консоль.
//!

View File

@@ -41,82 +41,107 @@ public:
PILog();
~PILog();
//! \~english Message category
//! \~russian Категория сообщения
enum class Level {
Error,
Warning,
Info,
Debug,
Error /** \~english Error \~russian Ошибка */,
Warning /** \~english Warning \~russian Предупреждение */,
Info /** \~english Information \~russian Информация */,
Debug /** \~english Debug \~russian Отладка */,
};
//! \~english Output channel
//! \~russian Канал вывода
enum Output {
File = 0x1,
Console = 0x2,
All = 0xFF,
File /** \~english File \~russian Файл */ = 0x1,
Console /** \~english Console \~russian Консоль */ = 0x2,
All /** \~english All \~russian Все */ = 0xFF,
};
//! \~english Set output target \"o\" to \"on\".
//! \~english Set output channel \"o\" to \"on\".
//! \~russian Установить канал вывода \"o\" в \"on\".
void setOutput(Output o, bool on = true) { output.setFlag(o, on); }
//! \~english Returns prefix for filename.
//! \~russian Возвращает префикс имени файла.
PIString logName() const { return log_name; }
//! \~english Set prefix for filename. Should be set \b before \a setDir()!
//! \~russian Устанавливает префикс имени файла. Должен быть установлен \b до вызова \a setDir()!
void setLogName(const PIString & n) { log_name = n; }
//! \~english Returns if color for console output enabled.
//! \~russian Возвращает использовать ли цвет для вывода в консоль.
bool colorConsole() const { return color_console; }
//! \~english Set color for console output enabled. True by default.
//! \~russian Устанавливает использовать ли цвет для вывода в консоль. Включено по умолчанию.
void setColorConsole(bool yes) { color_console = yes; }
//! \~english Returns directory for log files.
//! \~russian Возвращает директорию для файлов.
PIString dir() const { return log_dir; }
//! \~english Set directory for log files. Should be set \b after \a setApplicationName()!
//! \~english Set directory for log files. Should be set \b after \a setLogName()!
//! \~russian Устанавливает директорию для файлов. Должна быть установлена \b после вызова \a setLogName()!
void setDir(const PIString & d);
//! \~english Returns lifetime for file.
//! \~russian Возвращает время жизни файла.
PISystemTime fileSplitTime() const { return split_time; }
//! \~english Set lifetime for file. Each "st" interval new file will be created.
//! \~russian Устанавливает время жизни файла. Каждый интервал "st" будет создан новый файл.
void setFileSplitTime(PISystemTime st) { split_time = st; }
//! \~english Returns timestamp format for line.
//! \~russian Возвращает формат метки времени для строки.
PIString timestampFormat() const { return timestamp_format; }
//! \~english Set timestamp format for line. Default is "yyyy-MM-dd hh:mm:ss.zzz".
//! \~russian Устанавливает формат метки времени для строки. По умолчанию "yyyy-MM-dd hh:mm:ss.zzz".
void setTimestampFormat(const PIString & f) { timestamp_format = f; }
//! \~english Returns line format.
//! \~russian Возвращает формат строки.
PIString lineFormat() const { return line_format; }
//! \~english Set line format. "t" is timestamp, "c" is category and "m" is message. Default is "t - c: m".
//! \~russian Устанавливает формат строки. "t" - метка времени, "c" - категория и "m" - сообщение. По умолчанию "t - c: m".
void setLineFormat(const PIString & f);
//! \~english Returns maximum level.
//! \~russian Возвращает максимальную категорию.
Level level() const { return max_level; }
//! \~english Set maximum level. All levels greater than \"l\" will be ignored. Default if \a Level::Debug.
//! \~english Set maximum level. All levels greater than \"l\" will be ignored. Default is \a Level::Debug.
//! \~russian Устанавливает максимальную категорию. Все сообщения с большей категорией, чем \"l\", будут игнорироваться. По умолчанию \a
//! Level::Debug.
void setLevel(Level l);
//! \~english Returns PICout for Level::Error level.
//! \~english Returns \a PICout for \a Level::Error level.
//! \~russian Возвращает \a PICout для категории \a Level::Error.
PICout error(PIObject * context = nullptr);
//! \~english Returns PICout for Level::Warning level.
//! \~english Returns \a PICout for \a Level::Warning level.
//! \~russian Возвращает \a PICout для категории \a Level::Warning.
PICout warning(PIObject * context = nullptr);
//! \~english Returns PICout for Level::Info level.
//! \~english Returns \a PICout for \a Level::Info level.
//! \~russian Возвращает \a PICout для категории \a Level::Info.
PICout info(PIObject * context = nullptr);
//! \~english Returns PICout for Level::Debug level.
//! \~english Returns \a PICout for \a Level::Debug level.
//! \~russian Возвращает \a PICout для категории \a Level::Debug.
PICout debug(PIObject * context = nullptr);
//! \~english Write all queued lines and stop. Also called in destructor.
//! \~russian Записывает все строки из очереди и останавливается. Также вызывается в деструкторе.
void stop();
private:

View File

@@ -19,13 +19,14 @@
#include "pisystemmonitor.h"
#include <unistd.h>
#include "pidir.h"
#include "piliterals_string.h"
#include "piprocess.h"
#include "pisysteminfo.h"
#include "pitime_win.h"
#include "pitranslator.h"
#include <unistd.h>
#ifdef WINDOWS
# include <psapi.h>
# include <tlhelp32.h>
@@ -107,14 +108,14 @@ bool PISystemMonitor::startOnProcess(int pID, PISystemTime interval) {
PRIVATE->file.open(PRIVATE->proc_dir + "stat", PIIODevice::ReadOnly);
PRIVATE->filem.open(PRIVATE->proc_dir + "statm", PIIODevice::ReadOnly);
if (!PRIVATE->file.isOpened()) {
piCoutObj << "Can`t find process with ID = " << pID_ << "!";
piCoutObj << "Can`t find process with ID = %1!"_tr("PISystemMonitor").arg(pID_);
return false;
}
# endif
# else
PRIVATE->hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pID_);
if (PRIVATE->hProc == 0) {
piCoutObj << "Can`t open process with ID = " << pID_ << "," << errorString();
piCoutObj << "Can`t open process with ID = %1, %2!"_tr("PISystemMonitor").arg(pID_).arg(errorString());
return false;
}
PRIVATE->tm.reset();
@@ -376,12 +377,12 @@ void PISystemMonitor::gatherThread(llong id) {
FILETIME times[4];
HANDLE thdl = OpenThread(THREAD_QUERY_INFORMATION, FALSE, DWORD(id));
if (!thdl) {
piCout << "[PISystemMonitor] gatherThread(" << id << "):: OpenThread() error:" << errorString();
piCoutObj << "GatherThread(" << id << "):: OpenThread() error:" << errorString();
return;
}
if (GetThreadTimes(thdl, &(times[0]), &(times[1]), &(times[2]), &(times[3])) == 0) {
CloseHandle(thdl);
piCout << "[PISystemMonitor] gatherThread(" << id << "):: GetThreadTimes() error:" << errorString();
piCoutObj << "GatherThread(" << id << "):: GetThreadTimes() error:" << errorString();
return;
}
CloseHandle(thdl);

View File

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

View File

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

View File

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

View File

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

View File

@@ -49,6 +49,7 @@ public:
void listen(PINetworkAddress addr);
void listenAll(ushort port) { listen({0, port}); }
void stopServer();
void closeAll();
int getMaxClients() const { return max_clients; }
@@ -59,7 +60,6 @@ public:
void setClientFactory(std::function<ServerClient *()> f) { client_factory = f; }
private:
void stopServer();
void newClient(ServerClient * c);
void clientDisconnected(ServerClient * c);

View File

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

View File

@@ -343,6 +343,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
static const PIString s_typedef = PIStringAscii("typedef");
static const PIString s_namespace = PIStringAscii("namespace");
static const PIString s_template = PIStringAscii("template");
static const PIString s_L = PIStringAscii("$L");
bool mlc = false, cc = false;
int mls = 0, ole = -1, /*ccs = 0,*/ end = 0;
@@ -365,8 +366,9 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
}
if (i > 0)
if (c == '\\' && fc[i - 1].toAscii() != '\\') {
fc.cutMid(i, 2);
--i;
fc.cutMid(i, 1);
fc.replace(i, 1, s_L);
++i;
continue;
}
if (cc) continue;
@@ -390,6 +392,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
}
}
pfc = procMacros(fc);
pfc.removeAll(s_L);
if (main) return true;
@@ -495,6 +498,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
MetaMap smeta = maybeMeta(pfc);
meta << smeta;
}
// piCout << "pfc E" << cur_namespace << "," << tmp;
parseEnum(0, cur_namespace + tmp, pfc.takeRange('{', '}'), meta);
pfc.takeSymbol();
continue;
@@ -610,8 +614,8 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
int ps = -1;
bool def = false;
PIString prev_namespace = cur_namespace, stmp;
if (ce) cur_namespace += ce->name + s_ns;
// piCout << "parse class" << ce->name << "namespace" << cur_namespace;
if (ce) cur_namespace = ce->name + s_ns;
// piCout << "parse class" << (ce ? ce->name : "NULL") << "namespace" << cur_namespace;
// piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
while (!fc.isEmpty()) {
PIString cw = fc.takeCWord(), tmp;
@@ -663,6 +667,7 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
MetaMap smeta = maybeMeta(fc);
meta << smeta;
}
// piCout << "pc E" << cur_namespace << "," << tmp;
parseEnum(ce, cur_namespace + tmp, fc.takeRange('{', '}'), meta);
fc.takeSymbol();
continue;
@@ -1248,6 +1253,7 @@ PIString PICodeParser::procMacros(PIString fc) {
static const PIString s_elif = PIStringAscii("elif");
static const PIString s_else = PIStringAscii("else");
static const PIString s_endif = PIStringAscii("endif");
static const PIString s_L = PIStringAscii("$L");
if (fc.isEmpty()) return PIString();
int ifcnt = 0;
bool grab = false, skip = false, cond_ok = false;
@@ -1337,7 +1343,9 @@ bool PICodeParser::parseDirective(PIString d) {
static const PIString s_define = PIStringAscii("define");
static const PIString s_undef = PIStringAscii("undef");
static const PIString s_PIMETA = PIStringAscii("PIMETA");
static const PIString s_L = PIStringAscii("$L");
if (d.isEmpty()) return true;
d.replaceAll(s_L, '\n');
PIString dname = d.takeCWord();
// piCout << "parseDirective" << d;
if (dname == s_include) {

View File

@@ -360,8 +360,7 @@ void PIKbdListener::readKeyboard() {
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;
we.direction = short((mer.dwButtonState >> 16) & 0xFFFF) > 0;
wheelEvent(we, kbddata_);
break;
} else {

View File

@@ -37,6 +37,10 @@
template<typename T>
class PISet: public PIMap<T, uchar> {
typedef PIMap<T, uchar> _CSet;
template<typename P, typename T1>
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PISet<T1> & v);
template<typename P, typename T1>
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PISet<T1> & v);
public:
//! Contructs an empty set

View File

@@ -132,9 +132,7 @@ inline void piSwapBinary(const void *& f, const void *& s) {
//! \~english Example:\n \snippet piincludes.cpp compareBinary
//! \~russian Пример:\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;
return 0 == memcmp(f, s, size);
}
//! \~\brief

View File

@@ -340,6 +340,13 @@ bool PIInit::isBuildOptionEnabled(PIInit::BuildOption o) {
true;
# else
false;
# endif
case boConsole:
return
# ifdef PIP_CONSOLE
true;
# else
false;
# endif
default: return false;
}
@@ -357,6 +364,7 @@ PIStringList PIInit::buildOptions() {
if (isBuildOptionEnabled(boCompress)) ret << "Compress";
if (isBuildOptionEnabled(boOpenCL)) ret << "OpenCL";
if (isBuildOptionEnabled(boCloud)) ret << "Cloud";
if (isBuildOptionEnabled(boConsole)) ret << "Console";
return ret;
}

View File

@@ -67,6 +67,7 @@ public:
boCompress /*! \~english Zlib compression support \~russian Поддержка сжатия Zlib */ = 0x80,
boOpenCL /*! \~english OpenCL support \~russian Поддержка OpenCL */ = 0x100,
boCloud /*! \~english PICloud transport support \~russian Поддержка облачного транспорта PICloud */ = 0x200,
boConsole /*! \~english Console graphics support \~russian Поддержка графики в консоли */ = 0x400,
};
static PIInit * instance() { return __PIInit_Initializer__::__instance__; }

View File

@@ -0,0 +1,83 @@
#ifndef MICROHTTPD_SERVER_P_H
#define MICROHTTPD_SERVER_P_H
#include "pibase.h"
#include "piobject.h"
#include "pip_http_server_export.h"
struct MicrohttpdServerConnection;
class PIP_HTTP_SERVER_EXPORT MicrohttpdServer: public PIObject {
PIOBJECT(MicrohttpdServer)
friend struct MicrohttpdServerConnection;
public:
MicrohttpdServer();
virtual ~MicrohttpdServer();
enum class Method {
Unknown,
Get,
Head,
Post,
Put,
Delete,
Connect,
Options,
Trace,
Patch
};
enum class Option {
ConnectionLimit, // uint
ConnectionTimeout, // uint, sec
HTTPSEnabled, // bool
HTTPSMemKey, // const char * to key.pem data
HTTPSMemCert, // const char * to cert.pem data
HTTPSKeyPassword // const char * to passwd for key.pem
};
struct PIP_HTTP_SERVER_EXPORT Request {
MicrohttpdServer::Method method;
PIString path;
PIByteArray body;
PIMap<PIString, PIString> headers;
PIMap<PIString, PIString> args;
};
class PIP_HTTP_SERVER_EXPORT Reply {
friend struct MicrohttpdServerConnection;
public:
void addHeader(const PIString & header, const PIString & value);
void removeHeader(const PIString & header);
void setBody(const PIByteArray & b);
void setCode(int c);
private:
void addFixedHeaders();
int code = 200;
PIByteArray body;
PIMap<PIString, PIString> headers;
};
void setOption(Option o, PIVariant v);
void setFavicon(const PIByteArray & im);
bool listen(PINetworkAddress addr);
bool listenAll(ushort port) { return listen({0, port}); }
bool isListen() const;
void stop();
void setRequestCallback(std::function<Reply(Request)> c) { callback = c; }
private:
PRIVATE_DECLARATION(PIP_HTTP_SERVER_EXPORT)
PIByteArray favicon;
PIMap<Option, PIVariant> opts;
std::function<Reply(Request)> callback;
PIByteArray mem_key, mem_cert, key_pass;
};
#endif

View File

@@ -0,0 +1,33 @@
#ifndef PIHTTPSERVER_H
#define PIHTTPSERVER_H
#include "microhttpd_server_p.h"
#include "pip_http_server_export.h"
class PIP_HTTP_SERVER_EXPORT PIHTTPServer: public MicrohttpdServer {
PIOBJECT_SUBCLASS(PIHTTPServer, MicrohttpdServer)
public:
PIHTTPServer();
virtual ~PIHTTPServer();
using RequestFunction = std::function<MicrohttpdServer::Reply(const MicrohttpdServer::Request &)>;
void registerPath(const PIString & path, RequestFunction functor);
void addReplyHeader(const PIString & name, const PIString & value) { reply_headers[name] = value; }
void removeReplyHeader(const PIString & name) { reply_headers.remove(name); }
void clearReplyHeaders() { reply_headers.clear(); }
private:
struct Endpoint {
bool match(const PIStringList & in_path) const;
PIStringList path;
RequestFunction function;
};
PIMap<PIString, PIString> reply_headers;
PIMap<PIString, Endpoint> functions;
};
#endif

View File

@@ -24,6 +24,7 @@
#include "piliterals_time.h"
#include "pipropertystorage.h"
#include "pitime.h"
#include "pitranslator.h"
#define PIBINARYLOG_VERSION_OLD 0x31
@@ -100,7 +101,7 @@ bool PIBinaryLog::openDevice() {
index.clear();
log_size = 0;
if (mode_ == ReadWrite) {
piCoutObj << "Error: ReadWrite mode not supported, use WriteOnly or ReadOnly";
piCoutObj << "Error: ReadWrite mode not supported, use WriteOnly or ReadOnly"_tr("PIBinLog");
return false;
}
if (path().isEmpty() && mode_ == WriteOnly) {
@@ -122,21 +123,21 @@ bool PIBinaryLog::openDevice() {
}
}
if (!file.open(path(), mode_)) {
piCoutObj << "Error: Can't open file" << path();
piCoutObj << "Error: Can't open file \"%1\": %2"_tr("PIBinLog").arg(path()).arg(errorString());
return false;
}
setName(path());
if (mode_ == WriteOnly) {
file.clear();
if (!writeFileHeader()) {
piCoutObj << "Error: Can't write binlog file header" << path();
piCoutObj << "Error: Can't write binlog file header \"%1\""_tr("PIBinLog").arg(path());
return false;
}
is_started = true;
}
if (mode_ == ReadOnly) {
if (file.isEmpty()) {
piCoutObj << "Error: File is null" << path();
piCoutObj << "Error: File is null \"%1\""_tr("PIBinLog").arg(path());
fileError();
return false;
}
@@ -145,7 +146,7 @@ bool PIBinaryLog::openDevice() {
return false;
}
if (isEmpty()) {
piCoutObj << "Warning: Empty BinLog file" << path();
piCoutObj << "Warning: Empty BinLog file \"%1\""_tr("PIBinLog").arg(path());
fileEnd();
}
play_time = 0;
@@ -175,7 +176,7 @@ bool PIBinaryLog::closeDevice() {
bool PIBinaryLog::threadedRead(const uchar * readed, ssize_t size) {
// piCout << "binlog threaded read";
// piCout << "binlog threaded read";
if (!canRead() || isEnd()) return PIIODevice::threadedRead(readed, size);
is_thread_ok = false;
logmutex.lock();
@@ -258,7 +259,7 @@ PIString PIBinaryLog::getLogfilePath(const PIString & log_dir, const PIString &
dir.setDir(dir.absolutePath());
if (!dir.isExists()) {
piCout << "[PIBinaryLog]"
<< "Creating directory" << dir.path();
<< "Creating directory \"%1\""_tr("PIBinLog").arg(dir.path());
dir.make(true);
}
const PIString npath = log_dir + PIDir::separator + prefix + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss");
@@ -282,7 +283,7 @@ PIString PIBinaryLog::createNewFile() {
newFile(file.path());
return file.path();
}
piCoutObj << "Can't create new file, maybe LogDir" << ("\"" + logDir() + "\"") << "is invalid.";
piCoutObj << "Can't create new file, maybe LogDir \"%1\" is invalid"_tr("PIBinLog").arg(logDir());
return PIString();
}
@@ -291,7 +292,7 @@ void PIBinaryLog::createNewFile(const PIString & path) {
if (open(path, PIIODevice::WriteOnly)) {
newFile(file.path());
} else
piCoutObj << "Can't create new file, maybe path" << ("\"" + path + "\"") << "is invalid.";
piCoutObj << "Can't create new file, maybe path \"%1\" is invalid"_tr("PIBinLog").arg(path);
}
@@ -315,7 +316,7 @@ void PIBinaryLog::setPause(bool pause) {
int PIBinaryLog::writeBinLog(int id, const void * data, int size) {
if (size <= 0 || !canWrite()) return -1;
if (id == 0) {
piCoutObj << "Error: can`t write with id = 0! Id must be > 0";
piCoutObj << "Error: can`t write with id = 0! ID must be > 0"_tr("PIBinLog");
return -1;
}
if (is_pause) return 0;
@@ -359,7 +360,7 @@ PIByteArray PIBinaryLog::readBinLog(int id, PISystemTime * time, int * readed_id
Record br = readRecord();
logmutex.unlock();
if (br.id == -1) {
piCoutObj << "End of BinLog file";
piCoutObj << "End of BinLog file"_tr("PIBinLog");
fileEnd();
return PIByteArray();
}
@@ -373,7 +374,7 @@ PIByteArray PIBinaryLog::readBinLog(int id, PISystemTime * time, int * readed_id
br = readRecord();
logmutex.unlock();
if (br.id == -1) {
piCoutObj << "End of BinLog file";
piCoutObj << "End of BinLog file"_tr("PIBinLog");
fileEnd();
return PIByteArray();
}
@@ -382,7 +383,7 @@ PIByteArray PIBinaryLog::readBinLog(int id, PISystemTime * time, int * readed_id
if (readed_id) *readed_id = br.id;
return br.data;
}
piCoutObj << "Can't find record with id =" << id;
piCoutObj << "Can't find record with id = %1"_tr("PIBinLog").arg(id);
return PIByteArray();
}
@@ -428,15 +429,15 @@ ssize_t PIBinaryLog::readDevice(void * read_to, ssize_t max_size) {
}
if (br.id == -1) {
fileEnd();
piCoutObj << "End of BinLog file";
piCoutObj << "End of BinLog file"_tr("PIBinLog");
return 0;
}
if (br.id == 0) {
piCoutObj << "Read record error";
piCoutObj << "Read record error"_tr("PIBinLog");
return -1;
}
const ssize_t sz = piMini(max_size, br.data.size());
if (sz < br.data.size_s()) piCoutObj << "too small read buffer:" << max_size << ", data size:" << br.data.size();
if (sz < br.data.size_s()) piCoutObj << "too small read buffer: %1, data size: %2"_tr("PIBinLog").arg(max_size).arg(br.data.size());
memcpy(read_to, br.data.data(), sz);
return sz;
}
@@ -491,7 +492,7 @@ bool PIBinaryLog::checkFileHeader() {
for (uint i = 0; i < PIBINARYLOG_SIGNATURE_SIZE; i++)
if (read_sig[i] != binlog_sig[i]) correct = false;
if (!correct) {
piCoutObj << "BinLogFile signature is corrupted or invalid file";
piCoutObj << "BinLogFile signature is corrupted or invalid file"_tr("PIBinLog");
return false;
}
uchar read_version = 0;
@@ -509,9 +510,9 @@ bool PIBinaryLog::checkFileHeader() {
}
return true;
}
if (read_version == 0) piCoutObj << "BinLogFile has invalid version";
if (read_version < PIBINARYLOG_VERSION) piCoutObj << "BinLogFile has too old verion";
if (read_version > PIBINARYLOG_VERSION) piCoutObj << "BinLogFile has too newest version";
if (read_version == 0) piCoutObj << "BinLogFile has invalid version"_tr("PIBinLog");
if (read_version < PIBINARYLOG_VERSION) piCoutObj << "BinLogFile has too old verion"_tr("PIBinLog");
if (read_version > PIBINARYLOG_VERSION) piCoutObj << "BinLogFile has too new version"_tr("PIBinLog");
return false;
}
@@ -545,7 +546,7 @@ PIBinaryLog::Record PIBinaryLog::readRecord() {
if (br.id == 0) fileError();
moveIndex(index.index_pos.value(file.pos(), -1));
logmutex.unlock();
// piCoutObj << "readRecord done";
// piCoutObj << "readRecord done";
return br;
}
@@ -721,7 +722,7 @@ bool PIBinaryLog::cutBinLog(const PIBinaryLog::BinLogInfo & src, const PIString
PIBinaryLog slog;
if (!slog.open(src.path, PIIODevice::ReadOnly)) {
piCout << "[PIBinaryLog]"
<< "Error, can't open" << src.path;
<< "Error, can't open \"%1\""_tr("PIBinLog").arg(src.path);
return false;
}
const PIVector<int> ids = src.records.keys();
@@ -730,7 +731,7 @@ bool PIBinaryLog::cutBinLog(const PIBinaryLog::BinLogInfo & src, const PIString
dlog.createNewFile(dst);
if (!dlog.isOpened()) {
piCout << "[PIBinaryLog]"
<< "Error, can't create" << dst;
<< "Error, can't create \"%1\""_tr("PIBinLog").arg(dst);
return false;
}
bool first = true;
@@ -746,7 +747,7 @@ bool PIBinaryLog::cutBinLog(const PIBinaryLog::BinLogInfo & src, const PIString
if (ids.contains(br.id)) {
if (dlog.writeBinLog_raw(br.id, br.timestamp - st, br.data) <= 0) {
piCout << "[PIBinaryLog]"
<< "Error, can't write to file" << dst;
<< "Error, can't write to file \"%1\""_tr("PIBinLog").arg(dst);
return false;
}
}
@@ -772,7 +773,7 @@ bool PIBinaryLog::joinBinLogsSerial(const PIStringList & src,
for (const PIString & fn: src) {
if (!slog.open(fn, PIIODevice::ReadOnly)) {
piCout << "[PIBinaryLog]"
<< "Error, can't open" << fn;
<< "Error, can't open \"%1\""_tr("PIBinLog").arg(fn);
return false;
}
if (first) {
@@ -781,11 +782,11 @@ bool PIBinaryLog::joinBinLogsSerial(const PIStringList & src,
dlog.createNewFile(dst);
if (!dlog.isOpened()) {
piCout << "[PIBinaryLog]"
<< "Error, can't create" << dst;
<< "Error, can't create \"%1\""_tr("PIBinLog").arg(dst);
return false;
}
piCout << "[PIBinaryLog]"
<< "Start join binlogs to" << dst;
<< "Start join binlogs to \"%1\""_tr("PIBinLog").arg(dst);
} else {
dtime = lt;
}
@@ -799,7 +800,7 @@ bool PIBinaryLog::joinBinLogsSerial(const PIStringList & src,
lt = dtime + br.timestamp;
if (dlog.writeBinLog_raw(br.id, lt, br.data) <= 0) {
piCout << "[PIBinaryLog]"
<< "Error, can't write to file" << dst;
<< "Error, can't write to file \"%1\""_tr("PIBinLog").arg(dst);
return false;
}
if (tm.elapsed_s() > 0.1) {
@@ -821,7 +822,7 @@ bool PIBinaryLog::joinBinLogsSerial(const PIStringList & src,
// piCout << "[PIBinaryLog]" << "complete" << fn;
}
piCout << "[PIBinaryLog]"
<< "Finish join binlogs, total time" << PITime::fromSystemTime(lt).toString();
<< "Finish join binlogs, total time %1"_tr("PIBinLog").arg(PITime::fromSystemTime(lt).toString());
return true;
}
@@ -853,7 +854,7 @@ int PIBinaryLog::posForTime(const PISystemTime & time) {
void PIBinaryLog::seekTo(int rindex) {
// piCoutObj << "seekTo";
// piCoutObj << "seekTo";
logmutex.lock();
pausemutex.lock();
if (rindex < index.index.size_s() && rindex >= 0) {
@@ -866,7 +867,7 @@ void PIBinaryLog::seekTo(int rindex) {
startlogtime = PISystemTime::current() - lastrecord.timestamp;
}
}
// piCoutObj << "seekTo done";
// piCoutObj << "seekTo done";
pausemutex.unlock();
logmutex.unlock();
}
@@ -947,7 +948,7 @@ void PIBinaryLog::configureFromFullPathDevice(const PIString & full_path) {
break;
}
}
// piCoutObj << "configured";
// piCoutObj << "configured";
}
@@ -989,7 +990,7 @@ void PIBinaryLog::propertyChanged(const char * s) {
split_time = property("splitTime").toSystemTime();
split_size = property("splitFileSize").toLLong();
split_count = property("splitRecordCount").toInt();
// piCoutObj << "propertyChanged" << s << play_mode;
// piCoutObj << "propertyChanged" << s << play_mode;
}

View File

@@ -24,6 +24,7 @@
#include "piliterals.h"
#include "pipropertystorage.h"
#include "pisysteminfo.h"
#include "pitranslator.h"
// clang-format off
#ifdef QNX
# include <arpa/inet.h>
@@ -897,7 +898,9 @@ void PIEthernet::server_func(void * eth) {
piMSleep(10);
return;
}
if (ce->debug()) piCout << "[PIEthernet] Can`t accept new connection," << ethErrorString();
if (ce->debug())
piCout << "[PIEthernet]"
<< "Can`t accept new connection, %1"_tr("PIEthernet").arg(ethErrorString());
piMSleep(50);
return;
}
@@ -1081,14 +1084,16 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
ulong ulOutBufLen = sizeof(IP_ADAPTER_INFO);
PIP_ADAPTER_INFO pAdapterInfo = (PIP_ADAPTER_INFO)HeapAlloc(GetProcessHeap(), 0, sizeof(IP_ADAPTER_INFO));
if (!pAdapterInfo) {
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersInfo";
piCout << "[PIEthernet]"
<< "Error allocating memory needed to call GetAdaptersInfo"_tr("PIEthernet");
return il;
}
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
HeapFree(GetProcessHeap(), 0, pAdapterInfo);
pAdapterInfo = (PIP_ADAPTER_INFO)HeapAlloc(GetProcessHeap(), 0, ulOutBufLen);
if (!pAdapterInfo) {
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersInfo";
piCout << "[PIEthernet]"
<< "Error allocating memory needed to call GetAdaptersInfo"_tr("PIEthernet");
return il;
}
}
@@ -1134,7 +1139,8 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
ifc.ifc_len = 256;
ifc.ifc_buf = new char[ifc.ifc_len];
if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
piCout << "[PIEthernet] Can`t get interfaces:" << errorString();
piCout << "[PIEthernet]"
<< "Can`t get interfaces: %1"_tr("PIEthernet").arg(errorString());
delete[] ifc.ifc_buf;
return il;
}
@@ -1223,7 +1229,8 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
}
freeifaddrs(ret);
} else
piCout << "[PIEthernet] Can`t get interfaces:" << errorString();
piCout << "[PIEthernet]"
<< "Can`t get interfaces: %1"_tr("PIEthernet").arg(errorString());
if (s != -1) ::close(s);
# endif
# endif

View File

@@ -23,6 +23,7 @@
#include "piincludes_p.h"
#include "piiostream.h"
#include "pitime_win.h"
#include "pitranslator.h"
#ifdef WINDOWS
# undef S_IFDIR
# undef S_IFREG
@@ -295,7 +296,7 @@ void PIFile::resize(llong new_size, uchar fill_) {
clear();
return;
}
piCoutObj << "Downsize is not supported yet :-(";
piCoutObj << "Downsize is not supported yet :-("_tr("PIFile");
}

View File

@@ -56,12 +56,12 @@ bool PIIOByteArray::open(const PIByteArray & buffer) {
ssize_t PIIOByteArray::readDevice(void * read_to, ssize_t size) {
// piCout << "PIIOByteArray::read" << data_ << size << canRead();
// piCout << "PIIOByteArray::read" << data_ << size << canRead();
if (!canRead() || !data_) return -1;
int ret = piMini(size, data_->size_s() - pos);
if (ret <= 0) return -1;
memcpy(read_to, data_->data(pos), ret);
// piCout << "readed" << ret;
// piCout << "readed" << ret;
pos += size;
if (pos > data_->size_s()) pos = data_->size_s();
return ret;
@@ -69,12 +69,12 @@ ssize_t PIIOByteArray::readDevice(void * read_to, ssize_t size) {
ssize_t PIIOByteArray::writeDevice(const void * data, ssize_t size) {
// piCout << "PIIOByteArray::write" << data << size << canWrite();
// piCout << "PIIOByteArray::write" << data << size << canWrite();
if (!canWrite() || !data) return -1;
// piCout << "write" << data;
if (pos > data_->size_s()) pos = data_->size_s();
PIByteArray rs = PIByteArray(data, size);
// piCoutObj << rs;
// piCoutObj << rs;
data_->insert(pos, rs);
pos += rs.size_s();
return rs.size_s();

View File

@@ -25,6 +25,7 @@
#include "piliterals_time.h"
#include "pipropertystorage.h"
#include "pitime.h"
#include "pitranslator.h"
//! \class PIIODevice piiodevice.h
@@ -222,7 +223,7 @@ void PIIODevice::stopThreadedRead() {
if (!destroying) {
interrupt();
} else {
piCoutObj << "Error: Device is running after destructor!";
piCoutObj << "Error: Device is running after destructor!"_tr("PIIODevice");
}
#endif
}
@@ -535,7 +536,7 @@ void PIIODevice::splitFullPath(PIString fpwm, PIString * full_path, DeviceMode *
if (fpwm.find('(') > 0 && fpwm.find(')') > 0) {
PIString dms(fpwm.right(fpwm.length() - fpwm.findLast('(')).takeRange('(', ')').trim().toLowerCase().removeAll(' '));
PIStringList opts(dms.split(","));
piForeachC(PIString & o, opts) {
for (const auto & o: opts) {
// piCout << dms;
if (o == "r"_a || o == "ro"_a || o == "read"_a || o == "readonly"_a) dm |= ReadOnly;
if (o == "w"_a || o == "wo"_a || o == "write"_a || o == "writeonly"_a) dm |= WriteOnly;
@@ -666,7 +667,7 @@ PIMap<PIConstChars, PIIODevice::FabricInfo> & PIIODevice::fabrics() {
bool PIIODevice::threadedRead(const uchar * readed, ssize_t size) {
// piCout << "iodevice threaded read";
// piCout << "iodevice threaded read";
if (func_read) return func_read(readed, size, ret_data_);
return true;
}

View File

@@ -19,6 +19,8 @@
#include "piiostring.h"
#include "pitranslator.h"
//! \class PIIOString piiostring.h
//! \details
@@ -49,7 +51,7 @@ void PIIOString::clear() {
bool PIIOString::open(PIString * string, PIIODevice::DeviceMode mode) {
if (mode == PIIODevice::ReadWrite) {
piCoutObj << "Error: ReadWrite mode not supported, use WriteOnly or ReadOnly";
piCoutObj << "Error: ReadWrite mode not supported, use WriteOnly or ReadOnly"_tr("PIIOString");
str = nullptr;
return false;
}

View File

@@ -24,6 +24,7 @@
#include "piincludes_p.h"
#include "pipropertystorage.h"
#include "pitime.h"
#include "pitranslator.h"
#include "piwaitevent_p.h"
#include <errno.h>
@@ -463,10 +464,10 @@ int PISerial::convertSpeed(PISerial::Speed speed) {
default: break;
}
#ifdef WINDOWS
piCoutObj << "Warning: Custom speed" << (int)speed;
piCoutObj << "Warning: Custom speed %1"_tr("PISerial").arg((int)speed);
return (int)speed;
#else
piCoutObj << "Warning: Unknown speed" << (int)speed << ", using 115200";
piCoutObj << "Warning: Unknown speed %1, using 115200"_tr("PISerial").arg((int)speed);
return B115200;
#endif
}
@@ -691,7 +692,7 @@ bool PISerial::openDevice() {
}
}
if (p.isEmpty()) {
piCoutObj << "Unable to find device \"" << pl << "\"";
piCoutObj << "Unable to find device \"%1\""_tr("PISerial").arg(pl);
}
}
if (p.isEmpty()) return false;
@@ -708,7 +709,7 @@ bool PISerial::openDevice() {
PIString wp = "//./" + p;
PRIVATE->hCom = CreateFileA(wp.dataAscii(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
if (PRIVATE->hCom == INVALID_HANDLE_VALUE) {
piCoutObj << "Unable to open \"" << p << "\"" << errorString();
piCoutObj << "Unable to open \"%1\": %2"_tr("PISerial").arg(p).arg(errorString());
fd = -1;
return false;
}
@@ -722,7 +723,7 @@ bool PISerial::openDevice() {
}
fd = ::open(p.data(), O_NOCTTY | om);
if (fd == -1) {
piCoutObj << "Unable to open \"" << p << "\"";
piCoutObj << "Unable to open \"%1\": %2"_tr("PISerial").arg(p).arg(errorString());
return false;
}
tcgetattr(fd, &PRIVATE->desc);
@@ -747,7 +748,7 @@ bool PISerial::closeDevice() {
#ifdef WINDOWS
SetCommState(PRIVATE->hCom, &PRIVATE->sdesc);
SetCommMask(PRIVATE->hCom, PRIVATE->mask);
// piCoutObj << "close" <<
// piCoutObj << "close" <<
CloseHandle(PRIVATE->hCom);
PRIVATE->hCom = 0;
#else
@@ -788,7 +789,7 @@ void PISerial::applySettings() {
}
PRIVATE->desc.StopBits = params[PISerial::TwoStopBits] ? TWOSTOPBITS : ONESTOPBIT;
if (SetCommState(PRIVATE->hCom, &PRIVATE->desc) == -1) {
piCoutObj << "Unable to set comm state for \"" << path() << "\"";
piCoutObj << "Unable to set comm state for \"%1\""_tr("PISerial").arg(path());
return;
}
#else
@@ -822,7 +823,7 @@ void PISerial::applySettings() {
setTimeouts();
if (tcsetattr(fd, TCSANOW, &PRIVATE->desc) < 0) {
piCoutObj << "Can`t set attributes for \"" << path() << "\"";
piCoutObj << "Can`t set attributes for \"%1\""_tr("PISerial").arg(path());
return;
}
#endif
@@ -871,7 +872,7 @@ ssize_t PISerial::readDevice(void * read_to, ssize_t max_size) {
// piCoutObj << "read ..." << PRIVATE->hCom << max_size;
DWORD mask = 0;
if (GetCommMask(PRIVATE->hCom, &mask) == FALSE) {
piCoutObj << "read error" << errorString();
piCoutObj << "Read error: %1"_tr("PISerial").arg(errorString());
stop();
close();
return 0;
@@ -883,7 +884,7 @@ ssize_t PISerial::readDevice(void * read_to, ssize_t max_size) {
DWORD err = GetLastError();
// piCoutObj << "read" << err;
if (err == ERROR_BAD_COMMAND || err == ERROR_ACCESS_DENIED) {
piCoutObj << "read error" << errorString();
piCoutObj << "Read error: %1"_tr("PISerial").arg(errorString());
stop();
close();
return 0;

View File

@@ -21,9 +21,12 @@
#include "piliterals_time.h"
#include "pitime.h"
#include "pitranslator.h"
const uint PIBaseTransfer::signature = 0x54424950;
PIBaseTransfer::PIBaseTransfer(): crc(standardCRC_16()), diag(false) {
header.sig = signature;
crc_enabled = true;
@@ -96,7 +99,7 @@ void PIBaseTransfer::received(PIByteArray data) {
data >> h;
PacketType pt = (PacketType)h.type;
if (!h.check_sig()) {
piCoutObj << "invalid packet signature";
piCoutObj << "invalid packet signature"_tr("PIBaseTransfer");
diag.received(data.size(), false);
return;
} else
@@ -119,7 +122,7 @@ void PIBaseTransfer::received(PIByteArray data) {
ccrc = 0;
if (rcrc != ccrc) {
header.id = h.id;
piCoutObj << "invalid CRC";
piCoutObj << "invalid CRC"_tr("PIBaseTransfer");
sendReply(pt_ReplyInvalid);
} else {
mutex_session.lock();
@@ -170,9 +173,9 @@ void PIBaseTransfer::received(PIByteArray data) {
if (send_up > 20 && send_up > packets_count * 2) packets_count += piMaxi(packets_count / 10, 1);
// piCoutObj << packets_count;
} else
piCoutObj << "invalid reply id";
piCoutObj << "invalid reply id"_tr("PIBaseTransfer");
mutex_session.unlock();
// piCoutObj << "Done Packet" << h.id;
// piCoutObj << "Done Packet" << h.id;
}
if (is_receiving && h.id == 0) {
if (pt == pt_ReplySuccess) {
@@ -213,7 +216,7 @@ void PIBaseTransfer::received(PIByteArray data) {
}
if (is_receiving) {
if (header.session_id != h.session_id) {
piCoutObj << "restart receive";
piCoutObj << "restart receive"_tr("PIBaseTransfer");
mutex_header.unlock();
finish_receive(false, true);
} else {
@@ -344,7 +347,7 @@ bool PIBaseTransfer::send_process() {
mutex_send.unlock();
if (break_) return finish_send(false);
}
// piCoutObj << "send done, checking";
// piCoutObj << "send done, checking";
PITimeMeasurer rtm;
int prev_chk = 0;
mutex_send.lock();
@@ -516,7 +519,7 @@ bool PIBaseTransfer::getStartRequest() {
diag.sended(ba.size_s());
sendRequest(ba);
if (break_) return false;
// piCoutObj << replies[0];
// piCoutObj << replies[0];
mutex_session.lock();
if (replies[0] == pt_ReplySuccess) {
state_string = "send permited!";
@@ -532,7 +535,7 @@ bool PIBaseTransfer::getStartRequest() {
void PIBaseTransfer::processData(int id, PIByteArray & data) {
// piCoutObj << "received packet" << id << ", size" << data.size();
// piCoutObj << "received packet" << id << ", size" << data.size();
if (id < 1 || id > replies.size_s()) return;
if (!session[id - 1].isEmpty()) {
header.id = id;
@@ -595,7 +598,7 @@ PIByteArray PIBaseTransfer::build_packet(int id) {
hdr << header;
mutex_header.unlock();
ret.insert(0, hdr);
// piCoutObj << "Send Packet" << header.id << ret.size();
// piCoutObj << "Send Packet" << header.id << ret.size();
return ret;
}

View File

@@ -23,6 +23,7 @@
#include "piiostream.h"
#include "piliterals_time.h"
#include "pitime.h"
#include "pitranslator.h"
/** \class PIConnection
* \brief Complex Input/Output point
@@ -142,7 +143,7 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
// piCout << name_list << flt_list << chk_set;
chk_set.remove("");
if (!chk_set.isEmpty()) {
piCoutObj << "Error," << chk_set.toVector() << "names assigned to both devices and filters!";
piCoutObj << "Error,"_tr("PIConnection") << chk_set.toVector() << "names assigned to both devices and filters!"_tr("PIConnection");
return false;
}
PIMap<PIString, PIString> dev_aliases;
@@ -238,7 +239,7 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) {
}
setDebug(pdebug);
for (const PIString & f: filter_fails) {
piCoutObj << "\"addFilter\" error: no such device \"" << f << "\"!";
piCoutObj << "\"addFilter\" error: no such device \"%1\"!"_tr("PIConnection").arg(f);
}
for (const PIConfig::Entry * e: cb) {
PIString f(e->getValue("from").value()), t(e->getValue("to").value());
@@ -469,7 +470,7 @@ PIPacketExtractor * PIConnection::addFilter(const PIString & name_, const PIStri
if (extractors.value(full_path, nullptr)) pe = extractors.value(full_path, nullptr)->extractor;
if (pe) dev = pe;
if (!dev) {
piCoutObj << "\"addFilter\" error: no such device or filter \"" << full_path << "\"!";
piCoutObj << "\"addFilter\" error: no such device or filter \"%1\"!"_tr("PIConnection").arg(full_path);
return nullptr;
}
if (!e) {
@@ -508,7 +509,7 @@ PIPacketExtractor * PIConnection::addFilter(PIPacketExtractor * filter, const PI
if (pe) {
dev = pe;
} else {
piCoutObj << "\"addFilter\" error: no such device or filter \"" << full_path << "\"!";
piCoutObj << "\"addFilter\" error: no such device or filter \"%1\"!"_tr("PIConnection").arg(full_path);
return nullptr;
}
if (!e) {
@@ -739,7 +740,7 @@ void PIConnection::addSender(const PIString & name_, const PIString & full_path_
}
PIIODevice * dev = devByString(full_path_name);
if (!dev) {
piCoutObj << "\"addSender\" error: no such device \"" << full_path_name << "\"!";
piCoutObj << "\"addSender\" error: no such device \"%1\"!"_tr("PIConnection").arg(full_path_name);
return;
}
if (!s->isRunning() && start_) {
@@ -899,7 +900,7 @@ int PIConnection::writeByFullPath(const PIString & full_path, const PIByteArray
PIIODevice * dev = __device_pool__->device(fp);
// piCout << "SEND" << full_path << fp;
if (!dev) {
piCoutObj << "No such full path \"" << full_path << "\"!";
piCoutObj << "No such full path \"%1\"!"_tr("PIConnection").arg(full_path);
return -1;
}
return write(dev, data);
@@ -909,7 +910,7 @@ int PIConnection::writeByFullPath(const PIString & full_path, const PIByteArray
int PIConnection::writeByName(const PIString & name_, const PIByteArray & data) {
PIIODevice * dev = deviceByName(name_);
if (!dev) {
piCoutObj << "No such device \"" << name_ << "\"!";
piCoutObj << "No such device \"%1\"!"_tr("PIConnection").arg(name_);
return -1;
}
return write(dev, data);
@@ -918,12 +919,12 @@ int PIConnection::writeByName(const PIString & name_, const PIByteArray & data)
int PIConnection::write(PIIODevice * dev, const PIByteArray & data) {
if (!dev) {
piCoutObj << "Null Device!";
piCoutObj << "Null Device!"_tr("PIConnection");
return -1;
}
if (!dev->isOpened()) return -1;
if (!dev->canWrite()) {
piCoutObj << "Device \"" << dev->constructFullPath() << "\" can`t write!";
piCoutObj << "Device \"%1\" can`t write!"_tr("PIConnection").arg(dev->constructFullPath());
return -1;
}
int ret = dev->write(data);
@@ -982,7 +983,7 @@ PIIODevice * PIConnection::DevicePool::addDevice(PIConnection * parent, const PI
// piCout << "new device" << fp;
dd->dev = PIIODevice::createFromFullPath(fp);
if (!dd->dev) {
piCoutObj << "Error: can`t create device \"" << fp << "\"!"; //:" << errorString();
piCoutObj << "Error: can`t create device \"%1\"!"_tr("PIConnection").arg(fp);
return nullptr;
}
dd->dev->setProperty("__fullPath__", fp);
@@ -1258,7 +1259,7 @@ void PIConnection::unboundExtractor(PIPacketExtractor * pe) {
void PIConnection::packetExtractorReceived(const uchar * data, int size) {
PIString from(emitter() ? emitter()->name() : PIString());
PIIODevice * cd = (PIIODevice *)emitter();
// piCout << "packetExtractorReceived" << from << cd;
// piCout << "packetExtractorReceived" << from << cd;
if (cd) {
PIVector<PIPacketExtractor *> be(bounded_extractors.value(cd));
// piCout << be << (void*)data << size;

View File

@@ -20,6 +20,7 @@
#include "pidiagnostics.h"
#include "piliterals_time.h"
#include "pitranslator.h"
/** \class PIDiagnostics
@@ -40,7 +41,7 @@
PIDiagnostics::State::State() {
receive_speed = send_speed = PIString::readableSize(0) + "/s";
receive_speed = send_speed = PIString::readableSize(0) + PITranslator::tr("/s", "PIDiag");
}
@@ -151,6 +152,7 @@ void PIDiagnostics::sended(int size) {
void PIDiagnostics::tick(int) {
auto speed_sec = "/s"_tr("PIDiag");
mutex_state.lock();
// piCoutObj << "lock";
int tcnt_recv = 0;
@@ -176,8 +178,8 @@ void PIDiagnostics::tick(int) {
cur_state.sended_bytes_per_sec = ullong(double(send.bytes_ok) / its);
}
// piCoutObj << "tick" << recv.cnt_ok << send.cnt_ok;
cur_state.receive_speed = PIString::readableSize(cur_state.received_bytes_per_sec) + "/s";
cur_state.send_speed = PIString::readableSize(cur_state.sended_bytes_per_sec) + "/s";
cur_state.receive_speed = PIString::readableSize(cur_state.received_bytes_per_sec) + speed_sec;
cur_state.send_speed = PIString::readableSize(cur_state.sended_bytes_per_sec) + speed_sec;
int arc = recv.cnt_ok + recv.cnt_fail;
float good_percents = 0.f;
if (arc > 0) good_percents = (float)recv.cnt_ok / arc * 100.f;
@@ -195,7 +197,7 @@ void PIDiagnostics::tick(int) {
diag = PIDiagnostics::Good;
}
if ((tcnt_send + tcnt_recv) != 0) {
// piCoutObj << tcnt_recv << tcnt_send;
// piCoutObj << tcnt_recv << tcnt_send;
history_rec.dequeue();
history_send.dequeue();
Entry e;
@@ -223,7 +225,7 @@ PIDiagnostics::Entry PIDiagnostics::calcHistory(PIQueue<Entry> & hist, int & cnt
if (!hist[i].empty) cnt++;
}
e.empty = false;
// piCoutObj << hist.size() << cnt;
// piCoutObj << hist.size() << cnt;
return e;
}

View File

@@ -19,7 +19,6 @@
#include "piresourcesstorage.h"
#include "pichunkstream.h"
#include "piset.h"
@@ -42,11 +41,11 @@ void PIResourcesStorage::Section::add(const PIResourcesStorage::Section & s) {
void PIResourcesStorage::Section::purge() {
PIVector<PIByteArray *> bav = entries.values();
PISet<PIByteArray *> bas;
piForeach(PIByteArray * i, bav) {
for (auto i: bav) {
if (i) bas << i;
}
bav = bas.toVector();
piForeach(PIByteArray * i, bav)
for (auto i: bav)
delete i;
entries.clear();
}
@@ -76,14 +75,14 @@ void PIResourcesStorage::registerSection(const uchar * rc_data, const uchar * rc
PIVector<PIResourcesStorage::__RCEntry> el;
dba >> el;
PIMap<PIString, PIVector<PIResourcesStorage::__RCEntry>> ebs;
piForeachC(PIResourcesStorage::__RCEntry & e, el) {
for (const auto & e: el) {
ebs[e.section] << e;
}
auto it = ebs.makeIterator();
while (it.next()) {
PIResourcesStorage::Section s;
const PIVector<PIResourcesStorage::__RCEntry> & itv(it.value());
piForeachC(PIResourcesStorage::__RCEntry & e, itv) {
for (const auto & e: itv) {
// piCout << "add" << e.name << e.alias << PIString::readableSize(e.size);
PIByteArray * eba = new PIByteArray(&(rc_data[e.offset]), e.size);
s.entries[e.name] = eba;
@@ -123,7 +122,7 @@ PIByteArray PIResourcesStorage::get(const PIString & entry_name) const {
void PIResourcesStorage::clear() {
// piCout << "PIResourcesStorage clear";
PIVector<Section *> sv = sections.values();
piForeach(Section * i, sv) {
for (auto i: sv) {
if (i) i->purge();
}
sections.clear();

View File

@@ -29,6 +29,7 @@
#include "pibitarray.h"
#include "pimap.h"
#include "pimemoryblock.h"
#include "piset.h"
#include "pivector2d.h"
#define PIP_BINARY_STREAM
@@ -655,6 +656,46 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v)
}
//! \~english Store operator
//! \~russian Оператор сохранения
template<typename P, typename Key>
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PISet<Key> & v) {
s.binaryStreamAppend((int)v.pim_index.size_s());
for (uint i = 0; i < v.size(); ++i) {
s.binaryStreamAppend((int)v.pim_index[i].index);
s << v.pim_index[i].key;
}
return s;
}
//! \~english Restore operator
//! \~russian Оператор извлечения
template<typename P, typename Key>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PISet<Key> & v) {
int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) {
fprintf(stderr, "error with PISet<%s>\n", __PIP_TYPENAME__(Key));
v.clear();
return s;
}
v.pim_index.resize(sz);
v.pim_content.resize(sz, 0);
int ind = 0;
for (int i = 0; i < sz; ++i) {
ind = s.binaryStreamTakeInt();
s >> v.pim_index[i].key;
if (s.wasReadError()) {
fprintf(stderr, "error with PISet<%s>\n", __PIP_TYPENAME__(Key));
v.clear();
return s;
}
v.pim_index[i].index = ind;
}
return s;
}
// non-defined complex types

View File

@@ -20,7 +20,7 @@
#include "pistatemachine_state.h"
#include "pistatemachine_transition.h"
#include "pitranslator.h"
PIStateBase::~PIStateBase() {
piDeleteAll(transitions);
@@ -108,7 +108,7 @@ bool PIStateBase::start(bool force) {
setActive(true);
return initial_state->start();
} else {
piCout << "error:" << getName() << "no initial state!";
piCout << "Error: \"%1\" no initial state!"_tr("PIStateMachine").arg(getName());
return false;
}
} else {

View File

@@ -19,6 +19,7 @@
#include "piliterals_time.h"
#include "pitime.h"
#include "pitranslator.h"
#ifndef MICRO_PIP
# include "piincludes_p.h"
@@ -196,7 +197,7 @@ void PIProcess::startProc(bool detached) {
CloseHandle(PRIVATE->pi.hThread);
CloseHandle(PRIVATE->pi.hProcess);
} else
piCoutObj << "\"CreateProcess\" error, " << errorString();
piCoutObj << "\"CreateProcess\" error: %1"_tr("PIProcess").arg(errorString());
# else
// cout << "exec " << tf_in << ", " << tf_out << ", " << tf_err << endl;

View File

@@ -99,8 +99,8 @@ public:
//! \~russian Оператор сравнения
bool operator<=(const PIChar & o) const;
//! \~english Returns \b true if symbol is digit ('0' to '9')
//! \~russian Возвращает \b true если символ является
//! \~english Returns \b true if symbol is digit (from '0' to '9')
//! \~russian Возвращает \b true если символ является цифрой (от '0' до '9')
bool isDigit() const;
//! \~english Returns \b true if symbol is HEX digit ('0' to '9', 'a' to 'f', 'A' to 'F')

View File

@@ -23,6 +23,7 @@
#include "piliterals.h"
#include "pimathbase.h"
#include "pistringlist.h"
#include "pitranslator.h"
#ifdef PIP_ICU
# define U_NOEXCEPT
# include "unicode/ucnv.h"
@@ -296,7 +297,7 @@ llong PIString::toNumberBase(const PIString & value, int base, bool * ok) {
void PIString::appendFromChars(const char * c, int s, const char * codepage) {
// piCout << "appendFromChars";
// piCout << "appendFromChars";
if (s == 0) return;
int old_sz = size_s();
if (s == -1) s = strlen(c);
@@ -522,11 +523,47 @@ void PIString::trimsubstr(int & st, int & fn) const {
}
PIString PIString::minArgPlaceholder() {
if (size() < 2) return {};
int min = -1;
PIString ret, tmp;
for (int i = 0; i < size_s(); ++i) {
if (at(i) == '%') {
int j = 0;
for (j = i + 1; j < size_s(); ++j) {
if (!at(j).isDigit()) break;
}
bool ok = false;
tmp = mid(i + 1, j - i - 1);
int cur = tmp.toInt(10, &ok);
if (!ok) continue;
if (min < 0 || min > cur) {
min = cur;
ret = tmp;
}
}
}
if (ret.isEmpty()) return {};
return "%" + ret;
}
uint PIString::hash() const {
return piHashData((const uchar *)d.data(), d.size() * sizeof(PIChar));
}
PIByteArray PIString::toAscii() const {
if (isEmpty()) return PIByteArray();
PIByteArray ret;
ret.resize(size());
for (int i = 0; i < size_s(); ++i) {
ret[i] = uchar(at(i).ch);
}
return ret;
}
PIByteArray PIString::toSystem() const {
if (isEmpty()) return PIByteArray();
buildData(__syslocname__);
@@ -1208,6 +1245,17 @@ int PIString::entries(const PIString & str) const {
}
int PIString::lineNumber(int pos) const {
if (isEmpty()) return 0;
if (pos < 0 || pos >= size_s()) pos = size_s() - 1;
int line = 1;
for (int i = 0; i < pos; ++i) {
if (at(i) == '\n') ++line;
}
return line;
}
bool PIString::startsWith(const PIChar c) const {
if (isEmpty()) return false;
return front() == c;
@@ -1734,41 +1782,36 @@ ldouble PIString::toLDouble() const {
PIString & PIString::setReadableSize(llong bytes) {
clear();
if (bytes < 1024) {
*this += (PIString::fromNumber(bytes) + " B"_a);
*this += (PIString::fromNumber(bytes) + " "_a + "B"_tr("PIString"));
return *this;
}
double fres = bytes / 1024.;
llong res = bytes / 1024;
fres -= res;
if (res < 1024) {
*this += (PIString::fromNumber(res) + "."_a + PIString::fromNumber(llong(fres * 10)).left(1) + " KiB"_a);
return *this;
}
fres = res / 1024.;
res /= 1024;
fres -= res;
if (res < 1024) {
*this += (PIString::fromNumber(res) + "."_a + PIString::fromNumber(llong(fres * 10)).left(1) + " MiB"_a);
return *this;
}
fres = res / 1024.;
res /= 1024;
fres -= res;
if (res < 1024) {
*this += (PIString::fromNumber(res) + "."_a + PIString::fromNumber(llong(fres * 10)).left(1) + " GiB"_a);
return *this;
}
fres = res / 1024.;
res /= 1024;
fres -= res;
if (res < 1024) {
*this += (PIString::fromNumber(res) + "."_a + PIString::fromNumber(llong(fres * 10)).left(1) + " TiB"_a);
return *this;
}
fres = res / 1024.;
res /= 1024;
fres -= res;
*this += (PIString::fromNumber(res) + "."_a + PIString::fromNumber(llong(fres * 10)).left(1) + " PiB"_a);
double fres = bytes;
llong res = bytes;
auto checkRange = [this, &fres, &res](const PIString & unit, bool last = false) {
fres = res / 1024.;
res /= 1024;
fres -= res;
if (res < 1024 || last) {
*this += (PIString::fromNumber(res) + "."_a + PIString::fromNumber(llong(fres * 10)).left(1) + " "_a + unit);
return true;
}
return false;
};
if (checkRange("KiB"_tr("PIString"))) return *this;
if (checkRange("MiB"_tr("PIString"))) return *this;
if (checkRange("GiB"_tr("PIString"))) return *this;
if (checkRange("TiB"_tr("PIString"))) return *this;
if (checkRange("PiB"_tr("PIString"))) return *this;
if (checkRange("EiB"_tr("PIString"))) return *this;
if (checkRange("ZiB"_tr("PIString"))) return *this;
checkRange("YiB"_tr("PIString"), true);
return *this;
}
PIString & PIString::arg(const PIString & v) {
auto ph = minArgPlaceholder();
if (!ph.isEmpty()) replaceAll(ph, v);
return *this;
}

View File

@@ -1107,6 +1107,10 @@ public:
//! \~russian Тоже самое, что \a toUTF8().
PIByteArray toByteArray() const { return toUTF8(); }
//! \~english Returns \a PIByteArray contains \a dataAscii() of this string without terminating null-char.
//! \~russian Возвращает \a PIByteArray содержащий \a dataAscii() строки без завершающего нулевого байта.
PIByteArray toAscii() const;
//! \~english Returns \a PIByteArray contains \a data() of this string without terminating null-char.
//! \~russian Возвращает \a PIByteArray содержащий \a data() строки без завершающего нулевого байта.
PIByteArray toSystem() const;
@@ -1282,6 +1286,10 @@ public:
//! \endcode
int entries(const PIString & str) const;
//! \~english Returns line number of position "pos". Lines starts from 1.
//! \~russian Возвращает номер строки позиции "pos". Строки начинаются с 1.
int lineNumber(int pos) const;
//! \~english Returns if string starts with "c".
//! \~russian Возвращает начинается ли строка с "c".
bool startsWith(const char c) const { return startsWith(PIChar(c)); }
@@ -1678,6 +1686,69 @@ public:
//! \~\sa PIString::readableSize()
PIString & setReadableSize(llong bytes);
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
//! \~\details
//! \~\code
//! piCout << PIString("color %1 is not %2, but %1").arg("red").arg("green"); // color red is not green, but red
//! \endcode
PIString & arg(const PIString & v);
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
PIString & arg(short v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
PIString & arg(ushort v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
//! \~\details
//! \~\code
//! piCout << PIString("ten = %1").arg(10); // ten = 10
//! piCout << PIString("'%1' is max hex letter (%2 in dec)").arg(0xF, 16).arg(0xF); // 'F' is max hex letter (15 in dec)
//! \endcode
PIString & arg(int v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
PIString & arg(uint v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
PIString & arg(long v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
PIString & arg(ulong v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
PIString & arg(llong v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
PIString & arg(ullong v, int base = 10) { return arg(PIString::fromNumber(v, base)); }
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
PIString & arg(float v, char format = 'f', int precision = 8) { return arg(PIString::fromNumber(v, format, precision)); }
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
//! \~\details
//! \~\code
//! piCout << PIString("light speed = %1 %2").arg(M_LIGHT_SPEED, 'g', 4).arg("m/s"); // light speed = 2.998e+08 m/s
//! \endcode
PIString & arg(double v, char format = 'f', int precision = 8) { return arg(PIString::fromNumber(v, format, precision)); }
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
PIString & arg(ldouble v, char format = 'f', int precision = 8) { return arg(PIString::fromNumber(v, format, precision)); }
//! \~english Returns string contains numeric representation of "value" in base "base".
//! \~russian Возвращает строковое представление числа "value" по основанию "base".
//! \~\details
@@ -1863,6 +1934,7 @@ private:
void buildData(const char * cp = __syslocname__) const;
void deleteData() const;
void trimsubstr(int & st, int & fn) const;
PIString minArgPlaceholder();
PIDeque<PIChar> d;
mutable bool changed_ = true;

View File

@@ -0,0 +1,74 @@
/*! \file piprotectedvariable.h
* \ingroup Thread
* \~\brief
* \~english Thread-safe variable
* \~russian Потокобезопасная переменная
*/
/*
PIP - Platform Independent Primitives
Thread-safe variable
Ivan Pelipenko peri4ko@yandex.ru, Stephan Fomenko, 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 PIPROTECTEDVARIABLE_H
#define PIPROTECTEDVARIABLE_H
#include "pimutex.h"
template<typename T>
class PIP_EXPORT PIProtectedVariable {
public:
//! \~english Sets value to \"v\"
//! \~russian Устанавливает значение как \"v\"
void set(T v) {
PIMutexLocker _ml(mutex);
var = std::move(v);
}
//! \~english Returns copy of value
//! \~russian Возвращает копию значения
T get() const {
PIMutexLocker _ml(mutex);
return var;
}
//! \~english Lock mutex and returns reference of value
//! \~russian Блокирует мьютекс и возвращает ссылку на значение
T & lock() {
mutex.lock();
return var;
}
//! \~english Unlock mutex
//! \~russian Разблокирует мьютекс
void unlock() { mutex.unlock(); }
//! \~english Sets value to \"v\"
//! \~russian Устанавливает значение как \"v\"
PIProtectedVariable<T> & operator=(T v) {
set(std::move(v));
return *this;
}
private:
mutable PIMutex mutex;
T var;
};
#endif

View File

@@ -0,0 +1,234 @@
/*
PIP - Platform Independent Primitives
PIReadWriteLock, PIReadLocker, PIWriteLocker
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/>.
*/
//! \addtogroup Thread
//! \{
//! \class PIReadWriteLock pireadwritelock.h
//!
//! \~\brief
//! \~english Read/Write lock
//! \~russian Блокировка чтения/записи
//!
//!
//! \~\details
//! \~english \section PIReadWriteLock_sec0 Synopsis
//! \~russian \section PIReadWriteLock_sec0 Краткий обзор
//!
//! \~english
//! %PIReadWriteLock provides more complex critical code section defence between several threads.
//! %PIReadWriteLock permit only one thread to modify data, besides multiple thread can read data
//! simultaneously. Conatains methods:
//! \a lockWrite(), \a tryLockWrite(), \a unlockWrite(), \a lockRead(), \a tryLockRead() and \a unlockRead().
//!
//! For automatic read and write locks use \a PIReadLocker and \a PIWriteLocker.
//!
//! \~russian
//! %PIReadWriteLock предоставляет более сложную межпотоковую защиту критических секций кода.
//! %PIReadWriteLock разрешает только одному потоку изменять данные, в то время как читать данные
//! могут одновременно несколько потоков.
//! Содержит методы:
//! \a lockWrite(), \a tryLockWrite(), \a unlockWrite(), \a lockRead(), \a tryLockRead() и \a unlockRead().
//!
//! Для автоматической блокировки на чтение и запись используйте \a PIReadLocker и \a PIWriteLocker.
//!
//! \~english \section PIReadWriteLock_sec1 Usage
//! \~russian \section PIReadWriteLock_sec1 Использование
//!
//! \~english
//! When one thread lock for write with \a lockWrite(), all other threads (read and write) can`t access data until this thread
//! call \a unlockWrite(). In this way, write lock works similar to mutex.
//!
//! On the other hand, several threads can simultaneously read data. In other words, \a lockRead() increase read threads counter
//! and \a unlockRead() decrease. But thread can`t read data while other thread locked for write.
//!
//! \~russian
//! Когда один поток блокирует запись с помощью функции \a lockWrite(), все остальные потоки (чтение и запись) не смогут получить
//! доступ к данным, пока этот поток не вызовет \a unlockWrite(). Таким образом, блокировка записи работает аналогично мьютексу.
//!
//! С другой стороны, несколько потоков могут одновременно считывать данные. Другими словами, функция \a lockRead() увеличивает счетчик
//! потоков чтения, а функция \a unlockRead() уменьшает. Но поток не может считывать данные, пока другой поток заблокирован для записи.
//!
//! \~\code
//! \endcode
//! \}
//! \addtogroup Thread
//! \{
//! \class PIReadLocker pireadwritelock.h
//!
//! \~\brief
//! \~english %PIReadWriteLock read autolocker
//! \~russian Автоблокировщик на чтение %PIReadWriteLock
//!
//!
//! \~\details
//!
//! \~english
//! When a %PIReadLocker object is created, it lock %PIReadWriteLock for read, if "condition" \c true.
//! When control leaves the scope in which the %PIReadLocker object was created,
//! the %PIReadLocker is destructed and unlock for read, if "condition" was \c true.
//!
//! If "condition" \c false this class do nothing.
//!
//! The %PIReadLocker class is non-copyable.
//!
//! \~russian
//! При создании экземпляра %PIReadLocker он блокирует %PIReadWriteLock на чтение, если "condition" \c true.
//! Когда выполнение покидает область жизни объекта, вызывается его деструктор и освобождается блокировка на чтение,
//! если "condition" был \c true.
//!
//! Если "condition" \c false, то этот объект ничего не делает.
//!
//! Класс %PIReadLocker некопируемый.
//!
//! \~\code
//! // critical section start
//! {
//! PIReadLocker locker(rw_lock);
//! // ... your read code here
//! }
//! // critical section end
//! \endcode
//! \}
//! \addtogroup Thread
//! \{
//! \class PIWriteLocker pireadwritelock.h
//!
//! \~\brief
//! \~english %PIReadWriteLock write autolocker
//! \~russian Автоблокировщик на запись %PIReadWriteLock
//!
//!
//! \~\details
//!
//! \~english
//! When a %PIWriteLocker object is created, it lock %PIReadWriteLock for write, if "condition" \c true.
//! When control leaves the scope in which the %PIWriteLocker object was created,
//! the %PIWriteLocker is destructed and unlock for write, if "condition" was \c true.
//!
//! If "condition" \c false this class do nothing.
//!
//! The %PIWriteLocker class is non-copyable.
//!
//! \~russian
//! При создании экземпляра %PIWriteLocker он блокирует %PIReadWriteLock на запись, если "condition" \c true.
//! Когда выполнение покидает область жизни объекта, вызывается его деструктор и освобождается блокировка на запись,
//! если "condition" был \c true.
//!
//! Если "condition" \c false, то этот объект ничего не делает.
//!
//! Класс %PIWriteLocker некопируемый.
//!
//! \~\code
//! // critical section start
//! {
//! PIWriteLocker locker(rw_lock);
//! // ... your write code here
//! }
//! // critical section end
//! \endcode
//! \}
#include "pireadwritelock.h"
PIReadWriteLock::PIReadWriteLock() {}
PIReadWriteLock::~PIReadWriteLock() {
var.notifyAll();
}
void PIReadWriteLock::lockWrite() {
PIMutexLocker _ml(mutex);
while (reading > 0 || writing) {
var.wait(mutex);
}
writing = true;
}
bool PIReadWriteLock::tryLockWrite() {
PIMutexLocker _ml(mutex);
if (reading > 0 || writing) return false;
writing = true;
return true;
}
bool PIReadWriteLock::tryLockWrite(PISystemTime timeout) {
PITimeMeasurer tm;
PIMutexLocker _ml(mutex);
while (reading > 0 || writing) {
PISystemTime remain = timeout - tm.elapsed();
if (remain.isNegative()) return false;
var.waitFor(mutex, remain);
}
writing = true;
return true;
}
void PIReadWriteLock::unlockWrite() {
PIMutexLocker _ml(mutex);
writing = false;
var.notifyAll();
}
void PIReadWriteLock::lockRead() {
PIMutexLocker _ml(mutex);
while (writing) {
var.wait(mutex);
}
++reading;
}
bool PIReadWriteLock::tryLockRead() {
PIMutexLocker _ml(mutex);
if (writing) return false;
++reading;
return true;
}
bool PIReadWriteLock::tryLockRead(PISystemTime timeout) {
PITimeMeasurer tm;
PIMutexLocker _ml(mutex);
while (writing) {
PISystemTime remain = timeout - tm.elapsed();
if (remain.isNegative()) return false;
var.waitFor(mutex, remain);
}
++reading;
return true;
}
void PIReadWriteLock::unlockRead() {
PIMutexLocker _ml(mutex);
--reading;
var.notifyAll();
}

View File

@@ -0,0 +1,130 @@
/*! \file pireadwritelock.h
* \ingroup Read/Write lock
* \~\brief
* \~english Read/Write lock
* \~russian Блокировка чтения/записи
*/
/*
PIP - Platform Independent Primitives
PIReadWriteLock, PIReadLocker, PIWriteLocker
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 PIREADWRITELOCK_H
#define PIREADWRITELOCK_H
#include "piconditionvar.h"
class PIP_EXPORT PIReadWriteLock {
public:
NO_COPY_CLASS(PIReadWriteLock)
//! \~english Constructs %PIReadWriteLock.
//! \~russian Создает %PIReadWriteLock.
PIReadWriteLock();
//! \~english Destroy %PIReadWriteLock.
//! \~russian Деструктор %PIReadWriteLock.
~PIReadWriteLock();
//! \~english Lock for write. If already locked for write or read, than wait until all locks released.
//! \~russian Заблокировать на запись. Если уже заблокировано на запись или чтение, то ждёт освобождения блокировок.
void lockWrite();
//! \~english Try to lock for write. Returns if operation was successfull.
//! \~russian Пробует заблокировать на запись. Возвращает успех операции.
bool tryLockWrite();
//! \~english Try to lock for write for \"timeout\". Returns if operation was successfull (timeout has not expired).
//! \~russian Пробует заблокировать на запись в течении \"timeout\". Возвращает успех операции (не истек ли тайм-аут).
bool tryLockWrite(PISystemTime timeout);
//! \~english Release lock for write.
//! \~russian Освобождает блокировку на запись.
void unlockWrite();
//! \~english Lock for read. If already locked for write, than wait until write lock released.
//! \~russian Заблокировать на чтение. Если уже заблокировано на запись, то ждёт освобождения записывающей блокировки.
void lockRead();
//! \~english Try to lock for read. Returns if operation was successfull.
//! \~russian Пробует заблокировать на чтение. Возвращает успех операции.
bool tryLockRead();
//! \~english Try to lock for read for \"timeout\". Returns if operation was successfull (timeout has not expired).
//! \~russian Пробует заблокировать на чтение в течении \"timeout\". Возвращает успех операции (не истек ли тайм-аут).
bool tryLockRead(PISystemTime timeout);
//! \~english Release lock for read.
//! \~russian Освобождает блокировку на чтение.
void unlockRead();
private:
int reading = 0;
bool writing = false;
PIMutex mutex;
PIConditionVariable var;
};
class PIP_EXPORT PIReadLocker {
public:
NO_COPY_CLASS(PIReadLocker);
//! \~english Constructs and lock for read %PIReadWriteLock "l" if "condition" is \c true.
//! \~russian Создается и блокирует на чтение %PIReadWriteLock "l" если "condition" \c true.
PIReadLocker(PIReadWriteLock & l, bool condition = true): rwl(l), cond(condition) {
if (cond) rwl.lockRead();
}
//! \~english Release read lock on %PIReadWriteLock if "condition" was \c true.
//! \~russian Освобождает блокировку на чтение %PIReadWriteLock если "condition" был \c true.
~PIReadLocker() {
if (cond) rwl.unlockRead();
}
private:
PIReadWriteLock & rwl;
bool cond = true;
};
class PIP_EXPORT PIWriteLocker {
public:
NO_COPY_CLASS(PIWriteLocker);
//! \~english Constructs and lock for write %PIReadWriteLock "l" if "condition" is \c true.
//! \~russian Создается и блокирует на запись %PIReadWriteLock "l" если "condition" \c true.
PIWriteLocker(PIReadWriteLock & l, bool condition = true): rwl(l), cond(condition) {
if (cond) rwl.lockWrite();
}
//! \~english Release write lock on %PIReadWriteLock if "condition" was \c true.
//! \~russian Освобождает блокировку на запись %PIReadWriteLock если "condition" был \c true.
~PIWriteLocker() {
if (cond) rwl.unlockWrite();
}
private:
PIReadWriteLock & rwl;
bool cond = true;
};
#endif

View File

@@ -0,0 +1,152 @@
/*
PIP - Platform Independent Primitives
PISemaphore, PISemaphoreLocker
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/>.
*/
//! \addtogroup Thread
//! \{
//! \class PISemaphore pisemaphore.h
//!
//! \~\brief
//! \~english Basic semaphore
//! \~russian Простой семафор
//!
//!
//! \~\details
//! \~english \section PISemaphore_sec0 Synopsis
//! \~russian \section PISemaphore_sec0 Краткий обзор
//!
//! \~english
//! %PISemaphore provides critical code section defence between several threads with resource counting.
//! Semaphore contains logic counter and functions to change it:
//! \a release(), \a acquire() and \a tryAcquire().
//!
//! For automatic acquire-release use \a PISemaphoreLocker.
//!
//! \~russian
//! %PISemaphore предоставляет межпотоковую защиту критических секций кода с подсчетом ресурсов.
//! Семафор состоит из логического счетчика и методов для его изменения:
//! \a release(), \a acquire() and \a tryAcquire().
//!
//! Для автоматического захвата-освобождения используйте \a PISemaphoreLocker.
//!
//! \~english \section PISemaphore_sec1 Usage
//! \~russian \section PISemaphore_sec1 Использование
//!
//! \~english
//!
//! \~russian
//!
//! \~\code
//! \endcode
//! \}
//! \addtogroup Thread
//! \{
//! \class PISemaphoreLocker pisemaphore.h
//!
//! \~\brief
//! \~english %PISemaphore autolocker
//! \~russian Автоблокировщик %PISemaphore
//!
//!
//! \~\details
//!
//! \~english
//! When a %PISemaphoreLocker object is created, it attempts to acquire the semaphore resources, if "condition" \c true.
//! When control leaves the scope in which the %PISemaphoreLocker object was created,
//! the %PISemaphoreLocker is destructed and the resources are released, if "condition" was \c true.
//!
//! If "condition" \c false this class do nothing.
//!
//! The %PISemaphoreLocker class is non-copyable.
//!
//! \~russian
//! При создании экземпляра %PISemaphoreLocker захватываются ресурсы семафора, если "condition" \c true.
//! Когда выполнение покидает область жизни объекта, вызывается его деструктор и ресурсы
//! освобождаются, если "condition" был \c true.
//!
//! Если "condition" \c false, то этот объект ничего не делает.
//!
//! Класс %PISemaphoreLocker некопируемый.
//!
//! \~\code
//! // critical section start
//! {
//! PISemaphoreLocker locker(mutex, 5);
//! // ... your code here
//! }
//! // critical section end
//! \endcode
//! \}
#include "pisemaphore.h"
PISemaphore::PISemaphore(int initial) {
count = initial;
}
PISemaphore::~PISemaphore() {
var.notifyAll();
}
void PISemaphore::acquire(int cnt) {
PIMutexLocker _ml(mutex);
while (count < cnt) {
var.wait(mutex);
}
count -= cnt;
}
bool PISemaphore::tryAcquire(int cnt) {
PIMutexLocker _ml(mutex);
if (count < cnt) return false;
count -= cnt;
return true;
}
bool PISemaphore::tryAcquire(int cnt, PISystemTime timeout) {
PITimeMeasurer tm;
PIMutexLocker _ml(mutex);
while (count < cnt) {
PISystemTime remain = timeout - tm.elapsed();
if (remain.isNegative()) return false;
var.waitFor(mutex, remain);
}
count -= cnt;
return true;
}
void PISemaphore::release(int cnt) {
PIMutexLocker _ml(mutex);
count += cnt;
var.notifyAll();
}
int PISemaphore::available() const {
PIMutexLocker _ml(mutex);
return count;
}

View File

@@ -0,0 +1,95 @@
/*! \file pisemaphore.h
* \ingroup Semaphore
* \~\brief
* \~english Basic semaphore
* \~russian Простой семафор
*/
/*
PIP - Platform Independent Primitives
PISemaphore, PISemaphoreLocker
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 PISEMAPHORE_H
#define PISEMAPHORE_H
#include "piconditionvar.h"
class PIP_EXPORT PISemaphore {
public:
NO_COPY_CLASS(PISemaphore)
//! \~english Constructs semaphore with \"initial\" available resources.
//! \~russian Создает семафор с \"initial\" начальными свободными ресурсами.
PISemaphore(int initial = 0);
//! \~english Destroy semaphore.
//! \~russian Деструктор семафора.
~PISemaphore();
//! \~english Acquire \"cnt\" resources. If no available resources, than blocks until they freed.
//! \~russian Захватывает \"cnt\" ресурсов. Если свободных ресурсов недостаточно, то блокирует до их появления.
void acquire(int cnt = 1);
//! \~english Try to acquire \"cnt\" resources. Returns if operation was successfull.
//! \~russian Пробует захватывает \"cnt\" ресурсов. Возвращает успех захвата.
bool tryAcquire(int cnt = 1);
//! \~english Try to acquire \"cnt\" resources for \"timeout\". Returns if operation was successfull (timeout has not expired).
//! \~russian Пробует захватывает \"cnt\" ресурсов в течении \"timeout\". Возвращает успех захвата (не истек ли тайм-аут).
bool tryAcquire(int cnt, PISystemTime timeout);
//! \~english Release \"cnt\" resources.
//! \~russian Освобождает \"cnt\" ресурсов.
void release(int cnt = 1);
//! \~english Returns available resources count.
//! \~russian Возвращает количество свободных ресурсов.
int available() const;
private:
int count = 0;
mutable PIMutex mutex;
PIConditionVariable var;
};
class PIP_EXPORT PISemaphoreLocker {
public:
NO_COPY_CLASS(PISemaphoreLocker);
//! \~english Constructs and acquire \"cnt\" resources on semaphore "s" if "condition" is \c true.
//! \~russian Создается и захватывает \"cnt\" ресурсов у семафора "s" если "condition" \c true.
PISemaphoreLocker(PISemaphore & s, int cnt = 1, bool condition = true): sem(s), count(cnt), cond(condition) {
if (cond) sem.acquire(count);
}
//! \~english Release "cnt" resources on semaphore if "condition" was \c true.
//! \~russian Освобождает "cnt" ресурсов у семафора если "condition" был \c true.
~PISemaphoreLocker() {
if (cond) sem.release(count);
}
private:
PISemaphore & sem;
int count = 1;
bool cond = true;
};
#endif

View File

@@ -22,6 +22,7 @@
#include "piincludes_p.h"
#include "piintrospection_threads.h"
#include "pitime.h"
#include "pitranslator.h"
#ifndef MICRO_PIP
# include "pisystemtests.h"
#endif
@@ -568,7 +569,7 @@ PIThread::PIThread(bool startNow, PISystemTime loop_delay): PIObject() {
PIThread::~PIThread() {
PIINTROSPECTION_THREAD_DELETE(this);
if (!running_ || PRIVATE->thread == 0) return;
piCout << "[PIThread \"" << name() << "\"] Warning, terminate on destructor!";
piCout << "[PIThread \"%1\"] Warning, terminate on destructor!"_tr("PIThread").arg(name());
#ifdef FREERTOS
// void * ret(0);
// PICout(PICoutManipulators::DefaultControls) << "~PIThread" << PRIVATE->thread;
@@ -663,7 +664,7 @@ void PIThread::stop() {
void PIThread::terminate() {
piCoutObj << "Warning, terminate!";
piCoutObj << "Warning, terminate!"_tr("PIThread");
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "terminate ..." << running_;
#ifdef FREERTOS
PICout(PICoutManipulators::DefaultControls) << "FreeRTOS can't terminate pthreads! waiting for stop";
@@ -781,7 +782,7 @@ bool PIThread::_startThread(void * func) {
running_ = false;
PRIVATE->thread = 0;
piCoutObj << "Error: Can`t start new thread:" << errorString();
piCoutObj << "Error: Can`t start new thread: %1"_tr("PIThread").arg(errorString());
return false;
}

View File

@@ -55,6 +55,9 @@
#include "pigrabberbase.h"
#include "pimutex.h"
#include "pipipelinethread.h"
#include "piprotectedvariable.h"
#include "pireadwritelock.h"
#include "pisemaphore.h"
#include "pispinlock.h"
#include "pithread.h"
#include "pithreadnotifier.h"

View File

@@ -129,6 +129,20 @@ struct base64HelpStruct {
// clang-format on
bool PIByteArray::startsWith(const PIByteArray & o) const {
if (o.isEmpty()) return false;
if (size() < o.size()) return false;
return piCompareBinary(data(), o.data(), o.size());
}
bool PIByteArray::endsWith(const PIByteArray & o) const {
if (o.isEmpty()) return false;
if (size() < o.size()) return false;
return piCompareBinary(data(size() - o.size()), o.data(), o.size());
}
PIByteArray & PIByteArray::convertToBase64() {
return *this = toBase64();
}
@@ -396,6 +410,17 @@ PIByteArray PIByteArray::fromHex(PIString str) {
}
PIByteArray PIByteArray::fromAscii(const char * str) {
PIByteArray ret;
int ind = 0;
while (str[ind] != 0) {
ret.append(str[ind]);
++ind;
}
return ret;
}
PICout operator<<(PICout s, const PIByteArray & ba) {
s.space();
s.saveAndSetControls(0);

View File

@@ -340,6 +340,10 @@ public:
//! \~\sa \a every(), \a any(), \a contains(), \a indexWhere()
inline int entries(std::function<bool(uchar e)> test, ssize_t start = 0) const { return d.entries(test, start); }
bool startsWith(const PIByteArray & o) const;
bool endsWith(const PIByteArray & o) const;
//! \~english Returns the first index at which a given element `e`
//! can be found in the array, or `-1` if it is not present.
//! \~russian Возвращает первый индекс, по которому данный элемент `e`
@@ -1165,6 +1169,8 @@ public:
static PIByteArray fromHex(PIString str);
static PIByteArray fromAscii(const char * str);
//! \~english Return converted from Base 64 data
//! \~russian Возвращает массив из Base 64 представления
static PIByteArray fromBase64(const PIByteArray & base64);

View File

@@ -23,6 +23,7 @@
#include "piiostream.h"
#include "piliterals_time.h"
#include "pitime.h"
#include "pitranslator.h"
#include <ctime>
#ifdef QNX
@@ -320,7 +321,8 @@ PISystemTime PITimeMeasurer::elapsed() const {
PISystemTime PISystemTime::Frequency::toSystemTime() const {
if (value_hz <= 0.) {
piCout << "[PISystemTime::Frequency] toSystemTime() warning: invalid hertz" << value_hz;
piCout << "[PISystemTime::Frequency]"
<< "toSystemTime() Warning: invalid hertz: %1"_tr("PISystemTime").arg(value_hz);
return PISystemTime();
}
return PISystemTime::fromSeconds(1. / value_hz);
@@ -329,7 +331,8 @@ PISystemTime PISystemTime::Frequency::toSystemTime() const {
PISystemTime::Frequency PISystemTime::Frequency::fromSystemTime(const PISystemTime & st) {
if (st == PISystemTime()) {
piCout << "[PISystemTime::Frequency] fromSystemTime() warning: null frequency";
piCout << "[PISystemTime::Frequency]"
<< "fromSystemTime() Warning: null frequency"_tr("PISystemTime");
return Frequency();
}
return Frequency(1. / st.toSeconds());

View File

@@ -19,6 +19,8 @@
#include "pivariant.h"
#include "pitranslator.h"
//! \class PIVariant pivariant.h
//! \details
@@ -388,7 +390,7 @@ PIVariant PIVariant::fromValue(const PIByteArray & c, uint type_id) {
} else
#endif
{
piCout << "Can`t initialize PIVariant from unregistered typeID \"" << type_id << "\"!";
piCout << "Can`t initialize PIVariant from unregistered typeID \"%1\"!"_tr("PIVariant").arg(type_id);
return ret;
}
}
@@ -410,7 +412,7 @@ PIVariant PIVariant::fromValue(const PIByteArray & c, const PIString & type) {
} else
#endif
{
piCout << "Can`t initialize PIVariant from unregistered type \"" << type << "\"!";
piCout << "Can`t initialize PIVariant from unregistered type \"%1\"!"_tr("PIVariant").arg(type);
return ret;
}
}

View File

@@ -1,6 +1,7 @@
#include "piopencl.h"
#include "piresources.h"
#include "pitranslator.h"
#define CL_USE_DEPRECATED_OPENCL_1_2_APIS
#define CL_USE_DEPRECATED_OPENCL_2_0_APIS
#define CL_TARGET_OPENCL_VERSION 120
@@ -88,7 +89,8 @@ void PIOpenCL::Initializer::init() {
cl_uint plat_num = 0;
ret = clGetPlatformIDs(max_size, cl_platforms, &plat_num);
if (ret != 0) {
piCout << "[PIOpenCL] Error: OpenCL platforms not found!";
piCout << "[PIOpenCL]"
<< "Error: OpenCL platforms not found!"_tr("PIOpenCL");
return;
}
for (uint i = 0; i < plat_num; i++) {
@@ -504,7 +506,7 @@ bool PIOpenCL::Program::initKernels(PIVector<void *> kerns) {
bool PIOpenCL::Kernel::execute() {
if (dims.isEmpty()) {
piCout << "[PIOpenCL::Kernel]"
<< "Error: empty range";
<< "Error: empty range"_tr("PIOpenCL");
return false;
}
cl_int ret = clEnqueueNDRangeKernel(context_->PRIVATEWB->queue, PRIVATE->kernel, dims.size(), 0, dims.data(), 0, 0, 0, 0);
@@ -581,13 +583,13 @@ void setArgV(cl_kernel k, int index, T v) {
bool PIOpenCL::Kernel::setArgValueS(int index, const PIVariant & value) {
if (index < 0 || index >= args_.size_s()) {
piCout << "[PIOpenCL::Kernel]"
<< "setArgValue invalid index" << index;
<< "setArgValue invalid index %1"_tr("PIOpenCL").arg(index);
return false;
}
KernelArg & ka(args_[index]);
if (ka.dims > 0) {
piCout << "[PIOpenCL::Kernel]"
<< "setArgValue set scalar to \"" << ka.type_name << ka.arg_name << "\"";
<< "setArgValue set scalar to \"%1 %2\""_tr("PIOpenCL").arg(ka.type_name).arg(ka.arg_name);
return false;
}
switch (ka.arg_type) {
@@ -611,13 +613,13 @@ bool PIOpenCL::Kernel::bindArgValue(int index, Buffer * buffer) {
if (!buffer) return false;
if (index < 0 || index >= args_.size_s()) {
piCout << "[PIOpenCL::Kernel]"
<< "bindArgValue invalid index" << index;
<< "bindArgValue invalid index %1"_tr("PIOpenCL").arg(index);
return false;
}
KernelArg & ka(args_[index]);
if (ka.dims <= 0) {
piCout << "[PIOpenCL::Kernel]"
<< "bindArgValue set buffer to \"" << ka.type_name << ka.arg_name << "\"";
<< "bindArgValue set buffer to \"%1 %2\""_tr("PIOpenCL").arg(ka.type_name).arg(ka.arg_name);
return false;
}
clSetKernelArg(PRIVATE->kernel, index, sizeof(buffer->PRIVATEWB->buffer), &(buffer->PRIVATEWB->buffer));