Compare commits
51 Commits
7a6936ccd9
...
winconsole
| Author | SHA1 | Date | |
|---|---|---|---|
| 62c5523127 | |||
| daab41e41e | |||
| a61c8477c7 | |||
| 788ad8f2c0 | |||
| 78afc179c4 | |||
| 69ec4c9837 | |||
| 2368de6e93 | |||
| e5df76ab1d | |||
| fdec0e66a8 | |||
| 5f3baa5580 | |||
| 7083b2c32b | |||
| af02684dc5 | |||
| 2806086558 | |||
| ce962bfb40 | |||
| dcdd7db33d | |||
| 3c72db2de8 | |||
| 53faaeb396 | |||
| 2928a690b8 | |||
| 220ce225f8 | |||
| ac89c499ab | |||
| 8d1c97da04 | |||
| aa140fd4ec | |||
| 08161c9aad | |||
| 40cda7d988 | |||
| c05b8b4095 | |||
| 3d7ba1dee6 | |||
| a299ada873 | |||
| 91144ad338 | |||
| ef8b785ac6 | |||
| 27f37c9cc1 | |||
| f2464ed76b | |||
| a3615c5666 | |||
| 1b3f72d429 | |||
| 04152f05a9 | |||
| d95944dcfc | |||
| a17644a953 | |||
| 3426a3064e | |||
| a41379a40e | |||
| 39266f8c3c | |||
| 3bcb778628 | |||
| 781b430c33 | |||
| 0ac7ea3096 | |||
| d6a0ae6106 | |||
| 3625afa783 | |||
| 154cbd0160 | |||
| b6c5d65a8d | |||
| d4254121b8 | |||
| da30ae558f | |||
| d9719a7a50 | |||
| 30c4f215a2 | |||
| 6ffbbbe636 |
@@ -135,7 +135,7 @@ JavaScriptWrapImports: true
|
|||||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
LambdaBodyIndentation: Signature
|
LambdaBodyIndentation: Signature
|
||||||
MacroBlockBegin: "PRIVATE_DEFINITION_START|STATIC_INITIALIZER_BEGIN"
|
MacroBlockBegin: "PRIVATE_DEFINITION_START|STATIC_INITIALIZER_BEGIN"
|
||||||
MacroBlockEnd: "PRIVATE_DEFINITION_END|STATIC_INITIALIZER_END"
|
MacroBlockEnd: "PRIVATE_DEFINITION_END|PRIVATE_DEFINITION_END_NO_INITIALIZE|STATIC_INITIALIZER_END"
|
||||||
MaxEmptyLinesToKeep: 2
|
MaxEmptyLinesToKeep: 2
|
||||||
NamespaceIndentation: None
|
NamespaceIndentation: None
|
||||||
ObjCBinPackProtocolList: Auto
|
ObjCBinPackProtocolList: Auto
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ if (POLICY CMP0177)
|
|||||||
cmake_policy(SET CMP0177 OLD)
|
cmake_policy(SET CMP0177 OLD)
|
||||||
endif()
|
endif()
|
||||||
project(PIP)
|
project(PIP)
|
||||||
set(PIP_MAJOR 4)
|
set(PIP_MAJOR 5)
|
||||||
set(PIP_MINOR 8)
|
set(PIP_MINOR 3)
|
||||||
set(PIP_REVISION 0)
|
set(PIP_REVISION 0)
|
||||||
set(PIP_SUFFIX )
|
set(PIP_SUFFIX )
|
||||||
set(PIP_COMPANY SHS)
|
set(PIP_COMPANY SHS)
|
||||||
@@ -69,6 +69,9 @@ option(STD_IOSTREAM "Building with std iostream operators support" OFF)
|
|||||||
option(INTROSPECTION "Build with introspection" OFF)
|
option(INTROSPECTION "Build with introspection" OFF)
|
||||||
option(TESTS "Build tests and perform their before install step" OFF)
|
option(TESTS "Build tests and perform their before install step" OFF)
|
||||||
option(COVERAGE "Build project with coverage info" OFF)
|
option(COVERAGE "Build project with coverage info" OFF)
|
||||||
|
option(PIP_FFTW_F "Support fftw module for float" ON)
|
||||||
|
option(PIP_FFTW_L "Support fftw module for long double" ON)
|
||||||
|
option(PIP_FFTW_Q "Support fftw module for quad double" OFF)
|
||||||
set(PIP_UTILS 1)
|
set(PIP_UTILS 1)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
@@ -328,7 +331,7 @@ if(NOT PIP_FREERTOS)
|
|||||||
if(WIN32)
|
if(WIN32)
|
||||||
if(${C_COMPILER} STREQUAL "cl.exe")
|
if(${C_COMPILER} STREQUAL "cl.exe")
|
||||||
else()
|
else()
|
||||||
list(APPEND LIBS_MAIN ws2_32 iphlpapi psapi cfgmgr32 setupapi)
|
list(APPEND LIBS_MAIN ws2_32 iphlpapi psapi cfgmgr32 setupapi hid)
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
list(APPEND LIBS_MAIN dl)
|
list(APPEND LIBS_MAIN dl)
|
||||||
@@ -371,6 +374,9 @@ set(PCRE2_BUILD_PCRE2_32 OFF)
|
|||||||
set(PCRE2_BUILD_PCRE2GREP OFF)
|
set(PCRE2_BUILD_PCRE2GREP OFF)
|
||||||
set(PCRE2_BUILD_TESTS OFF)
|
set(PCRE2_BUILD_TESTS OFF)
|
||||||
set(PCRE2_SHOW_REPORT OFF)
|
set(PCRE2_SHOW_REPORT OFF)
|
||||||
|
if (WIN32)
|
||||||
|
set (ZLIB_ROOT "${MINGW_INCLUDE}")
|
||||||
|
endif()
|
||||||
add_subdirectory("3rd/pcre2" EXCLUDE_FROM_ALL)
|
add_subdirectory("3rd/pcre2" EXCLUDE_FROM_ALL)
|
||||||
list(APPEND LIBS_MAIN pcre2-16-static)
|
list(APPEND LIBS_MAIN pcre2-16-static)
|
||||||
|
|
||||||
@@ -433,8 +439,23 @@ if (NOT CROSSTOOLS)
|
|||||||
if (PIP_BUILD_FFTW)
|
if (PIP_BUILD_FFTW)
|
||||||
# Check if PIP support fftw3 for PIFFT using in math module
|
# Check if PIP support fftw3 for PIFFT using in math module
|
||||||
set(FFTW_LIB_NAME fftw3)
|
set(FFTW_LIB_NAME fftw3)
|
||||||
set(FFTW_LIB_SUFFIXES "" "f" "l" "q")
|
set(FFTW_LIB_SUFFIXES "")
|
||||||
|
if (PIP_FFTW_F)
|
||||||
|
list(APPEND FFTW_LIB_SUFFIXES "f")
|
||||||
|
endif()
|
||||||
|
if (PIP_FFTW_L)
|
||||||
|
list(APPEND FFTW_LIB_SUFFIXES "l")
|
||||||
|
endif()
|
||||||
|
if (PIP_FFTW_Q)
|
||||||
|
list(APPEND FFTW_LIB_SUFFIXES "q")
|
||||||
|
endif()
|
||||||
|
if (NOT "${FFTW_LIB_SUFFIXES}" STREQUAL "")
|
||||||
|
set(FFTW_LIB_SUFFIXES ";${FFTW_LIB_SUFFIXES}")
|
||||||
|
else()
|
||||||
|
list(APPEND FFTW_LIB_SUFFIXES "" "_")
|
||||||
|
endif()
|
||||||
set(FFTW_LIB_SUFFIXES2 "" "-3")
|
set(FFTW_LIB_SUFFIXES2 "" "-3")
|
||||||
|
set(FFTW_MSG "")
|
||||||
set(FFTW_LIBS)
|
set(FFTW_LIBS)
|
||||||
set(FFTW_ABS_LIBS)
|
set(FFTW_ABS_LIBS)
|
||||||
set(CMAKE_REQUIRED_INCLUDES fftw3.h)
|
set(CMAKE_REQUIRED_INCLUDES fftw3.h)
|
||||||
@@ -449,6 +470,10 @@ if (NOT CROSSTOOLS)
|
|||||||
set(${FFTW_CLN}_FOUND FALSE)
|
set(${FFTW_CLN}_FOUND FALSE)
|
||||||
set(${FFTW_CLNT}_FOUND FALSE)
|
set(${FFTW_CLNT}_FOUND FALSE)
|
||||||
if(${FFTW_CLN}_LIBRARIES)
|
if(${FFTW_CLN}_LIBRARIES)
|
||||||
|
if (NOT "${FFTW_MSG}" STREQUAL "")
|
||||||
|
set(FFTW_MSG "${FFTW_MSG}, ")
|
||||||
|
endif()
|
||||||
|
set(FFTW_MSG "${FFTW_MSG}${FFTW_CLN}")
|
||||||
set(${FFTW_CLN}_FOUND TRUE)
|
set(${FFTW_CLN}_FOUND TRUE)
|
||||||
list(APPEND FFTW_LIBS "${FFTW_CLN}")
|
list(APPEND FFTW_LIBS "${FFTW_CLN}")
|
||||||
list(APPEND FFTW_ABS_LIBS "${${FFTW_CLN}_LIBRARIES}")
|
list(APPEND FFTW_ABS_LIBS "${${FFTW_CLN}_LIBRARIES}")
|
||||||
@@ -472,7 +497,7 @@ if (NOT CROSSTOOLS)
|
|||||||
endforeach()
|
endforeach()
|
||||||
endforeach()
|
endforeach()
|
||||||
if(FFTW_LIBS)
|
if(FFTW_LIBS)
|
||||||
pip_module(fftw "${FFTW_LIBS}" "PIP FFTW support" "" "" "")
|
pip_module(fftw "${FFTW_LIBS}" "PIP FFTW support" "" "" " (${FFTW_MSG})")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -567,7 +592,7 @@ if (NOT CROSSTOOLS)
|
|||||||
if (NOT DEFINED ANDROID_PLATFORM)
|
if (NOT DEFINED ANDROID_PLATFORM)
|
||||||
if(microhttpd_FOUND AND curl_FOUND)
|
if(microhttpd_FOUND AND curl_FOUND)
|
||||||
add_executable(pip_test "main.cpp")
|
add_executable(pip_test "main.cpp")
|
||||||
target_link_libraries(pip_test pip pip_io_utils pip_client_server pip_http_server pip_http_client)
|
target_link_libraries(pip_test pip pip_io_utils pip_client_server pip_http_server pip_http_client pip_console)
|
||||||
if(sodium_FOUND)
|
if(sodium_FOUND)
|
||||||
add_executable(pip_cloud_test "main_picloud_test.cpp")
|
add_executable(pip_cloud_test "main_picloud_test.cpp")
|
||||||
target_link_libraries(pip_cloud_test pip_cloud)
|
target_link_libraries(pip_cloud_test pip_cloud)
|
||||||
@@ -612,7 +637,7 @@ if(NOT PIP_FREERTOS)
|
|||||||
add_subdirectory("utils/translator")
|
add_subdirectory("utils/translator")
|
||||||
add_subdirectory("utils/value_tree_translator")
|
add_subdirectory("utils/value_tree_translator")
|
||||||
if(PIP_UTILS AND (NOT CROSSTOOLS))
|
if(PIP_UTILS AND (NOT CROSSTOOLS))
|
||||||
add_subdirectory("utils/system_test")
|
add_subdirectory("utils/system_calib")
|
||||||
add_subdirectory("utils/udp_file_transfer")
|
add_subdirectory("utils/udp_file_transfer")
|
||||||
if(sodium_FOUND)
|
if(sodium_FOUND)
|
||||||
add_subdirectory("utils/system_daemon")
|
add_subdirectory("utils/system_daemon")
|
||||||
|
|||||||
@@ -189,8 +189,8 @@ void PIScreen::SystemConsole::print() {
|
|||||||
for (int j = 0; j < dh; ++j) {
|
for (int j = 0; j < dh; ++j) {
|
||||||
int k = j * dw + i;
|
int k = j * dw + i;
|
||||||
Cell & c(cells[j + dy0][i + dx0]);
|
Cell & c(cells[j + dy0][i + dx0]);
|
||||||
PRIVATE->chars[k].Char.UnicodeChar = 0;
|
PRIVATE->chars[k].Char.UnicodeChar = c.symbol.unicode16Code();
|
||||||
PRIVATE->chars[k].Char.AsciiChar = c.symbol.toConsole1Byte();
|
// PRIVATE->chars[k].Char.AsciiChar = c.symbol.toConsole1Byte();
|
||||||
PRIVATE->chars[k].Attributes = attributes(c);
|
PRIVATE->chars[k].Attributes = attributes(c);
|
||||||
}
|
}
|
||||||
// piCout << "draw" << dw << dh;
|
// piCout << "draw" << dw << dh;
|
||||||
@@ -200,7 +200,7 @@ void PIScreen::SystemConsole::print() {
|
|||||||
PRIVATE->srect.Top += dy0;
|
PRIVATE->srect.Top += dy0;
|
||||||
PRIVATE->srect.Right -= width - dx1 - 1;
|
PRIVATE->srect.Right -= width - dx1 - 1;
|
||||||
PRIVATE->srect.Bottom -= height - dy1 - 1;
|
PRIVATE->srect.Bottom -= height - dy1 - 1;
|
||||||
WriteConsoleOutput(PRIVATE->hOut, PRIVATE->chars.data(), PRIVATE->bs, PRIVATE->bc, &PRIVATE->srect);
|
WriteConsoleOutputW(PRIVATE->hOut, PRIVATE->chars.data(), PRIVATE->bs, PRIVATE->bc, &PRIVATE->srect);
|
||||||
#else
|
#else
|
||||||
PIString s;
|
PIString s;
|
||||||
int si = 0, sj = 0;
|
int si = 0, sj = 0;
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ bool MicrohttpdServerConnection::ready() {
|
|||||||
req.setPath(path);
|
req.setPath(path);
|
||||||
req.setBody(body);
|
req.setBody(body);
|
||||||
req.headers() = headers;
|
req.headers() = headers;
|
||||||
req.arguments() = args;
|
req.queryArguments() = args;
|
||||||
rep.setCode(Code::BadRequest);
|
rep.setCode(Code::BadRequest);
|
||||||
if (server->callback) rep = server->callback(req);
|
if (server->callback) rep = server->callback(req);
|
||||||
MicrohttpdServer::addFixedHeaders(rep);
|
MicrohttpdServer::addFixedHeaders(rep);
|
||||||
|
|||||||
@@ -7,20 +7,25 @@ PIHTTPServer::PIHTTPServer() {
|
|||||||
setRequestCallback([this](const PIHTTP::MessageConst & r) -> PIHTTP::MessageMutable {
|
setRequestCallback([this](const PIHTTP::MessageConst & r) -> PIHTTP::MessageMutable {
|
||||||
PIHTTP::MessageMutable reply;
|
PIHTTP::MessageMutable reply;
|
||||||
reply.setCode(PIHTTP::Code::NotFound);
|
reply.setCode(PIHTTP::Code::NotFound);
|
||||||
auto in_path = r.path().split("/");
|
auto in_path = splitPath(r.path());
|
||||||
in_path.removeAll("");
|
auto it = endpoints.makeReverseIterator();
|
||||||
auto it = functions.makeReverseIterator();
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
while (it.next()) {
|
while (it.next()) {
|
||||||
if (it.value().function) {
|
for (const auto & ep: it.value()) {
|
||||||
if (it.value().method == r.method()) {
|
if (ep.function && ep.method == r.method()) {
|
||||||
if (it.value().match(in_path)) {
|
PIMap<PIString, PIString> ext_args;
|
||||||
reply = it.value().function(r);
|
if (ep.match(in_path, ext_args)) {
|
||||||
|
auto & r_mut(static_cast<PIHTTP::MessageMutable &>(const_cast<PIHTTP::MessageConst &>(r)));
|
||||||
|
r_mut.pathArguments() = ext_args;
|
||||||
|
r_mut.arguments() = r_mut.pathArguments();
|
||||||
|
r_mut.arguments() << r_mut.queryArguments();
|
||||||
|
reply = ep.function(r);
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (found) break;
|
||||||
}
|
}
|
||||||
if (!found && unhandled) reply = unhandled(r);
|
if (!found && unhandled) reply = unhandled(r);
|
||||||
auto hit = reply_headers.makeIterator();
|
auto hit = reply_headers.makeIterator();
|
||||||
@@ -36,12 +41,13 @@ PIHTTPServer::~PIHTTPServer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIHTTPServer::registerPath(const PIString & path, PIHTTP::Method method, RequestFunction functor) {
|
bool PIHTTPServer::registerPath(const PIString & path, PIHTTP::Method method, RequestFunction functor) {
|
||||||
auto & ep(functions[path + PIString::fromNumber(static_cast<int>(method))]);
|
Endpoint ep;
|
||||||
ep.path = path.split("/");
|
if (!ep.create(path)) return false;
|
||||||
ep.method = method;
|
ep.method = method;
|
||||||
ep.function = functor;
|
ep.function = functor;
|
||||||
ep.path.removeAll("");
|
endpoints[ep.priority] << ep;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -51,40 +57,143 @@ void PIHTTPServer::registerUnhandled(RequestFunction functor) {
|
|||||||
|
|
||||||
|
|
||||||
void PIHTTPServer::unregisterPath(const PIString & path, PIHTTP::Method method) {
|
void PIHTTPServer::unregisterPath(const PIString & path, PIHTTP::Method method) {
|
||||||
auto pl = path.split("/");
|
auto pl = splitPath(path);
|
||||||
pl.removeAll("");
|
auto it = endpoints.makeIterator();
|
||||||
auto it = functions.makeIterator();
|
|
||||||
while (it.next()) {
|
while (it.next()) {
|
||||||
if (it.value().method == method) {
|
it.value().removeWhere([&pl, method](const Endpoint & ep) { return ep.path == pl && ep.method == method; });
|
||||||
if (it.value().path == pl) {
|
|
||||||
functions.remove(it.key());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
endpoints.removeWhere([](uint, const PIVector<Endpoint> & epl) { return epl.isEmpty(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIHTTPServer::unregisterPath(const PIString & path) {
|
void PIHTTPServer::unregisterPath(const PIString & path) {
|
||||||
auto pl = path.split("/");
|
auto pl = splitPath(path);
|
||||||
pl.removeAll("");
|
auto it = endpoints.makeIterator();
|
||||||
auto it = functions.makeIterator();
|
|
||||||
PIStringList keys;
|
|
||||||
while (it.next()) {
|
while (it.next()) {
|
||||||
if (it.value().path == pl) {
|
it.value().removeWhere([&pl](const Endpoint & ep) { return ep.path == pl; });
|
||||||
keys << it.key();
|
|
||||||
}
|
}
|
||||||
}
|
endpoints.removeWhere([](uint, const PIVector<Endpoint> & epl) { return epl.isEmpty(); });
|
||||||
for (const auto & k: keys)
|
|
||||||
functions.remove(k);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIHTTPServer::Endpoint::match(const PIStringList & in_path) const {
|
PIStringList PIHTTPServer::splitPath(const PIString & path) {
|
||||||
if (in_path.size() != path.size()) return false;
|
auto ret = path.split("/");
|
||||||
for (int i = 0; i < path.size_s(); ++i) {
|
ret.removeAll({});
|
||||||
if (path[i] == "*"_a) continue;
|
return ret;
|
||||||
if (path[i] != in_path[i]) return false;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIHTTPServer::PathElement::PathElement(const PIString & reg) {
|
||||||
|
source = reg;
|
||||||
|
if (reg == "*"_a) {
|
||||||
|
type = Type::AnyOne;
|
||||||
|
} else if (reg == "**"_a) {
|
||||||
|
type = Type::AnyMany;
|
||||||
|
} else if (reg.contains('*')) {
|
||||||
|
type = Type::AnyPart;
|
||||||
|
parts = reg.split('*');
|
||||||
|
} else if (reg.contains('{')) {
|
||||||
|
type = Type::Arguments;
|
||||||
|
int ind = 0, eind = 0, pind = 0;
|
||||||
|
for (;;) {
|
||||||
|
ind = reg.find('{', ind);
|
||||||
|
if (ind < 0) break;
|
||||||
|
eind = reg.find('}', ind + 1);
|
||||||
|
if (eind < 0) break;
|
||||||
|
arguments.insert(arguments.size_s(), reg.mid(ind + 1, eind - ind - 1));
|
||||||
|
if (ind == 0)
|
||||||
|
parts << PIString();
|
||||||
|
else {
|
||||||
|
if (ind > pind)
|
||||||
|
parts << reg.mid(pind, ind - pind);
|
||||||
|
else if (parts.isNotEmpty()) {
|
||||||
|
piCout << "[PIHTTPServer] Warning: sequential arguments, ignoring this path!";
|
||||||
|
type = Type::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ind = pind = eind + 1;
|
||||||
|
}
|
||||||
|
if (eind < reg.size_s() - 1) parts << reg.mid(eind + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIHTTPServer::PathElement::match(const PIString & in, PIMap<PIString, PIString> & ext_args) const {
|
||||||
|
// piCout << "match" << source << "with" << in;
|
||||||
|
if (type == Type::AnyOne) return true;
|
||||||
|
if (type == Type::AnyPart) {
|
||||||
|
int ind = 0;
|
||||||
|
for (const auto & m: parts) {
|
||||||
|
ind = in.find(m, ind);
|
||||||
|
if (ind < 0) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (type == Type::Arguments) {
|
||||||
|
int ind = 0, eind = 0;
|
||||||
|
for (int i = 0; i < parts.size_s(); ++i) {
|
||||||
|
const auto & m(parts[i]);
|
||||||
|
if (m.isNotEmpty()) {
|
||||||
|
ind = in.find(m, eind);
|
||||||
|
if (ind < 0) return false;
|
||||||
|
}
|
||||||
|
if (i > 0) {
|
||||||
|
ext_args[arguments.value(i - 1)] = in.mid(eind, ind - eind);
|
||||||
|
}
|
||||||
|
eind = ind + m.size_s();
|
||||||
|
}
|
||||||
|
if (parts.size() == arguments.size()) {
|
||||||
|
ext_args[arguments.value(arguments.size_s() - 1)] = in.mid(eind);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return source == in;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint PIHTTPServer::PathElement::priority() const {
|
||||||
|
switch (type) {
|
||||||
|
case Type::Fixed: return 0x10000; break;
|
||||||
|
case Type::Arguments: return 0x1000; break;
|
||||||
|
case Type::AnyPart: return 0x100; break;
|
||||||
|
case Type::AnyOne: return 0x10; break;
|
||||||
|
case Type::AnyMany: return 0x1; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIHTTPServer::Endpoint::create(const PIString & p) {
|
||||||
|
path = splitPath(p);
|
||||||
|
prepared_path.clear();
|
||||||
|
priority = 0;
|
||||||
|
for (const auto & i: path) {
|
||||||
|
PathElement pe(i);
|
||||||
|
prepared_path << pe;
|
||||||
|
path_types |= pe.type;
|
||||||
|
priority += pe.priority();
|
||||||
|
}
|
||||||
|
return !path_types[PathElement::Type::Invalid];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIHTTPServer::Endpoint::match(const PIStringList & in_path, PIMap<PIString, PIString> & ext_args) const {
|
||||||
|
if (path_types[PathElement::Type::AnyMany]) {
|
||||||
|
int any_ind = path.indexOf("**"_a);
|
||||||
|
for (int i = 0; i < any_ind; ++i) {
|
||||||
|
if (!prepared_path[i].match(in_path[i], ext_args)) return false;
|
||||||
|
}
|
||||||
|
int si = prepared_path.size_s() - 1, ii = in_path.size_s() - 1;
|
||||||
|
for (; si > any_ind && ii >= 0; --si, --ii) {
|
||||||
|
if (!prepared_path[si].match(in_path[ii], ext_args)) return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (in_path.size() != prepared_path.size()) return false;
|
||||||
|
for (int i = 0; i < prepared_path.size_s(); ++i) {
|
||||||
|
if (!prepared_path[i].match(in_path[i], ext_args)) return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ void PISystemMonitor::run() {
|
|||||||
// piCout << (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_ms;
|
// piCout << (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_ms;
|
||||||
# else
|
# else
|
||||||
PRIVATE->file.seekToBegin();
|
PRIVATE->file.seekToBegin();
|
||||||
PIString str = PIString::fromAscii(PRIVATE->file.readAll(true));
|
PIString str = PIString::fromAscii(PRIVATE->file.readAll());
|
||||||
int si = str.find('(') + 1, fi = 0, cc = 1;
|
int si = str.find('(') + 1, fi = 0, cc = 1;
|
||||||
for (int i = si; i < str.size_s(); ++i) {
|
for (int i = si; i < str.size_s(); ++i) {
|
||||||
if (str[i] == '(') cc++;
|
if (str[i] == '(') cc++;
|
||||||
@@ -250,7 +250,7 @@ void PISystemMonitor::run() {
|
|||||||
// piCout << sl[0] << sl[12] << sl[13];
|
// piCout << sl[0] << sl[12] << sl[13];
|
||||||
|
|
||||||
PRIVATE->filem.seekToBegin();
|
PRIVATE->filem.seekToBegin();
|
||||||
str = PIString::fromAscii(PRIVATE->filem.readAll(true));
|
str = PIString::fromAscii(PRIVATE->filem.readAll());
|
||||||
sl = str.split(" ");
|
sl = str.split(" ");
|
||||||
if (sl.size_s() < 6) return;
|
if (sl.size_s() < 6) return;
|
||||||
tstat.virtual_memsize = sl[0].toLong() * page_size;
|
tstat.virtual_memsize = sl[0].toLong() * page_size;
|
||||||
@@ -341,6 +341,7 @@ void PISystemMonitor::run() {
|
|||||||
stat = tstat;
|
stat = tstat;
|
||||||
stat.makeStrings();
|
stat.makeStrings();
|
||||||
stat_mutex.unlock();
|
stat_mutex.unlock();
|
||||||
|
measured();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -356,7 +357,7 @@ void PISystemMonitor::gatherThread(llong id) {
|
|||||||
PIFile f(PRIVATE->proc_dir + "task/" + PIString::fromNumber(id) + "/stat");
|
PIFile f(PRIVATE->proc_dir + "task/" + PIString::fromNumber(id) + "/stat");
|
||||||
// piCout << f.path();
|
// piCout << f.path();
|
||||||
if (!f.open(PIIODevice::ReadOnly)) return;
|
if (!f.open(PIIODevice::ReadOnly)) return;
|
||||||
PIString str = PIString::fromAscii(f.readAll(true));
|
PIString str = PIString::fromAscii(f.readAll());
|
||||||
int si = str.find('(') + 1, fi = 0, cc = 1;
|
int si = str.find('(') + 1, fi = 0, cc = 1;
|
||||||
for (int i = si; i < str.size_s(); ++i) {
|
for (int i = si; i < str.size_s(); ++i) {
|
||||||
if (str[i] == '(') cc++;
|
if (str[i] == '(') cc++;
|
||||||
|
|||||||
@@ -242,6 +242,9 @@ public:
|
|||||||
//! \~russian
|
//! \~russian
|
||||||
static ullong usedRAM();
|
static ullong usedRAM();
|
||||||
|
|
||||||
|
//! \~english
|
||||||
|
//! \~russian
|
||||||
|
EVENT(measured);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void run() override;
|
void run() override;
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ namespace PIClientServer {
|
|||||||
|
|
||||||
// ServerClient
|
// ServerClient
|
||||||
|
|
||||||
|
//! ~english Server-side client implementation
|
||||||
|
//! ~russian Серверная реализация клиента
|
||||||
class PIP_CLIENT_SERVER_EXPORT ServerClient: public ClientBase {
|
class PIP_CLIENT_SERVER_EXPORT ServerClient: public ClientBase {
|
||||||
friend class Server;
|
friend class Server;
|
||||||
NO_COPY_CLASS(ServerClient);
|
NO_COPY_CLASS(ServerClient);
|
||||||
@@ -41,6 +43,8 @@ public:
|
|||||||
ServerClient() {}
|
ServerClient() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
//! ~english Called before client destruction
|
||||||
|
//! ~russian Вызывается перед уничтожением клиента
|
||||||
virtual void aboutDelete() {}
|
virtual void aboutDelete() {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -50,6 +54,8 @@ private:
|
|||||||
|
|
||||||
// Client
|
// Client
|
||||||
|
|
||||||
|
//! ~english Client implementation for connecting to servers
|
||||||
|
//! ~russian Клиентская реализация для подключения к серверам
|
||||||
class PIP_CLIENT_SERVER_EXPORT Client: public ClientBase {
|
class PIP_CLIENT_SERVER_EXPORT Client: public ClientBase {
|
||||||
NO_COPY_CLASS(Client);
|
NO_COPY_CLASS(Client);
|
||||||
|
|
||||||
@@ -57,6 +63,8 @@ public:
|
|||||||
Client();
|
Client();
|
||||||
~Client();
|
~Client();
|
||||||
|
|
||||||
|
//! ~english Connects to specified server address
|
||||||
|
//! ~russian Подключается к указанному адресу сервера
|
||||||
void connect(PINetworkAddress addr);
|
void connect(PINetworkAddress addr);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ class Server;
|
|||||||
|
|
||||||
class ClientInterface {};
|
class ClientInterface {};
|
||||||
|
|
||||||
|
//! ~english Base class for client-server communication with diagnostics support
|
||||||
|
//! ~russian Базовый класс для клиент-серверного взаимодействия с поддержкой диагностики
|
||||||
// template<bool EnableDiagnostics = false>
|
// template<bool EnableDiagnostics = false>
|
||||||
class PIP_CLIENT_SERVER_EXPORT ClientBase {
|
class PIP_CLIENT_SERVER_EXPORT ClientBase {
|
||||||
friend class Server;
|
friend class Server;
|
||||||
@@ -46,16 +48,39 @@ public:
|
|||||||
ClientBase();
|
ClientBase();
|
||||||
virtual ~ClientBase();
|
virtual ~ClientBase();
|
||||||
|
|
||||||
|
//! ~english Gets underlying TCP connection
|
||||||
|
//! ~russian Возвращает TCP-соединение
|
||||||
const PIEthernet * getTCP() const { return tcp; }
|
const PIEthernet * getTCP() const { return tcp; }
|
||||||
|
|
||||||
|
//! ~english Closes the connection
|
||||||
|
//! ~russian Закрывает соединение
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
|
//! ~english Gracefully stops and waits for completion
|
||||||
|
//! ~russian Плавно останавливает и ожидает завершения
|
||||||
void stopAndWait();
|
void stopAndWait();
|
||||||
|
|
||||||
|
|
||||||
|
//! ~english Writes byte array to the connection
|
||||||
|
//! ~russian Записывает массив байтов в соединение
|
||||||
int write(const void * d, const size_t s);
|
int write(const void * d, const size_t s);
|
||||||
|
|
||||||
|
//! ~english Writes byte array to the connection
|
||||||
|
//! ~russian Записывает массив байтов в соединение
|
||||||
int write(const PIByteArray & ba) { return write(ba.data(), ba.size()); }
|
int write(const PIByteArray & ba) { return write(ba.data(), ba.size()); }
|
||||||
|
|
||||||
|
|
||||||
|
//! ~english Enables diagnostics collection
|
||||||
|
//! ~russian Включает сбор диагностики
|
||||||
void enableDiagnostics();
|
void enableDiagnostics();
|
||||||
|
|
||||||
|
//! ~english Gets current diagnostics state
|
||||||
|
//! ~russian Возвращает текущее состояние диагностики
|
||||||
PIDiagnostics::State diagnostics() const;
|
PIDiagnostics::State diagnostics() const;
|
||||||
|
|
||||||
|
|
||||||
|
//! ~english Gets current received packet bytes already received (all bytes count passed in \a receivePacketStart())
|
||||||
|
//! ~russian Возвращает сколько байт принимаемого пакета получено (общее количество передается в \a receivePacketStart())
|
||||||
int receivePacketProgress() const;
|
int receivePacketProgress() const;
|
||||||
|
|
||||||
const PIStreamPackerConfig & configuration() const { return stream.configuration(); }
|
const PIStreamPackerConfig & configuration() const { return stream.configuration(); }
|
||||||
@@ -63,10 +88,24 @@ public:
|
|||||||
void setConfiguration(const PIStreamPackerConfig & config) { stream.setConfiguration(config); }
|
void setConfiguration(const PIStreamPackerConfig & config) { stream.setConfiguration(config); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
//! ~english Called when data is received
|
||||||
|
//! ~russian Вызывается при получении данных
|
||||||
virtual void readed(PIByteArray data) {}
|
virtual void readed(PIByteArray data) {}
|
||||||
|
|
||||||
|
//! ~english Called when connection is established
|
||||||
|
//! ~russian Вызывается при установке соединения
|
||||||
virtual void connected() {}
|
virtual void connected() {}
|
||||||
|
|
||||||
|
//! ~english Called when connection is closed
|
||||||
|
//! ~russian Вызывается при закрытии соединения
|
||||||
virtual void disconnected() {}
|
virtual void disconnected() {}
|
||||||
|
|
||||||
|
//! ~english Called when packet receiving starts
|
||||||
|
//! ~russian Вызывается при начале получения пакета
|
||||||
virtual void receivePacketStart(int size) {}
|
virtual void receivePacketStart(int size) {}
|
||||||
|
|
||||||
|
//! ~english Called when packet receiving ends
|
||||||
|
//! ~russian Вызывается при завершении получения пакета
|
||||||
virtual void receivePacketEnd() {}
|
virtual void receivePacketEnd() {}
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ namespace PIClientServer {
|
|||||||
|
|
||||||
class ServerClient;
|
class ServerClient;
|
||||||
|
|
||||||
|
//! ~english TCP server for client-server communication
|
||||||
|
//! ~russian TCP сервер для клиент-серверного взаимодействия
|
||||||
class PIP_CLIENT_SERVER_EXPORT Server: public PIStreamPackerConfig {
|
class PIP_CLIENT_SERVER_EXPORT Server: public PIStreamPackerConfig {
|
||||||
friend class ServerClient;
|
friend class ServerClient;
|
||||||
NO_COPY_CLASS(Server);
|
NO_COPY_CLASS(Server);
|
||||||
@@ -46,17 +48,44 @@ public:
|
|||||||
Server();
|
Server();
|
||||||
virtual ~Server();
|
virtual ~Server();
|
||||||
|
|
||||||
|
//! ~english Starts listening on specified address
|
||||||
|
//! ~russian Начинает прослушивание на указанном адресе
|
||||||
void listen(PINetworkAddress addr);
|
void listen(PINetworkAddress addr);
|
||||||
|
|
||||||
|
//! ~english Starts listening on all interfaces
|
||||||
|
//! ~russian Начинает прослушивание на всех интерфейсах
|
||||||
void listenAll(ushort port) { listen({0, port}); }
|
void listenAll(ushort port) { listen({0, port}); }
|
||||||
|
|
||||||
|
|
||||||
|
//! ~english Stops the server
|
||||||
|
//! ~russian Останавливает сервер
|
||||||
void stopServer();
|
void stopServer();
|
||||||
|
|
||||||
|
//! ~english Closes all client connections
|
||||||
|
//! ~russian Закрывает все клиентские соединения
|
||||||
void closeAll();
|
void closeAll();
|
||||||
|
|
||||||
|
|
||||||
|
//! ~english Gets maximum allowed clients
|
||||||
|
//! ~russian Возвращает максимальное число клиентов
|
||||||
int getMaxClients() const { return max_clients; }
|
int getMaxClients() const { return max_clients; }
|
||||||
|
|
||||||
|
//! ~english Sets maximum allowed clients
|
||||||
|
//! ~russian Устанавливает максимальное число клиентов
|
||||||
void setMaxClients(int new_max_clients);
|
void setMaxClients(int new_max_clients);
|
||||||
|
|
||||||
|
//! ~english Gets current clients count
|
||||||
|
//! ~russian Возвращает текущее количество клиентов
|
||||||
int clientsCount() const;
|
int clientsCount() const;
|
||||||
|
|
||||||
|
|
||||||
|
//! ~english Executes function for each connected client
|
||||||
|
//! ~russian Выполняет функцию для каждого подключённого клиента
|
||||||
void forEachClient(std::function<void(ServerClient *)> func);
|
void forEachClient(std::function<void(ServerClient *)> func);
|
||||||
|
|
||||||
|
|
||||||
|
//! ~english Sets factory for creating new client instances
|
||||||
|
//! ~russian Устанавливает фабрику для создания клиентских экземпляров
|
||||||
void setClientFactory(std::function<ServerClient *()> f) { client_factory = f; }
|
void setClientFactory(std::function<ServerClient *()> f) { client_factory = f; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ PICodeInfo::__Storage__::__Storage__() {
|
|||||||
enumsInfo = new PIMap<PIConstChars, EnumInfo *>;
|
enumsInfo = new PIMap<PIConstChars, EnumInfo *>;
|
||||||
accessValueFunctions = new PIMap<PIConstChars, AccessValueFunction>;
|
accessValueFunctions = new PIMap<PIConstChars, AccessValueFunction>;
|
||||||
accessTypeFunctions = new PIMap<PIConstChars, AccessTypeFunction>;
|
accessTypeFunctions = new PIMap<PIConstChars, AccessTypeFunction>;
|
||||||
|
accessOffsetFunctions = new PIMap<PIConstChars, AccessOffsetFunction>;
|
||||||
(*enumsInfo)[""] = new EnumInfo();
|
(*enumsInfo)[""] = new EnumInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,6 +71,7 @@ PICodeInfo::__Storage__::~__Storage__() {
|
|||||||
piDeleteSafety(enumsInfo);
|
piDeleteSafety(enumsInfo);
|
||||||
piDeleteSafety(accessValueFunctions);
|
piDeleteSafety(accessValueFunctions);
|
||||||
piDeleteSafety(accessTypeFunctions);
|
piDeleteSafety(accessTypeFunctions);
|
||||||
|
piDeleteSafety(accessOffsetFunctions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ typedef PIFlags<PICodeInfo::TypeFlag> TypeFlags;
|
|||||||
typedef PIMap<PIString, PIString> MetaMap;
|
typedef PIMap<PIString, PIString> MetaMap;
|
||||||
typedef PIByteArray (*AccessValueFunction)(const void *, const char *);
|
typedef PIByteArray (*AccessValueFunction)(const void *, const char *);
|
||||||
typedef const char * (*AccessTypeFunction)(const char *);
|
typedef const char * (*AccessTypeFunction)(const char *);
|
||||||
|
typedef int (*AccessOffsetFunction)(const char *);
|
||||||
|
|
||||||
|
|
||||||
//! \~english Type information
|
//! \~english Type information
|
||||||
@@ -120,15 +121,15 @@ struct PIP_EXPORT FunctionInfo {
|
|||||||
//! \~english Class or struct information
|
//! \~english Class or struct information
|
||||||
//! \~russian Информация о классе или структуре
|
//! \~russian Информация о классе или структуре
|
||||||
struct PIP_EXPORT ClassInfo {
|
struct PIP_EXPORT ClassInfo {
|
||||||
ClassInfo() { has_name = true; }
|
ClassInfo() { is_anonymous = false; }
|
||||||
|
|
||||||
//! \~english Custom PIMETA content
|
//! \~english Custom PIMETA content
|
||||||
//! \~russian Произвольное содержимое PIMETA
|
//! \~russian Произвольное содержимое PIMETA
|
||||||
MetaMap meta;
|
MetaMap meta;
|
||||||
|
|
||||||
//! \~english Has name or not
|
//! \~english Anonymous or not
|
||||||
//! \~russian Имеет или нет имя
|
//! \~russian Анонимный или нет
|
||||||
bool has_name;
|
bool is_anonymous;
|
||||||
|
|
||||||
//! \~english Type
|
//! \~english Type
|
||||||
//! \~russian Тип
|
//! \~russian Тип
|
||||||
@@ -289,20 +290,24 @@ public:
|
|||||||
PIMap<PIConstChars, PICodeInfo::EnumInfo *> * enumsInfo;
|
PIMap<PIConstChars, PICodeInfo::EnumInfo *> * enumsInfo;
|
||||||
PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * accessValueFunctions;
|
PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * accessValueFunctions;
|
||||||
PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * accessTypeFunctions;
|
PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * accessTypeFunctions;
|
||||||
|
PIMap<PIConstChars, PICodeInfo::AccessOffsetFunction> * accessOffsetFunctions;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NO_COPY_CLASS(__Storage__)
|
NO_COPY_CLASS(__Storage__)
|
||||||
};
|
};
|
||||||
|
|
||||||
class PIP_EXPORT __StorageAccess__ {
|
class PIP_EXPORT
|
||||||
public:
|
__StorageAccess__{public:
|
||||||
//! \~english Getter for single storage of PICodeInfo::ClassInfo, access by name
|
//! \~english Getter for single storage of PICodeInfo::ClassInfo, access by name
|
||||||
//! \~russian Доступ к единому хранилищу PICodeInfo::ClassInfo, доступ по имени
|
//! \~russian Доступ к единому хранилищу PICodeInfo::ClassInfo, доступ по имени
|
||||||
static const PIMap<PIConstChars, PICodeInfo::ClassInfo *> & classes() { return *(__Storage__::instance()->classesInfo); }
|
static const PIMap<PIConstChars, PICodeInfo::ClassInfo *> & classes(){return *(__Storage__::instance()->classesInfo);
|
||||||
|
} // namespace PICodeInfo
|
||||||
|
|
||||||
//! \~english Getter for single storage of PICodeInfo::EnumInfo, access by name
|
//! \~english Getter for single storage of PICodeInfo::EnumInfo, access by name
|
||||||
//! \~russian Доступ к единому хранилищу хранилище PICodeInfo::EnumInfo, доступ по имени
|
//! \~russian Доступ к единому хранилищу хранилище PICodeInfo::EnumInfo, доступ по имени
|
||||||
static const PIMap<PIConstChars, PICodeInfo::EnumInfo *> & enums() { return *(__Storage__::instance()->enumsInfo); }
|
static const PIMap<PIConstChars, PICodeInfo::EnumInfo *> & enums() {
|
||||||
|
return *(__Storage__::instance()->enumsInfo);
|
||||||
|
}
|
||||||
|
|
||||||
static const PIMap<PIConstChars, PICodeInfo::AccessValueFunction> & accessValueFunctions() {
|
static const PIMap<PIConstChars, PICodeInfo::AccessValueFunction> & accessValueFunctions() {
|
||||||
return *(__Storage__::instance()->accessValueFunctions);
|
return *(__Storage__::instance()->accessValueFunctions);
|
||||||
@@ -311,44 +316,51 @@ public:
|
|||||||
static const PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> & accessTypeFunctions() {
|
static const PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> & accessTypeFunctions() {
|
||||||
return *(__Storage__::instance()->accessTypeFunctions);
|
return *(__Storage__::instance()->accessTypeFunctions);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
static const PIMap<PIConstChars, PICodeInfo::AccessOffsetFunction> & accessOffsetFunctions() {
|
||||||
|
return *(__Storage__::instance()->accessOffsetFunctions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
#define PICODEINFO PICodeInfo::__StorageAccess__
|
#define PICODEINFO PICodeInfo::__StorageAccess__
|
||||||
|
|
||||||
|
|
||||||
class PIP_EXPORT ClassInfoInterface {
|
class PIP_EXPORT
|
||||||
public:
|
ClassInfoInterface{public: const PIMap<PIConstChars, PICodeInfo::ClassInfo *> * operator->() const DEPRECATEDM("use PICODEINFO::classes()"){
|
||||||
const PIMap<PIConstChars, PICodeInfo::ClassInfo *> * operator->() const DEPRECATEDM("use PICODEINFO::classes()") {
|
|
||||||
return __Storage__::instance() -> classesInfo;
|
return __Storage__::instance() -> classesInfo;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
;
|
||||||
static ClassInfoInterface classesInfo;
|
static ClassInfoInterface classesInfo;
|
||||||
|
|
||||||
|
|
||||||
class PIP_EXPORT EnumsInfoInterface {
|
class PIP_EXPORT
|
||||||
public:
|
EnumsInfoInterface{public: const PIMap<PIConstChars, PICodeInfo::EnumInfo *> * operator->() const DEPRECATEDM("use PICODEINFO::enums()"){
|
||||||
const PIMap<PIConstChars, PICodeInfo::EnumInfo *> * operator->() const DEPRECATEDM("use PICODEINFO::enums()") {
|
|
||||||
return __Storage__::instance() -> enumsInfo;
|
return __Storage__::instance() -> enumsInfo;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
;
|
||||||
static EnumsInfoInterface enumsInfo;
|
static EnumsInfoInterface enumsInfo;
|
||||||
|
|
||||||
|
|
||||||
class PIP_EXPORT AccessValueFunctionInterface{
|
class PIP_EXPORT AccessValueFunctionInterface{
|
||||||
public:
|
public: const PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * operator->()
|
||||||
const PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * operator->() const DEPRECATEDM("use PICODEINFO::accessValueFunctions()") {
|
const DEPRECATEDM("use PICODEINFO::accessValueFunctions()"){
|
||||||
return __Storage__::instance() -> accessValueFunctions;
|
return __Storage__::instance() -> accessValueFunctions;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
;
|
||||||
static AccessValueFunctionInterface accessValueFunctions;
|
static AccessValueFunctionInterface accessValueFunctions;
|
||||||
|
|
||||||
|
|
||||||
class PIP_EXPORT AccessTypeFunctionInterface{
|
class PIP_EXPORT AccessTypeFunctionInterface{
|
||||||
public:
|
public: const PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * operator->()
|
||||||
const PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * operator->() const DEPRECATEDM("use PICODEINFO::accessTypeFunctions()") {
|
const DEPRECATEDM("use PICODEINFO::accessTypeFunctions()"){
|
||||||
return __Storage__::instance() -> accessTypeFunctions;
|
return __Storage__::instance() -> accessTypeFunctions;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
;
|
||||||
static AccessTypeFunctionInterface accessTypeFunctions;
|
static AccessTypeFunctionInterface accessTypeFunctions;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "picodeparser.h"
|
#include "picodeparser.h"
|
||||||
|
|
||||||
|
#include "piliterals_string.h"
|
||||||
|
|
||||||
|
|
||||||
PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
|
PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
|
||||||
PIStringList arg_vals;
|
PIStringList arg_vals;
|
||||||
@@ -454,7 +456,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
|||||||
cur_namespace += pfc.takeCWord() + s_ns;
|
cur_namespace += pfc.takeCWord() + s_ns;
|
||||||
ccmn = pfc.takeRange('{', '}');
|
ccmn = pfc.takeRange('{', '}');
|
||||||
// piCout << "namespace" << cur_namespace;
|
// piCout << "namespace" << cur_namespace;
|
||||||
parseClass(0, ccmn, true);
|
parseClass(nullptr, ccmn, true);
|
||||||
cur_namespace = prev_namespace;
|
cur_namespace = prev_namespace;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -483,8 +485,8 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ccmn = pfc.left(dind) + s_bo + pfc.mid(dind).takeRange('{', '}') + s_bc;
|
ccmn = pfc.left(dind) + s_bo + pfc.mid(dind).takeRange('{', '}') + s_bc;
|
||||||
pfc.remove(0, ccmn.size());
|
pfc.remove(0, ccmn.size() - 2);
|
||||||
parseClass(0, ccmn, false);
|
parseClass(nullptr, ccmn, false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pfc.left(4) == s_enum) {
|
if (pfc.left(4) == s_enum) {
|
||||||
@@ -499,17 +501,59 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
|||||||
meta << smeta;
|
meta << smeta;
|
||||||
}
|
}
|
||||||
// piCout << "pfc E" << cur_namespace << "," << tmp;
|
// piCout << "pfc E" << cur_namespace << "," << tmp;
|
||||||
parseEnum(0, cur_namespace + tmp, pfc.takeRange('{', '}'), meta);
|
parseEnum(nullptr, cur_namespace + tmp, pfc.takeRange('{', '}'), meta);
|
||||||
pfc.takeSymbol();
|
pfc.takeSymbol();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pfc.left(7) == s_typedef) {
|
if (pfc.left(7) == s_typedef) {
|
||||||
pfc.cutLeft(7);
|
pfc.cutLeft(7);
|
||||||
typedefs << parseTypedef(pfc.takeLeft(pfc.find(';')));
|
PIString typedef_type = pfc.takeCWord();
|
||||||
|
if (typedef_type == s_class || typedef_type == s_struct || typedef_type == s_union) {
|
||||||
|
int dind = pfc.find('{', 0), find = pfc.find(';', 0);
|
||||||
|
if (dind < 0 && find < 0) {
|
||||||
|
pfc.cutLeft(6);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (dind < 0 || find < dind) {
|
||||||
|
pfc.cutLeft(find + 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PIString cname = pfc.left(dind);
|
||||||
|
ccmn = cname + s_bo + pfc.mid(dind).takeRange('{', '}') + s_bc;
|
||||||
|
pfc.remove(0, ccmn.size() - 3);
|
||||||
|
if (cname.trimmed().isEmpty()) {
|
||||||
|
cname = pfc.takeCWord();
|
||||||
|
ccmn.prepend(cname);
|
||||||
|
}
|
||||||
|
ccmn.prepend(typedef_type + " "_a);
|
||||||
|
parseClass(nullptr, ccmn, false);
|
||||||
|
} else if (typedef_type == s_enum) {
|
||||||
|
tmp = pfc.takeCWord();
|
||||||
|
pfc.trim();
|
||||||
|
MetaMap meta = maybeMeta(pfc);
|
||||||
|
if (tmp == s_class || tmp == s_struct) {
|
||||||
|
tmp = pfc.takeCWord();
|
||||||
|
pfc.trim();
|
||||||
|
MetaMap smeta = maybeMeta(pfc);
|
||||||
|
meta << smeta;
|
||||||
|
}
|
||||||
|
ccmn = pfc.takeRange('{', '}');
|
||||||
|
if (tmp.isEmpty()) {
|
||||||
|
tmp = pfc.takeCWord();
|
||||||
|
}
|
||||||
|
// piCout << "pfc E" << cur_namespace << "," << tmp;
|
||||||
|
parseEnum(nullptr, cur_namespace + tmp, ccmn, meta);
|
||||||
|
} else {
|
||||||
|
pfc.prepend(typedef_type);
|
||||||
|
}
|
||||||
|
PIString last = pfc.takeLeft(pfc.find(';')).trim();
|
||||||
|
if (last.isNotEmpty()) {
|
||||||
|
typedefs << parseTypedef(last);
|
||||||
if (typedefs.back().first.isEmpty())
|
if (typedefs.back().first.isEmpty())
|
||||||
typedefs.pop_back();
|
typedefs.pop_back();
|
||||||
else
|
else
|
||||||
root_.typedefs << typedefs.back();
|
root_.typedefs << typedefs.back();
|
||||||
|
}
|
||||||
pfc.takeSymbol();
|
pfc.takeSymbol();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -567,15 +611,14 @@ PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc)
|
|||||||
Visibility vis = cur_def_vis;
|
Visibility vis = cur_def_vis;
|
||||||
cur_def_vis = (is_class ? Private : Public);
|
cur_def_vis = (is_class ? Private : Public);
|
||||||
PIString cn = cd.mid(6).trim();
|
PIString cn = cd.mid(6).trim();
|
||||||
bool has_name = !cn.isEmpty();
|
bool is_anonymous = cn.isEmpty();
|
||||||
if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>';
|
if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>';
|
||||||
// piCout << "found " << typename_ << cn;
|
// piCout << "found " << typename_ << cn;
|
||||||
if (cn.isEmpty()) return nullptr;
|
|
||||||
Entity * e = new Entity();
|
Entity * e = new Entity();
|
||||||
e->meta = meta;
|
e->meta = meta;
|
||||||
e->name = cur_namespace + cn;
|
e->name = cur_namespace + cn;
|
||||||
e->type = typename_;
|
e->type = typename_;
|
||||||
e->has_name = has_name;
|
e->is_anonymous = is_anonymous;
|
||||||
e->parents = parents;
|
e->parents = parents;
|
||||||
e->visibility = vis;
|
e->visibility = vis;
|
||||||
e->file = cur_file;
|
e->file = cur_file;
|
||||||
@@ -584,7 +627,7 @@ PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace) {
|
PICodeParser::Entity * PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace) {
|
||||||
static const PIString s_ns = PIStringAscii("::");
|
static const PIString s_ns = PIStringAscii("::");
|
||||||
static const PIString s_public = PIStringAscii("public");
|
static const PIString s_public = PIStringAscii("public");
|
||||||
static const PIString s_protected = PIStringAscii("protected");
|
static const PIString s_protected = PIStringAscii("protected");
|
||||||
@@ -599,7 +642,7 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
|
|||||||
static const PIString s_template = PIStringAscii("template");
|
static const PIString s_template = PIStringAscii("template");
|
||||||
Visibility prev_vis = cur_def_vis;
|
Visibility prev_vis = cur_def_vis;
|
||||||
int dind = fc.find('{'), find = fc.find(';'), end = 0;
|
int dind = fc.find('{'), find = fc.find(';'), end = 0;
|
||||||
if (dind < 0 && find < 0) return;
|
if (dind < 0 && find < 0) return nullptr;
|
||||||
// piCout << "parse class <****\n" << fc << "\n****>";
|
// piCout << "parse class <****\n" << fc << "\n****>";
|
||||||
Entity * ce = parent;
|
Entity * ce = parent;
|
||||||
if (!is_namespace) {
|
if (!is_namespace) {
|
||||||
@@ -608,7 +651,6 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
|
|||||||
}
|
}
|
||||||
// piCout << "found class <****\n" << fc << "\n****>";
|
// piCout << "found class <****\n" << fc << "\n****>";
|
||||||
if (ce) {
|
if (ce) {
|
||||||
if (parent) parent->children << ce;
|
|
||||||
ce->parent_scope = parent;
|
ce->parent_scope = parent;
|
||||||
}
|
}
|
||||||
int ps = -1;
|
int ps = -1;
|
||||||
@@ -650,11 +692,29 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
|
|||||||
fc.takeSymbol();
|
fc.takeSymbol();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tmp = fc.takeLeft(fc.find('{'));
|
tmp = fc.takeLeft(fc.find('{')).trim();
|
||||||
stmp = fc.takeRange('{', '}');
|
stmp = fc.takeRange('{', '}');
|
||||||
fc.takeSymbol();
|
|
||||||
stmp = cw + ' ' + tmp + '{' + stmp + '}';
|
stmp = cw + ' ' + tmp + '{' + stmp + '}';
|
||||||
parseClass(ce, stmp, false);
|
auto new_entity = parseClass(ce, stmp, false);
|
||||||
|
// piCout << "!!! > \"" << fc << "\"";
|
||||||
|
PIStringList vars;
|
||||||
|
PIString var;
|
||||||
|
do {
|
||||||
|
var = fc.takeCWord();
|
||||||
|
if (var.isNotEmpty()) vars << var;
|
||||||
|
if (fc.takeSymbol() == ";") break;
|
||||||
|
} while (var.isNotEmpty());
|
||||||
|
if (new_entity) {
|
||||||
|
Member me;
|
||||||
|
me.visibility = cur_def_vis;
|
||||||
|
me.type = new_entity->name;
|
||||||
|
if (tmp.isEmpty() && vars.isEmpty()) vars = {""};
|
||||||
|
for (const auto & v: vars) {
|
||||||
|
me.name = v;
|
||||||
|
ce->members << me;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// piCout << "!!! <" << vars;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (cw == s_enum) {
|
if (cw == s_enum) {
|
||||||
@@ -710,6 +770,7 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
|
|||||||
}
|
}
|
||||||
cur_def_vis = prev_vis;
|
cur_def_vis = prev_vis;
|
||||||
cur_namespace = prev_namespace;
|
cur_namespace = prev_namespace;
|
||||||
|
return ce;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -766,7 +827,7 @@ bool PICodeParser::parseEnum(Entity * parent, const PIString & name, PIString fc
|
|||||||
|
|
||||||
|
|
||||||
PICodeParser::Typedef PICodeParser::parseTypedef(PIString fc) {
|
PICodeParser::Typedef PICodeParser::parseTypedef(PIString fc) {
|
||||||
// piCout << "parse typedef" << fc;
|
// piCout << "parse typedef \"" << fc << "\"";
|
||||||
Typedef td;
|
Typedef td;
|
||||||
fc.replaceAll('\t', ' ');
|
fc.replaceAll('\t', ' ');
|
||||||
|
|
||||||
@@ -1197,7 +1258,7 @@ void PICodeParser::replaceMeta(PIString & dn) {
|
|||||||
PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) {
|
PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) {
|
||||||
for (auto * e: entities)
|
for (auto * e: entities)
|
||||||
if (e->name == en) return e;
|
if (e->name == en) return e;
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ public:
|
|||||||
struct PIP_EXPORT Entity {
|
struct PIP_EXPORT Entity {
|
||||||
Entity() {
|
Entity() {
|
||||||
visibility = Global;
|
visibility = Global;
|
||||||
has_name = true;
|
is_anonymous = false;
|
||||||
size = 0;
|
size = 0;
|
||||||
parent_scope = 0;
|
parent_scope = 0;
|
||||||
}
|
}
|
||||||
@@ -110,10 +110,9 @@ public:
|
|||||||
PIString file;
|
PIString file;
|
||||||
Visibility visibility;
|
Visibility visibility;
|
||||||
int size;
|
int size;
|
||||||
bool has_name;
|
bool is_anonymous;
|
||||||
Entity * parent_scope;
|
Entity * parent_scope;
|
||||||
PIVector<Entity *> parents;
|
PIVector<Entity *> parents;
|
||||||
PIVector<Entity *> children;
|
|
||||||
PIVector<Member> functions;
|
PIVector<Member> functions;
|
||||||
PIVector<Member> members;
|
PIVector<Member> members;
|
||||||
PIVector<Typedef> typedefs;
|
PIVector<Typedef> typedefs;
|
||||||
@@ -164,7 +163,7 @@ private:
|
|||||||
bool parseFileContent(PIString & fc, bool main);
|
bool parseFileContent(PIString & fc, bool main);
|
||||||
bool parseDirective(PIString d);
|
bool parseDirective(PIString d);
|
||||||
Entity * parseClassDeclaration(const PIString & fc);
|
Entity * parseClassDeclaration(const PIString & fc);
|
||||||
void parseClass(Entity * parent, PIString & fc, bool is_namespace);
|
Entity * parseClass(Entity * parent, PIString & fc, bool is_namespace);
|
||||||
MetaMap parseMeta(PIString & fc);
|
MetaMap parseMeta(PIString & fc);
|
||||||
bool parseEnum(Entity * parent, const PIString & name, PIString fc, const MetaMap & meta);
|
bool parseEnum(Entity * parent, const PIString & name, PIString fc, const MetaMap & meta);
|
||||||
Typedef parseTypedef(PIString fc);
|
Typedef parseTypedef(PIString fc);
|
||||||
|
|||||||
@@ -365,8 +365,8 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
if (other.size() == 2) {
|
if (other.size() == 2) {
|
||||||
insert(other.pim_index[0].key, other.pim_content[0]);
|
insert(other.pim_index[0].key, other.pim_content[other.pim_index[0].index]);
|
||||||
insert(other.pim_index[1].key, other.pim_content[1]);
|
insert(other.pim_index[1].key, other.pim_content[other.pim_index[1].index]);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < other.pim_index.size_s(); ++i) {
|
for (int i = 0; i < other.pim_index.size_s(); ++i) {
|
||||||
|
|||||||
@@ -333,9 +333,10 @@ typedef long long ssize_t;
|
|||||||
__PrivateInitializer__ __privateinitializer__;
|
__PrivateInitializer__ __privateinitializer__;
|
||||||
|
|
||||||
# define PRIVATE_DEFINITION_START(c) struct c::__Private__ {
|
# define PRIVATE_DEFINITION_START(c) struct c::__Private__ {
|
||||||
# define PRIVATE_DEFINITION_END(c) \
|
# define PRIVATE_DEFINITION_END_NO_INITIALIZE(c) \
|
||||||
} \
|
} \
|
||||||
; \
|
;
|
||||||
|
# define PRIVATE_DEFINITION_INITIALIZE(c) \
|
||||||
c::__PrivateInitializer__::__PrivateInitializer__() { \
|
c::__PrivateInitializer__::__PrivateInitializer__() { \
|
||||||
p = new c::__Private__(); \
|
p = new c::__Private__(); \
|
||||||
} \
|
} \
|
||||||
@@ -350,6 +351,10 @@ typedef long long ssize_t;
|
|||||||
p = new c::__Private__(); \
|
p = new c::__Private__(); \
|
||||||
return *this; \
|
return *this; \
|
||||||
}
|
}
|
||||||
|
# define PRIVATE_DEFINITION_END(c) \
|
||||||
|
PRIVATE_DEFINITION_END_NO_INITIALIZE \
|
||||||
|
(c) PRIVATE_DEFINITION_INITIALIZE(c)
|
||||||
|
|
||||||
|
|
||||||
# define PRIVATE (__privateinitializer__.p)
|
# define PRIVATE (__privateinitializer__.p)
|
||||||
# define PRIVATEWB __privateinitializer__.p
|
# define PRIVATEWB __privateinitializer__.p
|
||||||
|
|||||||
@@ -13,23 +13,51 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! ~english Main HTTP client class for performing requests with event callbacks.
|
||||||
|
//! ~russian Основной класс HTTP-клиента для выполнения запросов с callback-ми событий.
|
||||||
class PIP_HTTP_CLIENT_EXPORT PIHTTPClient: private PIHTTPClientBase {
|
class PIP_HTTP_CLIENT_EXPORT PIHTTPClient: private PIHTTPClientBase {
|
||||||
friend class PIHTTPClientBase;
|
friend class PIHTTPClientBase;
|
||||||
friend class CurlThreadPool;
|
friend class CurlThreadPool;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
//! ~english Creates a new HTTP request instance with the specified URL, method and message.
|
||||||
|
//! ~russian Создает новый экземпляр HTTP-запроса с указанным URL, методом и сообщением.
|
||||||
static PIHTTPClient * create(const PIString & url, PIHTTP::Method method = PIHTTP::Method::Get, const PIHTTP::MessageConst & req = {});
|
static PIHTTPClient * create(const PIString & url, PIHTTP::Method method = PIHTTP::Method::Get, const PIHTTP::MessageConst & req = {});
|
||||||
|
|
||||||
|
//! ~english Sets a callback for successful request completion (no parameters).
|
||||||
|
//! ~russian Устанавливает callback для успешного завершения запроса (без параметров).
|
||||||
PIHTTPClient * onFinish(std::function<void()> f);
|
PIHTTPClient * onFinish(std::function<void()> f);
|
||||||
|
|
||||||
|
//! ~english Sets a callback for successful request completion (with response).
|
||||||
|
//! ~russian Устанавливает callback для успешного завершения запроса (с ответом).
|
||||||
PIHTTPClient * onFinish(std::function<void(const PIHTTP::MessageConst &)> f);
|
PIHTTPClient * onFinish(std::function<void(const PIHTTP::MessageConst &)> f);
|
||||||
|
|
||||||
|
//! ~english Sets a callback for request errors (no parameters).
|
||||||
|
//! ~russian Устанавливает callback для ошибок запроса (без параметров).
|
||||||
PIHTTPClient * onError(std::function<void()> f);
|
PIHTTPClient * onError(std::function<void()> f);
|
||||||
|
|
||||||
|
//! ~english Sets a callback for request errors (with error response).
|
||||||
|
//! ~russian Устанавливает callback для ошибок запроса (с ответом об ошибке).
|
||||||
PIHTTPClient * onError(std::function<void(const PIHTTP::MessageConst &)> f);
|
PIHTTPClient * onError(std::function<void(const PIHTTP::MessageConst &)> f);
|
||||||
|
|
||||||
|
//! ~english Sets a callback for request abortion (no parameters).
|
||||||
|
//! ~russian Устанавливает callback для прерывания запроса (без параметров).
|
||||||
PIHTTPClient * onAbort(std::function<void()> f);
|
PIHTTPClient * onAbort(std::function<void()> f);
|
||||||
|
|
||||||
|
//! ~english Sets a callback for request abortion (with abort response).
|
||||||
|
//! ~russian Устанавливает callback для прерывания запроса (с ответом о прерывании).
|
||||||
PIHTTPClient * onAbort(std::function<void(const PIHTTP::MessageConst &)> f);
|
PIHTTPClient * onAbort(std::function<void(const PIHTTP::MessageConst &)> f);
|
||||||
|
|
||||||
|
//! ~english Starts the HTTP request execution.
|
||||||
|
//! ~russian Начинает выполнение HTTP-запроса.
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
|
//! ~english Aborts the current HTTP request.
|
||||||
|
//! ~russian Прерывает текущий HTTP-запрос.
|
||||||
void abort();
|
void abort();
|
||||||
|
|
||||||
|
//! ~english Returns the last error message.
|
||||||
|
//! ~russian Возвращает последнее сообщение об ошибке.
|
||||||
PIString lastError() const { return last_error; }
|
PIString lastError() const { return last_error; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -59,14 +59,26 @@ PIHTTP::MessageMutable & PIHTTP::MessageMutable::removeHeader(const PIString & h
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIHTTP::MessageMutable & PIHTTP::MessageMutable::addArgument(const PIString & arg, const PIString & value) {
|
PIHTTP::MessageMutable & PIHTTP::MessageMutable::addQueryArgument(const PIString & arg, const PIString & value) {
|
||||||
m_arguments[arg] = value;
|
m_query_arguments[arg] = value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIHTTP::MessageMutable & PIHTTP::MessageMutable::removeArgument(const PIString & arg) {
|
PIHTTP::MessageMutable & PIHTTP::MessageMutable::removeQueryArgument(const PIString & arg) {
|
||||||
m_arguments.remove(arg);
|
m_query_arguments.remove(arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIHTTP::MessageMutable & PIHTTP::MessageMutable::addPathArgument(const PIString & arg, const PIString & value) {
|
||||||
|
m_path_arguments[arg] = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIHTTP::MessageMutable & PIHTTP::MessageMutable::removePathArgument(const PIString & arg) {
|
||||||
|
m_path_arguments.remove(arg);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,20 +9,68 @@
|
|||||||
namespace PIHTTP {
|
namespace PIHTTP {
|
||||||
|
|
||||||
|
|
||||||
|
//! ~english Immutable HTTP message container with accessors for message components
|
||||||
|
//! ~russian Контейнер для неизменяемого HTTP-сообщения с методами доступа к компонентам
|
||||||
class PIP_EXPORT MessageConst {
|
class PIP_EXPORT MessageConst {
|
||||||
public:
|
public:
|
||||||
|
//! ~english Gets the HTTP method used in the message
|
||||||
|
//! ~russian Возвращает HTTP-метод, использованный в сообщении
|
||||||
PIHTTP::Method method() const { return m_method; }
|
PIHTTP::Method method() const { return m_method; }
|
||||||
|
|
||||||
|
//! ~english Gets the HTTP status code
|
||||||
|
//! ~russian Возвращает HTTP-статус код
|
||||||
PIHTTP::Code code() const { return m_code; }
|
PIHTTP::Code code() const { return m_code; }
|
||||||
|
|
||||||
|
//! ~english Checks if status code is informational (1xx)
|
||||||
|
//! ~russian Проверяет, является ли статус код информационным (1xx)
|
||||||
bool isCodeInformational() const;
|
bool isCodeInformational() const;
|
||||||
|
|
||||||
|
//! ~english Checks if status code indicates success (2xx)
|
||||||
|
//! ~russian Проверяет, указывает ли статус код на успех (2xx)
|
||||||
bool isCodeSuccess() const;
|
bool isCodeSuccess() const;
|
||||||
|
|
||||||
|
//! ~english Checks if status code indicates redirection (3xx)
|
||||||
|
//! ~russian Проверяет, указывает ли статус код на перенаправление (3xx)
|
||||||
bool isCodeRedirection() const;
|
bool isCodeRedirection() const;
|
||||||
|
|
||||||
|
//! ~english Checks if status code indicates client error (4xx)
|
||||||
|
//! ~russian Проверяет, указывает ли статус код на ошибку клиента (4xx)
|
||||||
bool isCodeClientError() const;
|
bool isCodeClientError() const;
|
||||||
|
|
||||||
|
//! ~english Checks if status code indicates server error (5xx)
|
||||||
|
//! ~russian Проверяет, указывает ли статус код на ошибку сервера (5xx)
|
||||||
bool isCodeServerError() const;
|
bool isCodeServerError() const;
|
||||||
|
|
||||||
|
//! ~english Checks if status code indicates any error (4xx or 5xx)
|
||||||
|
//! ~russian Проверяет, указывает ли статус код на любую ошибку (4xx или 5xx)
|
||||||
bool isCodeError() const { return isCodeClientError() || isCodeServerError(); }
|
bool isCodeError() const { return isCodeClientError() || isCodeServerError(); }
|
||||||
|
|
||||||
|
//! ~english Gets the request/response path
|
||||||
|
//! ~russian Возвращает путь запроса/ответа
|
||||||
const PIString & path() const { return m_path; }
|
const PIString & path() const { return m_path; }
|
||||||
|
|
||||||
|
//! ~english Gets path components as list
|
||||||
|
//! ~russian Возвращает компоненты пути в виде списка
|
||||||
PIStringList pathList() const { return m_path.split('/').removeAll({}); }
|
PIStringList pathList() const { return m_path.split('/').removeAll({}); }
|
||||||
|
|
||||||
|
//! ~english Gets the message body
|
||||||
|
//! ~russian Возвращает тело сообщения
|
||||||
const PIByteArray & body() const { return m_body; }
|
const PIByteArray & body() const { return m_body; }
|
||||||
|
|
||||||
|
//! ~english Gets all message headers
|
||||||
|
//! ~russian Возвращает все заголовки сообщения
|
||||||
const PIMap<PIString, PIString> & headers() const { return m_headers; }
|
const PIMap<PIString, PIString> & headers() const { return m_headers; }
|
||||||
|
|
||||||
|
//! ~english Gets URL query arguments
|
||||||
|
//! ~russian Возвращает URL query аргументы
|
||||||
|
const PIMap<PIString, PIString> & queryArguments() const { return m_query_arguments; }
|
||||||
|
|
||||||
|
//! ~english Gets URL path arguments
|
||||||
|
//! ~russian Возвращает URL path аргументы
|
||||||
|
const PIMap<PIString, PIString> & pathArguments() const { return m_path_arguments; }
|
||||||
|
|
||||||
|
//! ~english Gets all message arguments (query + path)
|
||||||
|
//! ~russian Возвращает все аргументы сообщения (query + path)
|
||||||
const PIMap<PIString, PIString> & arguments() const { return m_arguments; }
|
const PIMap<PIString, PIString> & arguments() const { return m_arguments; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -31,29 +79,82 @@ protected:
|
|||||||
PIString m_path;
|
PIString m_path;
|
||||||
PIByteArray m_body;
|
PIByteArray m_body;
|
||||||
PIMap<PIString, PIString> m_headers;
|
PIMap<PIString, PIString> m_headers;
|
||||||
PIMap<PIString, PIString> m_arguments;
|
PIMap<PIString, PIString> m_query_arguments, m_path_arguments, m_arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! ~english Mutable HTTP message container with modifiers for message components
|
||||||
|
//! ~russian Контейнер для изменяемого HTTP-сообщения с методами модификации
|
||||||
class PIP_EXPORT MessageMutable: public MessageConst {
|
class PIP_EXPORT MessageMutable: public MessageConst {
|
||||||
public:
|
public:
|
||||||
|
//! ~english Sets the HTTP method
|
||||||
|
//! ~russian Устанавливает HTTP-метод
|
||||||
MessageMutable & setMethod(PIHTTP::Method m);
|
MessageMutable & setMethod(PIHTTP::Method m);
|
||||||
|
|
||||||
|
//! ~english Sets the HTTP status code
|
||||||
|
//! ~russian Устанавливает HTTP-статус код
|
||||||
MessageMutable & setCode(PIHTTP::Code c);
|
MessageMutable & setCode(PIHTTP::Code c);
|
||||||
|
|
||||||
|
//! ~english Sets the request/response path
|
||||||
|
//! ~russian Устанавливает путь запроса/ответа
|
||||||
MessageMutable & setPath(PIString p);
|
MessageMutable & setPath(PIString p);
|
||||||
|
|
||||||
|
//! ~english Sets the message body
|
||||||
|
//! ~russian Устанавливает тело сообщения
|
||||||
MessageMutable & setBody(PIByteArray b);
|
MessageMutable & setBody(PIByteArray b);
|
||||||
|
|
||||||
const PIMap<PIString, PIString> & headers() const { return m_headers; }
|
const PIMap<PIString, PIString> & headers() const { return m_headers; }
|
||||||
const PIMap<PIString, PIString> & arguments() const { return m_arguments; }
|
|
||||||
PIMap<PIString, PIString> & headers() { return m_headers; }
|
|
||||||
MessageMutable & addHeader(const PIString & header, const PIString & value);
|
|
||||||
MessageMutable & removeHeader(const PIString & header);
|
|
||||||
PIMap<PIString, PIString> & arguments() { return m_arguments; }
|
PIMap<PIString, PIString> & arguments() { return m_arguments; }
|
||||||
MessageMutable & addArgument(const PIString & arg, const PIString & value);
|
const PIMap<PIString, PIString> & arguments() const { return m_arguments; }
|
||||||
MessageMutable & removeArgument(const PIString & arg);
|
const PIMap<PIString, PIString> & queryArguments() const { return m_query_arguments; }
|
||||||
|
const PIMap<PIString, PIString> & pathArguments() const { return m_path_arguments; }
|
||||||
|
|
||||||
|
PIMap<PIString, PIString> & headers() { return m_headers; }
|
||||||
|
|
||||||
|
//! ~english Adds a header to the message
|
||||||
|
//! ~russian Добавляет заголовок к сообщению
|
||||||
|
MessageMutable & addHeader(const PIString & header, const PIString & value);
|
||||||
|
|
||||||
|
//! ~english Removes a header from the message
|
||||||
|
//! ~russian Удаляет заголовок из сообщения
|
||||||
|
MessageMutable & removeHeader(const PIString & header);
|
||||||
|
|
||||||
|
//! ~english Gets reference to URL query arguments
|
||||||
|
//! ~russian Возвращает ссылку на URL query аргументы
|
||||||
|
PIMap<PIString, PIString> & queryArguments() { return m_query_arguments; }
|
||||||
|
|
||||||
|
//! ~english Adds an URL query argument to the message
|
||||||
|
//! ~russian Добавляет URL query аргумент к сообщению
|
||||||
|
MessageMutable & addQueryArgument(const PIString & arg, const PIString & value);
|
||||||
|
|
||||||
|
//! ~english Removes an URL query argument from the message
|
||||||
|
//! ~russian Удаляет URL query аргумент из сообщения
|
||||||
|
MessageMutable & removeQueryArgument(const PIString & arg);
|
||||||
|
|
||||||
|
//! ~english Gets reference to URL path arguments
|
||||||
|
//! ~russian Возвращает ссылку на URL path аргументы
|
||||||
|
PIMap<PIString, PIString> & pathArguments() { return m_path_arguments; }
|
||||||
|
|
||||||
|
//! ~english Adds an URL path argument to the message
|
||||||
|
//! ~russian Добавляет URL path аргумент к сообщению
|
||||||
|
MessageMutable & addPathArgument(const PIString & arg, const PIString & value);
|
||||||
|
|
||||||
|
//! ~english Removes an URL path argument from the message
|
||||||
|
//! ~russian Удаляет URL query path из сообщения
|
||||||
|
MessageMutable & removePathArgument(const PIString & arg);
|
||||||
|
|
||||||
|
//! ~english Creates message from HTTP status code
|
||||||
|
//! ~russian Создает сообщение из HTTP-статус кода
|
||||||
static MessageMutable fromCode(PIHTTP::Code c);
|
static MessageMutable fromCode(PIHTTP::Code c);
|
||||||
|
|
||||||
|
//! ~english Creates message from HTTP method
|
||||||
|
//! ~russian Создает сообщение из HTTP-метода
|
||||||
static MessageMutable fromMethod(PIHTTP::Method m);
|
static MessageMutable fromMethod(PIHTTP::Method m);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! ~english Gets string representation of HTTP method
|
||||||
|
//! ~russian Возвращает строковое представление HTTP-метода
|
||||||
PIP_EXPORT const char * methodName(Method m);
|
PIP_EXPORT const char * methodName(Method m);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
struct MicrohttpdServerConnection;
|
struct MicrohttpdServerConnection;
|
||||||
|
|
||||||
|
//! ~english Base HTTP server class implementing core functionality
|
||||||
|
//! ~runnan Базовый класс HTTP сервера, реализующий основную функциональность
|
||||||
class PIP_HTTP_SERVER_EXPORT MicrohttpdServer: public PIObject {
|
class PIP_HTTP_SERVER_EXPORT MicrohttpdServer: public PIObject {
|
||||||
PIOBJECT(MicrohttpdServer)
|
PIOBJECT(MicrohttpdServer)
|
||||||
friend struct MicrohttpdServerConnection;
|
friend struct MicrohttpdServerConnection;
|
||||||
@@ -15,30 +17,75 @@ public:
|
|||||||
MicrohttpdServer();
|
MicrohttpdServer();
|
||||||
virtual ~MicrohttpdServer();
|
virtual ~MicrohttpdServer();
|
||||||
|
|
||||||
|
//! ~english Server configuration options
|
||||||
|
//! ~russian Опции конфигурации сервера
|
||||||
enum class Option {
|
enum class Option {
|
||||||
ConnectionLimit, // uint
|
ConnectionLimit, //!< ~english Maximum concurrent connections
|
||||||
ConnectionTimeout, // uint, sec
|
//!< ~russian Максимальное количество соединений
|
||||||
HTTPSEnabled, // bool
|
ConnectionTimeout, //!< ~english Connection timeout in seconds
|
||||||
HTTPSMemKey, // const char * to key.pem data
|
//!< ~russian Таймаут соединения в секундах
|
||||||
HTTPSMemCert, // const char * to cert.pem data
|
HTTPSEnabled, //!< ~english Enable HTTPS support
|
||||||
HTTPSKeyPassword // const char * to passwd for key.pem
|
//!< ~russian Включить поддержку HTTPS
|
||||||
|
HTTPSMemKey, //!< ~english SSL key in memory (PIByteArray)
|
||||||
|
//!< ~russian SSL ключ в памяти (PIByteArray)
|
||||||
|
HTTPSMemCert, //!< ~english SSL certificate in memory (PIByteArray)
|
||||||
|
//!< ~russian SSL сертификат в памяти (PIByteArray)
|
||||||
|
HTTPSKeyPassword //!< ~english SSL key password (PIByteArray)
|
||||||
|
//!< ~russian Пароль SSL ключа (PIByteArray)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! ~english Sets server option
|
||||||
|
//! ~russian Устанавливает опцию сервера
|
||||||
void setOption(Option o, PIVariant v);
|
void setOption(Option o, PIVariant v);
|
||||||
|
|
||||||
|
//! ~english Sets server favicon
|
||||||
|
//! ~russian Устанавливает фавикон сервера
|
||||||
void setFavicon(const PIByteArray & im);
|
void setFavicon(const PIByteArray & im);
|
||||||
|
|
||||||
|
|
||||||
|
//! ~english Starts server on specified address
|
||||||
|
//! ~russian Запускает сервер на указанном адресе
|
||||||
bool listen(PINetworkAddress addr);
|
bool listen(PINetworkAddress addr);
|
||||||
|
|
||||||
|
//! ~english Starts server on all interfaces
|
||||||
|
//! ~russian Запускает сервер на всех интерфейсах
|
||||||
bool listenAll(ushort port) { return listen({0, port}); }
|
bool listenAll(ushort port) { return listen({0, port}); }
|
||||||
|
|
||||||
|
//! ~english Checks if server is running
|
||||||
|
//! ~russian Проверяет, работает ли сервер
|
||||||
bool isListen() const;
|
bool isListen() const;
|
||||||
|
|
||||||
|
//! ~english Stops the server
|
||||||
|
//! ~russian Останавливает сервер
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
|
|
||||||
|
//! ~english Enables basic authentication
|
||||||
|
//! ~russian Включает базовую аутентификацию
|
||||||
void enableBasicAuth() { setBasicAuthEnabled(true); }
|
void enableBasicAuth() { setBasicAuthEnabled(true); }
|
||||||
|
|
||||||
|
//! ~english Disables basic authentication
|
||||||
|
//! ~russian Выключает базовую аутентификацию
|
||||||
void disableBasicAuth() { setBasicAuthEnabled(false); }
|
void disableBasicAuth() { setBasicAuthEnabled(false); }
|
||||||
|
|
||||||
|
//! ~english Set basic authentication enabled to "yes"
|
||||||
|
//! ~russian Устанавливает базовую аутентификацию в "yes"
|
||||||
void setBasicAuthEnabled(bool yes) { use_basic_auth = yes; }
|
void setBasicAuthEnabled(bool yes) { use_basic_auth = yes; }
|
||||||
|
|
||||||
|
//! ~english Return if basic authentication enabled
|
||||||
|
//! ~russian Возвращает включена ли базовая аутентификация
|
||||||
bool isBasicAuthEnabled() const { return use_basic_auth; }
|
bool isBasicAuthEnabled() const { return use_basic_auth; }
|
||||||
|
|
||||||
|
//! ~english Sets basic authentication realm
|
||||||
|
//! ~russian Устанавливает область аутентификации
|
||||||
void setBasicAuthRealm(const PIString & r) { realm = r; }
|
void setBasicAuthRealm(const PIString & r) { realm = r; }
|
||||||
|
|
||||||
|
//! ~english Sets request processing callback
|
||||||
|
//! ~russian Устанавливает callback для обработки запросов
|
||||||
void setRequestCallback(std::function<PIHTTP::MessageMutable(const PIHTTP::MessageConst &)> c) { callback = c; }
|
void setRequestCallback(std::function<PIHTTP::MessageMutable(const PIHTTP::MessageConst &)> c) { callback = c; }
|
||||||
|
|
||||||
|
//! ~english Sets basic authentication callback
|
||||||
|
//! ~russian Устанавливает callback для базовой аутентификации
|
||||||
void setBasicAuthCallback(std::function<bool(const PIString &, const PIString &)> c) { callback_auth = c; }
|
void setBasicAuthCallback(std::function<bool(const PIString &, const PIString &)> c) { callback_auth = c; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "microhttpd_server.h"
|
#include "microhttpd_server.h"
|
||||||
|
|
||||||
|
//! ~english HTTP server
|
||||||
|
//! ~russian HTTP сервер
|
||||||
class PIP_HTTP_SERVER_EXPORT PIHTTPServer: public MicrohttpdServer {
|
class PIP_HTTP_SERVER_EXPORT PIHTTPServer: public MicrohttpdServer {
|
||||||
PIOBJECT_SUBCLASS(PIHTTPServer, MicrohttpdServer)
|
PIOBJECT_SUBCLASS(PIHTTPServer, MicrohttpdServer)
|
||||||
|
|
||||||
@@ -12,35 +14,90 @@ public:
|
|||||||
|
|
||||||
using RequestFunction = std::function<PIHTTP::MessageMutable(const PIHTTP::MessageConst &)>;
|
using RequestFunction = std::function<PIHTTP::MessageMutable(const PIHTTP::MessageConst &)>;
|
||||||
|
|
||||||
void registerPath(const PIString & path, PIHTTP::Method method, RequestFunction functor);
|
|
||||||
|
//! ~english Registers handler for specific path and HTTP method
|
||||||
|
//! ~russian Регистрирует обработчик для указанного пути и HTTP метода
|
||||||
|
bool registerPath(const PIString & path, PIHTTP::Method method, RequestFunction functor);
|
||||||
|
|
||||||
|
//! ~english Registers handler for specific path and HTTP method
|
||||||
|
//! ~russian Регистрирует обработчик для указанного пути и HTTP метода
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void
|
bool
|
||||||
registerPath(const PIString & path, PIHTTP::Method method, T * o, PIHTTP::MessageMutable (T::*function)(const PIHTTP::MessageConst &)) {
|
registerPath(const PIString & path, PIHTTP::Method method, T * o, PIHTTP::MessageMutable (T::*function)(const PIHTTP::MessageConst &)) {
|
||||||
registerPath(path, method, [o, function](const PIHTTP::MessageConst & m) { return (o->*function)(m); });
|
return registerPath(path, method, [o, function](const PIHTTP::MessageConst & m) { return (o->*function)(m); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! ~english Registers handler for unregistered pathes
|
||||||
|
//! ~russian Регистрирует обработчик для незарегистрированных путей
|
||||||
void registerUnhandled(RequestFunction functor);
|
void registerUnhandled(RequestFunction functor);
|
||||||
|
|
||||||
|
//! ~english Registers handler for unregistered pathes
|
||||||
|
//! ~russian Регистрирует обработчик для незарегистрированных путей
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void registerUnhandled(T * o, PIHTTP::MessageMutable (T::*function)(const PIHTTP::MessageConst &)) {
|
void registerUnhandled(T * o, PIHTTP::MessageMutable (T::*function)(const PIHTTP::MessageConst &)) {
|
||||||
registerUnhandled([o, function](const PIHTTP::MessageConst & m) { return (o->*function)(m); });
|
registerUnhandled([o, function](const PIHTTP::MessageConst & m) { return (o->*function)(m); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! ~english Unregisters handler for specific path and method
|
||||||
|
//! ~russian Удаляет обработчик для указанного пути и метода
|
||||||
void unregisterPath(const PIString & path, PIHTTP::Method method);
|
void unregisterPath(const PIString & path, PIHTTP::Method method);
|
||||||
|
|
||||||
|
//! ~english Unregisters all handlers for specific path
|
||||||
|
//! ~russian Удаляет все обработчики для указанного пути
|
||||||
void unregisterPath(const PIString & path);
|
void unregisterPath(const PIString & path);
|
||||||
|
|
||||||
// void registerBasicAuth() {}
|
|
||||||
|
|
||||||
|
//! ~english Adds header to all server responses
|
||||||
|
//! ~russian Добавляет заголовок ко всем ответам сервера
|
||||||
void addReplyHeader(const PIString & name, const PIString & value) { reply_headers[name] = value; }
|
void addReplyHeader(const PIString & name, const PIString & value) { reply_headers[name] = value; }
|
||||||
|
|
||||||
|
//! ~english Removes header from server responses
|
||||||
|
//! ~russian Удаляет заголовок из ответов сервера
|
||||||
void removeReplyHeader(const PIString & name) { reply_headers.remove(name); }
|
void removeReplyHeader(const PIString & name) { reply_headers.remove(name); }
|
||||||
|
|
||||||
|
//! ~english Clears all custom response headers
|
||||||
|
//! ~russian Очищает все пользовательские заголовки ответов
|
||||||
void clearReplyHeaders() { reply_headers.clear(); }
|
void clearReplyHeaders() { reply_headers.clear(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct PathElement {
|
||||||
|
enum class Type {
|
||||||
|
Invalid = 0x01,
|
||||||
|
Fixed = 0x02,
|
||||||
|
Arguments = 0x04,
|
||||||
|
AnyOne = 0x08,
|
||||||
|
AnyPart = 0x10,
|
||||||
|
AnyMany = 0x20
|
||||||
|
};
|
||||||
|
|
||||||
|
Type type = Type::Fixed;
|
||||||
|
PIString source;
|
||||||
|
PIStringList parts;
|
||||||
|
PIMap<int, PIString> arguments;
|
||||||
|
|
||||||
|
PathElement(const PIString & reg = {});
|
||||||
|
|
||||||
|
bool match(const PIString & in, PIMap<PIString, PIString> & ext_args) const;
|
||||||
|
uint priority() const;
|
||||||
|
};
|
||||||
|
|
||||||
struct Endpoint {
|
struct Endpoint {
|
||||||
bool match(const PIStringList & in_path) const;
|
|
||||||
PIStringList path;
|
PIStringList path;
|
||||||
PIHTTP::Method method = PIHTTP::Method::Unknown;
|
PIHTTP::Method method = PIHTTP::Method::Unknown;
|
||||||
RequestFunction function;
|
RequestFunction function;
|
||||||
|
PIFlags<PathElement::Type> path_types;
|
||||||
|
PIVector<PathElement> prepared_path;
|
||||||
|
uint priority = 0;
|
||||||
|
|
||||||
|
bool create(const PIString & p);
|
||||||
|
bool match(const PIStringList & in_path, PIMap<PIString, PIString> & ext_args) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static PIStringList splitPath(const PIString & path);
|
||||||
|
|
||||||
PIMap<PIString, PIString> reply_headers;
|
PIMap<PIString, PIString> reply_headers;
|
||||||
PIMap<PIString, Endpoint> functions;
|
PIMap<uint, PIVector<Endpoint>> endpoints;
|
||||||
RequestFunction unhandled;
|
RequestFunction unhandled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -938,7 +938,7 @@ PIString PIBinaryLog::constructFullPathDevice() const {
|
|||||||
void PIBinaryLog::configureFromFullPathDevice(const PIString & full_path) {
|
void PIBinaryLog::configureFromFullPathDevice(const PIString & full_path) {
|
||||||
const PIStringList pl = full_path.split(":");
|
const PIStringList pl = full_path.split(":");
|
||||||
for (int i = 0; i < pl.size_s(); ++i) {
|
for (int i = 0; i < pl.size_s(); ++i) {
|
||||||
const PIString p(pl[i]);
|
const PIString p(pl[i].trimmed());
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0: setLogDir(p); break;
|
case 0: setLogDir(p); break;
|
||||||
case 1: setFilePrefix(p); break;
|
case 1: setFilePrefix(p); break;
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ void PICAN::configureFromFullPathDevice(const PIString & full_path) {
|
|||||||
PIString p(pl[i]);
|
PIString p(pl[i]);
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0: setPath(p); break;
|
case 0: setPath(p); break;
|
||||||
case 1: setCANID(p.toInt(16)); break;
|
case 1: setCANID(p.trimmed().toInt(16)); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -298,9 +298,9 @@ bool sort_compare(const PIFile::FileInfo & v0, const PIFile::FileInfo & v1) {
|
|||||||
//! также "." и "..". Возвращаются абсолютные пути.
|
//! также "." и "..". Возвращаются абсолютные пути.
|
||||||
//! \attention Этот метод не читает содержимое директорий
|
//! \attention Этот метод не читает содержимое директорий
|
||||||
//! рекурсивно!
|
//! рекурсивно!
|
||||||
PIVector<PIFile::FileInfo> PIDir::entries() {
|
PIVector<PIFile::FileInfo> PIDir::entries(const PIRegularExpression & regexp) {
|
||||||
PIVector<PIFile::FileInfo> l;
|
if (!isExists()) return {};
|
||||||
if (!isExists()) return l;
|
PIVector<PIFile::FileInfo> ret;
|
||||||
PIString dp = absolutePath();
|
PIString dp = absolutePath();
|
||||||
PIString p(dp);
|
PIString p(dp);
|
||||||
if (dp == ".")
|
if (dp == ".")
|
||||||
@@ -309,9 +309,9 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
|
|||||||
dp += separator;
|
dp += separator;
|
||||||
// piCout << "start entries from" << p;
|
// piCout << "start entries from" << p;
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
|
PIFile::FileInfo fi;
|
||||||
if (dp == separator) {
|
if (dp == separator) {
|
||||||
char letters[1024];
|
char letters[1024];
|
||||||
PIFile::FileInfo fi;
|
|
||||||
DWORD ll = GetLogicalDriveStringsA(1023, letters);
|
DWORD ll = GetLogicalDriveStringsA(1023, letters);
|
||||||
PIString clet;
|
PIString clet;
|
||||||
for (DWORD i = 0; i < ll; ++i) {
|
for (DWORD i = 0; i < ll; ++i) {
|
||||||
@@ -319,7 +319,12 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
|
|||||||
clet.resize(2);
|
clet.resize(2);
|
||||||
fi.path = clet;
|
fi.path = clet;
|
||||||
fi.flags = PIFile::FileInfo::Dir;
|
fi.flags = PIFile::FileInfo::Dir;
|
||||||
l << fi;
|
if (regexp.isValid()) {
|
||||||
|
if (regexp.match(fi.name())) {
|
||||||
|
ret << fi;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
ret << fi;
|
||||||
clet.clear();
|
clet.clear();
|
||||||
} else
|
} else
|
||||||
clet += PIChar(letters[i]);
|
clet += PIChar(letters[i]);
|
||||||
@@ -329,21 +334,27 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
|
|||||||
piZeroMemory(fd);
|
piZeroMemory(fd);
|
||||||
p += "\\*";
|
p += "\\*";
|
||||||
void * hf = FindFirstFileA((LPCSTR)(p.data()), &fd);
|
void * hf = FindFirstFileA((LPCSTR)(p.data()), &fd);
|
||||||
if (!hf) return l;
|
if (!hf) return ret;
|
||||||
bool hdd = false;
|
bool hdd = false;
|
||||||
do {
|
do {
|
||||||
PIString fn(fd.cFileName);
|
PIString fn(fd.cFileName);
|
||||||
if (fn == "..") hdd = true;
|
if (fn == "..") hdd = true;
|
||||||
l << PIFile::fileInfo(dp + fn);
|
fi = PIFile::fileInfo(dp + fn);
|
||||||
|
if (regexp.isValid()) {
|
||||||
|
if (regexp.match(fi.name())) {
|
||||||
|
ret << fi;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
ret << fi;
|
||||||
piZeroMemory(fd);
|
piZeroMemory(fd);
|
||||||
} while (FindNextFileA(hf, &fd) != 0);
|
} while (FindNextFileA(hf, &fd) != 0);
|
||||||
FindClose(hf);
|
FindClose(hf);
|
||||||
l.sort(sort_compare);
|
ret.sort(sort_compare);
|
||||||
if (!hdd) {
|
if (!hdd) {
|
||||||
PIFile::FileInfo fi;
|
PIFile::FileInfo fi;
|
||||||
fi.path = "..";
|
fi.path = "..";
|
||||||
fi.flags = PIFile::FileInfo::Dir | PIFile::FileInfo::DotDot;
|
fi.flags = PIFile::FileInfo::Dir | PIFile::FileInfo::DotDot;
|
||||||
l.push_front(fi);
|
ret.push_front(fi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,7 +367,7 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
de = readdir(dir);
|
de = readdir(dir);
|
||||||
if (!de) break;
|
if (!de) break;
|
||||||
l << PIFile::fileInfo(dp + PIString(de->d_name));
|
ret << PIFile::fileInfo(dp + PIString(de->d_name));
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
}
|
}
|
||||||
@@ -371,14 +382,14 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
|
|||||||
versionsort);
|
versionsort);
|
||||||
# endif
|
# endif
|
||||||
for (int i = 0; i < cnt; ++i) {
|
for (int i = 0; i < cnt; ++i) {
|
||||||
l << PIFile::fileInfo(dp + PIString(list[i]->d_name));
|
ret << PIFile::fileInfo(dp + PIString(list[i]->d_name));
|
||||||
free(list[i]);
|
free(list[i]);
|
||||||
}
|
}
|
||||||
free(list);
|
free(list);
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
// piCout << "end entries from" << p;
|
// piCout << "end entries from" << p;
|
||||||
return l;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -394,7 +405,7 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
|
|||||||
//! одним списком, сортированным по алфавиту. Список не содержит
|
//! одним списком, сортированным по алфавиту. Список не содержит
|
||||||
//! "." и "..". Возвращаются абсолютные пути, причём файлы
|
//! "." и "..". Возвращаются абсолютные пути, причём файлы
|
||||||
//! располагаются после директорий.
|
//! располагаются после директорий.
|
||||||
PIVector<PIFile::FileInfo> PIDir::allEntries() {
|
PIVector<PIFile::FileInfo> PIDir::allEntries(const PIRegularExpression & regexp) {
|
||||||
PIVector<PIFile::FileInfo> ret;
|
PIVector<PIFile::FileInfo> ret;
|
||||||
PIVector<PIFile::FileInfo> dirs;
|
PIVector<PIFile::FileInfo> dirs;
|
||||||
PIStringList cdirs, ndirs;
|
PIStringList cdirs, ndirs;
|
||||||
@@ -409,10 +420,16 @@ PIVector<PIFile::FileInfo> PIDir::allEntries() {
|
|||||||
if (de.isDir()) {
|
if (de.isDir()) {
|
||||||
dirs << de;
|
dirs << de;
|
||||||
ndirs << de.path;
|
ndirs << de.path;
|
||||||
} else
|
} else {
|
||||||
|
if (regexp.isValid()) {
|
||||||
|
if (!regexp.match(de.name())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
ret << de;
|
ret << de;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
cdirs = ndirs;
|
cdirs = ndirs;
|
||||||
ndirs.clear();
|
ndirs.clear();
|
||||||
}
|
}
|
||||||
@@ -516,8 +533,8 @@ PIDir PIDir::temporary() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIVector<PIFile::FileInfo> PIDir::allEntries(const PIString & path) {
|
PIVector<PIFile::FileInfo> PIDir::allEntries(const PIString & path, const PIRegularExpression & regexp) {
|
||||||
return PIDir(path).allEntries();
|
return PIDir(path).allEntries(regexp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#define PIDIR_H
|
#define PIDIR_H
|
||||||
|
|
||||||
#include "pifile.h"
|
#include "pifile.h"
|
||||||
|
#include "piregularexpression.h"
|
||||||
|
|
||||||
|
|
||||||
//! \ingroup IO
|
//! \ingroup IO
|
||||||
@@ -104,11 +105,11 @@ public:
|
|||||||
|
|
||||||
//! \~english Returns this directory content
|
//! \~english Returns this directory content
|
||||||
//! \~russian Возвращает содержимое этой директории
|
//! \~russian Возвращает содержимое этой директории
|
||||||
PIVector<PIFile::FileInfo> entries();
|
PIVector<PIFile::FileInfo> entries(const PIRegularExpression & regexp = {});
|
||||||
|
|
||||||
//! \~english Returns this directory content recursively
|
//! \~english Returns this directory content recursively
|
||||||
//! \~russian Возвращает содержимое этой директории рекурсивно
|
//! \~russian Возвращает содержимое этой директории рекурсивно
|
||||||
PIVector<PIFile::FileInfo> allEntries();
|
PIVector<PIFile::FileInfo> allEntries(const PIRegularExpression & regexp = {});
|
||||||
|
|
||||||
//! \~english Make this directory, recursively if "withParents"
|
//! \~english Make this directory, recursively if "withParents"
|
||||||
//! \~russian Создаёт эту директорию, рекурсивно если "withParents"
|
//! \~russian Создаёт эту директорию, рекурсивно если "withParents"
|
||||||
@@ -155,7 +156,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Returns directory "path" content recursively
|
//! \~english Returns directory "path" content recursively
|
||||||
//! \~russian Возвращает содержимое директории "path" рекурсивно
|
//! \~russian Возвращает содержимое директории "path" рекурсивно
|
||||||
static PIVector<PIFile::FileInfo> allEntries(const PIString & path);
|
static PIVector<PIFile::FileInfo> allEntries(const PIString & path, const PIRegularExpression & regexp = {});
|
||||||
|
|
||||||
//! \~english Returns if directory "path" exists
|
//! \~english Returns if directory "path" exists
|
||||||
//! \~russian Возвращает существует ли эта директория
|
//! \~russian Возвращает существует ли эта директория
|
||||||
|
|||||||
@@ -1047,7 +1047,7 @@ void PIEthernet::configureFromFullPathDevice(const PIString & full_path) {
|
|||||||
PIStringList pl = full_path.split(":");
|
PIStringList pl = full_path.split(":");
|
||||||
bool mcast = false;
|
bool mcast = false;
|
||||||
for (int i = 0; i < pl.size_s(); ++i) {
|
for (int i = 0; i < pl.size_s(); ++i) {
|
||||||
PIString p(pl[i]);
|
PIString p(pl[i].trimmed());
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0:
|
case 0:
|
||||||
p = p.toLowerCase();
|
p = p.toLowerCase();
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "pidir.h"
|
#include "pidir.h"
|
||||||
#include "piincludes_p.h"
|
#include "piincludes_p.h"
|
||||||
#include "piiostream.h"
|
#include "piiostream.h"
|
||||||
|
#include "piliterals_bytes.h"
|
||||||
#include "pitime_win.h"
|
#include "pitime_win.h"
|
||||||
#include "pitranslator.h"
|
#include "pitranslator.h"
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
@@ -251,25 +252,18 @@ llong PIFile::readAll(void * data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIByteArray PIFile::readAll(bool forceRead) {
|
PIByteArray PIFile::readAll() {
|
||||||
PIByteArray a;
|
if (!isOpened()) return {};
|
||||||
llong cp = pos();
|
llong prev_pos = pos();
|
||||||
if (forceRead) {
|
PIByteArray ret, buffer(4_KiB);
|
||||||
seekToBegin();
|
seekToBegin();
|
||||||
while (!isEnd())
|
for (;;) {
|
||||||
a.push_back(readChar());
|
size_t readed = fread(buffer.data(), 1, buffer.size(), PRIVATE->fd);
|
||||||
seek(cp);
|
if (readed == 0) break;
|
||||||
return a;
|
ret.append(buffer.data(), readed);
|
||||||
}
|
}
|
||||||
llong s = size();
|
seek(prev_pos);
|
||||||
if (s < 0) return a;
|
return ret;
|
||||||
a.resize(s);
|
|
||||||
seekToBegin();
|
|
||||||
auto _r = fread(a.data(), 1, s, PRIVATE->fd);
|
|
||||||
NO_UNUSED(_r);
|
|
||||||
seek(cp);
|
|
||||||
if (s >= 0) a.resize(s);
|
|
||||||
return a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -628,10 +622,10 @@ bool PIFile::applyFileInfo(const PIString & path, const PIFile::FileInfo & info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIByteArray PIFile::readAll(const PIString & path, bool forceRead) {
|
PIByteArray PIFile::readAll(const PIString & path) {
|
||||||
PIFile f(path, PIIODevice::ReadOnly);
|
PIFile f(path, PIIODevice::ReadOnly);
|
||||||
if (!f.isOpened()) return PIByteArray();
|
if (!f.isOpened()) return PIByteArray();
|
||||||
return f.readAll(forceRead);
|
return f.readAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -225,8 +225,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Read all file content to byte array and return it. Position leaved unchanged
|
//! \~english Read all file content to byte array and return it. Position leaved unchanged
|
||||||
//! \~russian Читает всё содержимое файла и возвращает его как массив байтов. Позиция остаётся неизменной
|
//! \~russian Читает всё содержимое файла и возвращает его как массив байтов. Позиция остаётся неизменной
|
||||||
PIByteArray readAll(bool forceRead = false);
|
PIByteArray readAll();
|
||||||
|
|
||||||
|
|
||||||
//! \~english Set file path to "path" and reopen file if need
|
//! \~english Set file path to "path" and reopen file if need
|
||||||
//! \~russian Устанавливает путь файла на "path" и переоткрывает его при необходимости
|
//! \~russian Устанавливает путь файла на "path" и переоткрывает его при необходимости
|
||||||
@@ -295,7 +294,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Read all file content at path "path" to byte array and return it.
|
//! \~english Read all file content at path "path" to byte array and return it.
|
||||||
//! \~russian Читает всё содержимое файла по пути "path" и возвращает его как массив байтов.
|
//! \~russian Читает всё содержимое файла по пути "path" и возвращает его как массив байтов.
|
||||||
static PIByteArray readAll(const PIString & path, bool forceRead = false);
|
static PIByteArray readAll(const PIString & path);
|
||||||
|
|
||||||
//! \~english Clear file at path "path" and write "data", returns written bytes.
|
//! \~english Clear file at path "path" and write "data", returns written bytes.
|
||||||
//! \~russian Очищает файл по пути "path", пишет туда "data" и возвращает количество записанных байт.
|
//! \~russian Очищает файл по пути "path", пишет туда "data" и возвращает количество записанных байт.
|
||||||
|
|||||||
@@ -1067,7 +1067,7 @@ PIString PIPeer::constructFullPathDevice() const {
|
|||||||
void PIPeer::configureFromFullPathDevice(const PIString & full_path) {
|
void PIPeer::configureFromFullPathDevice(const PIString & full_path) {
|
||||||
PIStringList pl = full_path.split(":");
|
PIStringList pl = full_path.split(":");
|
||||||
for (int i = 0; i < pl.size_s(); ++i) {
|
for (int i = 0; i < pl.size_s(); ++i) {
|
||||||
PIString p(pl[i]);
|
PIString p(pl[i].trimmed());
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0: changeName(p); break;
|
case 0: changeName(p); break;
|
||||||
case 1: setTrustPeerName(p); break;
|
case 1: setTrustPeerName(p); break;
|
||||||
|
|||||||
@@ -983,7 +983,7 @@ void PISerial::configureFromFullPathDevice(const PIString & full_path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < pl.size_s(); ++i) {
|
for (int i = 0; i < pl.size_s(); ++i) {
|
||||||
PIString p(pl[i]);
|
PIString p(pl[i].trimmed());
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0: setProperty("path", p); break;
|
case 0: setProperty("path", p); break;
|
||||||
case 1:
|
case 1:
|
||||||
@@ -1208,7 +1208,7 @@ PIVector<PISerial::DeviceInfo> PISerial::availableDevicesInfo(bool test) {
|
|||||||
# endif
|
# endif
|
||||||
PIFile file_prefixes("/proc/tty/drivers", PIIODevice::ReadOnly);
|
PIFile file_prefixes("/proc/tty/drivers", PIIODevice::ReadOnly);
|
||||||
if (file_prefixes.open()) {
|
if (file_prefixes.open()) {
|
||||||
PIString fc = PIString::fromAscii(file_prefixes.readAll(true)), line, cpref;
|
PIString fc = PIString::fromAscii(file_prefixes.readAll()), line, cpref;
|
||||||
PIStringList words;
|
PIStringList words;
|
||||||
file_prefixes.close();
|
file_prefixes.close();
|
||||||
while (!fc.isEmpty()) {
|
while (!fc.isEmpty()) {
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ void PISharedMemory::configureFromFullPathDevice(const PIString & full_path) {
|
|||||||
initPrivate();
|
initPrivate();
|
||||||
PIStringList pl = full_path.split(":");
|
PIStringList pl = full_path.split(":");
|
||||||
for (int i = 0; i < pl.size_s(); ++i) {
|
for (int i = 0; i < pl.size_s(); ++i) {
|
||||||
PIString p(pl[i]);
|
PIString p(pl[i].trimmed());
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0: setPath(p); break;
|
case 0: setPath(p); break;
|
||||||
case 1: dsize = p.toInt(); break;
|
case 1: dsize = p.toInt(); break;
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ PIString PISPI::constructFullPathDevice() const {
|
|||||||
void PISPI::configureFromFullPathDevice(const PIString & full_path) {
|
void PISPI::configureFromFullPathDevice(const PIString & full_path) {
|
||||||
PIStringList pl = full_path.split(":");
|
PIStringList pl = full_path.split(":");
|
||||||
for (int i = 0; i < pl.size_s(); ++i) {
|
for (int i = 0; i < pl.size_s(); ++i) {
|
||||||
PIString p(pl[i]);
|
PIString p(pl[i].trimmed());
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0: setPath(p); break;
|
case 0: setPath(p); break;
|
||||||
case 1: setSpeed(p.toInt()); break;
|
case 1: setSpeed(p.toInt()); break;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include "piliterals_bytearray.h"
|
#include "piliterals_bytearray.h"
|
||||||
#include "piliterals_bytes.h"
|
#include "piliterals_bytes.h"
|
||||||
|
#include "piliterals_regularexpression.h"
|
||||||
#include "piliterals_string.h"
|
#include "piliterals_string.h"
|
||||||
#include "piliterals_time.h"
|
#include "piliterals_time.h"
|
||||||
|
|
||||||
|
|||||||
46
libs/main/literals/piliterals_regularexpression.h
Normal file
46
libs/main/literals/piliterals_regularexpression.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*! \file piliterals_regularexpression.h
|
||||||
|
* \ingroup Core
|
||||||
|
* \~\brief
|
||||||
|
* \~english PIRegularExpression C++11 literals
|
||||||
|
* \~russian C++11 суффиксы PIString
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
PIP - Platform Independent Primitives
|
||||||
|
PIRegularExpression C++11 literals
|
||||||
|
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 PILITERALS_REGULAREXPRESSION_H
|
||||||
|
#define PILITERALS_REGULAREXPRESSION_H
|
||||||
|
|
||||||
|
#include "piregularexpression.h"
|
||||||
|
|
||||||
|
//! \~\brief
|
||||||
|
//! \~english PIRegularExpression from string pattern in PCRE2 format
|
||||||
|
//! \~russian PIRegularExpression из строки в формате PCRE2
|
||||||
|
inline PIRegularExpression operator""_regex(const char * v, size_t sz) {
|
||||||
|
return PIRegularExpression(PIString::fromUTF8(v, sz));
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~\brief
|
||||||
|
//! \~english PIRegularExpression from string pattern in Glob format
|
||||||
|
//! \~russian PIRegularExpression из строки в формате Glob
|
||||||
|
inline PIRegularExpression operator""_glob(const char * v, size_t sz) {
|
||||||
|
return PIRegularExpression::fromGlob(PIString::fromUTF8(v, sz));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -60,6 +60,9 @@ inline PIJSON piSerializeJSON(const T & v) {
|
|||||||
|
|
||||||
// known types
|
// known types
|
||||||
|
|
||||||
|
inline PIJSON piSerializeJSON(const PIJSON & v) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
template<>
|
template<>
|
||||||
inline PIJSON piSerializeJSON(const PIVariant & v) {
|
inline PIJSON piSerializeJSON(const PIVariant & v) {
|
||||||
return PIJSON() = v;
|
return PIJSON() = v;
|
||||||
@@ -248,6 +251,9 @@ inline void piDeserializeJSON(T & v, const PIJSON & js) {
|
|||||||
|
|
||||||
// known types
|
// known types
|
||||||
|
|
||||||
|
inline void piDeserializeJSON(PIJSON & v, const PIJSON & js) {
|
||||||
|
v = js;
|
||||||
|
}
|
||||||
template<>
|
template<>
|
||||||
inline void piDeserializeJSON(PIVariant & v, const PIJSON & js) {
|
inline void piDeserializeJSON(PIVariant & v, const PIJSON & js) {
|
||||||
v = js.value();
|
v = js.value();
|
||||||
|
|||||||
643
libs/main/system/pihidevice.cpp
Normal file
643
libs/main/system/pihidevice.cpp
Normal file
@@ -0,0 +1,643 @@
|
|||||||
|
#include "pihidevice.h"
|
||||||
|
|
||||||
|
#include "piliterals_string.h"
|
||||||
|
#include "piliterals_time.h"
|
||||||
|
#ifndef WINDOWS
|
||||||
|
# include "pidir.h"
|
||||||
|
# include "pifile.h"
|
||||||
|
# include "piiostream.h"
|
||||||
|
|
||||||
|
# include <fcntl.h>
|
||||||
|
# include <linux/input-event-codes.h>
|
||||||
|
# include <linux/input.h>
|
||||||
|
# include <sys/ioctl.h>
|
||||||
|
# include <sys/time.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
#else
|
||||||
|
// clang-format off
|
||||||
|
# include <windows.h>
|
||||||
|
# include <setupapi.h>
|
||||||
|
extern "C" {
|
||||||
|
# include <hidsdi.h>
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
bool PIHIDeviceInfo::match(const PIString & str) const {
|
||||||
|
if (product.toLowerCase().contains(str.toLowerCase())) return true;
|
||||||
|
if (path.toLowerCase().contains(str.toLowerCase())) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int PIHIDeviceInfo::axesAbsoluteCount() const {
|
||||||
|
int ret = 0;
|
||||||
|
for (const auto & a: axes)
|
||||||
|
if (!a.is_relative) ++ret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int PIHIDeviceInfo::axesRelativeCount() const {
|
||||||
|
int ret = 0;
|
||||||
|
for (const auto & a: axes)
|
||||||
|
if (a.is_relative) ++ret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIHIDeviceInfo::prepare() {
|
||||||
|
axis_by_dataindex.clear();
|
||||||
|
button_by_dataindex.clear();
|
||||||
|
for (const auto & i: axes)
|
||||||
|
axis_by_dataindex[i.data_index] = i;
|
||||||
|
for (const auto & i: buttons)
|
||||||
|
button_by_dataindex[i.data_index] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PICout operator<<(PICout s, const PIHIDeviceInfo & v) {
|
||||||
|
s.saveAndSetControls(0);
|
||||||
|
s << "PIHIDeviceInfo(" << v.product << " (" << v.manufacturer << "), " << v.VID << ":" << v.PID
|
||||||
|
<< ", " //<< "path \"" << v.path << "\", "
|
||||||
|
<< v.axesAbsoluteCount() << " abs axes, " << v.axesRelativeCount() << " rel axes, " << v.buttonsCount() << " buttons)";
|
||||||
|
s.restoreControls();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PRIVATE_DEFINITION_START(PIHIDevice)
|
||||||
|
#ifndef WINDOWS
|
||||||
|
PIFile file;
|
||||||
|
bool is_js = false;
|
||||||
|
#else
|
||||||
|
PIByteArray buffer;
|
||||||
|
HANDLE deviceHandle = nullptr;
|
||||||
|
PHIDP_PREPARSED_DATA preparsed = nullptr;
|
||||||
|
#endif
|
||||||
|
PRIVATE_DEFINITION_END(PIHIDevice)
|
||||||
|
|
||||||
|
|
||||||
|
PIHIDevice::~PIHIDevice() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PIHIDevice::isOpened() const {
|
||||||
|
#ifndef WINDOWS
|
||||||
|
return PRIVATE->file.isOpened();
|
||||||
|
#else
|
||||||
|
return PRIVATE->deviceHandle;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIHIDevice::open(const PIHIDeviceInfo & device) {
|
||||||
|
close();
|
||||||
|
cur_axes.clear();
|
||||||
|
cur_buttons.clear();
|
||||||
|
di = device;
|
||||||
|
di.prepare();
|
||||||
|
if (device.isNull()) return false;
|
||||||
|
#ifndef WINDOWS
|
||||||
|
if (!PRIVATE->file.open(di.path, PIIODevice::ReadOnly)) {
|
||||||
|
piCout << "PIHIDevice::open" << di.path << "error:" << errorString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PRIVATE->is_js = PIFile::FileInfo(di.path).name().startsWith("js"_a);
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
PRIVATE->deviceHandle = CreateFileA(di.path.dataAscii(),
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
nullptr,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
0,
|
||||||
|
nullptr);
|
||||||
|
if (PRIVATE->deviceHandle == INVALID_HANDLE_VALUE) {
|
||||||
|
piCoutObj << "PIHIDevice::open" << di.path << "error:" << errorString();
|
||||||
|
PRIVATE->deviceHandle = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
HidD_GetPreparsedData(PRIVATE->deviceHandle, &PRIVATE->preparsed);
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIHIDevice::open() {
|
||||||
|
return open(di);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIHIDevice::close() {
|
||||||
|
stop();
|
||||||
|
#ifndef WINDOWS
|
||||||
|
PRIVATE->file.close();
|
||||||
|
#else
|
||||||
|
if (PRIVATE->deviceHandle) {
|
||||||
|
CloseHandle(PRIVATE->deviceHandle);
|
||||||
|
PRIVATE->deviceHandle = nullptr;
|
||||||
|
}
|
||||||
|
if (PRIVATE->preparsed) {
|
||||||
|
HidD_FreePreparsedData(PRIVATE->preparsed);
|
||||||
|
PRIVATE->preparsed = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIHIDevice::start() {
|
||||||
|
if (!isOpened()) return;
|
||||||
|
PIThread::start(200_Hz);
|
||||||
|
#ifndef WINDOWS
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIHIDevice::stop() {
|
||||||
|
PIThread::stop();
|
||||||
|
#ifdef WINDOWS
|
||||||
|
if (PRIVATE->deviceHandle) {
|
||||||
|
CancelIoEx(PRIVATE->deviceHandle, nullptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!waitForFinish(1000_ms)) terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIHIDevice::run() {
|
||||||
|
Event e;
|
||||||
|
#ifndef WINDOWS
|
||||||
|
# pragma pack(push, 1)
|
||||||
|
struct input_event {
|
||||||
|
struct timeval time;
|
||||||
|
ushort type;
|
||||||
|
ushort code;
|
||||||
|
uint value;
|
||||||
|
};
|
||||||
|
struct js_event {
|
||||||
|
uint time; /* event timestamp in milliseconds */
|
||||||
|
short value; /* value */
|
||||||
|
uchar type; /* event type */
|
||||||
|
uchar number; /* axis/button number */
|
||||||
|
};
|
||||||
|
# pragma pack(pop)
|
||||||
|
if (PRIVATE->is_js) {
|
||||||
|
js_event ie;
|
||||||
|
while (PRIVATE->file.read(&ie, sizeof(ie)) == sizeof(ie)) {
|
||||||
|
if (ie.type == 0) continue;
|
||||||
|
bool ok = false;
|
||||||
|
switch (ie.type) {
|
||||||
|
case 2: {
|
||||||
|
// piCout << ie.value;
|
||||||
|
cur_axes[ie.number] = procDeadZone(ie.value / 32767. / 2. + 0.5);
|
||||||
|
ok = true;
|
||||||
|
} break;
|
||||||
|
case 1:
|
||||||
|
// piCout << ie.code;
|
||||||
|
cur_buttons[ie.number] = ie.value;
|
||||||
|
ok = true;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
// piCout << ok << ie.type << ie.code << ie.value;
|
||||||
|
if (!ok) continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
input_event ie;
|
||||||
|
while (PRIVATE->file.read(&ie, sizeof(ie)) == sizeof(ie)) {
|
||||||
|
if (ie.type == 0) continue;
|
||||||
|
bool ok = false;
|
||||||
|
switch (ie.type) {
|
||||||
|
case 2: { // rel axis
|
||||||
|
auto vi = di.axis_by_dataindex.value(ie.code);
|
||||||
|
if (vi.isValid()) {
|
||||||
|
e.type = Event::tAxisMove;
|
||||||
|
e.axis = vi;
|
||||||
|
e.value = static_cast<int>(ie.value);
|
||||||
|
event(e);
|
||||||
|
}
|
||||||
|
ok = true;
|
||||||
|
} break;
|
||||||
|
case 3: { // abs axis
|
||||||
|
auto vi = di.axis_by_dataindex.value(ie.code);
|
||||||
|
float fv = (ie.value - vi.min) / piMaxf(1.f, (float)(vi.max - vi.min));
|
||||||
|
cur_axes[ie.code] = procDeadZone(fv);
|
||||||
|
ok = true;
|
||||||
|
} break;
|
||||||
|
case 1: // button
|
||||||
|
// piCout << ie.code;
|
||||||
|
cur_buttons[ie.code] = ie.value;
|
||||||
|
ok = true;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
// piCout << ok << ie.type << ie.code << ie.value;
|
||||||
|
if (!ok) continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
PRIVATE->buffer.resize(di.input_report_size).fill(0);
|
||||||
|
DWORD readed = 0;
|
||||||
|
// piCout << "read" << PRIVATE->deviceHandle << PRIVATE->buffer.size();
|
||||||
|
HIDP_DATA gdd[256];
|
||||||
|
ULONG gdd_len = 256;
|
||||||
|
if (ReadFile(PRIVATE->deviceHandle, PRIVATE->buffer.data(), PRIVATE->buffer.size_s(), &readed, nullptr) != TRUE) return;
|
||||||
|
// piCout << readed << PRIVATE->buffer.size();
|
||||||
|
if (readed != PRIVATE->buffer.size()) return;
|
||||||
|
auto gd = HidP_GetData(HidP_Input, gdd, &gdd_len, PRIVATE->preparsed, (PCHAR)PRIVATE->buffer.data(), PRIVATE->buffer.size_s());
|
||||||
|
NO_UNUSED(gd);
|
||||||
|
// piCout << "readed" << PRIVATE->buffer << gdd_len;
|
||||||
|
auto cbit = cur_buttons.makeIterator();
|
||||||
|
while (cbit.next())
|
||||||
|
cbit.value() = 0;
|
||||||
|
for (ULONG i = 0; i < gdd_len; ++i) {
|
||||||
|
const auto & cd(gdd[i]);
|
||||||
|
// piCout << cd.DataIndex << cd.RawValue;
|
||||||
|
auto vi = di.axis_by_dataindex.value(cd.DataIndex);
|
||||||
|
if (vi.isValid()) {
|
||||||
|
if (vi.is_relative) {
|
||||||
|
e.type = Event::tAxisMove;
|
||||||
|
e.axis = vi;
|
||||||
|
e.value = static_cast<LONG>(cd.RawValue);
|
||||||
|
event(e);
|
||||||
|
} else {
|
||||||
|
// auto & axis(cur_axes[cd.DataIndex]);
|
||||||
|
float fv = (cd.RawValue - vi.min) / piMaxf(1.f, (float)(vi.max - vi.min));
|
||||||
|
cur_axes[vi.data_index] = procDeadZone(fv);
|
||||||
|
}
|
||||||
|
// piCout << "axis" << vi.data_index << "->" << cur_axes[vi.data_index];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto bi = di.button_by_dataindex.value(cd.DataIndex);
|
||||||
|
if (bi.isValid()) {
|
||||||
|
cur_buttons[bi.data_index] = 1;
|
||||||
|
// piCout << "button" << bi.data_index << "-> 1";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto ait = cur_axes.makeIterator();
|
||||||
|
e.type = Event::tAxisMove;
|
||||||
|
while (ait.next()) {
|
||||||
|
if (ait.value() != prev_axes.value(ait.key())) {
|
||||||
|
e.axis = di.axis_by_dataindex.value(ait.key());
|
||||||
|
e.value = ait.value();
|
||||||
|
event(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev_axes = cur_axes;
|
||||||
|
|
||||||
|
auto bit = cur_buttons.makeIterator();
|
||||||
|
e.type = Event::tButton;
|
||||||
|
while (bit.next()) {
|
||||||
|
if (bit.value() != prev_buttons.value(bit.key())) {
|
||||||
|
e.button = di.button_by_dataindex.value(bit.key());
|
||||||
|
e.value = bit.value();
|
||||||
|
event(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev_buttons = cur_buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double PIHIDevice::procDeadZone(double in) {
|
||||||
|
double cv = (in - 0.5) * 2.;
|
||||||
|
if (piAbsd(cv) < dead_zone) return 0.;
|
||||||
|
if (cv < 0)
|
||||||
|
return (cv + dead_zone) / (1. - dead_zone);
|
||||||
|
else
|
||||||
|
return (cv - dead_zone) / (1. - dead_zone);
|
||||||
|
return cv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIVector<PIHIDeviceInfo> PIHIDevice::allDevices(bool try_open) {
|
||||||
|
PIVector<PIHIDeviceInfo> ret;
|
||||||
|
|
||||||
|
#ifndef WINDOWS
|
||||||
|
|
||||||
|
auto readFile = [](const PIString & path) {
|
||||||
|
auto ba = PIFile::readAll(path);
|
||||||
|
PIString ret;
|
||||||
|
for (const auto & b: ba) {
|
||||||
|
if (!PIChar(b).isAscii()) break;
|
||||||
|
ret += PIChar(b);
|
||||||
|
}
|
||||||
|
return ret.trim();
|
||||||
|
};
|
||||||
|
auto isDir = [](const PIFile::FileInfo & fi) {
|
||||||
|
return fi.isDir() && !fi.flags[PIFile::FileInfo::Dot] && !fi.flags[PIFile::FileInfo::DotDot];
|
||||||
|
};
|
||||||
|
auto checkBit = [](const ullong & flags, ullong bit, const PIString & name) { return (flags & (1ULL << bit)) > 0; };
|
||||||
|
|
||||||
|
PIDir hid_dir("/sys/bus/hid/devices"_a);
|
||||||
|
auto hid_devs = hid_dir.entries();
|
||||||
|
for (auto hd: hid_devs) {
|
||||||
|
// piCout << d.path;
|
||||||
|
if (!isDir(hd)) continue;
|
||||||
|
PIDir dir_input(hd.path + "/input"_a);
|
||||||
|
auto hid_inputs = dir_input.entries();
|
||||||
|
for (auto hd_i: hid_inputs) {
|
||||||
|
if (!isDir(hd_i)) continue;
|
||||||
|
// now in /sys/bus/hid/devices/<dev>/input/input<N>
|
||||||
|
// piCout << hd_i.path;
|
||||||
|
PIHIDeviceInfo dev;
|
||||||
|
dev.product = readFile(hd_i.path + "/name"_a);
|
||||||
|
// piCout << readFile(hd_i.path + "/name"_a);
|
||||||
|
dev.VID = readFile(hd_i.path + "/id/vendor"_a);
|
||||||
|
dev.PID = readFile(hd_i.path + "/id/product"_a);
|
||||||
|
dev.version = readFile(hd_i.path + "/id/version"_a);
|
||||||
|
dev.manufacturer = readFile(hd_i.path + "/id/manufacturer"_a);
|
||||||
|
|
||||||
|
// piCout << dev.product;
|
||||||
|
dev.input_report_size = 24;
|
||||||
|
PIDir dir_e(hd_i.path);
|
||||||
|
PIStringList devs;
|
||||||
|
auto dl_e = dir_e.entries();
|
||||||
|
for (auto d_e: dl_e) {
|
||||||
|
if (!d_e.isDir() || d_e.flags[PIFile::FileInfo::Dot] || d_e.flags[PIFile::FileInfo::DotDot]) continue;
|
||||||
|
devs << d_e.name();
|
||||||
|
}
|
||||||
|
/*bool dev_found = false;
|
||||||
|
for (const auto & d: devs) {
|
||||||
|
if (d.startsWith("js"_a)) {
|
||||||
|
dev.path = "/dev/input/"_a + d;
|
||||||
|
dev_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!dev_found) {*/
|
||||||
|
// search for event<N> dir
|
||||||
|
for (const auto & d: devs) {
|
||||||
|
if (d.startsWith("event"_a)) {
|
||||||
|
dev.path = "/dev/input/"_a + d;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev.path.isEmpty()) continue;
|
||||||
|
|
||||||
|
if (try_open) {
|
||||||
|
PIFile test_f(dev.path, PIIODevice::ReadOnly);
|
||||||
|
if (test_f.isClosed()) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ullong ev = readFile(hd_i.path + "/capabilities/ev"_a).toULLong(16);
|
||||||
|
|
||||||
|
auto readAxes = [readFile, checkBit, &hd_i, &dev](const PIString & file, bool is_relative) {
|
||||||
|
PIVector<PIHIDeviceInfo::AxisInfo> ret;
|
||||||
|
ullong bits = readFile(hd_i.path + file).toULLong(16);
|
||||||
|
// piCout<< PICoutManipulators::Bin << abs;
|
||||||
|
if (bits > 0) {
|
||||||
|
int fd = ::open(dev.path.dataAscii(), O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
// piCout << "Warning: can`t open" << dev.path << errorString();
|
||||||
|
}
|
||||||
|
PIHIDeviceInfo::AxisInfo ai;
|
||||||
|
ai.is_relative = is_relative;
|
||||||
|
for (int bit = 0; bit < 64; ++bit) {
|
||||||
|
if (checkBit(bits, bit, PIString::fromNumber(bit))) {
|
||||||
|
ai.data_index = bit;
|
||||||
|
if (fd >= 0) {
|
||||||
|
struct input_absinfo abs_info;
|
||||||
|
if (ioctl(fd, EVIOCGABS(bit), &abs_info) != -1) {
|
||||||
|
ai.min = abs_info.minimum;
|
||||||
|
ai.max = abs_info.maximum;
|
||||||
|
// piCout << "axis" << bit << abs_info.minimum << abs_info.maximum << abs_info.flat << abs_info.fuzz;
|
||||||
|
} else {
|
||||||
|
ai.min = 0;
|
||||||
|
ai.max = 1024;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret << ai;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fd >= 0) ::close(fd);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
dev.axes << readAxes("/capabilities/abs"_a, false) << readAxes("/capabilities/rel"_a, true);
|
||||||
|
for (int i = 0; i < dev.axes.size_s(); ++i)
|
||||||
|
dev.axes[i].index = i;
|
||||||
|
|
||||||
|
PIString key_str = readFile(hd_i.path + "/capabilities/key"_a);
|
||||||
|
PIVector<ulong> key_words;
|
||||||
|
while (key_str.isNotEmpty()) {
|
||||||
|
PIString w = key_str.takeWord().trimmed();
|
||||||
|
if (w.isEmpty()) break;
|
||||||
|
key_words.prepend(w.toULong(16));
|
||||||
|
}
|
||||||
|
PIBitArray key_bits((const uchar *)key_words.data(), key_words.size_s() * sizeof(ulong));
|
||||||
|
|
||||||
|
PIHIDeviceInfo::ButtonInfo bi;
|
||||||
|
for (uint b = 0; b < key_bits.bitSize(); ++b) {
|
||||||
|
if (!key_bits[b]) continue;
|
||||||
|
bi.index = dev.buttons.size_s();
|
||||||
|
bi.code = b;
|
||||||
|
bi.data_index = b;
|
||||||
|
dev.buttons << bi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev.manufacturer.isEmpty()) {
|
||||||
|
for (const auto * hwp: {"/usr/share/hwdata/usb.ids", "/var/lib/usbutils/usb.ids"}) {
|
||||||
|
PIFile hwf(hwp, PIIODevice::ReadOnly);
|
||||||
|
if (hwf.isClosed()) continue;
|
||||||
|
// piCout << "search" << dev.VID << "in" << hwp;
|
||||||
|
PIString line;
|
||||||
|
PIIOTextStream ts(&hwf);
|
||||||
|
while (!hwf.isEnd()) {
|
||||||
|
line = ts.readLine();
|
||||||
|
if (line.startsWith(dev.VID)) {
|
||||||
|
line.takeWord();
|
||||||
|
line.trim();
|
||||||
|
dev.manufacturer = line;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev.isNotNull() && (dev.buttonsCount() > 0 || dev.axesCount() > 0)) ret << dev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
GUID guid;
|
||||||
|
HidD_GetHidGuid(&guid);
|
||||||
|
HDEVINFO deviceInfoSet = SetupDiGetClassDevs(&guid, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||||
|
if (deviceInfoSet == INVALID_HANDLE_VALUE) {
|
||||||
|
piCout << "SetupDiGetClassDevs error:" << errorString();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
|
||||||
|
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
||||||
|
for (DWORD i = 0; SetupDiEnumDeviceInterfaces(deviceInfoSet, nullptr, &guid, i, &deviceInterfaceData); ++i) {
|
||||||
|
PIHIDeviceInfo dev;
|
||||||
|
|
||||||
|
DWORD requiredSize = 0;
|
||||||
|
SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, nullptr, 0, &requiredSize, nullptr);
|
||||||
|
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData =
|
||||||
|
reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(new BYTE[requiredSize]);
|
||||||
|
PIScopeExitCall exit_call([&deviceInterfaceDetailData]() { delete[] reinterpret_cast<BYTE *>(deviceInterfaceDetailData); });
|
||||||
|
deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
|
||||||
|
if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet,
|
||||||
|
&deviceInterfaceData,
|
||||||
|
deviceInterfaceDetailData,
|
||||||
|
requiredSize,
|
||||||
|
nullptr,
|
||||||
|
nullptr)) {
|
||||||
|
piCout << "SetupDiGetDeviceInterfaceDetail error:" << errorString();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (try_open) {
|
||||||
|
auto test_f = CreateFileA(deviceInterfaceDetailData->DevicePath,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
nullptr,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
0,
|
||||||
|
nullptr);
|
||||||
|
if (test_f == INVALID_HANDLE_VALUE) continue;
|
||||||
|
CloseHandle(test_f);
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE deviceHandle =
|
||||||
|
CreateFileA(deviceInterfaceDetailData->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||||
|
if (deviceHandle == INVALID_HANDLE_VALUE) {
|
||||||
|
piCout << "CreateFileA error:" << errorString();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// piCout << i << deviceHandle;
|
||||||
|
|
||||||
|
PHIDP_PREPARSED_DATA preparsed = nullptr;
|
||||||
|
if (HidD_GetPreparsedData(deviceHandle, &preparsed) == FALSE) {
|
||||||
|
piCout << "HidD_GetPreparsedData error:" << errorString();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// auto pp = PIByteArray(preparsed, 64);
|
||||||
|
// piCout << piChangedEndian(pp.dataAs<ushort>(7)) << piChangedEndian(pp.dataAs<ushort>(8)) <<
|
||||||
|
// piChangedEndian(pp.dataAs<ushort>(9));
|
||||||
|
// piCout << pp;
|
||||||
|
|
||||||
|
dev.path = deviceInterfaceDetailData->DevicePath;
|
||||||
|
|
||||||
|
HIDD_ATTRIBUTES attr;
|
||||||
|
PIByteArray str_buff(1024);
|
||||||
|
HidD_GetAttributes(deviceHandle, &attr);
|
||||||
|
dev.VID.setNumber(attr.VendorID, 16).expandLeftTo(4, '0').toLowerCase();
|
||||||
|
dev.PID.setNumber(attr.ProductID, 16).expandLeftTo(4, '0').toLowerCase();
|
||||||
|
dev.version.setNumber(attr.VersionNumber);
|
||||||
|
|
||||||
|
HIDP_CAPS caps;
|
||||||
|
HidP_GetCaps(preparsed, &caps);
|
||||||
|
dev.input_report_size = caps.InputReportByteLength;
|
||||||
|
|
||||||
|
str_buff.fill(0);
|
||||||
|
HidD_GetManufacturerString(deviceHandle, str_buff.data(), str_buff.size_s());
|
||||||
|
dev.manufacturer = PIString(reinterpret_cast<wchar_t *>(str_buff.data()));
|
||||||
|
|
||||||
|
str_buff.fill(0);
|
||||||
|
HidD_GetProductString(deviceHandle, str_buff.data(), str_buff.size_s());
|
||||||
|
dev.product = PIString(reinterpret_cast<wchar_t *>(str_buff.data()));
|
||||||
|
|
||||||
|
str_buff.fill(0);
|
||||||
|
HidD_GetSerialNumberString(deviceHandle, str_buff.data(), str_buff.size_s());
|
||||||
|
dev.serial = PIString(reinterpret_cast<wchar_t *>(str_buff.data()));
|
||||||
|
|
||||||
|
PIVector<PIHIDeviceInfo::AxisInfo> axes_abs, axes_rel;
|
||||||
|
HIDP_VALUE_CAPS value_caps[1024];
|
||||||
|
USHORT _cnt = caps.NumberInputValueCaps;
|
||||||
|
memset(value_caps, 0, sizeof(value_caps[0]) * 1024);
|
||||||
|
HidP_GetValueCaps(HidP_Input, value_caps, &_cnt, preparsed);
|
||||||
|
for (int i = 0; i < caps.NumberInputValueCaps; ++i) {
|
||||||
|
const auto & vc(value_caps[i]);
|
||||||
|
PIHIDeviceInfo::AxisInfo vi;
|
||||||
|
vi.bits = vc.BitSize;
|
||||||
|
vi.min = vc.LogicalMin;
|
||||||
|
vi.max = vc.LogicalMax;
|
||||||
|
vi.is_relative = vc.IsAbsolute == 0;
|
||||||
|
if (vi.max == vi.min) ++vi.max;
|
||||||
|
if (vc.IsRange == 1) {
|
||||||
|
int count = vc.Range.UsageMax - vc.Range.UsageMin + 1;
|
||||||
|
int cur_index = vc.Range.DataIndexMin;
|
||||||
|
for (int v = 0; v < count; ++v) {
|
||||||
|
vi.data_index = cur_index;
|
||||||
|
if (vi.is_relative)
|
||||||
|
axes_rel << vi;
|
||||||
|
else
|
||||||
|
axes_abs << vi;
|
||||||
|
++cur_index;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vi.data_index = vc.NotRange.DataIndex;
|
||||||
|
if (vi.is_relative)
|
||||||
|
axes_rel << vi;
|
||||||
|
else
|
||||||
|
axes_abs << vi;
|
||||||
|
}
|
||||||
|
// piCout << vc.LinkCollection << vc.LinkUsage << vc.LinkUsagePage;
|
||||||
|
}
|
||||||
|
dev.axes << axes_abs << axes_rel;
|
||||||
|
for (int i = 0; i < dev.axes.size_s(); ++i)
|
||||||
|
dev.axes[i].index = i;
|
||||||
|
|
||||||
|
HIDP_BUTTON_CAPS button_caps[1024];
|
||||||
|
_cnt = caps.NumberInputButtonCaps;
|
||||||
|
memset(button_caps, 0, sizeof(button_caps[0]) * 1024);
|
||||||
|
HidP_GetButtonCaps(HidP_Input, button_caps, &_cnt, preparsed);
|
||||||
|
for (int i = 0; i < _cnt; ++i) {
|
||||||
|
const auto & bc(button_caps[i]);
|
||||||
|
PIHIDeviceInfo::ButtonInfo bi;
|
||||||
|
// dev.values.append(PIHIDeviceInfo::ValueInfo{value_caps[i].BitSize, value_caps[i].LogicalMin, value_caps[i].LogicalMax});
|
||||||
|
if (bc.IsRange == 1) {
|
||||||
|
int count = bc.Range.UsageMax - bc.Range.UsageMin + 1;
|
||||||
|
int cur_index = bc.Range.DataIndexMin;
|
||||||
|
for (int b = 0; b < count; ++b) {
|
||||||
|
bi.index = dev.buttons.size_s();
|
||||||
|
bi.data_index = cur_index;
|
||||||
|
dev.buttons << bi;
|
||||||
|
++cur_index;
|
||||||
|
// piCout << b << (start_bit / 8) << (start_bit % 8);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bi.index = dev.buttons.size_s();
|
||||||
|
bi.data_index = bc.NotRange.DataIndex;
|
||||||
|
dev.buttons << bi;
|
||||||
|
// piCout << (bi.bit / 8) << (bi.bit % 8);
|
||||||
|
}
|
||||||
|
// piCout << bc.IsRange << bc.Range.UsageMin << bc.Range.UsageMax
|
||||||
|
// << bc.Range.DataIndexMin << bc.Range.DataIndexMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
HidD_FreePreparsedData(preparsed);
|
||||||
|
CloseHandle(deviceHandle);
|
||||||
|
|
||||||
|
if (dev.buttonsCount() > 0 || dev.axesCount() > 0) ret << dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIHIDeviceInfo PIHIDevice::findDevice(const PIString & name) {
|
||||||
|
if (name.isEmpty()) return PIHIDeviceInfo();
|
||||||
|
auto devices = PIHIDevice::allDevices();
|
||||||
|
for (auto d: devices) {
|
||||||
|
if (d.match(name)) return d;
|
||||||
|
}
|
||||||
|
return PIHIDeviceInfo();
|
||||||
|
}
|
||||||
122
libs/main/system/pihidevice.h
Normal file
122
libs/main/system/pihidevice.h
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*! \file pihidevice.h
|
||||||
|
* \ingroup System
|
||||||
|
* \~\brief
|
||||||
|
* \~english HID device
|
||||||
|
* \~russian HID устройство
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
PIP - Platform Independent Primitives
|
||||||
|
HID device
|
||||||
|
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 PIHIDEVICE_H
|
||||||
|
#define PIHIDEVICE_H
|
||||||
|
|
||||||
|
#include "pithread.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct PIP_EXPORT PIHIDeviceInfo {
|
||||||
|
friend class PIHIDevice;
|
||||||
|
struct PIP_EXPORT ValueInfoBase {
|
||||||
|
bool isValid() const { return index >= 0; }
|
||||||
|
int index = -1;
|
||||||
|
int data_index = -1;
|
||||||
|
};
|
||||||
|
struct PIP_EXPORT AxisInfo: public ValueInfoBase {
|
||||||
|
int bits = 0;
|
||||||
|
int min = 0;
|
||||||
|
int max = 1;
|
||||||
|
bool is_relative = false;
|
||||||
|
};
|
||||||
|
struct PIP_EXPORT ButtonInfo: public ValueInfoBase {
|
||||||
|
int code = 0;
|
||||||
|
};
|
||||||
|
PIString path;
|
||||||
|
PIString manufacturer;
|
||||||
|
PIString product;
|
||||||
|
PIString serial;
|
||||||
|
PIString version;
|
||||||
|
PIString VID;
|
||||||
|
PIString PID;
|
||||||
|
PIVector<AxisInfo> axes;
|
||||||
|
PIVector<ButtonInfo> buttons;
|
||||||
|
bool isNull() const { return path.isEmpty(); }
|
||||||
|
bool isNotNull() const { return !isNull(); }
|
||||||
|
bool match(const PIString & str) const;
|
||||||
|
int axesCount() const { return axes.size_s(); }
|
||||||
|
int axesAbsoluteCount() const;
|
||||||
|
int axesRelativeCount() const;
|
||||||
|
int buttonsCount() const { return buttons.size_s(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void prepare();
|
||||||
|
PIMap<int, AxisInfo> axis_by_dataindex;
|
||||||
|
PIMap<int, ButtonInfo> button_by_dataindex;
|
||||||
|
int input_report_size = 0;
|
||||||
|
int output_report_size = 0;
|
||||||
|
int feature_report_size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
PIP_EXPORT PICout operator<<(PICout s, const PIHIDeviceInfo & v);
|
||||||
|
|
||||||
|
|
||||||
|
class PIP_EXPORT PIHIDevice: public PIThread {
|
||||||
|
PIOBJECT_SUBCLASS(PIHIDevice, PIThread)
|
||||||
|
|
||||||
|
public:
|
||||||
|
~PIHIDevice();
|
||||||
|
|
||||||
|
struct PIP_EXPORT Event {
|
||||||
|
enum Type {
|
||||||
|
tNone,
|
||||||
|
tButton,
|
||||||
|
tAxisMove,
|
||||||
|
};
|
||||||
|
Type type = tNone;
|
||||||
|
PIHIDeviceInfo::AxisInfo axis;
|
||||||
|
PIHIDeviceInfo::ButtonInfo button;
|
||||||
|
float value = 0.;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isOpened() const;
|
||||||
|
bool open(const PIHIDeviceInfo & device);
|
||||||
|
bool open();
|
||||||
|
void close();
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
void setDeadZone(float v) { dead_zone = v; }
|
||||||
|
float deadZone() const { return dead_zone; }
|
||||||
|
|
||||||
|
EVENT1(event, PIHIDevice::Event, e);
|
||||||
|
|
||||||
|
static PIVector<PIHIDeviceInfo> allDevices(bool try_open = true);
|
||||||
|
static PIHIDeviceInfo findDevice(const PIString & name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void run() override;
|
||||||
|
double procDeadZone(double in);
|
||||||
|
|
||||||
|
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||||
|
PIHIDeviceInfo di;
|
||||||
|
PIMap<int, float> prev_axes, cur_axes;
|
||||||
|
PIMap<int, int> prev_buttons, cur_buttons;
|
||||||
|
float dead_zone = 0.f;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public License
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#
|
|
||||||
#ifndef PILIBRARY_H
|
#ifndef PILIBRARY_H
|
||||||
#define PILIBRARY_H
|
#define PILIBRARY_H
|
||||||
|
|
||||||
|
|||||||
@@ -17,16 +17,17 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "piliterals_time.h"
|
|
||||||
#include "pitime.h"
|
#include "pitime.h"
|
||||||
#include "pitranslator.h"
|
|
||||||
#ifndef MICRO_PIP
|
#ifndef MICRO_PIP
|
||||||
|
|
||||||
# include "piincludes_p.h"
|
# include "piincludes_p.h"
|
||||||
|
# include "piliterals_bytes.h"
|
||||||
# include "piprocess.h"
|
# include "piprocess.h"
|
||||||
|
# include "pitranslator.h"
|
||||||
# ifndef WINDOWS
|
# ifndef WINDOWS
|
||||||
# include <csignal>
|
# include <csignal>
|
||||||
# include <sys/wait.h>
|
# include <sys/wait.h>
|
||||||
|
# include <fcntl.h>
|
||||||
# endif
|
# endif
|
||||||
# ifdef MAC_OS
|
# ifdef MAC_OS
|
||||||
# include <crt_externs.h>
|
# include <crt_externs.h>
|
||||||
@@ -63,14 +64,189 @@
|
|||||||
//!
|
//!
|
||||||
|
|
||||||
|
|
||||||
PRIVATE_DEFINITION_START(PIProcess)
|
namespace {
|
||||||
|
enum PipeDirection {
|
||||||
|
PipeRead,
|
||||||
|
PipeWrite,
|
||||||
|
PipeLast = PipeWrite
|
||||||
|
};
|
||||||
|
|
||||||
|
enum StdFile {
|
||||||
|
StdIn,
|
||||||
|
StdOut,
|
||||||
|
StdErr,
|
||||||
|
StdLast = StdErr
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr int PipesDirections = PipeLast + 1;
|
||||||
|
constexpr int StdFileCount = StdLast + 1;
|
||||||
|
|
||||||
|
# ifdef WINDOWS
|
||||||
|
using PipeHandleType = HANDLE;
|
||||||
|
using SizeType = DWORD;
|
||||||
|
# else
|
||||||
|
using SizeType = ssize_t;
|
||||||
|
using PipeHandleType = int;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef WINDOWS
|
||||||
|
PIString convertWindowsCmd(PIStringList sl) {
|
||||||
|
if (sl.isNotEmpty()) {
|
||||||
|
sl[0].replaceAll('/', '\\');
|
||||||
|
sl[0].quote();
|
||||||
|
}
|
||||||
|
return sl.join(' ');
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
char * const * convertToCharArrays(const PIStringList & sl) {
|
||||||
|
char ** cc = new char *[sl.size() + 1];
|
||||||
|
for (int i = 0; i < sl.size_s(); ++i) {
|
||||||
|
cc[i] = const_cast<char *>(sl[i].data());
|
||||||
|
}
|
||||||
|
cc[sl.size()] = 0;
|
||||||
|
return cc;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
PRIVATE_DEFINITION_START(PIProcess)
|
||||||
|
|
||||||
# ifdef WINDOWS
|
# ifdef WINDOWS
|
||||||
STARTUPINFOA si;
|
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
# else
|
# else
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
# endif
|
# endif
|
||||||
FILE *tf_in, *tf_out, *tf_err;
|
PipeHandleType pipes[StdFileCount][PipesDirections];
|
||||||
|
bool grab[StdFileCount];
|
||||||
|
|
||||||
|
|
||||||
|
void forEachPipe(std::function<void(PipeHandleType &)> func) {
|
||||||
|
for (int i = 0; i < StdFileCount; ++i) {
|
||||||
|
for (int j = 0; j < PipesDirections; ++j) {
|
||||||
|
func(pipes[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void initGrab() {
|
||||||
|
for (int i = 0; i < StdFileCount; ++i) {
|
||||||
|
grab[i] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool createPipe(StdFile pipe_type) {
|
||||||
|
const int pt = pipe_type;
|
||||||
|
# ifdef WINDOWS
|
||||||
|
SECURITY_ATTRIBUTES saAttr;
|
||||||
|
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||||
|
saAttr.bInheritHandle = TRUE;
|
||||||
|
saAttr.lpSecurityDescriptor = NULL;
|
||||||
|
if (!CreatePipe(&(pipes[pt][PipeRead]), &(pipes[pt][PipeWrite]), &saAttr, 0)) return false;
|
||||||
|
return true;
|
||||||
|
# else
|
||||||
|
int ret = pipe(pipes[pt]);
|
||||||
|
return ret != -1;
|
||||||
|
# endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool createPipes() {
|
||||||
|
for (int i = 0; i < StdFileCount; ++i) {
|
||||||
|
if (grab[i]) {
|
||||||
|
if (!createPipe(static_cast<StdFile>(i))) {
|
||||||
|
piCout << "CreatePipe failed";
|
||||||
|
# ifdef WINDOWS
|
||||||
|
piCout << GetLastError();
|
||||||
|
# endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# ifdef WINDOWS
|
||||||
|
if (grab[StdIn]) SetHandleInformation(pipes[StdIn][PipeWrite], HANDLE_FLAG_INHERIT, 0);
|
||||||
|
if (grab[StdOut]) SetHandleInformation(pipes[StdOut][PipeRead], HANDLE_FLAG_INHERIT, 0);
|
||||||
|
if (grab[StdErr]) SetHandleInformation(pipes[StdErr][PipeRead], HANDLE_FLAG_INHERIT, 0);
|
||||||
|
# endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void closePipe(StdFile pipe_type, PipeDirection direction) {
|
||||||
|
closePipe(pipes[pipe_type][direction]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void closePipe(PipeHandleType & hpipe) {
|
||||||
|
# ifdef WINDOWS
|
||||||
|
if (hpipe != 0) {
|
||||||
|
CloseHandle(hpipe);
|
||||||
|
hpipe = 0;
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
if (hpipe != -1) {
|
||||||
|
::close(hpipe);
|
||||||
|
hpipe = -1;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void closeAllPipes() {
|
||||||
|
forEachPipe([this](PipeHandleType & hpipe) { closePipe(hpipe); });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIByteArray readPipe(StdFile pipe_type) {
|
||||||
|
if (!grab[pipe_type]) return {};
|
||||||
|
constexpr size_t read_buffer_size = 4_KiB;
|
||||||
|
PIByteArray read_buffer;
|
||||||
|
read_buffer.resize(read_buffer_size);
|
||||||
|
SizeType bytes_read = 0;
|
||||||
|
size_t offset = 0;
|
||||||
|
while (1) {
|
||||||
|
# ifdef WINDOWS
|
||||||
|
DWORD available = 0;
|
||||||
|
bytes_read = 0;
|
||||||
|
PeekNamedPipe(pipes[pipe_type][PipeRead], nullptr, 0, nullptr, &available, nullptr);
|
||||||
|
if (available > 0) {
|
||||||
|
BOOL ok = ReadFile(pipes[pipe_type][PipeRead],
|
||||||
|
read_buffer.data(offset),
|
||||||
|
piMini(available, read_buffer.size() - offset),
|
||||||
|
&bytes_read,
|
||||||
|
nullptr);
|
||||||
|
if (!ok) bytes_read = 0;
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
bytes_read = ::read(pipes[pipe_type][PipeRead], read_buffer.data(offset), read_buffer.size() - offset);
|
||||||
|
# endif
|
||||||
|
if (bytes_read > 0) {
|
||||||
|
offset += bytes_read;
|
||||||
|
read_buffer.resize(offset + read_buffer_size);
|
||||||
|
} else {
|
||||||
|
read_buffer.resize(offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return read_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool writePipe(const PIByteArray & data) {
|
||||||
|
SizeType sz = 0;
|
||||||
|
# ifdef WINDOWS
|
||||||
|
BOOL ok = WriteFile(pipes[StdIn][PipeWrite], data.data(), data.size(), &sz, NULL);
|
||||||
|
if (!ok) sz = 0;
|
||||||
|
# else
|
||||||
|
sz = ::write(pipes[StdIn][PipeWrite], data.data(), data.size());
|
||||||
|
# endif
|
||||||
|
return sz == (SizeType)data.size_s();
|
||||||
|
}
|
||||||
|
|
||||||
PRIVATE_DEFINITION_END(PIProcess)
|
PRIVATE_DEFINITION_END(PIProcess)
|
||||||
|
|
||||||
|
|
||||||
@@ -80,177 +256,129 @@ PIProcess::PIProcess(): PIThread() {
|
|||||||
PRIVATE->pi.dwProcessId = 0;
|
PRIVATE->pi.dwProcessId = 0;
|
||||||
# else
|
# else
|
||||||
PRIVATE->pid = 0;
|
PRIVATE->pid = 0;
|
||||||
|
PRIVATE->forEachPipe([](PipeHandleType & pipe) { pipe = -1; });
|
||||||
# endif
|
# endif
|
||||||
is_exec = false;
|
exec_start = false;
|
||||||
g_in = g_out = g_err = false;
|
exec_finished = false;
|
||||||
t_in = t_out = t_err = false;
|
PRIVATE->initGrab();
|
||||||
PRIVATE->tf_in = PRIVATE->tf_out = PRIVATE->tf_err = 0;
|
|
||||||
env = PIProcess::currentEnvironment();
|
env = PIProcess::currentEnvironment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIProcess::~PIProcess() {
|
PIProcess::~PIProcess() {
|
||||||
PIThread::stopAndWait();
|
PIThread::stopAndWait();
|
||||||
if (t_in) f_in.remove();
|
PRIVATE->closeAllPipes();
|
||||||
if (t_out) f_out.remove();
|
|
||||||
if (t_err) f_err.remove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIProcess::exec_() {
|
void PIProcess::exec_() {
|
||||||
is_exec = false;
|
exec_finished = false;
|
||||||
|
exec_start = false;
|
||||||
|
PRIVATE->closeAllPipes();
|
||||||
startOnce();
|
startOnce();
|
||||||
// cout << "exec wait" << endl;
|
|
||||||
while (!is_exec)
|
|
||||||
piMinSleep();
|
|
||||||
// cout << "exec end" << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIProcess::startProc(bool detached) {
|
void PIProcess::startProc(bool detached) {
|
||||||
// cout << "run" << endl;
|
const PIString & str = args.front();
|
||||||
PIString str;
|
|
||||||
/// arguments convertion
|
|
||||||
int as = 0;
|
|
||||||
const char * argscc[args.size() + 1];
|
|
||||||
int argsl[args.size()];
|
|
||||||
for (int i = 0; i < args.size_s(); ++i) {
|
|
||||||
argscc[i] = args[i].data();
|
|
||||||
argsl[i] = strlen(argscc[i]);
|
|
||||||
as += argsl[i] + 3;
|
|
||||||
}
|
|
||||||
argscc[args.size()] = 0;
|
|
||||||
# ifdef WINDOWS
|
|
||||||
char * a = new char[as];
|
|
||||||
memset(a, ' ', as - 1);
|
|
||||||
as = 0;
|
|
||||||
for (int i = 0; i < args.size_s(); ++i) {
|
|
||||||
str = args[i];
|
|
||||||
a[as] = '"';
|
|
||||||
memcpy(&(a[as + 1]), argscc[i], argsl[i]);
|
|
||||||
a[as + argsl[i] + 1] = '"';
|
|
||||||
as += argsl[i] + 3;
|
|
||||||
}
|
|
||||||
a[as - 1] = 0;
|
|
||||||
// piCout << a;
|
|
||||||
# endif
|
|
||||||
# ifndef WINDOWS
|
|
||||||
/// environment convertion
|
|
||||||
const char * envcc[env.size() + 1];
|
|
||||||
envcc[env.size_s()] = 0;
|
|
||||||
for (int i = 0; i < env.size_s(); ++i) {
|
|
||||||
envcc[i] = env[i].data();
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
/// files for stdin/out/err
|
|
||||||
t_in = t_out = t_err = false;
|
|
||||||
if (f_in.path().isEmpty()) {
|
|
||||||
f_in.openTemporary(PIIODevice::ReadWrite);
|
|
||||||
t_in = true;
|
|
||||||
}
|
|
||||||
if (f_out.path().isEmpty()) {
|
|
||||||
f_out.openTemporary(PIIODevice::ReadWrite);
|
|
||||||
t_out = true;
|
|
||||||
}
|
|
||||||
if (f_err.path().isEmpty()) {
|
|
||||||
f_err.openTemporary(PIIODevice::ReadWrite);
|
|
||||||
t_err = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
str = args.front();
|
|
||||||
is_exec = true;
|
|
||||||
if (!detached) execStarted(str);
|
if (!detached) execStarted(str);
|
||||||
# ifndef WINDOWS
|
if (!PRIVATE->createPipes()) return;
|
||||||
int pid_ = fork();
|
|
||||||
if (!detached) PRIVATE->pid = pid_;
|
|
||||||
if (pid_ == 0) {
|
|
||||||
# endif
|
|
||||||
PRIVATE->tf_in = PRIVATE->tf_out = PRIVATE->tf_err = 0;
|
|
||||||
// cout << "exec " << tf_in << ", " << tf_out << ", " << tf_err << endl;
|
|
||||||
// cout << f_out.path() << endl;
|
|
||||||
if (g_in) PRIVATE->tf_in = freopen(f_in.path().data(), "r", stdin);
|
|
||||||
if (g_out) PRIVATE->tf_out = freopen(f_out.path().data(), "w", stdout);
|
|
||||||
if (g_err) PRIVATE->tf_err = freopen(f_err.path().data(), "w", stderr);
|
|
||||||
|
|
||||||
# ifdef WINDOWS
|
# ifdef WINDOWS
|
||||||
GetStartupInfoA(&(PRIVATE->si));
|
STARTUPINFOA si;
|
||||||
piZeroMemory(PRIVATE->pi);
|
piZeroMemory(si);
|
||||||
|
si.cb = sizeof(STARTUPINFOA);
|
||||||
|
if (PRIVATE->grab[StdIn]) si.hStdInput = PRIVATE->pipes[StdIn][PipeRead];
|
||||||
|
if (PRIVATE->grab[StdOut]) si.hStdOutput = PRIVATE->pipes[StdOut][PipeWrite];
|
||||||
|
if (PRIVATE->grab[StdErr]) si.hStdError = PRIVATE->pipes[StdErr][PipeWrite];
|
||||||
|
si.dwFlags |= STARTF_USESTDHANDLES;
|
||||||
|
const auto cmd = convertWindowsCmd(args);
|
||||||
if (CreateProcessA(0, // No module name (use command line)
|
if (CreateProcessA(0, // No module name (use command line)
|
||||||
a, // Command line
|
(LPSTR)cmd.data(), // Command line
|
||||||
0, // Process handle not inheritable
|
0, // Process handle not inheritable
|
||||||
0, // Thread handle not inheritable
|
0, // Thread handle not inheritable
|
||||||
false, // Set handle inheritance to FALSE
|
true, // Set handle inheritance to FALSE
|
||||||
detached ? DETACHED_PROCESS /*CREATE_NEW_CONSOLE*/ : 0, // Creation flags
|
detached ? DETACHED_PROCESS /*CREATE_NEW_CONSOLE*/ : 0, // Creation flags
|
||||||
0, // envcc, // Use environment
|
0, // Use environment
|
||||||
wd.isEmpty() ? 0 : wd.data(), // Use working directory
|
wd.isEmpty() ? 0 : wd.data(), // Use working directory
|
||||||
&(PRIVATE->si), // Pointer to STARTUPINFO structure
|
&si, // Pointer to STARTUPINFO structure
|
||||||
&(PRIVATE->pi))) // Pointer to PROCESS_INFORMATION structure
|
&(PRIVATE->pi))) // Pointer to PROCESS_INFORMATION structure
|
||||||
{
|
{
|
||||||
|
exec_start = true;
|
||||||
if (!detached) {
|
if (!detached) {
|
||||||
WaitForSingleObject(PRIVATE->pi.hProcess, INFINITE);
|
WaitForSingleObject(PRIVATE->pi.hProcess, INFINITE);
|
||||||
DWORD code = -1;
|
DWORD code = -1;
|
||||||
if (GetExitCodeProcess(PRIVATE->pi.hProcess, &code) != 0) exit_code = code;
|
if (GetExitCodeProcess(PRIVATE->pi.hProcess, &code) != 0) exit_code = code;
|
||||||
|
exec_finished = true;
|
||||||
}
|
}
|
||||||
CloseHandle(PRIVATE->pi.hThread);
|
CloseHandle(PRIVATE->pi.hThread);
|
||||||
CloseHandle(PRIVATE->pi.hProcess);
|
CloseHandle(PRIVATE->pi.hProcess);
|
||||||
} else {
|
} else {
|
||||||
piCoutObj << "\"CreateProcess\" error: %1"_tr("PIProcess").arg(errorString());
|
piCoutObj << "\"CreateProcess\" error: %1"_tr("PIProcess").arg(errorString());
|
||||||
}
|
}
|
||||||
# endif
|
# else
|
||||||
# ifndef WINDOWS
|
auto largs = convertToCharArrays(args);
|
||||||
|
auto lenv = convertToCharArrays(env);
|
||||||
|
int pid_ = fork();
|
||||||
|
if (!detached) PRIVATE->pid = pid_;
|
||||||
|
if (pid_ == 0) {
|
||||||
if (!wd.isEmpty()) {
|
if (!wd.isEmpty()) {
|
||||||
if (!chdir(wd.data())) piCoutObj << "Error while set working directory";
|
if (!chdir(wd.data())) piCoutObj << "Error while set working directory";
|
||||||
}
|
}
|
||||||
// cout << "exec " << tf_in << ", " << tf_out << ", " << tf_err << endl;
|
PRIVATE->closePipe(StdIn, PipeWrite);
|
||||||
if (execve(str.data(), (char * const *)argscc, (char * const *)envcc) < 0) {
|
PRIVATE->closePipe(StdOut, PipeRead);
|
||||||
|
PRIVATE->closePipe(StdErr, PipeRead);
|
||||||
|
|
||||||
|
if (PRIVATE->grab[StdIn]) dup2(PRIVATE->pipes[StdIn][PipeRead], STDIN_FILENO);
|
||||||
|
if (PRIVATE->grab[StdOut]) dup2(PRIVATE->pipes[StdOut][PipeWrite], STDOUT_FILENO);
|
||||||
|
if (PRIVATE->grab[StdErr]) dup2(PRIVATE->pipes[StdErr][PipeWrite], STDERR_FILENO);
|
||||||
|
|
||||||
|
PRIVATE->closePipe(StdIn, PipeRead);
|
||||||
|
PRIVATE->closePipe(StdOut, PipeWrite);
|
||||||
|
PRIVATE->closePipe(StdErr, PipeWrite);
|
||||||
|
|
||||||
|
execve(str.data(), largs, lenv);
|
||||||
|
// normaly execve can't return, if it returns - error occured
|
||||||
piCoutObj << "\"execve" << str << args << "\" error :" << errorString();
|
piCoutObj << "\"execve" << str << args << "\" error :" << errorString();
|
||||||
}
|
exit(127);
|
||||||
} else {
|
} else {
|
||||||
piMinSleep();
|
PRIVATE->closePipe(StdIn, PipeRead);
|
||||||
// cout << "wait" << endl;
|
PRIVATE->closePipe(StdOut, PipeWrite);
|
||||||
|
PRIVATE->closePipe(StdErr, PipeWrite);
|
||||||
|
|
||||||
|
if (PRIVATE->grab[StdOut]) fcntl(PRIVATE->pipes[StdOut][PipeRead], F_SETFL, O_NONBLOCK);
|
||||||
|
if (PRIVATE->grab[StdErr]) fcntl(PRIVATE->pipes[StdErr][PipeRead], F_SETFL, O_NONBLOCK);
|
||||||
|
|
||||||
|
exec_start = true;
|
||||||
if (!detached) {
|
if (!detached) {
|
||||||
waitpid(pid_, &exit_code, 0);
|
waitpid(pid_, &exit_code, 0);
|
||||||
|
if (WIFEXITED(exit_code)) {
|
||||||
|
exec_finished = WEXITSTATUS(exit_code) != 127;
|
||||||
|
}
|
||||||
pid_ = 0;
|
pid_ = 0;
|
||||||
if (!detached) PRIVATE->pid = pid_;
|
if (!detached) PRIVATE->pid = pid_;
|
||||||
// cout << "wait done" << endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
delete[] largs;
|
||||||
|
delete[] lenv;
|
||||||
# endif
|
# endif
|
||||||
if (!detached) execFinished(str, exit_code);
|
if (!detached) execFinished(str, exit_code);
|
||||||
is_exec = false;
|
exec_start = false;
|
||||||
# ifdef WINDOWS
|
|
||||||
delete[] a;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
PIByteArray PIProcess::readFile(PIFile & f, bool clear)
|
|
||||||
{
|
|
||||||
f.open(PIIODevice::ReadOnly);
|
|
||||||
const auto ret = f.readAll();
|
|
||||||
if (clear) {
|
|
||||||
f.clear();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIProcess::terminate() {
|
void PIProcess::terminate() {
|
||||||
# ifdef WINDOWS
|
# ifdef WINDOWS
|
||||||
if (is_exec)
|
if (exec_start) {
|
||||||
if (!TerminateProcess(PRIVATE->pi.hProcess, 0)) return;
|
if (!TerminateProcess(PRIVATE->pi.hProcess, 0)) return;
|
||||||
|
}
|
||||||
PRIVATE->pi.dwProcessId = 0;
|
PRIVATE->pi.dwProcessId = 0;
|
||||||
# else
|
# else
|
||||||
if (is_exec) kill(PRIVATE->pid, SIGKILL);
|
if (exec_start) kill(PRIVATE->pid, SIGKILL);
|
||||||
PRIVATE->pid = 0;
|
PRIVATE->pid = 0;
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIProcess::waitForFinish() {
|
|
||||||
return PIThread::waitForFinish(1_m);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void PIProcess::execIndependent(const PIString & program, const PIStringList & args_) {
|
void PIProcess::execIndependent(const PIString & program, const PIStringList & args_) {
|
||||||
PIProcess p;
|
PIProcess p;
|
||||||
p.args << program << args_;
|
p.args << program << args_;
|
||||||
@@ -266,12 +394,45 @@ int PIProcess::pID() const {
|
|||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
PIByteArray PIProcess::readOutput(bool clear) {
|
|
||||||
return readFile(f_out, clear);
|
PIByteArray PIProcess::readOutput() {
|
||||||
|
return PRIVATE->readPipe(StdOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
PIByteArray PIProcess::readError(bool clear) {
|
|
||||||
return readFile(f_err, clear);
|
PIByteArray PIProcess::readError() {
|
||||||
|
return PRIVATE->readPipe(StdErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIProcess::writeInput(const PIByteArray & data) {
|
||||||
|
if (PRIVATE->grab[StdIn]) return PRIVATE->writePipe(data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIProcess::closeInput() {
|
||||||
|
if (PRIVATE->grab[StdIn]) {
|
||||||
|
# ifdef WINDOWS
|
||||||
|
PRIVATE->writePipe({0x1A});
|
||||||
|
# endif
|
||||||
|
PRIVATE->closePipe(StdIn, PipeWrite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIProcess::enableWriteStdIn(bool on) {
|
||||||
|
PRIVATE->grab[StdIn] = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIProcess::enableReadStdOut(bool on) {
|
||||||
|
PRIVATE->grab[StdOut] = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIProcess::enableReadStdErr(bool on) {
|
||||||
|
PRIVATE->grab[StdErr] = on;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,14 +28,45 @@
|
|||||||
|
|
||||||
#ifndef MICRO_PIP
|
#ifndef MICRO_PIP
|
||||||
|
|
||||||
# include "pifile.h"
|
|
||||||
# include "pithread.h"
|
# include "pithread.h"
|
||||||
|
|
||||||
|
//! \class PIProcess
|
||||||
//! \ingroup System
|
//! \ingroup System
|
||||||
//! \~\brief
|
//! \~english
|
||||||
//! \~english External process.
|
//! \brief Class for managing external processes
|
||||||
//! \~russian Внешний процесс.
|
//! \details
|
||||||
|
//! The PIProcess class provides functionality to create, control and interact with external processes.
|
||||||
|
//! It allows both attached execution (with full control over input/output streams) and detached execution.
|
||||||
|
//!
|
||||||
|
//! Key features:
|
||||||
|
//! - Start processes with arguments and environment variables
|
||||||
|
//! - Monitor process state (running/finished)
|
||||||
|
//! - Read from stdout/stderr streams
|
||||||
|
//! - Write to stdin stream
|
||||||
|
//! - Set custom working directory
|
||||||
|
//! - Modify environment variables
|
||||||
|
//! - Wait for process completion
|
||||||
|
//! - Terminate processes
|
||||||
|
//! - Retrieve exit codes and process IDs
|
||||||
|
//!
|
||||||
|
//! This class inherits from PIThread and provides event-based notifications for process lifecycle events.
|
||||||
|
//! \~russian
|
||||||
|
//! \brief Класс для управления внешними процессами
|
||||||
|
//! \details
|
||||||
|
//! Класс PIProcess предоставляет функциональность для создания, управления и взаимодействия с внешними процессами.
|
||||||
|
//! Поддерживает как присоединенное выполнение (с полным контролем потоков ввода/вывода), так и независимое выполнение.
|
||||||
|
//!
|
||||||
|
//! Основные возможности:
|
||||||
|
//! - Запуск процессов с аргументами и переменными окружения
|
||||||
|
//! - Мониторинг состояния процесса (запущен/завершен)
|
||||||
|
//! - Чтение из потоков stdout/stderr
|
||||||
|
//! - Запись в поток stdin
|
||||||
|
//! - Установка рабочей директории
|
||||||
|
//! - Изменение переменных окружения
|
||||||
|
//! - Ожидание завершения процесса
|
||||||
|
//! - Завершение процессов
|
||||||
|
//! - Получение кодов завершения и идентификаторов процессов
|
||||||
|
//!
|
||||||
class PIP_EXPORT PIProcess: public PIThread {
|
class PIP_EXPORT PIProcess: public PIThread {
|
||||||
PIOBJECT_SUBCLASS(PIProcess, PIThread);
|
PIOBJECT_SUBCLASS(PIProcess, PIThread);
|
||||||
|
|
||||||
@@ -55,74 +86,64 @@ public:
|
|||||||
//! \~russian Возвращает ID процесса текущего выполнения
|
//! \~russian Возвращает ID процесса текущего выполнения
|
||||||
int pID() const;
|
int pID() const;
|
||||||
|
|
||||||
void setGrabInput(bool yes) { g_in = yes; }
|
|
||||||
|
|
||||||
//! \~english Set attached execution grab output stream enabled
|
|
||||||
//! \~russian
|
|
||||||
void setGrabOutput(bool yes) { g_out = yes; }
|
|
||||||
|
|
||||||
//! \~english Set attached execution grab error stream enabled
|
|
||||||
//! \~russian
|
|
||||||
void setGrabError(bool yes) { g_err = yes; }
|
|
||||||
|
|
||||||
void setInputFile(const PIString & path) { f_in.setPath(path); }
|
|
||||||
|
|
||||||
//! \~english Set attached execution grab output stream file
|
|
||||||
//! \~russian
|
|
||||||
void setOutputFile(const PIString & path) { f_out.setPath(path); }
|
|
||||||
|
|
||||||
//! \~english Set attached execution grab error stream file
|
|
||||||
//! \~russian
|
|
||||||
void setErrorFile(const PIString & path) { f_err.setPath(path); }
|
|
||||||
|
|
||||||
void unsetInputFile() { f_in.setPath(""); }
|
|
||||||
|
|
||||||
//! \~english Reset attached execution grab output stream file
|
|
||||||
//! \~russian
|
|
||||||
void unsetOutputFile() { f_out.setPath(""); }
|
|
||||||
|
|
||||||
//! \~english Reset attached execution grab error stream file
|
|
||||||
//! \~russian
|
|
||||||
void unsetErrorFile() { f_err.setPath(""); }
|
|
||||||
|
|
||||||
//! \~english Returns current attached execution working directory or empty string if it wasn`t set
|
//! \~english Returns current attached execution working directory or empty string if it wasn`t set
|
||||||
//! \~russian
|
//! \~russian Возвращает рабочую директорию выполнения или пустую строку, если не установлена
|
||||||
PIString workingDirectory() const { return wd; }
|
PIString workingDirectory() const { return wd; }
|
||||||
|
|
||||||
//! \~english Set attached execution working directory
|
//! \~english Set attached execution working directory
|
||||||
//! \~russian
|
//! \~russian Устанавливает рабочую директорию для выполнения
|
||||||
void setWorkingDirectory(const PIString & path) { wd = path; }
|
void setWorkingDirectory(const PIString & path) { wd = path; }
|
||||||
|
|
||||||
//! \~english Rseet attached execution working directory, application working dir will be used
|
//! \~english Rseet attached execution working directory, application working dir will be used
|
||||||
//! \~russian
|
//! \~russian Сбрасывает рабочую директорию, будет использоваться директория приложения
|
||||||
void resetWorkingDirectory() { wd.clear(); }
|
void resetWorkingDirectory() { wd.clear(); }
|
||||||
|
|
||||||
//! \~english Returns all attached execution output stream
|
//! \~english Returns all attached execution output stream
|
||||||
//! \~russian
|
//! \~russian Возвращает весь вывод из стандартного потока вывода (stdout)
|
||||||
PIByteArray readOutput(bool clear = false);
|
PIByteArray readOutput();
|
||||||
|
|
||||||
//! \~english Returns all attached execution error stream
|
//! \~english Returns all attached execution error stream
|
||||||
//! \~russian
|
//! \~russian Возвращает весь вывод из потока ошибок (stderr)
|
||||||
PIByteArray readError(bool clear = false);
|
PIByteArray readError();
|
||||||
|
|
||||||
|
//! \~english Write data to attached execution input stream
|
||||||
|
//! \~russian Записывает данные в стандартный поток ввода (stdin)
|
||||||
|
bool writeInput(const PIByteArray & data);
|
||||||
|
|
||||||
|
//! \~english Close attached execution input stream and send EOF
|
||||||
|
//! \~russian Закрывает поток ввода (stdin) и отправляет EOF
|
||||||
|
void closeInput();
|
||||||
|
|
||||||
|
//! \~english Enable or disable writing to process stdin
|
||||||
|
//! \~russian Включает или отключает запись в стандартный поток ввода (stdin) процесса
|
||||||
|
void enableWriteStdIn(bool on = true);
|
||||||
|
|
||||||
|
//! \~english Enable or disable reading from process stdout
|
||||||
|
//! \~russian Включает или отключает чтение из стандартного потока вывода (stdout) процесса
|
||||||
|
void enableReadStdOut(bool on = true);
|
||||||
|
|
||||||
|
//! \~english Enable or disable reading from process stderr
|
||||||
|
//! \~russian Включает или отключает чтение из потока ошибок (stderr) процесса
|
||||||
|
void enableReadStdErr(bool on = true);
|
||||||
|
|
||||||
//! \~english Returns current attached execution environment
|
//! \~english Returns current attached execution environment
|
||||||
//! \~russian
|
//! \~russian Возвращает текущее окружение выполнения
|
||||||
PIStringList environment() { return env; }
|
PIStringList environment() { return env; }
|
||||||
|
|
||||||
//! \~english Clear current attached execution environment. Call before \a exec()
|
//! \~english Clear current attached execution environment. Call before \a exec()
|
||||||
//! \~russian
|
//! \~russian Очищает окружение выполнения. Вызывать перед \a exec()
|
||||||
void clearEnvironment() { env.clear(); }
|
void clearEnvironment() { env.clear(); }
|
||||||
|
|
||||||
//! \~english Remove variable "variable" from current attached execution environment. Call before \a exec()
|
//! \~english Remove variable "variable" from current attached execution environment. Call before \a exec()
|
||||||
//! \~russian
|
//! \~russian Удаляет переменную "variable" из окружения выполнения. Вызывать перед \a exec()
|
||||||
void removeEnvironmentVariable(const PIString & variable);
|
void removeEnvironmentVariable(const PIString & variable);
|
||||||
|
|
||||||
//! \~english Set variable "variable" to "value" in current attached execution environment. Call before \a exec()
|
//! \~english Set variable "variable" to "value" in current attached execution environment. Call before \a exec()
|
||||||
//! \~russian
|
//! \~russian Устанавливает значение "value" для переменной "variable" в окружении выполнения. Вызывать перед \a exec()
|
||||||
void setEnvironmentVariable(const PIString & variable, const PIString & value);
|
void setEnvironmentVariable(const PIString & variable, const PIString & value);
|
||||||
|
|
||||||
//! \~english Start attached execution "program" with one argument "arg"
|
//! \~english Start attached execution "program" with one argument "arg"
|
||||||
//! \~russian
|
//! \~russian Запускает выполнение "program" с одним аргументом "arg"
|
||||||
void exec(const PIString & program, const PIString & arg) {
|
void exec(const PIString & program, const PIString & arg) {
|
||||||
args.clear();
|
args.clear();
|
||||||
args << program << arg;
|
args << program << arg;
|
||||||
@@ -140,36 +161,43 @@ public:
|
|||||||
exec_();
|
exec_();
|
||||||
}
|
}
|
||||||
EVENT_HANDLER(void, terminate);
|
EVENT_HANDLER(void, terminate);
|
||||||
EVENT_HANDLER(bool, waitForFinish);
|
EVENT_HANDLER(bool, waitForFinish) { return PIThread::waitForFinish(); }
|
||||||
EVENT_HANDLER1(bool, waitForFinish, PISystemTime, timeout) { return PIThread::waitForFinish(timeout); }
|
EVENT_HANDLER1(bool, waitForFinish, PISystemTime, timeout) { return PIThread::waitForFinish(timeout); }
|
||||||
|
|
||||||
EVENT1(execStarted, PIString, program);
|
EVENT1(execStarted, PIString, program);
|
||||||
EVENT2(execFinished, PIString, program, int, exit_code);
|
EVENT2(execFinished, PIString, program, int, exit_code);
|
||||||
|
|
||||||
|
//! \~english Check if attached execution has finished
|
||||||
|
//! \~russian Проверяет, завершилось ли выполнение процесса
|
||||||
|
bool isExecFinished() const { return exec_finished; }
|
||||||
|
|
||||||
|
//! \~english Check if attached execution has started
|
||||||
|
//! \~russian Проверяет, запущен ли процесс выполнения
|
||||||
|
bool isExecStarted() const { return exec_start; }
|
||||||
|
|
||||||
//! \~english Start detached execution "program" without arguments
|
//! \~english Start detached execution "program" without arguments
|
||||||
//! \~russian
|
//! \~russian Запускает независимое выполнение "program" без аргументов
|
||||||
static void execIndependent(const PIString & program) { execIndependent(program, PIStringList()); }
|
static void execIndependent(const PIString & program) { execIndependent(program, PIStringList()); }
|
||||||
|
|
||||||
//! \~english Start detached execution "program" with one argument "arg"
|
//! \~english Start detached execution "program" with one argument "arg"
|
||||||
//! \~russian
|
//! \~russian Запускает независимое выполнение "program" с одним аргументом "arg"
|
||||||
static void execIndependent(const PIString & program, const PIString & arg) { execIndependent(program, PIStringList() << arg); }
|
static void execIndependent(const PIString & program, const PIString & arg) { execIndependent(program, PIStringList() << arg); }
|
||||||
|
|
||||||
//! \~english Start detached execution "program" with arguments "args"
|
//! \~english Start detached execution "program" with arguments "args"
|
||||||
//! \~russian
|
//! \~russian Запускает независимое выполнение "program" с аргументами "args"
|
||||||
static void execIndependent(const PIString & program, const PIStringList & args);
|
static void execIndependent(const PIString & program, const PIStringList & args);
|
||||||
|
|
||||||
|
|
||||||
//! \~english Returns application environment
|
//! \~english Returns application environment
|
||||||
//! \~russian
|
//! \~russian Возвращает окружение текущего приложения
|
||||||
static PIStringList currentEnvironment();
|
static PIStringList currentEnvironment();
|
||||||
|
|
||||||
//! \~english Returns application process ID
|
//! \~english Returns application process ID
|
||||||
//! \~russian
|
//! \~russian Возвращает ID процесса текущего приложения
|
||||||
static int currentPID();
|
static int currentPID();
|
||||||
|
|
||||||
//! \~english Returns variable "variable" value from application environment
|
//! \~english Returns variable "variable" value from application environment
|
||||||
//! \~russian
|
//! \~russian Возвращает значение переменной "variable" из окружения приложения
|
||||||
static PIString getEnvironmentVariable(const PIString & variable);
|
static PIString getEnvironmentVariable(const PIString & variable);
|
||||||
|
|
||||||
//! \handlers
|
//! \handlers
|
||||||
@@ -178,27 +206,27 @@ public:
|
|||||||
//! \fn void exec(const PIString & program)
|
//! \fn void exec(const PIString & program)
|
||||||
//! \brief
|
//! \brief
|
||||||
//! \~english Start attached execution "program" without arguments
|
//! \~english Start attached execution "program" without arguments
|
||||||
//! \~russian
|
//! \~russian Запускает выполнение "program" без аргументов
|
||||||
|
|
||||||
//! \fn void exec(const PIString & program, const PIStringList & args)
|
//! \fn void exec(const PIString & program, const PIStringList & args)
|
||||||
//! \brief
|
//! \brief
|
||||||
//! \~english Start attached execution "program" with arguments "args"
|
//! \~english Start attached execution "program" with arguments "args"
|
||||||
//! \~russian
|
//! \~russian Запускает выполнение "program" с аргументами "args"
|
||||||
|
|
||||||
//! \fn void terminate()
|
//! \fn void terminate()
|
||||||
//! \brief
|
//! \brief
|
||||||
//! \~english Immediately terminate attached execution
|
//! \~english Immediately terminate attached execution
|
||||||
//! \~russian
|
//! \~russian Немедленно завершает выполнение
|
||||||
|
|
||||||
//! \fn bool waitForFinish()
|
//! \fn bool waitForFinish()
|
||||||
//! \brief
|
//! \brief
|
||||||
//! \~english Wait for attached execution finish maximum for 60 seconds
|
//! \~english Wait for attached execution finish maximum for 60 seconds
|
||||||
//! \~russian
|
//! \~russian Ожидает завершения выполнения (максимум 60 секунд)
|
||||||
|
|
||||||
//! \fn bool waitForFinish(PISystemTime timeout)
|
//! \fn bool waitForFinish(PISystemTime timeout)
|
||||||
//! \brief
|
//! \brief
|
||||||
//! \~english Wait for attached execution finish maximum for "timeout_"
|
//! \~english Wait for attached execution finish maximum for "timeout_"
|
||||||
//! \~russian
|
//! \~russian Ожидает завершения выполнения в течение "timeout_"
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
//! \events
|
//! \events
|
||||||
@@ -207,12 +235,12 @@ public:
|
|||||||
//! \fn void execStarted(PIString program)
|
//! \fn void execStarted(PIString program)
|
||||||
//! \brief
|
//! \brief
|
||||||
//! \~english Raise on attached execution start
|
//! \~english Raise on attached execution start
|
||||||
//! \~russian
|
//! \~russian Генерируется при запуске выполнения
|
||||||
|
|
||||||
//! \fn void execFinished(PIString program)
|
//! \fn void execFinished(PIString program)
|
||||||
//! \brief
|
//! \brief
|
||||||
//! \~english Raise on attached execution finish
|
//! \~english Raise on attached execution finish
|
||||||
//! \~russian
|
//! \~russian Генерируется при завершении выполнения
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -220,16 +248,14 @@ private:
|
|||||||
void run() override;
|
void run() override;
|
||||||
void exec_();
|
void exec_();
|
||||||
void startProc(bool detached);
|
void startProc(bool detached);
|
||||||
PIByteArray readFile(PIFile & f, bool clear);
|
|
||||||
|
|
||||||
|
private:
|
||||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||||
PIStringList args, env;
|
PIStringList args, env;
|
||||||
PIString wd;
|
PIString wd;
|
||||||
PIByteArray out;
|
|
||||||
PIFile f_in, f_out, f_err;
|
|
||||||
bool g_in, g_out, g_err, t_in, t_out, t_err;
|
|
||||||
int exit_code;
|
int exit_code;
|
||||||
bool is_exec;
|
std::atomic_bool exec_start;
|
||||||
|
std::atomic_bool exec_finished;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MICRO_PIP
|
#endif // MICRO_PIP
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ PIString PISystemInfo::machineKey() {
|
|||||||
PISystemInfo * si = instance();
|
PISystemInfo * si = instance();
|
||||||
PIByteArray salt;
|
PIByteArray salt;
|
||||||
PIString conf = confDir() + "/.pip_machine_salt";
|
PIString conf = confDir() + "/.pip_machine_salt";
|
||||||
if (PIFile::isExists(conf)) salt = PIFile::readAll(conf, false);
|
if (PIFile::isExists(conf)) salt = PIFile::readAll(conf);
|
||||||
if (salt.size_s() != SALT_SIZE) {
|
if (salt.size_s() != SALT_SIZE) {
|
||||||
salt = generateSalt();
|
salt = generateSalt();
|
||||||
PIFile::writeAll(conf, salt);
|
PIFile::writeAll(conf, salt);
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
#ifndef PISYSTEMMODULE_H
|
#ifndef PISYSTEMMODULE_H
|
||||||
#define PISYSTEMMODULE_H
|
#define PISYSTEMMODULE_H
|
||||||
|
|
||||||
|
#include "pihidevice.h"
|
||||||
#include "pilibrary.h"
|
#include "pilibrary.h"
|
||||||
#include "piplugin.h"
|
#include "piplugin.h"
|
||||||
#include "piprocess.h"
|
#include "piprocess.h"
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ public:
|
|||||||
if (isNull() && s.isNull()) return true;
|
if (isNull() && s.isNull()) return true;
|
||||||
if (isNull() xor s.isNull()) return false;
|
if (isNull() xor s.isNull()) return false;
|
||||||
if (size() != s.size()) return false;
|
if (size() != s.size()) return false;
|
||||||
return strcmp(str, s.str) == 0;
|
return strncmp(str, s.str, size()) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \~english Compare operator.
|
//! \~english Compare operator.
|
||||||
@@ -209,7 +209,7 @@ public:
|
|||||||
if (isNull() && s.isNull()) return false;
|
if (isNull() && s.isNull()) return false;
|
||||||
if (isNull() && !s.isNull()) return true;
|
if (isNull() && !s.isNull()) return true;
|
||||||
if (!isNull() && s.isNull()) return false;
|
if (!isNull() && s.isNull()) return false;
|
||||||
if (size() == s.size()) return strcmp(str, s.str) < 0;
|
if (size() == s.size()) return strncmp(str, s.str, size()) < 0;
|
||||||
return size() < s.size();
|
return size() < s.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +219,7 @@ public:
|
|||||||
if (isNull() && s.isNull()) return false;
|
if (isNull() && s.isNull()) return false;
|
||||||
if (isNull() && !s.isNull()) return false;
|
if (isNull() && !s.isNull()) return false;
|
||||||
if (!isNull() && s.isNull()) return true;
|
if (!isNull() && s.isNull()) return true;
|
||||||
if (size() == s.size()) return strcmp(str, s.str) > 0;
|
if (size() == s.size()) return strncmp(str, s.str, size()) > 0;
|
||||||
return size() > s.size();
|
return size() > s.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -192,25 +192,8 @@ int PIRegularExpression::captureGroupIndex(const PIString & gname) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIRegularExpression::Matcher PIRegularExpression::matchIterator(PIString & subject, size_t offset) {
|
PIRegularExpression::Matcher PIRegularExpression::matchIterator(const PIString & subject, size_t offset) const {
|
||||||
PIRegularExpression::Matcher ret(this);
|
PIRegularExpression::Matcher ret(const_cast<PIRegularExpression *>(this));
|
||||||
ret.start_offset = offset;
|
|
||||||
ret.subject = &subject;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PIRegularExpression::Matcher PIRegularExpression::matchIterator(PIString && subject, size_t offset) {
|
|
||||||
PIRegularExpression::Matcher ret(this);
|
|
||||||
ret.start_offset = offset;
|
|
||||||
ret.subject_own = std::move(subject);
|
|
||||||
ret.subject = &ret.subject_own;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PIRegularExpression::Matcher PIRegularExpression::matchIterator(const PIString & subject, size_t offset) {
|
|
||||||
PIRegularExpression::Matcher ret(this);
|
|
||||||
ret.start_offset = offset;
|
ret.start_offset = offset;
|
||||||
ret.subject_own = subject;
|
ret.subject_own = subject;
|
||||||
ret.subject = &ret.subject_own;
|
ret.subject = &ret.subject_own;
|
||||||
@@ -218,27 +201,44 @@ PIRegularExpression::Matcher PIRegularExpression::matchIterator(const PIString &
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIRegularExpression::Matcher PIRegularExpression::match(PIString & subject, size_t offset) {
|
PIRegularExpression::Matcher PIRegularExpression::matchIterator(PIString & subject, size_t offset) const {
|
||||||
|
PIRegularExpression::Matcher ret(const_cast<PIRegularExpression *>(this));
|
||||||
|
ret.start_offset = offset;
|
||||||
|
ret.subject = &subject;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIRegularExpression::Matcher PIRegularExpression::matchIterator(PIString && subject, size_t offset) const {
|
||||||
|
PIRegularExpression::Matcher ret(const_cast<PIRegularExpression *>(this));
|
||||||
|
ret.start_offset = offset;
|
||||||
|
ret.subject_own = std::move(subject);
|
||||||
|
ret.subject = &ret.subject_own;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIRegularExpression::Matcher PIRegularExpression::match(const PIString & subject, size_t offset) const {
|
||||||
PIRegularExpression::Matcher ret = matchIterator(subject, offset);
|
PIRegularExpression::Matcher ret = matchIterator(subject, offset);
|
||||||
PRIVATE->match(ret);
|
PRIVATE->match(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIRegularExpression::Matcher PIRegularExpression::match(PIString && subject, size_t offset) {
|
PIRegularExpression::Matcher PIRegularExpression::match(PIString & subject, size_t offset) const {
|
||||||
|
PIRegularExpression::Matcher ret = matchIterator(subject, offset);
|
||||||
|
PRIVATE->match(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIRegularExpression::Matcher PIRegularExpression::match(PIString && subject, size_t offset) const {
|
||||||
PIRegularExpression::Matcher ret = matchIterator(std::move(subject), offset);
|
PIRegularExpression::Matcher ret = matchIterator(std::move(subject), offset);
|
||||||
PRIVATE->match(ret);
|
PRIVATE->match(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIRegularExpression::Matcher PIRegularExpression::match(const PIString & subject, size_t offset) {
|
|
||||||
PIRegularExpression::Matcher ret = matchIterator(subject, offset);
|
|
||||||
PRIVATE->match(ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PIRegularExpression::Matcher::Matcher(PIRegularExpression * p): parent(p) {}
|
PIRegularExpression::Matcher::Matcher(PIRegularExpression * p): parent(p) {}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,40 +28,135 @@
|
|||||||
|
|
||||||
#include "pistring.h"
|
#include "pistring.h"
|
||||||
|
|
||||||
|
//! \ingroup Text
|
||||||
|
//! \brief Regular expression class
|
||||||
|
//! \~english Class for working with regular expressions
|
||||||
|
//! \~russian Класс для работы с регулярными выражениями
|
||||||
|
//!
|
||||||
class PIP_EXPORT PIRegularExpression {
|
class PIP_EXPORT PIRegularExpression {
|
||||||
public:
|
public:
|
||||||
|
//! \brief
|
||||||
|
//! \~english Options for regular expression matching behavior
|
||||||
|
//! \~russian Опции поведения регулярного выражения
|
||||||
enum Option {
|
enum Option {
|
||||||
None = 0x0,
|
None = 0x0, /*!< \~english No special options \~russian Без специальных опций */
|
||||||
CaseInsensitive = 0x01,
|
CaseInsensitive = 0x01, /*!< \~english Case insensitive matching \~russian Регистронезависимое сопоставление */
|
||||||
Singleline = 0x02,
|
Singleline = 0x02, /*!< \~english Dot matches newline \~russian Точка соответствует символу новой строки */
|
||||||
Multiline = 0x04,
|
Multiline = 0x04, /*!< \~english ^ and $ match at line boundaries \~russian ^ и $ соответствуют границам строк */
|
||||||
InvertedGreediness = 0x08,
|
InvertedGreediness = 0x08, /*!< \~english Quantifiers are non-greedy by default \~russian Квантификаторы по умолчанию нежадные */
|
||||||
Extended = 0x10
|
Extended = 0x10 /*!< \~english Extended pattern syntax \~russian Расширенный синтаксис шаблона */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Combination of regular expression options
|
||||||
|
//! \~russian Комбинация флагов опций регулярного выражения
|
||||||
typedef PIFlags<Option> Options;
|
typedef PIFlags<Option> Options;
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Creates regular expression with given pattern and options
|
||||||
|
//! \~russian Создает регулярное выражение с указанным шаблоном и опциями
|
||||||
|
//! \~english \param pattern Regular expression pattern
|
||||||
|
//! \~russian \param pattern Шаблон регулярного выражения
|
||||||
|
//! \~english \param opt Matching options
|
||||||
|
//! \~russian \param opt Опции сопоставления
|
||||||
PIRegularExpression(const PIString & pattern = {}, Options opt = None);
|
PIRegularExpression(const PIString & pattern = {}, Options opt = None);
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Creates copy of regular expression
|
||||||
|
//! \~russian Создает копию регулярного выражения
|
||||||
|
//! \~english \param o Source regular expression
|
||||||
|
//! \~russian \param o Исходное регулярное выражение
|
||||||
PIRegularExpression(const PIRegularExpression & o);
|
PIRegularExpression(const PIRegularExpression & o);
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Assigns regular expression
|
||||||
|
//! \~russian Присваивает регулярное выражение
|
||||||
|
//! \~english \param o Source regular expression
|
||||||
|
//! \~russian \param o Исходное регулярное выражение
|
||||||
PIRegularExpression & operator=(const PIRegularExpression & o);
|
PIRegularExpression & operator=(const PIRegularExpression & o);
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Destroys regular expression object
|
||||||
|
//! \~russian Уничтожает объект регулярного выражения
|
||||||
~PIRegularExpression();
|
~PIRegularExpression();
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Class containing regular expression match results
|
||||||
|
//! \~russian Класс, содержащий результаты сопоставления регулярного выражения
|
||||||
class PIP_EXPORT Matcher {
|
class PIP_EXPORT Matcher {
|
||||||
friend class PIRegularExpression;
|
friend class PIRegularExpression;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns true if match was found
|
||||||
|
//! \~russian Возвращает true, если совпадение найдено
|
||||||
operator bool() const { return hasMatch(); }
|
operator bool() const { return hasMatch(); }
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns true if match was found
|
||||||
|
//! \~russian Возвращает true, если совпадение найдено
|
||||||
bool hasMatch() const;
|
bool hasMatch() const;
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Attempts to find next match in subject string
|
||||||
|
//! \~russian Пытается найти следующее совпадение в строке
|
||||||
|
//! \~english \return true if next match was found
|
||||||
|
//! \~russian \return true, если следующее совпадение найдено
|
||||||
bool next();
|
bool next();
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns list of all matched strings
|
||||||
|
//! \~russian Возвращает список всех совпавших строк
|
||||||
PIStringList matchedStrings() const;
|
PIStringList matchedStrings() const;
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns matched substring by index
|
||||||
|
//! \~russian Возвращает совпавшую подстроку по индексу
|
||||||
|
//! \~english \param index Capture group index (0 for entire match)
|
||||||
|
//! \~russian \param index Индекс группы захвата (0 для полного совпадения)
|
||||||
PIString matchedString(int index = 0) const;
|
PIString matchedString(int index = 0) const;
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns start position of matched substring
|
||||||
|
//! \~russian Возвращает начальную позицию совпавшей подстроки
|
||||||
|
//! \~english \param index Capture group index (0 for entire match)
|
||||||
|
//! \~russian \param index Индекс группы захвата (0 для полного совпадения)
|
||||||
int matchedStart(int index = 0) const;
|
int matchedStart(int index = 0) const;
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns length of matched substring
|
||||||
|
//! \~russian Возвращает длину совпавшей подстроки
|
||||||
|
//! \~english \param index Capture group index (0 for entire match)
|
||||||
|
//! \~russian \param index Индекс группы захвата (0 для полного совпадения)
|
||||||
int matchedSize(int index = 0) const;
|
int matchedSize(int index = 0) const;
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns matched substring by group name
|
||||||
|
//! \~russian Возвращает совпавшую подстроку по имени группы
|
||||||
|
//! \~english \param gname Capture group name
|
||||||
|
//! \~russian \param gname Имя группы захвата
|
||||||
PIString matchedString(const PIString & gname) const;
|
PIString matchedString(const PIString & gname) const;
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns start position of named capture group
|
||||||
|
//! \~russian Возвращает начальную позицию именованной группы захвата
|
||||||
|
//! \~english \param gname Capture group name
|
||||||
|
//! \~russian \param gname Имя группы захвата
|
||||||
int matchedStart(const PIString & gname) const;
|
int matchedStart(const PIString & gname) const;
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns length of named capture group match
|
||||||
|
//! \~russian Возвращает длину совпадения именованной группы захвата
|
||||||
|
//! \~english \param gname Capture group name
|
||||||
|
//! \~russian \param gname Имя группы захвата
|
||||||
int matchedSize(const PIString & gname) const;
|
int matchedSize(const PIString & gname) const;
|
||||||
|
|
||||||
Matcher(Matcher &&) = default;
|
Matcher(Matcher &&) = default;
|
||||||
@@ -87,31 +182,142 @@ public:
|
|||||||
size_t start_offset = 0;
|
size_t start_offset = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns regular expression pattern
|
||||||
|
//! \~russian Возвращает шаблон регулярного выражения
|
||||||
PIString pattern() const { return pat_; }
|
PIString pattern() const { return pat_; }
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns regular expression options
|
||||||
|
//! \~russian Возвращает опции регулярного выражения
|
||||||
Options options() const { return opt_; }
|
Options options() const { return opt_; }
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Sets regular expression pattern
|
||||||
|
//! \~russian Устанавливает шаблон регулярного выражения
|
||||||
|
//! \~english \param pattern New pattern
|
||||||
|
//! \~russian \param pattern Новый шаблон
|
||||||
void setPattern(const PIString & pattern);
|
void setPattern(const PIString & pattern);
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Sets regular expression pattern and options
|
||||||
|
//! \~russian Устанавливает шаблон и опции регулярного выражения
|
||||||
|
//! \~english \param pattern New pattern
|
||||||
|
//! \~russian \param pattern Новый шаблон
|
||||||
|
//! \~english \param opt New options
|
||||||
|
//! \~russian \param opt Новые опции
|
||||||
void setPattern(const PIString & pattern, Options opt);
|
void setPattern(const PIString & pattern, Options opt);
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns true if regular expression is valid
|
||||||
|
//! \~russian Возвращает true, если регулярное выражение валидно
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns true if regular expression is not valid
|
||||||
|
//! \~russian Возвращает true, если регулярное выражение невалидно
|
||||||
bool isNotValid() const { return !isValid(); }
|
bool isNotValid() const { return !isValid(); }
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns error description if pattern is invalid
|
||||||
|
//! \~russian Возвращает описание ошибки, если шаблон невалиден
|
||||||
PIString errorString() const;
|
PIString errorString() const;
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Returns position of error in pattern
|
||||||
|
//! \~russian Возвращает позицию ошибки в шаблоне
|
||||||
int errorPosition() const;
|
int errorPosition() const;
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Gets the number of capture groups in the pattern
|
||||||
|
//! \~russian Возвращает количество групп захвата в шаблоне
|
||||||
int captureGroupsCount() const;
|
int captureGroupsCount() const;
|
||||||
|
|
||||||
|
//! \~english Gets the list of named capture groups
|
||||||
|
//! \~russian Возвращает список именованных групп захвата
|
||||||
PIStringList captureGroupNames() const;
|
PIStringList captureGroupNames() const;
|
||||||
|
|
||||||
|
//! \~english Gets the name of capture group by index
|
||||||
|
//! \~russian Возвращает имя группы захвата по индексу
|
||||||
|
//! \~english \param index Group index
|
||||||
|
//! \~russian \param index Индекс группы
|
||||||
PIString captureGroupName(int index) const;
|
PIString captureGroupName(int index) const;
|
||||||
|
|
||||||
|
//! \~english Gets the index of named capture group
|
||||||
|
//! \~russian Возвращает индекс именованной группы захвата
|
||||||
|
//! \~english \param gname Group name
|
||||||
|
//! \~russian \param gname Имя группы
|
||||||
int captureGroupIndex(const PIString & gname) const;
|
int captureGroupIndex(const PIString & gname) const;
|
||||||
|
|
||||||
Matcher match(const PIString & subject, size_t offset = 0);
|
|
||||||
Matcher match(PIString & subject, size_t offset = 0);
|
|
||||||
Matcher match(PIString && subject, size_t offset = 0);
|
|
||||||
|
|
||||||
Matcher matchIterator(const PIString & subject, size_t offset = 0);
|
//! \~english Matches regular expression against deep copy of subject string
|
||||||
Matcher matchIterator(PIString & subject, size_t offset = 0);
|
//! \~russian Сопоставляет регулярное выражение с внутренней копией строки
|
||||||
Matcher matchIterator(PIString && subject, size_t offset = 0);
|
//! \~english \param subject String to match against
|
||||||
|
//! \~russian \param subject Строка для сопоставления
|
||||||
|
//! \~english \param offset Starting position for matching
|
||||||
|
//! \~russian \param offset Начальная позиция для сопоставления
|
||||||
|
Matcher match(const PIString & subject, size_t offset = 0) const;
|
||||||
|
|
||||||
|
//! \~english Matches regular expression against subject string
|
||||||
|
//! \~russian Сопоставляет регулярное выражение со строкой
|
||||||
|
//! \~english \param subject String to match against
|
||||||
|
//! \~russian \param subject Строка для сопоставления
|
||||||
|
//! \~english \param offset Starting position for matching
|
||||||
|
//! \~russian \param offset Начальная позиция для сопоставления
|
||||||
|
Matcher match(PIString & subject, size_t offset = 0) const;
|
||||||
|
|
||||||
|
//! \~english Matches regular expression against subject string
|
||||||
|
//! \~russian Сопоставляет регулярное выражение со строкой
|
||||||
|
//! \~english \param subject String to match against
|
||||||
|
//! \~russian \param subject Строка для сопоставления
|
||||||
|
//! \~english \param offset Starting position for matching
|
||||||
|
//! \~russian \param offset Начальная позиция для сопоставления
|
||||||
|
Matcher match(PIString && subject, size_t offset = 0) const;
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Prepere match regular expression against deep copy of subject string
|
||||||
|
//! \~russian Подготавливает сопоставление регулярного выражения с внутренней копией строки
|
||||||
|
//! \~english \param subject String to match against
|
||||||
|
//! \~russian \param subject Строка для сопоставления
|
||||||
|
//! \~english \param offset Starting position for matching
|
||||||
|
//! \~russian \param offset Начальная позиция для сопоставления
|
||||||
|
Matcher matchIterator(const PIString & subject, size_t offset = 0) const;
|
||||||
|
|
||||||
|
//! \~english Prepere match regular expression against subject string
|
||||||
|
//! \~russian Подготавливает сопоставление регулярного выражения со строкой
|
||||||
|
//! \~english \param subject String to match against
|
||||||
|
//! \~russian \param subject Строка для сопоставления
|
||||||
|
//! \~english \param offset Starting position for matching
|
||||||
|
//! \~russian \param offset Начальная позиция для сопоставления
|
||||||
|
Matcher matchIterator(PIString & subject, size_t offset = 0) const;
|
||||||
|
|
||||||
|
//! \~english Prepere match regular expression against subject string
|
||||||
|
//! \~russian Подготавливает сопоставление регулярного выражения со строкой
|
||||||
|
//! \~english \param subject String to match against
|
||||||
|
//! \~russian \param subject Строка для сопоставления
|
||||||
|
//! \~english \param offset Starting position for matching
|
||||||
|
//! \~russian \param offset Начальная позиция для сопоставления
|
||||||
|
Matcher matchIterator(PIString && subject, size_t offset = 0) const;
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Creates regular expression from glob pattern
|
||||||
|
//! \~russian Создает регулярное выражение из glob-шаблона
|
||||||
|
//! \~english \param pattern Glob pattern
|
||||||
|
//! \~russian \param pattern Glob-шаблон
|
||||||
|
//! \~english \param opt Matching options
|
||||||
|
//! \~russian \param opt Опции сопоставления
|
||||||
static PIRegularExpression fromGlob(const PIString & pattern, Options opt = None);
|
static PIRegularExpression fromGlob(const PIString & pattern, Options opt = None);
|
||||||
|
|
||||||
|
//! \~english Creates regular expression from POSIX pattern
|
||||||
|
//! \~russian Создает регулярное выражение из POSIX-шаблона
|
||||||
|
//! \~english \param pattern POSIX pattern
|
||||||
|
//! \~russian \param pattern POSIX-шаблон
|
||||||
|
//! \~english \param opt Matching options
|
||||||
|
//! \~russian \param opt Опции сопоставления
|
||||||
static PIRegularExpression fromPOSIX(const PIString & pattern, Options opt = None);
|
static PIRegularExpression fromPOSIX(const PIString & pattern, Options opt = None);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -998,6 +998,11 @@ PIStringList PIString::split(const PIString & delim) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIString::contains(const PIRegularExpression & regexp) const {
|
||||||
|
return regexp.match(const_cast<PIString &>(*this)).hasMatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//! \~\details
|
//! \~\details
|
||||||
//! \~\code
|
//! \~\code
|
||||||
//! PIString s("012345012345");
|
//! PIString s("012345012345");
|
||||||
@@ -1033,6 +1038,11 @@ int PIString::find(const PIString & str, const int start) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int PIString::find(const PIRegularExpression & regexp, const int start) const {
|
||||||
|
return regexp.match(const_cast<PIString &>(*this), start).matchedStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//! \~\details
|
//! \~\details
|
||||||
//! \~\code
|
//! \~\code
|
||||||
//! piCout << PIString("1.str").findAny(".,:"); // 1
|
//! piCout << PIString("1.str").findAny(".,:"); // 1
|
||||||
@@ -1090,6 +1100,16 @@ int PIString::findLast(const PIString & str, const int start) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int PIString::findLast(const PIRegularExpression & regexp, const int start) const {
|
||||||
|
auto m = regexp.match(const_cast<PIString &>(*this), start);
|
||||||
|
int ret = m.matchedStart();
|
||||||
|
while (m.next()) {
|
||||||
|
ret = m.matchedStart();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//! \~\details
|
//! \~\details
|
||||||
//! \~\code
|
//! \~\code
|
||||||
//! piCout << PIString(".str.0").findAnyLast(".,:"); // 4
|
//! piCout << PIString(".str.0").findAnyLast(".,:"); // 4
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
|
|
||||||
class PIStringList;
|
class PIStringList;
|
||||||
|
class PIRegularExpression;
|
||||||
|
|
||||||
//! \ingroup Text
|
//! \ingroup Text
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
@@ -1174,6 +1175,10 @@ public:
|
|||||||
//! \~russian Возвращает содержит ли строка подстроку "str".
|
//! \~russian Возвращает содержит ли строка подстроку "str".
|
||||||
bool contains(const PIString & str) const { return find(str) >= 0; }
|
bool contains(const PIString & str) const { return find(str) >= 0; }
|
||||||
|
|
||||||
|
//! \~english Returns if string match "regexp".
|
||||||
|
//! \~russian Возвращает совпадает ли строка "regexp".
|
||||||
|
bool contains(const PIRegularExpression & regexp) const;
|
||||||
|
|
||||||
|
|
||||||
//! \~english Search character "c" from character at index "start" and return first occur position.
|
//! \~english Search character "c" from character at index "start" and return first occur position.
|
||||||
//! \~russian Ищет символ "c" от символа "start" и возвращает первое вхождение.
|
//! \~russian Ищет символ "c" от символа "start" и возвращает первое вхождение.
|
||||||
@@ -1200,6 +1205,10 @@ public:
|
|||||||
//! \~\sa \a findAny(), \a findLast(), \a findAnyLast(), \a findWord(), \a findCWord(), \a findRange()
|
//! \~\sa \a findAny(), \a findLast(), \a findAnyLast(), \a findWord(), \a findCWord(), \a findRange()
|
||||||
int find(const char * str, const int start = 0) const { return find(PIString(str), start); }
|
int find(const char * str, const int start = 0) const { return find(PIString(str), start); }
|
||||||
|
|
||||||
|
//! \~english Search match of "regexp" from character at index "start" and return first occur position.
|
||||||
|
//! \~russian Ищет совпадение с "regexp" от символа "start" и возвращает первое вхождение.
|
||||||
|
int find(const PIRegularExpression & regexp, const int start = 0) const;
|
||||||
|
|
||||||
//! \~english Search any character of "str" from character at index "start" and return first occur position.
|
//! \~english Search any character of "str" from character at index "start" and return first occur position.
|
||||||
//! \~russian Ищет любой символ строки "str" от симола "start" и возвращает первое вхождение.
|
//! \~russian Ищет любой символ строки "str" от симола "start" и возвращает первое вхождение.
|
||||||
int findAny(const PIString & str, const int start = 0) const;
|
int findAny(const PIString & str, const int start = 0) const;
|
||||||
@@ -1240,6 +1249,10 @@ public:
|
|||||||
//! \~\sa \a find(), \a findAny(), \a findAnyLast(), \a findWord(), \a findCWord(), \a findRange()
|
//! \~\sa \a find(), \a findAny(), \a findAnyLast(), \a findWord(), \a findCWord(), \a findRange()
|
||||||
int findLast(const char * str, const int start = 0) const { return findLast(PIString(str), start); }
|
int findLast(const char * str, const int start = 0) const { return findLast(PIString(str), start); }
|
||||||
|
|
||||||
|
//! \~english Search match of "regexp" from character at index "start" and return last occur position.
|
||||||
|
//! \~russian Ищет совпадение с "regexp" от символа "start" и возвращает последнее вхождение.
|
||||||
|
int findLast(const PIRegularExpression & regexp, const int start = 0) const;
|
||||||
|
|
||||||
//! \~english Search any character of "str" from character at index "start" and return last occur position.
|
//! \~english Search any character of "str" from character at index "start" and return last occur position.
|
||||||
//! \~russian Ищет любой символ строки "str" от символа "start" и возвращает последнее вхождение.
|
//! \~russian Ищет любой символ строки "str" от символа "start" и возвращает последнее вхождение.
|
||||||
int findAnyLast(const PIString & str, const int start = 0) const;
|
int findAnyLast(const PIString & str, const int start = 0) const;
|
||||||
|
|||||||
@@ -493,8 +493,8 @@ public:
|
|||||||
inline const uchar * data(size_t index = 0) const { return d.data(index); }
|
inline const uchar * data(size_t index = 0) const { return d.data(index); }
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T dataAs(size_t index = 0) {
|
inline T dataAs(size_t index = 0) const {
|
||||||
return *(T *)d.data(index);
|
return *(const T *)d.data(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \~english Clear array, remove all elements.
|
//! \~english Clear array, remove all elements.
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Constructor with flags = Enum "e"
|
//! \~english Constructor with flags = Enum "e"
|
||||||
//! \~russian Создает флаги со значением = Enum "e"
|
//! \~russian Создает флаги со значением = Enum "e"
|
||||||
PIFlags(Enum e): flags(e) { ; }
|
PIFlags(Enum e): flags((int)e) { ; }
|
||||||
|
|
||||||
//! \~english Constructor with flags = int "i"
|
//! \~english Constructor with flags = int "i"
|
||||||
//! \~russian Создает флаги со значением = int "i"
|
//! \~russian Создает флаги со значением = int "i"
|
||||||
@@ -80,9 +80,9 @@ public:
|
|||||||
//! \~russian Устанавливает флаг "e" в "on"
|
//! \~russian Устанавливает флаг "e" в "on"
|
||||||
PIFlags & setFlag(const Enum & e, bool on = true) {
|
PIFlags & setFlag(const Enum & e, bool on = true) {
|
||||||
if (on)
|
if (on)
|
||||||
flags |= e;
|
flags |= (int)e;
|
||||||
else
|
else
|
||||||
flags &= ~e;
|
flags &= ~(int)e;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Assign operator
|
//! \~english Assign operator
|
||||||
//! \~russian Оператор присваивания
|
//! \~russian Оператор присваивания
|
||||||
void operator=(const Enum & e) { flags = e; }
|
void operator=(const Enum & e) { flags = (int)e; }
|
||||||
|
|
||||||
//! \~english Assign operator
|
//! \~english Assign operator
|
||||||
//! \~russian Оператор присваивания
|
//! \~russian Оператор присваивания
|
||||||
@@ -110,7 +110,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Compare operator
|
//! \~english Compare operator
|
||||||
//! \~russian Оператор сравнения
|
//! \~russian Оператор сравнения
|
||||||
bool operator==(const Enum & e) { return flags == e; }
|
bool operator==(const Enum & e) { return flags == (int)e; }
|
||||||
|
|
||||||
//! \~english Compare operator
|
//! \~english Compare operator
|
||||||
//! \~russian Оператор сравнения
|
//! \~russian Оператор сравнения
|
||||||
@@ -122,7 +122,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Compare operator
|
//! \~english Compare operator
|
||||||
//! \~russian Оператор сравнения
|
//! \~russian Оператор сравнения
|
||||||
bool operator!=(const Enum & e) { return flags != e; }
|
bool operator!=(const Enum & e) { return flags != (int)e; }
|
||||||
|
|
||||||
//! \~english Compare operator
|
//! \~english Compare operator
|
||||||
//! \~russian Оператор сравнения
|
//! \~russian Оператор сравнения
|
||||||
@@ -134,7 +134,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Compare operator
|
//! \~english Compare operator
|
||||||
//! \~russian Оператор сравнения
|
//! \~russian Оператор сравнения
|
||||||
bool operator>(const Enum & e) { return flags > e; }
|
bool operator>(const Enum & e) { return flags > (int)e; }
|
||||||
|
|
||||||
//! \~english Compare operator
|
//! \~english Compare operator
|
||||||
//! \~russian Оператор сравнения
|
//! \~russian Оператор сравнения
|
||||||
@@ -146,7 +146,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Compare operator
|
//! \~english Compare operator
|
||||||
//! \~russian Оператор сравнения
|
//! \~russian Оператор сравнения
|
||||||
bool operator<(const Enum & e) { return flags < e; }
|
bool operator<(const Enum & e) { return flags < (int)e; }
|
||||||
|
|
||||||
//! \~english Compare operator
|
//! \~english Compare operator
|
||||||
//! \~russian Оператор сравнения
|
//! \~russian Оператор сравнения
|
||||||
@@ -158,7 +158,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Compare operator
|
//! \~english Compare operator
|
||||||
//! \~russian Оператор сравнения
|
//! \~russian Оператор сравнения
|
||||||
bool operator>=(const Enum & e) { return flags >= e; }
|
bool operator>=(const Enum & e) { return flags >= (int)e; }
|
||||||
|
|
||||||
//! \~english Compare operator
|
//! \~english Compare operator
|
||||||
//! \~russian Оператор сравнения
|
//! \~russian Оператор сравнения
|
||||||
@@ -170,7 +170,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Compare operator
|
//! \~english Compare operator
|
||||||
//! \~russian Оператор сравнения
|
//! \~russian Оператор сравнения
|
||||||
bool operator<=(const Enum & e) { return flags <= e; }
|
bool operator<=(const Enum & e) { return flags <= (int)e; }
|
||||||
|
|
||||||
//! \~english Compare operator
|
//! \~english Compare operator
|
||||||
//! \~russian Оператор сравнения
|
//! \~russian Оператор сравнения
|
||||||
@@ -182,7 +182,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Bit-wise AND operator
|
//! \~english Bit-wise AND operator
|
||||||
//! \~russian Оператор побитового И
|
//! \~russian Оператор побитового И
|
||||||
void operator&=(const Enum & e) { flags &= e; }
|
void operator&=(const Enum & e) { flags &= (int)e; }
|
||||||
|
|
||||||
//! \~english Bit-wise AND operator
|
//! \~english Bit-wise AND operator
|
||||||
//! \~russian Оператор побитового И
|
//! \~russian Оператор побитового И
|
||||||
@@ -194,7 +194,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Bit-wise OR operator
|
//! \~english Bit-wise OR operator
|
||||||
//! \~russian Оператор побитового ИЛИ
|
//! \~russian Оператор побитового ИЛИ
|
||||||
void operator|=(const Enum & e) { flags |= e; }
|
void operator|=(const Enum & e) { flags |= (int)e; }
|
||||||
|
|
||||||
//! \~english Bit-wise OR operator
|
//! \~english Bit-wise OR operator
|
||||||
//! \~russian Оператор побитового ИЛИ
|
//! \~russian Оператор побитового ИЛИ
|
||||||
@@ -206,7 +206,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Bit-wise XOR operator
|
//! \~english Bit-wise XOR operator
|
||||||
//! \~russian Оператор побитового исключающего ИЛИ
|
//! \~russian Оператор побитового исключающего ИЛИ
|
||||||
void operator^=(const Enum & e) { flags ^= e; }
|
void operator^=(const Enum & e) { flags ^= (int)e; }
|
||||||
|
|
||||||
//! \~english Bit-wise XOR operator
|
//! \~english Bit-wise XOR operator
|
||||||
//! \~russian Оператор побитового исключающего ИЛИ
|
//! \~russian Оператор побитового исключающего ИЛИ
|
||||||
@@ -222,7 +222,7 @@ public:
|
|||||||
//! \~english Bit-wise AND operator
|
//! \~english Bit-wise AND operator
|
||||||
//! \~russian Оператор побитового И
|
//! \~russian Оператор побитового И
|
||||||
PIFlags operator&(Enum e) const {
|
PIFlags operator&(Enum e) const {
|
||||||
PIFlags tf(flags & e);
|
PIFlags tf(flags & (int)e);
|
||||||
return tf;
|
return tf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +243,7 @@ public:
|
|||||||
//! \~english Bit-wise OR operator
|
//! \~english Bit-wise OR operator
|
||||||
//! \~russian Оператор побитового ИЛИ
|
//! \~russian Оператор побитового ИЛИ
|
||||||
PIFlags operator|(Enum e) const {
|
PIFlags operator|(Enum e) const {
|
||||||
PIFlags tf(flags | e);
|
PIFlags tf(flags | (int)e);
|
||||||
return tf;
|
return tf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +264,7 @@ public:
|
|||||||
//! \~english Bit-wise XOR operator
|
//! \~english Bit-wise XOR operator
|
||||||
//! \~russian Оператор побитового исключающего ИЛИ
|
//! \~russian Оператор побитового исключающего ИЛИ
|
||||||
PIFlags operator^(Enum e) const {
|
PIFlags operator^(Enum e) const {
|
||||||
PIFlags tf(flags ^ e);
|
PIFlags tf(flags ^ (int)e);
|
||||||
return tf;
|
return tf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,7 +277,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Test flag operator
|
//! \~english Test flag operator
|
||||||
//! \~russian Оператор проверки флага
|
//! \~russian Оператор проверки флага
|
||||||
bool operator[](Enum e) const { return (flags & e) == e; }
|
bool operator[](Enum e) const { return (flags & (int)e) == (int)e; }
|
||||||
|
|
||||||
//! \~english Implicity conversion to \c int
|
//! \~english Implicity conversion to \c int
|
||||||
//! \~russian Оператор неявного преобразования в \c int
|
//! \~russian Оператор неявного преобразования в \c int
|
||||||
|
|||||||
@@ -225,17 +225,20 @@ bool PIVariant::operator==(const PIVariant & v) const {
|
|||||||
PIVariant::Type PIVariant::typeFromName(const PIString & tname) {
|
PIVariant::Type PIVariant::typeFromName(const PIString & tname) {
|
||||||
PIString s = tname.trimmed().toLowerCase().replaceAll(" ", "");
|
PIString s = tname.trimmed().toLowerCase().replaceAll(" ", "");
|
||||||
if (s == "bool" || s == "boolean") return PIVariant::pivBool;
|
if (s == "bool" || s == "boolean") return PIVariant::pivBool;
|
||||||
if (s == "char" || s == "sbyte") return PIVariant::pivChar;
|
if (s == "char" || s == "sbyte" || s == "int8_t") return PIVariant::pivChar;
|
||||||
if (s == "short" || s == "shortint" || s == "signedshort" || s == "signedshortint" || s == "sword") return PIVariant::pivShort;
|
if (s == "short" || s == "shortint" || s == "signedshort" || s == "signedshortint" || s == "sword" || s == "int16_t")
|
||||||
if (s == "int" || s == "signed" || s == "signedint") return PIVariant::pivInt;
|
return PIVariant::pivShort;
|
||||||
|
if (s == "int" || s == "signed" || s == "signedint" || s == "int32_t") return PIVariant::pivInt;
|
||||||
if (s == "long" || s == "longint" || s == "signedlong" || s == "signedlongint" || s == "sdword") return PIVariant::pivInt;
|
if (s == "long" || s == "longint" || s == "signedlong" || s == "signedlongint" || s == "sdword") return PIVariant::pivInt;
|
||||||
if (s == "llong" || s == "longlong" || s == "longlongint" || s == "signedlonglong" || s == "signedlonglongint" || s == "sqword")
|
if (s == "llong" || s == "longlong" || s == "longlongint" || s == "signedlonglong" || s == "signedlonglongint" || s == "sqword" ||
|
||||||
|
s == "int64_t")
|
||||||
return PIVariant::pivLLong;
|
return PIVariant::pivLLong;
|
||||||
if (s == "uchar" || s == "byte") return PIVariant::pivUChar;
|
if (s == "uchar" || s == "byte" || s == "uint8_t") return PIVariant::pivUChar;
|
||||||
if (s == "ushort" || s == "unsignedshort" || s == "unsignedshortint" || s == "word") return PIVariant::pivUShort;
|
if (s == "ushort" || s == "unsignedshort" || s == "unsignedshortint" || s == "word" || s == "uint16_t") return PIVariant::pivUShort;
|
||||||
if (s == "uint" || s == "unsigned" || s == "unsignedint") return PIVariant::pivUInt;
|
if (s == "uint" || s == "unsigned" || s == "unsignedint" || s == "uint32_t") return PIVariant::pivUInt;
|
||||||
if (s == "ulong" || s == "unsignedlong" || s == "unsignedlongint" || s == "dword") return PIVariant::pivUInt;
|
if (s == "ulong" || s == "unsignedlong" || s == "unsignedlongint" || s == "dword") return PIVariant::pivUInt;
|
||||||
if (s == "ullong" || s == "unsignedlonglong" || s == "unsignedlonglongint" || s == "qword") return PIVariant::pivULLong;
|
if (s == "ullong" || s == "unsignedlonglong" || s == "unsignedlonglongint" || s == "qword" || s == "uint64_t")
|
||||||
|
return PIVariant::pivULLong;
|
||||||
if (s == "float") return PIVariant::pivFloat;
|
if (s == "float") return PIVariant::pivFloat;
|
||||||
if (s == "double" || s == "real") return PIVariant::pivDouble;
|
if (s == "double" || s == "real") return PIVariant::pivDouble;
|
||||||
if (s == "ldouble" || s == "longdouble") return PIVariant::pivLDouble;
|
if (s == "ldouble" || s == "longdouble") return PIVariant::pivLDouble;
|
||||||
@@ -709,6 +712,11 @@ int PIVariant::toInt() const {
|
|||||||
ba >> r;
|
ba >> r;
|
||||||
return (int)r.rgba;
|
return (int)r.rgba;
|
||||||
}
|
}
|
||||||
|
case PIVariant::pivMathVector: {
|
||||||
|
PIMathVectord r;
|
||||||
|
ba >> r;
|
||||||
|
return r.size() > 0 ? r[0] : 0;
|
||||||
|
}
|
||||||
case PIVariant::pivCustom: return getAsValue<int>(*this);
|
case PIVariant::pivCustom: return getAsValue<int>(*this);
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
@@ -814,6 +822,11 @@ llong PIVariant::toLLong() const {
|
|||||||
ba >> r;
|
ba >> r;
|
||||||
return llong(r.selectedValue());
|
return llong(r.selectedValue());
|
||||||
}
|
}
|
||||||
|
case PIVariant::pivMathVector: {
|
||||||
|
PIMathVectord r;
|
||||||
|
ba >> r;
|
||||||
|
return r.size() > 0 ? r[0] : 0L;
|
||||||
|
}
|
||||||
case PIVariant::pivCustom: return getAsValue<llong>(*this);
|
case PIVariant::pivCustom: return getAsValue<llong>(*this);
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
@@ -919,6 +932,11 @@ float PIVariant::toFloat() const {
|
|||||||
ba >> r;
|
ba >> r;
|
||||||
return float(r.selectedValue());
|
return float(r.selectedValue());
|
||||||
}
|
}
|
||||||
|
case PIVariant::pivMathVector: {
|
||||||
|
PIMathVectord r;
|
||||||
|
ba >> r;
|
||||||
|
return r.size() > 0 ? r[0] : 0.f;
|
||||||
|
}
|
||||||
case PIVariant::pivCustom: return getAsValue<float>(*this);
|
case PIVariant::pivCustom: return getAsValue<float>(*this);
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
@@ -1024,6 +1042,11 @@ double PIVariant::toDouble() const {
|
|||||||
ba >> r;
|
ba >> r;
|
||||||
return double(r.selectedValue());
|
return double(r.selectedValue());
|
||||||
}
|
}
|
||||||
|
case PIVariant::pivMathVector: {
|
||||||
|
PIMathVectord r;
|
||||||
|
ba >> r;
|
||||||
|
return r.size() > 0 ? r[0] : 0.;
|
||||||
|
}
|
||||||
case PIVariant::pivCustom: return getAsValue<double>(*this);
|
case PIVariant::pivCustom: return getAsValue<double>(*this);
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
@@ -1129,6 +1152,11 @@ ldouble PIVariant::toLDouble() const {
|
|||||||
ba >> r;
|
ba >> r;
|
||||||
return ldouble(r.selectedValue());
|
return ldouble(r.selectedValue());
|
||||||
}
|
}
|
||||||
|
case PIVariant::pivMathVector: {
|
||||||
|
PIMathVectord r;
|
||||||
|
ba >> r;
|
||||||
|
return r.size() > 0 ? r[0] : 0.;
|
||||||
|
}
|
||||||
case PIVariant::pivCustom: return getAsValue<float>(*this);
|
case PIVariant::pivCustom: return getAsValue<float>(*this);
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
@@ -1754,16 +1782,24 @@ PIVariantTypes::IODevice PIVariant::toIODevice() const {
|
|||||||
//!
|
//!
|
||||||
PIPointd PIVariant::toPoint() const {
|
PIPointd PIVariant::toPoint() const {
|
||||||
PIByteArray ba(_content);
|
PIByteArray ba(_content);
|
||||||
|
if (_type == PIVariant::pivPoint) {
|
||||||
|
PIPointd r;
|
||||||
|
ba >> r;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
if (_type == PIVariant::pivString) {
|
if (_type == PIVariant::pivString) {
|
||||||
PIString r;
|
PIString r;
|
||||||
ba >> r;
|
ba >> r;
|
||||||
PIStringList l = r.split(';');
|
PIStringList l = r.split(';');
|
||||||
if (l.size() >= 2) return PIPointd(l[0].toDouble(), l[1].toDouble());
|
if (l.size() >= 2) return PIPointd(l[0].toDouble(), l[1].toDouble());
|
||||||
}
|
}
|
||||||
if (_type == PIVariant::pivPoint) {
|
if (_type == PIVariant::pivMathVector) {
|
||||||
PIPointd r;
|
PIMathVectord r;
|
||||||
ba >> r;
|
ba >> r;
|
||||||
return r;
|
PIPointd ret;
|
||||||
|
if (r.size() > 0) ret.x = r[0];
|
||||||
|
if (r.size() > 1) ret.y = r[1];
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
return PIPointd();
|
return PIPointd();
|
||||||
}
|
}
|
||||||
@@ -1880,6 +1916,14 @@ PIMathVectord PIVariant::toMathVector() const {
|
|||||||
ba >> r;
|
ba >> r;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
if (_type == PIVariant::pivPoint) {
|
||||||
|
PIPointd r;
|
||||||
|
ba >> r;
|
||||||
|
PIMathVectord ret(2);
|
||||||
|
ret[0] = r.x;
|
||||||
|
ret[1] = r.y;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
return PIMathVectord();
|
return PIMathVectord();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
416
main.cpp
416
main.cpp
@@ -8,363 +8,91 @@
|
|||||||
using namespace PICoutManipulators;
|
using namespace PICoutManipulators;
|
||||||
using namespace PIHTTP;
|
using namespace PIHTTP;
|
||||||
|
|
||||||
|
PIMathVectord data;
|
||||||
|
|
||||||
struct SN {
|
void _sfplot(const PIMathVectord & sf, PIString * str, const int lines, const int length) {
|
||||||
int _ii;
|
int offset = (data.size() - length) / 2 / 2;
|
||||||
complexf _co;
|
double max_sf = 0;
|
||||||
PIIODevice::DeviceMode m;
|
for (int i = 0; i < length * 2; i++) {
|
||||||
|
if (sf[offset + i] > max_sf) {
|
||||||
|
max_sf = sf[offset + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static PIVector2D<uchar> grid;
|
||||||
|
grid.clear();
|
||||||
|
grid.resize(lines * 2, length * 2);
|
||||||
|
// clang-format off
|
||||||
|
static const PIChar dots[16] = {
|
||||||
|
PIChar::fromUTF8(" "), PIChar::fromUTF8("▘"), PIChar::fromUTF8("▝"), PIChar::fromUTF8("▀"),
|
||||||
|
PIChar::fromUTF8("▖"), PIChar::fromUTF8("▌"), PIChar::fromUTF8("▞"), PIChar::fromUTF8("▛"),
|
||||||
|
PIChar::fromUTF8("▗"), PIChar::fromUTF8("▚"), PIChar::fromUTF8("▐"), PIChar::fromUTF8("▜"),
|
||||||
|
PIChar::fromUTF8("▄"), PIChar::fromUTF8("▙"), PIChar::fromUTF8("▟"), PIChar::fromUTF8("█"),
|
||||||
};
|
};
|
||||||
struct S {
|
// clang-format on
|
||||||
bool _b;
|
memset(grid.data(), 0, grid.size());
|
||||||
int _i;
|
for (int c = 0; c < grid.cols(); c++) {
|
||||||
float _f;
|
double rind = piClampi(piRound(sf[offset + c] / max_sf * (grid.rows() - 1)), 0, grid.rows() - 1);
|
||||||
PIString str;
|
grid.element(rind, c) = 1;
|
||||||
// SN _sn;
|
}
|
||||||
PIVector2D<bool> v2d;
|
union helper {
|
||||||
PIByteArray ba;
|
uint index = 0;
|
||||||
PISystemTime st;
|
struct {
|
||||||
PINetworkAddress na;
|
uint tl: 1;
|
||||||
PIPointd po;
|
uint tr: 1;
|
||||||
PILined li;
|
uint bl: 1;
|
||||||
PIRectd re;
|
uint br: 1;
|
||||||
};
|
};
|
||||||
|
};
|
||||||
template<>
|
for (int i = 0; i < lines; i++) {
|
||||||
PIJSON piSerializeJSON(const SN & v) {
|
str[i].resize(length);
|
||||||
PIJSON ret;
|
}
|
||||||
ret["_ii"] = piSerializeJSON(v._ii);
|
helper h;
|
||||||
ret["_co"] = piSerializeJSON(v._co);
|
for (int l = 0; l < lines; l++) {
|
||||||
ret["m"] = piSerializeJSON(v.m);
|
for (int c = 0; c < length; c++) {
|
||||||
return ret;
|
int l2 = l + l;
|
||||||
|
int c2 = c + c;
|
||||||
|
h.bl = grid.element(l2, c2);
|
||||||
|
h.br = grid.element(l2, c2 + 1);
|
||||||
|
h.tl = grid.element(l2 + 1, c2);
|
||||||
|
h.tr = grid.element(l2 + 1, c2 + 1);
|
||||||
|
// piCout << h.index;
|
||||||
|
str[lines - 1 - l][c] = dots[h.index];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
template<>
|
|
||||||
PIJSON piSerializeJSON(const S & v) {
|
|
||||||
PIJSON ret;
|
|
||||||
ret["_b"] = piSerializeJSON(v._b);
|
|
||||||
ret["_i"] = piSerializeJSON(v._i);
|
|
||||||
ret["_f"] = piSerializeJSON(v._f);
|
|
||||||
ret["str"] = piSerializeJSON(v.str);
|
|
||||||
// ret["_sn"] = piSerializeJSON(v._sn);
|
|
||||||
ret["v2d"] = piSerializeJSON(v.v2d);
|
|
||||||
ret["ba"] = piSerializeJSON(v.ba);
|
|
||||||
ret["st"] = piSerializeJSON(v.st);
|
|
||||||
ret["na"] = piSerializeJSON(v.na);
|
|
||||||
ret["po"] = piSerializeJSON(v.po);
|
|
||||||
ret["li"] = piSerializeJSON(v.li);
|
|
||||||
ret["re"] = piSerializeJSON(v.re);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
|
||||||
void piDeserializeJSON(SN & v, const PIJSON & js) {
|
TileSimple * test_tile;
|
||||||
v = {};
|
PIScreen screen;
|
||||||
piDeserializeJSON(v._ii, js["_ii"]);
|
PIMathVectord asf;
|
||||||
piDeserializeJSON(v._co, js["_co"]);
|
|
||||||
piDeserializeJSON(v.m, js["m"]);
|
|
||||||
}
|
|
||||||
template<>
|
|
||||||
void piDeserializeJSON(S & v, const PIJSON & js) {
|
|
||||||
v = {};
|
|
||||||
piDeserializeJSON(v._b, js["_b"]);
|
|
||||||
piDeserializeJSON(v._i, js["_i"]);
|
|
||||||
piDeserializeJSON(v._f, js["_f"]);
|
|
||||||
piDeserializeJSON(v.str, js["str"]);
|
|
||||||
// piDeserializeJSON(v._sn, js["_sn"]);
|
|
||||||
piDeserializeJSON(v.v2d, js["v2d"]);
|
|
||||||
piDeserializeJSON(v.ba, js["ba"]);
|
|
||||||
piDeserializeJSON(v.st, js["st"]);
|
|
||||||
piDeserializeJSON(v.na, js["na"]);
|
|
||||||
piDeserializeJSON(v.po, js["po"]);
|
|
||||||
piDeserializeJSON(v.li, js["li"]);
|
|
||||||
piDeserializeJSON(v.re, js["re"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
// PIRegularExpression pire("привет"_u8, PIRegularExpression::CaseInsensitive);
|
test_tile = new TileSimple();
|
||||||
// PIString subj = "the dog ПриВет sat on the cat"_u8;
|
screen.rootTile()->addTile(test_tile);
|
||||||
// PIRegularExpression pire("^(?<date>\\d\\d)/(?<month>\\d\\d)/(?<year>\\d\\d\\d\\d)$"_u8);
|
screen.rootTile()->addTile(new TilePICout());
|
||||||
// PIString subj = "08/12/1985"_u8;
|
PITimer _t;
|
||||||
|
PIString str[9];
|
||||||
|
asf.resize(80);
|
||||||
|
_t.start(20_Hz, [&str] {
|
||||||
|
static double t = 0;
|
||||||
|
t += 0.1;
|
||||||
|
for (uint i = 0; i < asf.size(); ++i)
|
||||||
|
asf[i] = 1. + sin(t + 2. * i * M_2PI / asf.size());
|
||||||
|
_sfplot(asf, str, 9, 28);
|
||||||
|
|
||||||
PIString pat = "*.Exe";
|
screen.lock();
|
||||||
PIRegularExpression re_g = PIRegularExpression::fromGlob(pat, PIRegularExpression::CaseInsensitive);
|
test_tile->content.resize(9);
|
||||||
PIRegularExpression re_p = PIRegularExpression::fromPOSIX(pat, PIRegularExpression::CaseInsensitive);
|
for (int i = 0; i < 9; i++) {
|
||||||
PIStringList files = {
|
test_tile->content[i].first = str[i];
|
||||||
"(Audio) 20250318-0852-16.8641941.m4a",
|
|
||||||
"dxwebsetup.exe",
|
|
||||||
"Firefox Installer.exe",
|
|
||||||
"LTA8092XS8_R8.pdf",
|
|
||||||
"SteamSetup.exe",
|
|
||||||
"TBT_1.41.1325.0.exe",
|
|
||||||
};
|
|
||||||
piCout << " src pat" << pat.quoted();
|
|
||||||
piCout << " Glob pat" << re_g.pattern().quoted();
|
|
||||||
piCout << "POSIX pat" << re_p.pattern().quoted();
|
|
||||||
piCout << "\nG P File";
|
|
||||||
for (auto f: files) {
|
|
||||||
piCout << (re_g.match(f) ? 1 : 0) << (re_p.match(f) ? 1 : 0) << f;
|
|
||||||
}
|
}
|
||||||
// return 0;
|
screen.unlock();
|
||||||
PIRegularExpression pire("(?:\\/\\/\\s*)?.*\\n?(?:\\bfunction\\b)\\s*(?<name>\\b\\w+\\b)\\s*(?:\\((?<args>[^;()]*?)\\))",
|
piCout << "Время: "_u8 << t;
|
||||||
PIRegularExpression::Multiline);
|
|
||||||
PIString subj = PIString::fromUTF8(PIFile::readAll("telegram.qs", false));
|
|
||||||
|
|
||||||
piCout << "Pattern:" << pire.pattern();
|
|
||||||
piCout << "Valid:" << pire.isValid();
|
|
||||||
piCout << "Error at" << pire.errorPosition() << ":" << pire.errorString();
|
|
||||||
piCout << "Groups count:" << pire.captureGroupsCount();
|
|
||||||
piCout << "Named groups:" << pire.captureGroupNames();
|
|
||||||
piCout << "";
|
|
||||||
|
|
||||||
auto mr = pire.matchIterator(subj);
|
|
||||||
auto pire2 = pire;
|
|
||||||
|
|
||||||
while (mr.next()) {
|
|
||||||
// piCout << "Subject" << subj;
|
|
||||||
piCout << "Matched:" << mr.hasMatch();
|
|
||||||
|
|
||||||
piCout << "By number";
|
|
||||||
for (int i = 0; i <= pire.captureGroupsCount(); ++i)
|
|
||||||
piCout << i << "=" << mr.matchedString(i).trimmed();
|
|
||||||
|
|
||||||
piCout << "By name";
|
|
||||||
for (auto g: pire.captureGroupNames())
|
|
||||||
piCout << g.quoted() << "=" << mr.matchedString(g);
|
|
||||||
|
|
||||||
piCout << "";
|
|
||||||
}
|
|
||||||
|
|
||||||
piCout << "!!!!!!!!!!!!!!!!!";
|
|
||||||
|
|
||||||
pire.match("vfsmndvbjbdlgdvb gdgf");
|
|
||||||
pire.match(subj);
|
|
||||||
|
|
||||||
{
|
|
||||||
PIVector<complexf> vec;
|
|
||||||
vec << complexf{0.1, 0.2} << complexf{-1, 0.5};
|
|
||||||
auto js = PIJSON::serialize(vec);
|
|
||||||
piCout << vec;
|
|
||||||
piCout << js;
|
|
||||||
piCout << PIJSON::deserialize<typeof(vec)>(js);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
/*PICodeParser parser;
|
|
||||||
parser.parseFile("c:/work/shstk/pip/test_header.h", false);
|
|
||||||
|
|
||||||
for (const auto * e: parser.entities) {
|
|
||||||
piCout << e->type << e->name << "{";
|
|
||||||
for (const auto & m: e->members) {
|
|
||||||
piCout << " " << m.type << m.name;
|
|
||||||
}
|
|
||||||
piCout << "}";
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;*/
|
|
||||||
|
|
||||||
// PIJSON j = piSerializeJSON(s);
|
|
||||||
// piDeserializeJSON(s, j);
|
|
||||||
PIVector<complexf> vec;
|
|
||||||
vec << complexf{0.1, 0.2} << complexf{-1, 0.5};
|
|
||||||
auto js = PIJSON::serialize(vec);
|
|
||||||
piCout << vec;
|
|
||||||
piCout << js;
|
|
||||||
piCout << PIJSON::deserialize<typeof(vec)>(js);
|
|
||||||
|
|
||||||
/*PIVector<S> s;
|
|
||||||
s << S{false, 0, 0.1} << S{true, 1, -10.1};
|
|
||||||
PIMap<int, S> m;
|
|
||||||
m[1] = S{false, 0, 0.15};
|
|
||||||
m[2] = S{true, 1, -10.1};
|
|
||||||
// m[1]._sn._co = {3, 4};
|
|
||||||
PIJSON j = piSerializeJSON(m);
|
|
||||||
piCout << j;
|
|
||||||
piDeserializeJSON(m, j);
|
|
||||||
piCout << m[1]._f;*/
|
|
||||||
// piCout << m[1]._sn._co;
|
|
||||||
|
|
||||||
/*PIVector<int> v({-1, 0, 10, 200});
|
|
||||||
PIMap<int, float> m({
|
|
||||||
{-1, -0.1 },
|
|
||||||
{0, 0.1 },
|
|
||||||
{100, 200.2}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
piCout << v;
|
screen.enableExitCapture();
|
||||||
piCout << piSerializeJSON(v);
|
WAIT_FOR_EXIT;
|
||||||
piDeserializeJSON(v, piSerializeJSON(v));
|
|
||||||
piCout << v;
|
|
||||||
piCout << m;
|
|
||||||
piDeserializeJSON(m, piSerializeJSON(m));
|
|
||||||
piCout << piSerializeJSON(m);*/
|
|
||||||
|
|
||||||
return 0;
|
screen.stopAndWait();
|
||||||
|
|
||||||
/*auto src = PIByteArray::fromAscii("The quick brown fox jumps over the lazy dog");
|
|
||||||
auto key = PIByteArray::fromAscii("key");
|
|
||||||
|
|
||||||
PIStringList tnl;
|
|
||||||
int max_size = 0;
|
|
||||||
for (int t = 0; t < (int)PIDigest::Type::C ount; ++t) {
|
|
||||||
tnl << PIDigest::typeName((PIDigest::Type)t);
|
|
||||||
max_size = piMaxi(max_size, tnl.back().size_s());
|
|
||||||
}
|
|
||||||
PIByteArray hs;
|
|
||||||
piCout << PIString::fromAscii(src);
|
|
||||||
for (int t = 0; t < (int)PIDigest::Type::Count; ++t) {
|
|
||||||
hs = PIDigest::calculate(src, (PIDigest::Type)t);
|
|
||||||
piCout << tnl[t].expandLeftTo(max_size, ' ') << "->" << hs.toHex();
|
|
||||||
}
|
|
||||||
for (int t = 0; t < (int)PIDigest::Type::Count; ++t) {
|
|
||||||
const int bench_count = 100000;
|
|
||||||
PITimeMeasurer tm;
|
|
||||||
piForTimes(bench_count) {
|
|
||||||
hs = PIDigest::calculate(src, (PIDigest::Type)t);
|
|
||||||
}
|
|
||||||
auto el = tm.elapsed();
|
|
||||||
piCout << tnl[t].expandLeftTo(max_size, ' ') << "time" << el.toMilliseconds();
|
|
||||||
}
|
|
||||||
|
|
||||||
// src.clear();
|
|
||||||
// crypto_hash_sha512(sout.data(), src.data(), src.size());
|
|
||||||
// piCout << "sod:" << sout.toHex();
|
|
||||||
// piCout << "512:" << sha5xx(src, initial_512, 64).toHex();
|
|
||||||
return 0;*/
|
|
||||||
|
|
||||||
/*PIHTTPServer server;
|
|
||||||
server.listen({"127.0.0.1:7777"});
|
|
||||||
// server.setBasicAuthRealm("pip");
|
|
||||||
// server.setBasicAuthEnabled(true);
|
|
||||||
// server.setBasicAuthCallback([](const PIString & u, const PIString & p) -> bool {
|
|
||||||
// piCout << "basic auth" << u << p;
|
|
||||||
// return (u == "u" && p == "p");
|
|
||||||
// });
|
|
||||||
server.registerPath("sendMessage", Method::Post, [](const PIHTTP::MessageConst & msg) -> PIHTTP::MessageMutable {
|
|
||||||
return MessageMutable().setCode(Code::Accepted);
|
|
||||||
});
|
|
||||||
server.registerUnhandled([](const PIHTTP::MessageConst & msg) -> PIHTTP::MessageMutable {
|
|
||||||
PIHTTP::MessageMutable ret;
|
|
||||||
piCout << "server rec:\n\tpath: %1\n\tmethod: %2\n\targs: %3\n\theaders: %4\n\tbody: %5\n"_a.arg(msg.path())
|
|
||||||
.arg(PIHTTP::methodName(msg.method()))
|
|
||||||
.arg(piStringify(msg.arguments()))
|
|
||||||
.arg(PIStringList(msg.headers().map<PIString>([](PIString k, PIString v) { return k + " = " + v; })).join("\n\t\t "))
|
|
||||||
.arg(PIString::fromUTF8(msg.body()));
|
|
||||||
ret.setCode(PIHTTP::Code::BadRequest);
|
|
||||||
ret.setBody(PIByteArray::fromAscii("hello client! 0123456789"));
|
|
||||||
piSleep(5.);
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
kbd.waitForFinish();
|
|
||||||
return 0;*/
|
|
||||||
|
|
||||||
/*PIHTTP::MessageMutable req;
|
|
||||||
req.setBody(PIByteArray::fromAscii("hello server!")).addArgument("a0", "val.0").addArgument("a~r1", "знач,1"_u8);
|
|
||||||
auto * c = PIHTTPClient::create("http://u:p@127.0.0.1:7777/api", PIHTTP::Method::Get, req);
|
|
||||||
c->onFinish([](PIHTTP::MessageConst msg) {
|
|
||||||
piCout << "client rec:\n\tpath: %1\n\tmethod: %2\n\targs: %3\n\theaders: %4\n\tbody: %5\n"_a.arg(msg.path())
|
|
||||||
.arg(PIHTTP::methodName(msg.method()))
|
|
||||||
.arg(piStringify(msg.arguments()))
|
|
||||||
.arg(
|
|
||||||
PIStringList(msg.headers().map<PIString>([](PIString k, PIString v) { return k + " = " + v; })).join("\n\t\t
|
|
||||||
")) .arg(PIString::fromUTF8(msg.body()));
|
|
||||||
})
|
|
||||||
->onError([c](PIHTTP::MessageConst r) {
|
|
||||||
piCout << "error" << (int)r.code();
|
|
||||||
piCout << "msg" << c->lastError();
|
|
||||||
})
|
|
||||||
->onAbort([c](PIHTTP::MessageConst r) {
|
|
||||||
piCout << "abort" << (int)r.code();
|
|
||||||
piCout << "msg" << c->lastError();
|
|
||||||
})
|
|
||||||
->start();*/
|
|
||||||
auto * c = PIHTTPClient::create(
|
|
||||||
PIString("127.0.0.1:7777/%1").arg("sendMessag"),
|
|
||||||
Method::Post,
|
|
||||||
MessageMutable().addHeader(Header::ContentType, "application/json").setBody(PIByteArray::fromAscii("{hello}")));
|
|
||||||
c->onFinish([](const PIHTTP::MessageConst & msg) { piCout << "message finish" << (int)msg.code() << PIString::fromUTF8(msg.body()); })
|
|
||||||
->onError([c](const PIHTTP::MessageConst & msg) { piCout << "message error" << c->lastError(); })
|
|
||||||
->onAbort([c](const PIHTTP::MessageConst & msg) { piCout << "aborted"; })
|
|
||||||
->start();
|
|
||||||
|
|
||||||
piMSleep(1000);
|
|
||||||
// CurlThreadPool::instance()->destroy();
|
|
||||||
// kbd.enableExitCapture();
|
|
||||||
// WAIT_FOR_EXIT
|
|
||||||
// kbd.stopAndWait();
|
|
||||||
|
|
||||||
// server.stop();
|
|
||||||
c->abort();
|
|
||||||
piMSleep(10);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// piCout << PIString::readableSize(PISystemMonitor::usedRAM());
|
|
||||||
|
|
||||||
/*PIVector<int> vi;
|
|
||||||
piForTimes(10) {
|
|
||||||
piSleep(2.);
|
|
||||||
vi.enlarge(1000000);
|
|
||||||
piCout << "now" << vi.size() << vi.capacity();
|
|
||||||
}
|
|
||||||
|
|
||||||
piSleep(5.);*/
|
|
||||||
/*kbd.enableExitCapture();
|
|
||||||
|
|
||||||
PIHTTPServer server;
|
|
||||||
|
|
||||||
server.setFavicon(PIFile::readAll("logo.png", false));
|
|
||||||
// server.setOption(MicrohttpdServer::Option::HTTPSEnabled, true);
|
|
||||||
server.listen({"127.0.0.1", 7777});
|
|
||||||
// server.listen({"192.168.1.10", 7778});
|
|
||||||
|
|
||||||
server.registerPath("/", MicrohttpdServer::Method::Get, [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
|
||||||
MicrohttpdServer::Reply ret;
|
|
||||||
ret.setBody(PIByteArray::fromAscii(pageTitle));
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
|
|
||||||
server.registerPath("/html", MicrohttpdServer::Method::Get, [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
|
||||||
MicrohttpdServer::Reply ret;
|
|
||||||
ret.setBody("<!DOCTYPE html><html><body><p>arg=%1</p></body></html>"_a.arg(r.args.value("a0")).toUTF8());
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
|
|
||||||
server.registerPath("/api", MicrohttpdServer::Method::Put, [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
|
||||||
MicrohttpdServer::Reply ret;
|
|
||||||
ret.setBody(PIByteArray::fromAscii("<!DOCTYPE html><html><body>API</body></html>"));
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
|
|
||||||
server.registerPath("/api/", MicrohttpdServer::Method::Post, [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
|
||||||
MicrohttpdServer::Reply ret;
|
|
||||||
ret.setBody("<!DOCTYPE html><html><body>API etry %1</body></html>"_a.arg(r.path).toUTF8());
|
|
||||||
ret.setCode(405);
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
|
|
||||||
server.registerUnhandled([](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
|
||||||
MicrohttpdServer::Reply ret;
|
|
||||||
ret.setBody("<!DOCTYPE html><html><body>Unknown</body></html>"_a.arg(r.path).toUTF8());
|
|
||||||
ret.setCode(404);
|
|
||||||
return ret;
|
|
||||||
});*/
|
|
||||||
|
|
||||||
/*server.setRequestCallback([](MicrohttpdServer::Request r) -> MicrohttpdServer::Reply {
|
|
||||||
MicrohttpdServer::Reply rep;
|
|
||||||
piCout << "request" << r.path;
|
|
||||||
piCout << " header" << r.headers;
|
|
||||||
piCout << " args" << r.args;
|
|
||||||
piCout << " body" << r.body;
|
|
||||||
piCout << "";
|
|
||||||
rep.setBody(PIByteArray::fromAscii("[{\"value1\": true, \"value2\": \"ыекштп\"}]"));
|
|
||||||
return rep;
|
|
||||||
});*/
|
|
||||||
|
|
||||||
/*piCout << "start" << server.isListen();
|
|
||||||
|
|
||||||
WAIT_FOR_EXIT
|
|
||||||
|
|
||||||
server.stop();*/
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,3 +36,4 @@ pip_test(core)
|
|||||||
pip_test(piobject)
|
pip_test(piobject)
|
||||||
pip_test(client_server pip_client_server)
|
pip_test(client_server pip_client_server)
|
||||||
pip_test(io)
|
pip_test(io)
|
||||||
|
pip_test(system)
|
||||||
|
|||||||
98
tests/system/process_test.cpp
Normal file
98
tests/system/process_test.cpp
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#include "piprocess.h"
|
||||||
|
#include "pitime.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessTest: public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
PIProcess launcher;
|
||||||
|
const PIString command =
|
||||||
|
#ifdef _WIN32
|
||||||
|
"C:/Windows/System32/cmd.exe";
|
||||||
|
#else
|
||||||
|
"/bin/sh";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void SetUp() override {
|
||||||
|
launcher.enableWriteStdIn(false);
|
||||||
|
launcher.enableReadStdOut();
|
||||||
|
launcher.enableReadStdErr();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override {
|
||||||
|
if (launcher.isRunning()) {
|
||||||
|
launcher.waitForFinish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(ProcessTest, Output) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
const PIStringList args = {"/c", "echo Hello from stdout && echo Hello from stderr 1>&2"};
|
||||||
|
#else
|
||||||
|
const PIStringList args = {"-c", "echo Hello from stdout; echo Hello from stderr 1>&2"};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
launcher.exec(command, args);
|
||||||
|
ASSERT_TRUE(launcher.isRunning());
|
||||||
|
|
||||||
|
ASSERT_TRUE(launcher.waitForFinish());
|
||||||
|
ASSERT_TRUE(launcher.isExecFinished());
|
||||||
|
|
||||||
|
const auto out = PIString::fromAscii(launcher.readOutput());
|
||||||
|
const auto err = PIString::fromAscii(launcher.readError());
|
||||||
|
|
||||||
|
EXPECT_TRUE(out.contains("Hello from stdout"));
|
||||||
|
EXPECT_TRUE(err.contains("Hello from stderr"));
|
||||||
|
|
||||||
|
const int exit_code = launcher.exitCode();
|
||||||
|
EXPECT_FALSE(launcher.isRunning());
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
EXPECT_EQ(exit_code, 0);
|
||||||
|
#else
|
||||||
|
EXPECT_TRUE(WIFEXITED(exit_code));
|
||||||
|
EXPECT_EQ(WEXITSTATUS(exit_code), 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(ProcessTest, Input) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
const PIStringList args = {"/c", "more"};
|
||||||
|
#else
|
||||||
|
const PIStringList args = {"-c", "read input; echo $input"};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
launcher.enableWriteStdIn();
|
||||||
|
launcher.exec(command, args);
|
||||||
|
ASSERT_TRUE(launcher.isRunning());
|
||||||
|
piMSleep(100);
|
||||||
|
EXPECT_TRUE(launcher.isExecStarted());
|
||||||
|
EXPECT_TRUE(!launcher.isExecFinished());
|
||||||
|
|
||||||
|
PIString test_input = "Test input string\n";
|
||||||
|
EXPECT_TRUE(launcher.writeInput(test_input.toAscii()));
|
||||||
|
launcher.closeInput();
|
||||||
|
|
||||||
|
ASSERT_TRUE(launcher.waitForFinish());
|
||||||
|
EXPECT_TRUE(launcher.isExecFinished());
|
||||||
|
|
||||||
|
const auto out = PIString::fromAscii(launcher.readOutput());
|
||||||
|
EXPECT_TRUE(out.contains("Test input string"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(ProcessTest, NonexistentCommand) {
|
||||||
|
const PIString command = {"nonexistent_command_12345"};
|
||||||
|
|
||||||
|
launcher.enableWriteStdIn(false);
|
||||||
|
launcher.enableReadStdOut(false);
|
||||||
|
launcher.enableReadStdErr(false);
|
||||||
|
launcher.exec(command);
|
||||||
|
ASSERT_TRUE(launcher.isRunning());
|
||||||
|
ASSERT_TRUE(launcher.waitForFinish());
|
||||||
|
EXPECT_FALSE(launcher.isExecFinished());
|
||||||
|
}
|
||||||
@@ -46,8 +46,15 @@ const char help_string[] = "-M (Metainfo)\n"
|
|||||||
"with simple << and >> operators.\n"
|
"with simple << and >> operators.\n"
|
||||||
"If PIMETA(no-stream) presence, then class or struct ignored.\n"
|
"If PIMETA(no-stream) presence, then class or struct ignored.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"-J (JSON serialization)\n"
|
||||||
|
"Generate serialize/deserialize methods for classes and structures.\n"
|
||||||
|
"These methods uses by PIJSON::serialize(T v) and PIJSON::deserialize(json)\n"
|
||||||
|
"allow automatic conversion to/from PIJSON. Use member name as key.\n"
|
||||||
|
"Member can be skipped by providing PIMETA(id=-).\n"
|
||||||
|
"If PIMETA(no-json) presence, then class or struct ignored.\n"
|
||||||
|
"\n"
|
||||||
"-G (Getter functions)\n"
|
"-G (Getter functions)\n"
|
||||||
"Generate anonymous access methods for member typenames and values.\n"
|
"Generate anonymous access methods for member typenames, values and offsets.\n"
|
||||||
"Every class or struct member typename can be obtained with:\n"
|
"Every class or struct member typename can be obtained with:\n"
|
||||||
"const char * getMemberType(const char * class_name, const char * member_name)\n"
|
"const char * getMemberType(const char * class_name, const char * member_name)\n"
|
||||||
"Member value can be obtained with:\n"
|
"Member value can be obtained with:\n"
|
||||||
@@ -55,6 +62,7 @@ const char help_string[] = "-M (Metainfo)\n"
|
|||||||
"where \"p\" - class or struct pointer, and returns serialized value.\n"
|
"where \"p\" - class or struct pointer, and returns serialized value.\n"
|
||||||
"PIVariant getMemberAsVariant(const void * p, const char * class_name, const char * member_name)\n"
|
"PIVariant getMemberAsVariant(const void * p, const char * class_name, const char * member_name)\n"
|
||||||
"where \"p\" - class or struct pointer, and returns value as registered PIVariant.\n"
|
"where \"p\" - class or struct pointer, and returns value as registered PIVariant.\n"
|
||||||
|
"If PIMETA(no-getter) presence, then class or struct ignored.\n"
|
||||||
"";
|
"";
|
||||||
|
|
||||||
|
|
||||||
@@ -62,7 +70,7 @@ void header() {
|
|||||||
piCout << Bold << "PIP Code model generator";
|
piCout << Bold << "PIP Code model generator";
|
||||||
piCout << Cyan << "Version" << Bold << PIPVersion() << NewLine;
|
piCout << Cyan << "Version" << Bold << PIPVersion() << NewLine;
|
||||||
piCout << Green << Bold << "Usage:" << Default
|
piCout << Green << Bold << "Usage:" << Default
|
||||||
<< "\"pip_cmg [-hHqPpsAMESTG] -o <output_file> [-I<include_dir1>] [-I<include_dir1>] [...] [-D<define1>] [-D<define1>] [...] "
|
<< "\"pip_cmg [-hHqPpsAMESTGJ] -o <output_file> [-I<include_dir1>] [-I<include_dir1>] [...] [-D<define1>] [-D<define1>] [...] "
|
||||||
"<file1> [<file2>] [<file3>] [...]\""
|
"<file1> [<file2>] [<file3>] [...]\""
|
||||||
<< NewLine;
|
<< NewLine;
|
||||||
}
|
}
|
||||||
@@ -90,6 +98,7 @@ void usage() {
|
|||||||
piCout << "-E " << Green << "- write enums";
|
piCout << "-E " << Green << "- write enums";
|
||||||
piCout << "-S " << Green << "- write stream operators";
|
piCout << "-S " << Green << "- write stream operators";
|
||||||
piCout << "-G " << Green << "- write getter functions";
|
piCout << "-G " << Green << "- write getter functions";
|
||||||
|
piCout << "-J " << Green << "- write JSON functions";
|
||||||
// piCout << "-T " << Green << "- write text serialize functions";
|
// piCout << "-T " << Green << "- write text serialize functions";
|
||||||
piCout << "-o <output_file> " << Green
|
piCout << "-o <output_file> " << Green
|
||||||
<< "- output file for code model without extension (e.g. \"ccm\" - files \"ccm.h\" and \"ccm.cpp\" will be created)";
|
<< "- output file for code model without extension (e.g. \"ccm\" - files \"ccm.h\" and \"ccm.cpp\" will be created)";
|
||||||
@@ -125,3 +134,8 @@ PIString toCName(const PIString & s) {
|
|||||||
ret.replaceAll("__", "_");
|
ret.replaceAll("__", "_");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PICodeParser::Entity * findEntity(Runtime & rt, const PIString & type) {
|
||||||
|
return rt.parser.findEntityByName(type);
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,5 +35,6 @@ void usage();
|
|||||||
void help();
|
void help();
|
||||||
|
|
||||||
PIString toCName(const PIString & s);
|
PIString toCName(const PIString & s);
|
||||||
|
PICodeParser::Entity * findEntity(Runtime & rt, const PIString & type);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,27 +22,100 @@
|
|||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
|
||||||
|
|
||||||
|
void writeGetterTypeMembers(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) {
|
||||||
|
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
|
||||||
|
PISet<int> used_id;
|
||||||
|
for (const PICodeParser::Member & m: e->members) {
|
||||||
|
if (m.is_type_ptr || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue;
|
||||||
|
auto type = findEntity(rt, m.type);
|
||||||
|
if (type) {
|
||||||
|
if (type->is_anonymous) {
|
||||||
|
writeGetterTypeMembers(rt, type, var_prefix + m.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rt.ts << "\tif (strcmp(name, \"" << var_prefix << m.name << "\") == 0) return \"" << m.type;
|
||||||
|
// if (m.isBitfield()) rt.ts << ":" << m.bits;
|
||||||
|
rt.ts << "\";\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void writeGetterValueMembers(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) {
|
||||||
|
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
|
||||||
|
PISet<int> used_id;
|
||||||
|
for (const PICodeParser::Member & m: e->members) {
|
||||||
|
if (m.is_type_ptr || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue;
|
||||||
|
auto type = findEntity(rt, m.type);
|
||||||
|
if (type) {
|
||||||
|
if (type->is_anonymous) {
|
||||||
|
writeGetterValueMembers(rt, type, var_prefix + m.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rt.ts << "\tif (strcmp(name, \"" << var_prefix << m.name << "\") == 0) {";
|
||||||
|
if (m.isBitfield()) {
|
||||||
|
rt.ts << "ret = piSerialize(static_cast<" << m.type << ">(o->" << var_prefix << m.name << "));";
|
||||||
|
} else
|
||||||
|
rt.ts << "serialize(ret, o->" << var_prefix << m.name << ");";
|
||||||
|
rt.ts << " return ret;}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void writeGetterOffsetMembers(Runtime & rt, const PICodeParser::Entity * e, PIString entity_name, PIString var_prefix) {
|
||||||
|
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
|
||||||
|
PISet<int> used_id;
|
||||||
|
for (const PICodeParser::Member & m: e->members) {
|
||||||
|
if (m.is_type_ptr || !m.dims.isEmpty() || m.isBitfield() || (m.visibility != PICodeParser::Public)) continue;
|
||||||
|
auto type = findEntity(rt, m.type);
|
||||||
|
if (type) {
|
||||||
|
if (type->is_anonymous) {
|
||||||
|
writeGetterOffsetMembers(rt, type, entity_name, var_prefix + m.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rt.ts << "\tif (strcmp(name, \"" << var_prefix << m.name << "\") == 0) ";
|
||||||
|
rt.ts << "return PICODEINFO_OFFSET(" << entity_name << ", " << var_prefix << m.name << ");\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void makeGetterType(Runtime & rt, const PICodeParser::Entity * e) {
|
void makeGetterType(Runtime & rt, const PICodeParser::Entity * e) {
|
||||||
if (!needClassStream(e)) return;
|
if (!needClassGetter(e)) return;
|
||||||
rt.ts << "\nconst char * getterType" << toCName(e->name) << "(const char * name) {\n";
|
rt.ts << "\nconst char * getterType" << toCName(e->name) << "(const char * name) {\n";
|
||||||
rt.ts << "\tif (!name) return \"\";\n";
|
rt.ts << "\tif (!name) return \"\";\n";
|
||||||
for (const PICodeParser::Member & m: e->members) {
|
writeGetterTypeMembers(rt, e);
|
||||||
if (m.is_type_ptr || m.isBitfield() || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue;
|
|
||||||
rt.ts << "\tif (strcmp(name, \"" << m.name << "\") == 0) return \"" << m.type << "\";\n";
|
|
||||||
}
|
|
||||||
rt.ts << "\treturn \"\";\n}\n";
|
rt.ts << "\treturn \"\";\n}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void makeGetterValue(Runtime & rt, const PICodeParser::Entity * e) {
|
void makeGetterValue(Runtime & rt, const PICodeParser::Entity * e) {
|
||||||
if (!needClassStream(e)) return;
|
if (!needClassGetter(e)) return;
|
||||||
rt.ts << "\nPIByteArray getterValue" << toCName(e->name) << "(const void * p, const char * name) {\n";
|
rt.ts << "\nPIByteArray getterValue" << toCName(e->name) << "(const void * p, const char * name) {\n";
|
||||||
rt.ts << "\tPIByteArray ret;\n";
|
rt.ts << "\tPIByteArray ret;\n";
|
||||||
rt.ts << "\tif (!p || !name) return ret;\n";
|
rt.ts << "\tif (!p || !name) return ret;\n";
|
||||||
rt.ts << "\t" << e->name << " * o = (" << e->name << "*)p;\n";
|
rt.ts << "\t" << e->name << " * o = (" << e->name << "*)p;\n";
|
||||||
for (const PICodeParser::Member & m: e->members) {
|
writeGetterValueMembers(rt, e);
|
||||||
if (m.is_type_ptr || m.isBitfield() || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue;
|
|
||||||
rt.ts << "\tif (strcmp(name, \"" << m.name << "\") == 0) {serialize(ret, o->" << m.name << "); return ret;}\n";
|
|
||||||
}
|
|
||||||
rt.ts << "\treturn ret;\n}\n";
|
rt.ts << "\treturn ret;\n}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void makeGetterOffset(Runtime & rt, const PICodeParser::Entity * e) {
|
||||||
|
if (!needClassGetter(e)) return;
|
||||||
|
rt.ts << "\nint getterOffset" << toCName(e->name) << "(const char * name) {\n";
|
||||||
|
rt.ts << "\tif (!name) return 0;\n";
|
||||||
|
writeGetterOffsetMembers(rt, e, e->name);
|
||||||
|
rt.ts << "\treturn 0;\n}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool needClassGetter(const PICodeParser::Entity * e) {
|
||||||
|
if (e->meta.contains("no-getter")) return false;
|
||||||
|
for (const PICodeParser::Member & m: e->members) {
|
||||||
|
if (m.is_type_ptr || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue;
|
||||||
|
if (m.attributes[PICodeParser::Static]) continue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,7 +22,12 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
void writeGetterTypeMembers(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix = {});
|
||||||
|
void writeGetterValueMembers(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix = {});
|
||||||
|
void writeGetterOffsetMembers(Runtime & rt, const PICodeParser::Entity * e, PIString entity_name, PIString var_prefix = {});
|
||||||
void makeGetterType(Runtime & rt, const PICodeParser::Entity * e);
|
void makeGetterType(Runtime & rt, const PICodeParser::Entity * e);
|
||||||
void makeGetterValue(Runtime & rt, const PICodeParser::Entity * e);
|
void makeGetterValue(Runtime & rt, const PICodeParser::Entity * e);
|
||||||
|
void makeGetterOffset(Runtime & rt, const PICodeParser::Entity * e);
|
||||||
|
bool needClassGetter(const PICodeParser::Entity * e);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,7 +22,8 @@
|
|||||||
#include "pitranslator.h"
|
#include "pitranslator.h"
|
||||||
|
|
||||||
|
|
||||||
bool writeClassJSONMembersOut(Runtime & rt, const PICodeParser::Entity * e) {
|
bool writeClassJSONMembersOut(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) {
|
||||||
|
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
|
||||||
PIVector<PICodeParser::Member> ml;
|
PIVector<PICodeParser::Member> ml;
|
||||||
for (const PICodeParser::Member & m: e->members) {
|
for (const PICodeParser::Member & m: e->members) {
|
||||||
if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue;
|
if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue;
|
||||||
@@ -30,12 +31,19 @@ bool writeClassJSONMembersOut(Runtime & rt, const PICodeParser::Entity * e) {
|
|||||||
}
|
}
|
||||||
bool is_union = e->type == "union";
|
bool is_union = e->type == "union";
|
||||||
for (const PICodeParser::Member & m: ml) {
|
for (const PICodeParser::Member & m: ml) {
|
||||||
if (is_union && m.isBitfield()) continue;
|
if (m.isBitfield()) continue;
|
||||||
if (m.attributes[PICodeParser::Static]) continue;
|
if (m.attributes[PICodeParser::Static]) continue;
|
||||||
if (m.meta.value("id") == "-") continue;
|
if (m.meta.value("id") == "-") continue;
|
||||||
// if (m.meta.contains("id")) cnt = m.meta.value("id").toInt();
|
// if (m.meta.contains("id")) cnt = m.meta.value("id").toInt();
|
||||||
|
auto type = findEntity(rt, m.type);
|
||||||
|
if (type) {
|
||||||
|
if (type->is_anonymous) {
|
||||||
|
writeClassJSONMembersOut(rt, type, var_prefix + m.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (m.dims.isEmpty()) {
|
if (m.dims.isEmpty()) {
|
||||||
rt.ts << "\tret[\"" << m.name << "\"] = piSerializeJSON(v." << m.name << ");\n";
|
rt.ts << "\tret[\"" << var_prefix << m.name << "\"] = piSerializeJSON(v." << var_prefix << m.name << ");\n";
|
||||||
} else {
|
} else {
|
||||||
PIString ptype = m.type.left(m.type.find('[')).trim();
|
PIString ptype = m.type.left(m.type.find('[')).trim();
|
||||||
PIString size = m.dims[0];
|
PIString size = m.dims[0];
|
||||||
@@ -43,21 +51,22 @@ bool writeClassJSONMembersOut(Runtime & rt, const PICodeParser::Entity * e) {
|
|||||||
size += " * ";
|
size += " * ";
|
||||||
size += m.dims[i];
|
size += m.dims[i];
|
||||||
}
|
}
|
||||||
rt.ts << "\tret[\"" << m.name << "\"] = piSerializeJSON(PIVector<" << ptype << " >((const " << ptype << " *)(v." << m.name
|
rt.ts << "\tret[\"" << var_prefix << m.name << "\"] = piSerializeJSON(PIVector<" << ptype << " >((const " << ptype << " *)(v."
|
||||||
<< "), " << size << "));\n";
|
<< var_prefix << m.name << "), " << size << "));\n";
|
||||||
}
|
}
|
||||||
if (is_union) break;
|
if (is_union) break;
|
||||||
}
|
}
|
||||||
if (is_union) return true;
|
if (is_union) return true;
|
||||||
for (const PICodeParser::Entity * ce: e->children) {
|
/*for (const PICodeParser::Entity * ce: e->children) {
|
||||||
if (ce->has_name) continue;
|
if (!ce->is_anonymous) continue;
|
||||||
if (!writeClassJSONMembersOut(rt, ce)) return false;
|
if (!writeClassJSONMembersOut(rt, ce)) return false;
|
||||||
}
|
}*/
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool writeClassJSONMembersIn(Runtime & rt, const PICodeParser::Entity * e) {
|
bool writeClassJSONMembersIn(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) {
|
||||||
|
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
|
||||||
PIVector<PICodeParser::Member> ml;
|
PIVector<PICodeParser::Member> ml;
|
||||||
for (const PICodeParser::Member & m: e->members) {
|
for (const PICodeParser::Member & m: e->members) {
|
||||||
if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue;
|
if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue;
|
||||||
@@ -66,12 +75,19 @@ bool writeClassJSONMembersIn(Runtime & rt, const PICodeParser::Entity * e) {
|
|||||||
bool is_union = e->type == "union";
|
bool is_union = e->type == "union";
|
||||||
PISet<int> used_id;
|
PISet<int> used_id;
|
||||||
for (const PICodeParser::Member & m: ml) {
|
for (const PICodeParser::Member & m: ml) {
|
||||||
if (is_union && m.isBitfield()) continue;
|
if (m.isBitfield()) continue;
|
||||||
if (m.attributes[PICodeParser::Static]) continue;
|
if (m.attributes[PICodeParser::Static]) continue;
|
||||||
if (m.meta.value("id") == "-") continue;
|
if (m.meta.value("id") == "-") continue;
|
||||||
|
auto type = findEntity(rt, m.type);
|
||||||
|
if (type) {
|
||||||
|
if (type->is_anonymous) {
|
||||||
|
writeClassJSONMembersIn(rt, type, var_prefix + m.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
// if (m.meta.contains("id")) cnt = m.meta.value("id").toInt();
|
// if (m.meta.contains("id")) cnt = m.meta.value("id").toInt();
|
||||||
if (m.dims.isEmpty()) {
|
if (m.dims.isEmpty()) {
|
||||||
rt.ts << "\tpiDeserializeJSON(v." << m.name << ", js[\"" << m.name << "\"]);\n";
|
rt.ts << "\tpiDeserializeJSON(v." << var_prefix << m.name << ", js[\"" << var_prefix << m.name << "\"]);\n";
|
||||||
} else {
|
} else {
|
||||||
PIString ptype = m.type.left(m.type.find('[')).trim();
|
PIString ptype = m.type.left(m.type.find('[')).trim();
|
||||||
PIString size = m.dims[0];
|
PIString size = m.dims[0];
|
||||||
@@ -80,19 +96,19 @@ bool writeClassJSONMembersIn(Runtime & rt, const PICodeParser::Entity * e) {
|
|||||||
size += m.dims[i];
|
size += m.dims[i];
|
||||||
}
|
}
|
||||||
rt.ts << "\t{\n\t\tPIVector<" << ptype << " > d;\n";
|
rt.ts << "\t{\n\t\tPIVector<" << ptype << " > d;\n";
|
||||||
rt.ts << "\t\tpiDeserializeJSON(d, js[\"" << m.name << "\"]);\n";
|
rt.ts << "\t\tpiDeserializeJSON(d, js[\"" << var_prefix << m.name << "\"]);\n";
|
||||||
rt.ts << "\t\tint cnt = piMini(d.size_s(), " << size << ");\n";
|
rt.ts << "\t\tint cnt = piMini(d.size_s(), " << size << ");\n";
|
||||||
rt.ts << "\t\tfor (int i = 0; i < cnt; ++i)\n";
|
rt.ts << "\t\tfor (int i = 0; i < cnt; ++i)\n";
|
||||||
rt.ts << "\t\t\t((" << ptype << " *)(v." << m.name << "))[i] = d[i];\n";
|
rt.ts << "\t\t\t((" << ptype << " *)(v." << var_prefix << m.name << "))[i] = d[i];\n";
|
||||||
rt.ts << "\t}\n";
|
rt.ts << "\t}\n";
|
||||||
}
|
}
|
||||||
if (is_union) break;
|
if (is_union) break;
|
||||||
}
|
}
|
||||||
if (is_union) return true;
|
if (is_union) return true;
|
||||||
for (const PICodeParser::Entity * ce: e->children) {
|
/*for (const PICodeParser::Entity * ce: e->children) {
|
||||||
if (ce->has_name) continue;
|
if (!ce->is_anonymous) continue;
|
||||||
if (!writeClassJSONMembersIn(rt, ce)) return false;
|
if (!writeClassJSONMembersIn(rt, ce)) return false;
|
||||||
}
|
}*/
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
bool writeClassJSONMembersOut(Runtime & rt, const PICodeParser::Entity * e);
|
bool writeClassJSONMembersOut(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix = {});
|
||||||
bool writeClassJSONMembersIn(Runtime & rt, const PICodeParser::Entity * e);
|
bool writeClassJSONMembersIn(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix = {});
|
||||||
bool needClassJSON(const PICodeParser::Entity * e);
|
bool needClassJSON(const PICodeParser::Entity * e);
|
||||||
bool makeClassJSON(Runtime & rt, const PICodeParser::Entity * e);
|
bool makeClassJSON(Runtime & rt, const PICodeParser::Entity * e);
|
||||||
|
|
||||||
|
|||||||
@@ -66,11 +66,15 @@ bool writeModel(PICodeParser & parser,
|
|||||||
if (meta || enums || getters) {
|
if (meta || enums || getters) {
|
||||||
if (getters) {
|
if (getters) {
|
||||||
ts << "\n\n// Getter funtions\n";
|
ts << "\n\n// Getter funtions\n";
|
||||||
|
ts << "\n#define PICODEINFO_OFFSET(type, member) reinterpret_cast<size_t>(&reinterpret_cast<const char &>((((type "
|
||||||
|
"*)nullptr)->member)))\n";
|
||||||
for (const PICodeParser::Entity * e: parser.entities) {
|
for (const PICodeParser::Entity * e: parser.entities) {
|
||||||
if (!e->has_name || e->name.startsWith("_PI")) continue;
|
if (e->is_anonymous || e->name.startsWith("_PI")) continue;
|
||||||
makeGetterType(rt, e);
|
makeGetterType(rt, e);
|
||||||
makeGetterValue(rt, e);
|
makeGetterValue(rt, e);
|
||||||
|
makeGetterOffset(rt, e);
|
||||||
}
|
}
|
||||||
|
ts << "\n#undef PICODEINFO_OFFSET\n";
|
||||||
}
|
}
|
||||||
ts << "\n\n// Metainformation\n\n__ClassInfo_" << defname << "_Initializer__::__ClassInfo_" << defname << "_Initializer__() {\n";
|
ts << "\n\n// Metainformation\n\n__ClassInfo_" << defname << "_Initializer__::__ClassInfo_" << defname << "_Initializer__() {\n";
|
||||||
ts << "\tstatic __ClassInfo_" << defname << "_Initializer__::Content content;\n";
|
ts << "\tstatic __ClassInfo_" << defname << "_Initializer__::Content content;\n";
|
||||||
@@ -83,6 +87,7 @@ bool writeModel(PICodeParser & parser,
|
|||||||
if (getters) {
|
if (getters) {
|
||||||
ts << "\tauto & ci_avf(*ci_ins->accessValueFunctions);\n";
|
ts << "\tauto & ci_avf(*ci_ins->accessValueFunctions);\n";
|
||||||
ts << "\tauto & ci_atf(*ci_ins->accessTypeFunctions);\n";
|
ts << "\tauto & ci_atf(*ci_ins->accessTypeFunctions);\n";
|
||||||
|
ts << "\tauto & ci_aof(*ci_ins->accessOffsetFunctions);\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta) {
|
if (meta) {
|
||||||
@@ -95,7 +100,7 @@ bool writeModel(PICodeParser & parser,
|
|||||||
if (meta) {
|
if (meta) {
|
||||||
ts << "\n\n// Classes\n";
|
ts << "\n\n// Classes\n";
|
||||||
for (const PICodeParser::Entity * e: parser.entities) {
|
for (const PICodeParser::Entity * e: parser.entities) {
|
||||||
if (e->name.startsWith("_PI")) continue;
|
if (e->name.startsWith("_PI") || e->is_anonymous) continue;
|
||||||
makeClassInfo(rt, e);
|
makeClassInfo(rt, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,9 +113,11 @@ bool writeModel(PICodeParser & parser,
|
|||||||
ts << "\n// Getters\n";
|
ts << "\n// Getters\n";
|
||||||
for (const PICodeParser::Entity * e: parser.entities) {
|
for (const PICodeParser::Entity * e: parser.entities) {
|
||||||
if (!needClassStream(e)) continue;
|
if (!needClassStream(e)) continue;
|
||||||
if (!e->has_name || e->name.startsWith("_PI")) continue;
|
if (e->is_anonymous || e->name.startsWith("_PI")) continue;
|
||||||
ts << "\tci_avf[\"" << e->name << "\"] = getterValue" << toCName(e->name) << ";\n";
|
auto cname = toCName(e->name);
|
||||||
ts << "\tci_atf[\"" << e->name << "\"] = getterType" << toCName(e->name) << ";\n";
|
ts << "\tci_avf[\"" << e->name << "\"] = getterValue" << cname << ";\n";
|
||||||
|
ts << "\tci_atf[\"" << e->name << "\"] = getterType" << cname << ";\n";
|
||||||
|
ts << "\tci_aof[\"" << e->name << "\"] = getterOffset" << cname << ";\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ts << "}\n\n";
|
ts << "}\n\n";
|
||||||
@@ -121,11 +128,12 @@ bool writeModel(PICodeParser & parser,
|
|||||||
if (getters) {
|
if (getters) {
|
||||||
ts << "\tauto & ci_avf(*ci_ins->accessValueFunctions);\n";
|
ts << "\tauto & ci_avf(*ci_ins->accessValueFunctions);\n";
|
||||||
ts << "\tauto & ci_atf(*ci_ins->accessTypeFunctions);\n";
|
ts << "\tauto & ci_atf(*ci_ins->accessTypeFunctions);\n";
|
||||||
|
ts << "\tauto & ci_aof(*ci_ins->accessOffsetFunctions);\n";
|
||||||
}
|
}
|
||||||
if (meta) {
|
if (meta) {
|
||||||
ts << "\n// Classes clean\n";
|
ts << "\n// Classes clean\n";
|
||||||
for (const PICodeParser::Entity * e: parser.entities) {
|
for (const PICodeParser::Entity * e: parser.entities) {
|
||||||
if (e->name.startsWith("_PI")) continue;
|
if (e->name.startsWith("_PI") || e->is_anonymous) continue;
|
||||||
ts << "\tpiDeleteSafety(ci_ci[\"" << e->name << "\"]);\n";
|
ts << "\tpiDeleteSafety(ci_ci[\"" << e->name << "\"]);\n";
|
||||||
ts << "\tci_ins->classesInfo->remove(\"" << e->name << "\");\n";
|
ts << "\tci_ins->classesInfo->remove(\"" << e->name << "\");\n";
|
||||||
}
|
}
|
||||||
@@ -143,9 +151,10 @@ bool writeModel(PICodeParser & parser,
|
|||||||
ts << "\n// Getters clean\n";
|
ts << "\n// Getters clean\n";
|
||||||
for (const PICodeParser::Entity * e: parser.entities) {
|
for (const PICodeParser::Entity * e: parser.entities) {
|
||||||
if (!needClassStream(e)) continue;
|
if (!needClassStream(e)) continue;
|
||||||
if (!e->has_name || e->name.startsWith("_PI")) continue;
|
if (e->is_anonymous || e->name.startsWith("_PI")) continue;
|
||||||
ts << "\tci_avf.remove(\"" << e->name << "\");\n";
|
ts << "\tci_avf.remove(\"" << e->name << "\");\n";
|
||||||
ts << "\tci_atf.remove(\"" << e->name << "\");\n";
|
ts << "\tci_atf.remove(\"" << e->name << "\");\n";
|
||||||
|
ts << "\tci_aof.remove(\"" << e->name << "\");\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ts << "}\n";
|
ts << "}\n";
|
||||||
@@ -173,7 +182,7 @@ bool writeModel(PICodeParser & parser,
|
|||||||
if (streams) {
|
if (streams) {
|
||||||
ts << "\n\n// Stream operators\n";
|
ts << "\n\n// Stream operators\n";
|
||||||
for (const PICodeParser::Entity * e: parser.entities) {
|
for (const PICodeParser::Entity * e: parser.entities) {
|
||||||
if (!e->has_name || e->name.startsWith("_PI") ||
|
if (e->is_anonymous || e->name.startsWith("_PI") ||
|
||||||
!(e->visibility == PICodeParser::Global || e->visibility == PICodeParser::Public))
|
!(e->visibility == PICodeParser::Global || e->visibility == PICodeParser::Public))
|
||||||
continue;
|
continue;
|
||||||
if (!makeClassStream(rt, e)) return false;
|
if (!makeClassStream(rt, e)) return false;
|
||||||
@@ -182,7 +191,7 @@ bool writeModel(PICodeParser & parser,
|
|||||||
if (json) {
|
if (json) {
|
||||||
ts << "\n\n// JSON serialization\n";
|
ts << "\n\n// JSON serialization\n";
|
||||||
for (const PICodeParser::Entity * e: parser.entities) {
|
for (const PICodeParser::Entity * e: parser.entities) {
|
||||||
if (!e->has_name || e->name.startsWith("_PI") ||
|
if (e->is_anonymous || e->name.startsWith("_PI") ||
|
||||||
!(e->visibility == PICodeParser::Global || e->visibility == PICodeParser::Public))
|
!(e->visibility == PICodeParser::Global || e->visibility == PICodeParser::Public))
|
||||||
continue;
|
continue;
|
||||||
if (!makeClassJSON(rt, e)) return false;
|
if (!makeClassJSON(rt, e)) return false;
|
||||||
|
|||||||
@@ -20,27 +20,17 @@
|
|||||||
#include "metainfo.h"
|
#include "metainfo.h"
|
||||||
|
|
||||||
|
|
||||||
void makeClassInfo(Runtime & rt, const PICodeParser::Entity * e) {
|
void writeClassInfoMembers(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) {
|
||||||
rt.ts << "\n\t{\n\tClassInfo * ci = new ClassInfo();\n";
|
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
|
||||||
rt.ts << "\tci->type = \"" << e->type << "\";\n";
|
|
||||||
rt.ts << "\tci->name = \"" << e->name << "\";\n";
|
|
||||||
rt.ts << "\tci->has_name = " << (e->has_name ? "true" : "false") << ";\n";
|
|
||||||
if (!e->meta.isEmpty()) {
|
|
||||||
auto i = e->meta.makeIterator();
|
|
||||||
while (i.next())
|
|
||||||
rt.ts << "\tci->meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n";
|
|
||||||
}
|
|
||||||
rt.ts << "\tci_ci[ci->name] = ci;\n";
|
|
||||||
if (e->parent_scope) {
|
|
||||||
rt.ts << "\tpci = "
|
|
||||||
<< "ci_ci.value(\"" << e->parent_scope->name << "\", 0);\n";
|
|
||||||
rt.ts << "\tif (pci) pci->children_info << ci;\n";
|
|
||||||
}
|
|
||||||
for (const PICodeParser::Entity * p: e->parents)
|
|
||||||
rt.ts << "\tci->parents << \"" << p->name << "\";\n";
|
|
||||||
if (!e->members.isEmpty()) rt.ts << "\n\tTypeInfo ti;\n";
|
|
||||||
for (const PICodeParser::Member & m: e->members) {
|
for (const PICodeParser::Member & m: e->members) {
|
||||||
rt.ts << "\tti = TypeInfo(\"" << m.name << "\", \"" << m.type << "\"";
|
auto type = findEntity(rt, m.type);
|
||||||
|
if (type) {
|
||||||
|
if (type->is_anonymous) {
|
||||||
|
writeClassInfoMembers(rt, type, var_prefix + m.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rt.ts << "\tti = TypeInfo(\"" << var_prefix << m.name << "\", \"" << m.type << "\"";
|
||||||
if (m.attributes != 0) {
|
if (m.attributes != 0) {
|
||||||
bool fir = true;
|
bool fir = true;
|
||||||
rt.ts << ", ";
|
rt.ts << ", ";
|
||||||
@@ -97,6 +87,29 @@ void makeClassInfo(Runtime & rt, const PICodeParser::Entity * e) {
|
|||||||
}
|
}
|
||||||
rt.ts << "\tci->variables << ti;\n";
|
rt.ts << "\tci->variables << ti;\n";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void makeClassInfo(Runtime & rt, const PICodeParser::Entity * e) {
|
||||||
|
rt.ts << "\n\t{\n\tClassInfo * ci = new ClassInfo();\n";
|
||||||
|
rt.ts << "\tci->type = \"" << e->type << "\";\n";
|
||||||
|
rt.ts << "\tci->name = \"" << e->name << "\";\n";
|
||||||
|
// rt.ts << "\tci->is_anonymous = " << (e->is_anonymous ? "true" : "false") << ";\n";
|
||||||
|
if (!e->meta.isEmpty()) {
|
||||||
|
auto i = e->meta.makeIterator();
|
||||||
|
while (i.next())
|
||||||
|
rt.ts << "\tci->meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n";
|
||||||
|
}
|
||||||
|
rt.ts << "\tci_ci[ci->name] = ci;\n";
|
||||||
|
if (e->parent_scope) {
|
||||||
|
rt.ts << "\tpci = "
|
||||||
|
<< "ci_ci.value(\"" << e->parent_scope->name << "\", 0);\n";
|
||||||
|
rt.ts << "\tif (pci) pci->children_info << ci;\n";
|
||||||
|
}
|
||||||
|
for (const PICodeParser::Entity * p: e->parents)
|
||||||
|
rt.ts << "\tci->parents << \"" << p->name << "\";\n";
|
||||||
|
if (!e->members.isEmpty()) rt.ts << "\n\tTypeInfo ti;\n";
|
||||||
|
writeClassInfoMembers(rt, e);
|
||||||
PIString arg;
|
PIString arg;
|
||||||
bool has_fi = false;
|
bool has_fi = false;
|
||||||
for (const PICodeParser::Member & m: e->functions) {
|
for (const PICodeParser::Member & m: e->functions) {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
void writeClassInfoMembers(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix = {});
|
||||||
void makeClassInfo(Runtime & rt, const PICodeParser::Entity * e);
|
void makeClassInfo(Runtime & rt, const PICodeParser::Entity * e);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,7 +22,8 @@
|
|||||||
#include "pitranslator.h"
|
#include "pitranslator.h"
|
||||||
|
|
||||||
|
|
||||||
bool writeClassStreamMembersOut(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple) {
|
bool writeClassStreamMembersOut(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple, PIString var_prefix) {
|
||||||
|
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
|
||||||
PIVector<PICodeParser::Member> ml;
|
PIVector<PICodeParser::Member> ml;
|
||||||
for (const PICodeParser::Member & m: e->members) {
|
for (const PICodeParser::Member & m: e->members) {
|
||||||
if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue;
|
if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue;
|
||||||
@@ -31,9 +32,16 @@ bool writeClassStreamMembersOut(Runtime & rt, const PICodeParser::Entity * e, in
|
|||||||
bool is_union = e->type == "union";
|
bool is_union = e->type == "union";
|
||||||
PISet<int> used_id;
|
PISet<int> used_id;
|
||||||
for (const PICodeParser::Member & m: ml) {
|
for (const PICodeParser::Member & m: ml) {
|
||||||
if (is_union && m.isBitfield()) continue;
|
if (m.isBitfield()) continue;
|
||||||
if (m.attributes[PICodeParser::Static]) continue;
|
if (m.attributes[PICodeParser::Static]) continue;
|
||||||
if (m.meta.value("id") == "-") continue;
|
if (m.meta.value("id") == "-") continue;
|
||||||
|
auto type = findEntity(rt, m.type);
|
||||||
|
if (type) {
|
||||||
|
if (type->is_anonymous) {
|
||||||
|
if (!writeClassStreamMembersOut(rt, type, cnt, simple, var_prefix + m.name)) return false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
++cnt;
|
++cnt;
|
||||||
if (m.meta.contains("id")) cnt = m.meta.value("id").toInt();
|
if (m.meta.contains("id")) cnt = m.meta.value("id").toInt();
|
||||||
if (used_id[cnt]) {
|
if (used_id[cnt]) {
|
||||||
@@ -44,11 +52,11 @@ bool writeClassStreamMembersOut(Runtime & rt, const PICodeParser::Entity * e, in
|
|||||||
if (simple) {
|
if (simple) {
|
||||||
rt.ts << "\ts << ";
|
rt.ts << "\ts << ";
|
||||||
if (rt.parser.isEnum(m.type)) rt.ts << "(int)";
|
if (rt.parser.isEnum(m.type)) rt.ts << "(int)";
|
||||||
rt.ts << "v." << m.name << ";\n";
|
rt.ts << "v." << var_prefix << m.name << ";\n";
|
||||||
} else {
|
} else {
|
||||||
rt.ts << "\tcs.add(" << cnt << ", ";
|
rt.ts << "\tcs.add(" << cnt << ", ";
|
||||||
if (rt.parser.isEnum(m.type)) rt.ts << "(int)";
|
if (rt.parser.isEnum(m.type)) rt.ts << "(int)";
|
||||||
rt.ts << "v." << m.name << ");\n";
|
rt.ts << "v." << var_prefix << m.name << ");\n";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PIString ptype = m.type.left(m.type.find('[')).trim();
|
PIString ptype = m.type.left(m.type.find('[')).trim();
|
||||||
@@ -59,24 +67,22 @@ bool writeClassStreamMembersOut(Runtime & rt, const PICodeParser::Entity * e, in
|
|||||||
}
|
}
|
||||||
if (simple) {
|
if (simple) {
|
||||||
rt.ts << "\tfor (int i = 0; i < " << size << "; ++i)\n";
|
rt.ts << "\tfor (int i = 0; i < " << size << "; ++i)\n";
|
||||||
rt.ts << "\t\ts << ((const " << ptype << " *)(v." << m.name << "))[i];\n";
|
rt.ts << "\t\ts << ((const " << ptype << " *)(" << "v." << var_prefix << m.name << "))[i];\n";
|
||||||
} else {
|
} else {
|
||||||
rt.ts << "\tcs << cs.chunk(" << cnt << ", PIVector<" << ptype << " >((const " << ptype << " *)(v." << m.name << "), ";
|
rt.ts << "\tcs << cs.chunk(" << cnt << ", PIVector<" << ptype << " >((const " << ptype << " *)(" << "v." << var_prefix
|
||||||
|
<< m.name << "), ";
|
||||||
rt.ts << size << "));\n";
|
rt.ts << size << "));\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_union) break;
|
if (is_union) break;
|
||||||
}
|
}
|
||||||
if (is_union) return true;
|
if (is_union) return true;
|
||||||
for (const PICodeParser::Entity * ce: e->children) {
|
|
||||||
if (ce->has_name) continue;
|
|
||||||
if (!writeClassStreamMembersOut(rt, ce, cnt, simple)) return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple) {
|
bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple, PIString var_prefix) {
|
||||||
|
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
|
||||||
PIVector<PICodeParser::Member> ml;
|
PIVector<PICodeParser::Member> ml;
|
||||||
for (const PICodeParser::Member & m: e->members) {
|
for (const PICodeParser::Member & m: e->members) {
|
||||||
if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue;
|
if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue;
|
||||||
@@ -85,9 +91,16 @@ bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int
|
|||||||
bool is_union = e->type == "union";
|
bool is_union = e->type == "union";
|
||||||
PISet<int> used_id;
|
PISet<int> used_id;
|
||||||
for (const PICodeParser::Member & m: ml) {
|
for (const PICodeParser::Member & m: ml) {
|
||||||
if (is_union && m.isBitfield()) continue;
|
if (m.isBitfield()) continue;
|
||||||
if (m.attributes[PICodeParser::Static]) continue;
|
if (m.attributes[PICodeParser::Static]) continue;
|
||||||
if (m.meta.value("id") == "-") continue;
|
if (m.meta.value("id") == "-") continue;
|
||||||
|
auto type = findEntity(rt, m.type);
|
||||||
|
if (type) {
|
||||||
|
if (type->is_anonymous) {
|
||||||
|
if (!writeClassStreamMembersIn(rt, type, cnt, simple, var_prefix + m.name)) return false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
++cnt;
|
++cnt;
|
||||||
if (m.meta.contains("id")) cnt = m.meta.value("id").toInt();
|
if (m.meta.contains("id")) cnt = m.meta.value("id").toInt();
|
||||||
if (used_id[cnt]) {
|
if (used_id[cnt]) {
|
||||||
@@ -104,8 +117,8 @@ bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int
|
|||||||
if (is_enum)
|
if (is_enum)
|
||||||
rt.ts << "i;";
|
rt.ts << "i;";
|
||||||
else
|
else
|
||||||
rt.ts << "v." << m.name << ";";
|
rt.ts << "v." << var_prefix << m.name << ";";
|
||||||
if (is_enum) rt.ts << " v." << m.name << " = (" << m.type << ")i;}";
|
if (is_enum) rt.ts << " v. << var_prefix" << m.name << " = (" << m.type << ")i;}";
|
||||||
rt.ts << "\n";
|
rt.ts << "\n";
|
||||||
} else {
|
} else {
|
||||||
rt.ts << "\t\tcase " << cnt << ":";
|
rt.ts << "\t\tcase " << cnt << ":";
|
||||||
@@ -114,9 +127,9 @@ bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int
|
|||||||
if (is_enum)
|
if (is_enum)
|
||||||
rt.ts << "i";
|
rt.ts << "i";
|
||||||
else
|
else
|
||||||
rt.ts << "v." << m.name;
|
rt.ts << "v." << var_prefix << m.name;
|
||||||
rt.ts << ");";
|
rt.ts << ");";
|
||||||
if (is_enum) rt.ts << " v." << m.name << " = (" << m.type << ")i;}";
|
if (is_enum) rt.ts << " v." << var_prefix << m.name << " = (" << m.type << ")i;}";
|
||||||
rt.ts << " break;\n";
|
rt.ts << " break;\n";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -128,12 +141,12 @@ bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int
|
|||||||
}
|
}
|
||||||
if (simple) {
|
if (simple) {
|
||||||
rt.ts << "\tfor (int i = 0; i < " << size << "; ++i)\n";
|
rt.ts << "\tfor (int i = 0; i < " << size << "; ++i)\n";
|
||||||
rt.ts << "\t\ts >> ((" << ptype << " *)(v." << m.name << "))[i];\n";
|
rt.ts << "\t\ts >> ((" << ptype << " *)(" << "v." << var_prefix << m.name << "))[i];\n";
|
||||||
} else {
|
} else {
|
||||||
rt.ts << "\t\tcase " << cnt << ": {\n\t\t\tPIVector<" << ptype << " > d; cs.get(d);\n";
|
rt.ts << "\t\tcase " << cnt << ": {\n\t\t\tPIVector<" << ptype << " > d; cs.get(d);\n";
|
||||||
rt.ts << "\t\t\tint cnt = piMini(d.size_s(), " << size << ");\n";
|
rt.ts << "\t\t\tint cnt = piMini(d.size_s(), " << size << ");\n";
|
||||||
rt.ts << "\t\t\tfor (int i = 0; i < cnt; ++i)\n";
|
rt.ts << "\t\t\tfor (int i = 0; i < cnt; ++i)\n";
|
||||||
rt.ts << "\t\t\t\t((" << ptype << " *)(v." << m.name << "))[i] = d[i];\n";
|
rt.ts << "\t\t\t\t((" << ptype << " *)(" << "v." << var_prefix << m.name << "))[i] = d[i];\n";
|
||||||
rt.ts << "\t\t\t}\n";
|
rt.ts << "\t\t\t}\n";
|
||||||
rt.ts << "\t\t\tbreak;\n";
|
rt.ts << "\t\t\tbreak;\n";
|
||||||
}
|
}
|
||||||
@@ -141,10 +154,6 @@ bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int
|
|||||||
if (is_union) break;
|
if (is_union) break;
|
||||||
}
|
}
|
||||||
if (is_union) return true;
|
if (is_union) return true;
|
||||||
for (const PICodeParser::Entity * ce: e->children) {
|
|
||||||
if (ce->has_name) continue;
|
|
||||||
if (!writeClassStreamMembersIn(rt, ce, cnt, simple)) return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
bool writeClassStreamMembersOut(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple);
|
bool writeClassStreamMembersOut(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple, PIString var_prefix = {});
|
||||||
bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple);
|
bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple, PIString var_prefix = {});
|
||||||
bool needClassStream(const PICodeParser::Entity * e);
|
bool needClassStream(const PICodeParser::Entity * e);
|
||||||
bool makeClassStream(Runtime & rt, const PICodeParser::Entity * e);
|
bool makeClassStream(Runtime & rt, const PICodeParser::Entity * e);
|
||||||
|
|
||||||
|
|||||||
@@ -462,13 +462,18 @@ bool procDpkg(const PIString & l) {
|
|||||||
PIFile::FileInfo fi;
|
PIFile::FileInfo fi;
|
||||||
fi.path = l;
|
fi.path = l;
|
||||||
PIString cmd = dpkg + dpkgdir + " -S " + fi.name() + ign_err_suffix;
|
PIString cmd = dpkg + dpkgdir + " -S " + fi.name() + ign_err_suffix;
|
||||||
// PICout(true) << cmd;
|
// PICout(true) << "** dpkg:" << cmd;
|
||||||
PIString vs = execute(cmd);
|
PIString vs = execute(cmd).trim();
|
||||||
if (!vs.isEmpty()) {
|
if (!vs.isEmpty()) {
|
||||||
vs = vs.left(vs.find(":"));
|
PIStringList lines = vs.split('\n').reverse();
|
||||||
if (!vs.isEmpty() && !vs.endsWith("-cross")) all_deps << vs;
|
for (auto l: lines) {
|
||||||
|
auto sl = l;
|
||||||
|
l = l.left(l.find(":"));
|
||||||
|
if (!l.isEmpty() && !l.endsWith("-cross") && !l.contains(' ')) all_deps << l;
|
||||||
|
// PICout(true) << "** found \"" << l << "\" in \"" << sl << "\"";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// piCout << "No dep on" << l;
|
// piCout << "No dep on" << l;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -787,7 +792,16 @@ int main(int argc, char * argv[]) {
|
|||||||
out_dir.replaceAll("/", "\\");
|
out_dir.replaceAll("/", "\\");
|
||||||
#endif
|
#endif
|
||||||
PIVector<PIString> clibs = all_libs.toVector();
|
PIVector<PIString> clibs = all_libs.toVector();
|
||||||
|
static PIStringList ignore_libs({"libc.so"});
|
||||||
for (auto l: clibs) {
|
for (auto l: clibs) {
|
||||||
|
bool ignore_lib = false;
|
||||||
|
for (auto il: ignore_libs) {
|
||||||
|
if (l.startsWith(il)) {
|
||||||
|
ignore_lib = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ignore_lib) continue;
|
||||||
PIFile::FileInfo fi;
|
PIFile::FileInfo fi;
|
||||||
fi.path = l;
|
fi.path = l;
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
|
|||||||
7
utils/system_calib/CMakeLists.txt
Executable file
7
utils/system_calib/CMakeLists.txt
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
list(APPEND PIP_UTILS_LIST "pip_system_calib")
|
||||||
|
set(PIP_UTILS_LIST ${PIP_UTILS_LIST} PARENT_SCOPE)
|
||||||
|
add_executable(pip_system_calib "main.cpp")
|
||||||
|
target_link_libraries(pip_system_calib pip)
|
||||||
|
if (DEFINED LIB)
|
||||||
|
install(TARGETS pip_system_calib DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||||
|
endif ()
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
list(APPEND PIP_UTILS_LIST "pip_system_test")
|
|
||||||
set(PIP_UTILS_LIST ${PIP_UTILS_LIST} PARENT_SCOPE)
|
|
||||||
add_executable(pip_system_test "main.cpp")
|
|
||||||
target_link_libraries(pip_system_test pip)
|
|
||||||
if (DEFINED LIB)
|
|
||||||
install(TARGETS pip_system_test DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
|
||||||
endif ()
|
|
||||||
Reference in New Issue
Block a user