diff --git a/CMakeLists.txt b/CMakeLists.txt index 036cde4b..30e5156b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,23 +1,29 @@ project(pip) -find_package(Qt4) cmake_minimum_required(VERSION 2.6) -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${QT_INCLUDES} . ../peri4_widgets) +include_directories(${CMAKE_CURRENT_SOURCE_DIR} .) +set(VERSION "0.0304") +set(SOVERSION ${VERSION}) +set(CMAKE_BUILD_TYPE "Release") file(GLOB CPPS "pi*.cpp") if (${WIN32}) - add_definitions(-Wall -O2) -else (${WIN32}) - add_definitions(-Wall -O2 -g3 --fast-math) -endif (${WIN32}) -add_library(pip SHARED ${CPPS}) -if (${WIN32}) - target_link_libraries(pip pthread ws2_32 Iphlpapi) + include(GenerateExportHeader) + execute_process(COMMAND "make_rc_win.bat") + add_definitions("-O2") + #add_definitions(-DEF) + list(APPEND CPPS "pip_resource_win.o") + add_library(pip SHARED ${CPPS}) + generate_export_header(pip) + target_link_libraries(pip ws2_32 Iphlpapi) else (${WIN32}) + if(DEFINED ENV{QNX_HOST}) + add_definitions("-O2") + add_library(pip STATIC ${CPPS}) + else() + add_definitions("-Wall -O2 -g3") + add_library(pip SHARED ${CPPS}) + endif() target_link_libraries(pip pthread rt) endif (${WIN32}) add_executable(pip_test "main.cpp") -if (${WIN32}) - target_link_libraries(pip_test pthread ws2_32 Iphlpapi pip) -else (${WIN32}) - target_link_libraries(pip_test pip ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} pcollection) -endif (${WIN32}) +target_link_libraries(pip_test pip) add_subdirectory(system_test) diff --git a/main.cpp b/main.cpp index 9b27b362..d07f29e4 100644 --- a/main.cpp +++ b/main.cpp @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ - +//#define PIP_DEBUG #include "pip.h" @@ -52,7 +52,7 @@ private: void signalFunc(PISignals::Signal signal) { if (signal != PISignals::Interrupt) return; - cout << "Ctrl+C pressed, exiting ..." << endl; + cout << endl << "Ctrl+C pressed, exiting ..." << endl; exit(0); }; @@ -71,293 +71,252 @@ void timerEvent2(void * data, int delim) { class ObjectTest: public PIObject { + PIOBJECT(ObjectTest) public: ObjectTest(const PIString & name = PIString()): PIObject(name) {h = hi = ht = false;} - EVENT_HANDLER(ObjectTest, void, handler) {h = true; cout << " handler in \"" << name() << "\"" << endl;} - EVENT_HANDLER2(ObjectTest, void, handler_i_s, int, i, PIString, s) {hi = true; cout << " handler_i_s in \"" << name() << "\", i = " << i << ", s = \"" << s << "\"" << endl;} - EVENT_HANDLER2(ObjectTest, void, handler_timeout, void * , data, int, delim) {ht = true; cout << " handler_timeout in \"" << name() << "\", data = " << data << ", delim = " << delim << endl;} + EVENT_HANDLER(void, handler) {h = true; cout << " handler in \"" << name() << "\"" << endl;} + EVENT_HANDLER2(void, handler_i_s, int, i, PIString, s) {hi = true; cout << " handler_i_s in \"" << name() << "\", i = " << i << ", s = \"" << s << "\"" << endl;} + EVENT_HANDLER2(void, handler_timeout, void * , data, int, delim) {ht = true; cout << " handler_timeout in \"" << name() << "\", data = " << data << ", delim = " << delim << endl;} bool h, hi, ht; }; class ObjectTest2: public PIObject { + PIOBJECT(ObjectTest2) public: ObjectTest2(const PIString & name = PIString()): PIObject(name) {;} void raise0(const PIString & e) {cout << " event \"" << e << "\" from \"" << name() << "\"" << endl; raiseEvent(this, e);} void raise2(const PIString & e, int i, const PIString & s) {cout << " event \"" << e << "\" from \"" << name() << "\"" << endl; raiseEvent(this, e, i, s);} - EVENT(ObjectTest2, event0) - EVENT(ObjectTest2, event2) + EVENT(event0) + EVENT(event2) }; class CA: public PIObject { + PIOBJECT(CA) public: CA(const PIString & n): PIObject(n) {;} - EVENT_HANDLER(CA, void, handler_ca) {a = true; cout << " handler CA" << endl;} - EVENT(CA, event_ca) + EVENT_HANDLER(void, handler_ca) {a = true; cout << " handler CA" << endl;} + EVENT(event_ca) bool a; }; class CB: public CA { + PIOBJECT(CB) public: CB(const PIString & n): CA(n) {;} - EVENT_HANDLER(CB, void, handler_cb) {b = true; cout << " handler CB" << endl;} + EVENT_HANDLER(void, handler_cb) {b = true; cout << " handler CB" << endl;} bool b; }; class CC: public CB { + PIOBJECT(CC) public: CC(const PIString & n): CB(n) {;} - EVENT_HANDLER(CC, void, handler_cc) {c = true; cout << " handler CC" << endl;} + EVENT_HANDLER(void, handler_cc) {c = true; cout << " handler CC" << endl;} bool c; }; class CD: public CC { + PIOBJECT(CD) public: CD(const PIString & n): CC(n) {;} - EVENT_HANDLER(CD, void, handler_cd) {d = true; cout << " handler CD" << endl;} + EVENT_HANDLER(void, handler_cd) {d = true; cout << " handler CD" << endl;} bool d; }; +PIDiagnostics diag; +bool corr = true; +void te(void * , int) { + diag.received(256, corr); + diag.sended(512); +} -struct Packet { - int from; - int to; - float data; - int cs; + +class ObjectA: public PIObject { + PIOBJECT(ObjectA) +public: + EVENT_HANDLER1(void, handlerA, const PIString & , str) {piCout << "handler A:" << str;} + EVENT2(eventA2, int, i, float, f); + EVENT1(eventA1, const PIString & , str); +}; + +class ObjectB: public PIObject { + PIOBJECT(ObjectB) +public: + EVENT_HANDLER2(void, handlerB, int, i, float, f) {piCout << "handler B:" << i << "," << f;} + EVENT1(eventB, PIString, str); +}; + +#pragma pack(push, 1) + +struct msgHeader { + msgHeader(ushort msg_id_ = 0) { + sign[0] = 'B'; + sign[1] = 'R'; + sign[2] = 'K'; + sign[3] = 'D'; + msg_id = msg_id_; + sys_id = 2; + subsys_id = 1; + fragment = security = cnt = 0; + size = sizeof(msgHeader); + } + char sign[4]; + ushort size; + ushort cnt; + uchar fragment; + ushort msg_id; + uchar sys_id; + uchar subsys_id; + uchar security; + bool verify_sign() {return (sign[0] == 'B' && sign[1] == 'R' && sign[2] == 'K' && sign[3] == 'D');} }; -#pragma pack(push,1) +struct msg2105base { + msgHeader header; + union { + ullong msgTime; + struct { + uint time_ns; + uint time_s; + }; + }; + uint id; + ushort type1kod; + float type1ver; + ushort type2kod; + float type2ver; + ushort type3kod; + float type3ver; + double azimut; + ullong imp_recv_time; + double geo_width_PEC; + double geo_length_PEC; + double geo_width_CP; + double geo_length_CP; + float height; + float kurs_CP; + float kren_CP; + float tangaj_CP; +}; + struct InpuData { - uint first_number; // Номер первого отсчета - struct { - uchar packet_number: 7; // Идентификационный код пакета - uchar packet_last : 1; // Признак последнего пакета - }; - struct { - uchar antenna_number : 3; // Номер антенного канала - uchar frequency_number: 3; // Номер частотного канала - uchar data_type : 2; // Вид передаваемой информации: 0 – оцифровка, 1 – измеренные параметры - }; - uchar data[122]; // Данные -}; - -struct msgHeader { - char sign[4]; - unsigned short size; - unsigned short cnt; - unsigned char fragment; - unsigned short msg_id; - unsigned char sys_id; - unsigned char subsys_id; - unsigned char security; - bool verify_sign() - { - bool ok; - ok = sign[0] == 'B'; - ok = ok && sign[1] == 'R'; - ok = ok && sign[2] == 'K'; - ok = ok && sign[3] == 'D'; - return ok; - } -}; -struct FilterCommand { - FilterCommand() { - memset(this, 0, sizeof(FilterCommand)); - header.sign[0] = 'B'; header.sign[1] = 'R'; header.sign[2] = 'K'; header.sign[3] = 'D'; - header.size = sizeof(FilterCommand); - header.cnt = header.fragment = header.security = 0; - header.msg_id = 2102; - header.sys_id = header.subsys_id = 2; - command = 3; - } - + InpuData() {header.msg_id = 2113;} msgHeader header; - uchar command; // 3 + uint first_number; struct { - uchar fi_number: 7; // номер частотного участка, 1 - 36 - uchar bort : 1; // борт: 0 - левый, 1 - правый + uchar packet_number: 7; + uchar packet_last : 1; }; - ushort freq_start; // начальная частота, 0 - 6100 - ushort freq_end; // конечная частота, 0 - 6100 - uchar filter_bandwith; // полоса проспускания фильтра - ushort filter_time_step; // время шага фильтра по времени - uchar reserve; - ushort record_time_start; // начальное время записи, 1 - 60 мс - ushort record_time_end; // конечное время записи, 1 - 60 мс - uchar record_channels; // номера каналов для записи, 0 - 5 биты - uchar play_channels; // номера каналов для воспроизведения, 0 - 5 биты - uchar signal_type; // тип сигнала для выдачи, 0 - С3, 1 - С4, 2 - С4Ф, 3 - выборка - ushort play_time_start; // начальное время воспроизведения, 1 - 60 мс - ushort play_time_end; // конечное время воспроизведения, 1 - 60 мс - uchar checksum; + struct { + uchar antenna_number : 3; + uchar frequency_number: 3; + uchar data_type : 2; + }; + uchar data[122]; }; #pragma pack(pop) -void te(void*, int); -PITimer tm_(te); -PISerial ser("/dev/ttyS0"); -bool pins[9]; -void te(void*, int) { - for (int i = 1; i <= 9; ++i) - pins[i - 1] = ser.isPin(i); -} -void ke(char key, void*) { - int p = key - '0'; - if (key >= '1' && key <= '9') - ser.setPin(p, !pins[p - 1]); -} -int main(int argc, char * argv[]) { - PIKbdListener kbd; - kbd.enableExitCapture(); - PICLI cli(argc, argv); - cli.addArgument("sender"); - PIEthernet eth; - int i = 0; - bool _ok; - if (cli.hasArgument("sender")) { - while (!PIKbdListener::exiting) { - _ok = eth.send("234.0.2.1", 10101, &i, sizeof(i)); - cout << "send " << i << " - " << (_ok ? "ok" : "fail") << endl; - i++; - msleep(100); - } - } else { - eth.setParameter(PIEthernet::Broadcast); - eth.open(":10101"); - eth.joinMulticastGroup("234.0.2.1"); - while (!PIKbdListener::exiting) { - eth.read(&i, sizeof(i)); - cout << "receive " << i << endl; - } - } - return 0; - - /*tm_.start(10.); - PIConsole con(false, ke); - con.enableExitCapture(); - //ser.setParameter(PISerial::HardwareFlowControl); - ser.open(); - con.addVariable("1 (CAR)", pins); - con.addVariable("2 (SR) ", pins + 1); - con.addVariable("3 (ST) ", pins + 2); - con.addVariable("4 (DTR)", pins + 3); - con.addVariable("5 (GND)", pins + 4); - con.addVariable("6 (DSR)", pins + 5); - con.addVariable("7 (RTS)", pins + 6); - con.addVariable("8 (CTS)", pins + 7); - con.addVariable("9 (RNG)", pins + 8); - con.start(); - con.waitForFinish(); - return 0;*/ - - /*FilterCommand fc; - PIEthernet eth(PIEthernet::TCP_SingleTCP); - eth.open("127.0.0.1:10201"); - while (1) { - eth.read(&fc, sizeof(fc)); - cout << int(fc.fi_number) << ", " << int(fc.bort) << ", " << int(fc.freq_start) << ", " << int(fc.freq_end) << ", " << int(fc.play_channels) << ", " << int(fc.record_channels) << endl; - } - return 0;*/ +class RC: public PIObject { + PIOBJECT(RC) +public: + EVENT_HANDLER2(void, re, ullong, id, int, size) {piCout << "written id =" << id << "size =" << size;} +}; - /*PIDir dir(argv[1]); - FILE*f = popen("cd ../ && pwd", "w"); - char fd[4096]; - int ret = fread(fd, 4096, 1, f); - pclose(f); - cout << PIString(fd, ret); - f = popen("cd ../ && pwd", "w"); - ret = fread(fd, 4096, 1, f); - pclose(f); - cout << PIString(fd, ret); - return 0; - cout << dir.path() << endl; - dir.up(); - cout << dir.path() << endl; - PIVector ent = dir.entries(); - piForeachC (PIDir::DirEntry & i, ent) - cout << i.mode << " " << PIString::readableSize(i.size).expandRightTo(10, ' ') << " " << i.name << endl;*/ - - /*PISystemTime st_time, inc_time; - PITimer tm_; - tm_.reset(); - inc_time = PISystemTime::fromMilliseconds(50); - st_time = currentSystemTime() + inc_time; - int cnt = 100; - while (cnt--) { - (st_time - currentSystemTime()).sleep(); - { - msleep(49); - cout << "tick " << cnt << endl; - } - st_time += inc_time; - } - cout << tm_.elapsed_s() - 0.049 << endl;*/ - - /*PISystemTime t0, inc_time; - PITimer tm_; - tm_.reset(); - inc_time = PISystemTime::fromMilliseconds(50); - inc_time.sleep(); - int cnt = 100; - while (cnt--) { - t0 = currentSystemTime(); - { - msleep(49); - cout << "tick " << cnt << endl; - } - (inc_time - (currentSystemTime() - t0)).sleep(); - } - cout << tm_.elapsed_s() - 0.049 << endl;*/ - - //return 0; - - /*InpuData data; + +int main(int argc, char ** argv) { + InpuData data; PIEthernet eth(PIEthernet::UDP); - data.first_number = 0; - data.packet_number = 0; - data.packet_last = 0; data.antenna_number = data.frequency_number = data.data_type = 0; - PIBitArray ba_; - for (int i = 0; i < 97; ++i) { - for (int b = 0; b < 10; ++b) - ba_.push_back(((i >> b) & 1) == 1); + float t = 0.f; + int pc = 20, cnt = 0; + for (int p = 0; p < pc; ++p) { + data.packet_number = p; + data.packet_last = (p == pc - 1 ? 1 : 0); + data.first_number = p * 97; + PIBitArray ba_; + int ci = 0; + for (int i = 0; i < 97; ++i) { + t += M_PI/4; + ci = sin(t) * 511 + 511; + if (cnt % 500 > 80) ci = 512; + cnt++; + for (int b = 0; b < 10; ++b) + ba_.push_back(((ci >> b) & 1) == 1); + } + //cout << ba_.byteSize() << ", " << ba_.bitSize() << endl; + memcpy(data.data, ba_.data(), 122); + eth.send("127.0.0.1:5000", &data, sizeof(data)); } - //cout << ba_.byteSize() << ", " << ba_.bitSize() << endl; - memcpy(data.data, ba_.data(), 122); - cout << ba_ << endl; + /*cout << ba_ << endl; for (int i = 0; i < 122; ++i) cout << int(data.data[i]) << ", "; - cout << endl; - eth.send("127.0.0.1:5000", &data, sizeof(data)); + cout << endl;*/ + return 0; + + /*PIKbdListener kbd; + kbd.enableExitCapture(); + PIEthernet * _eth; + PIByteArray ba_(16); + if (PIString(argv[argc - 1]) == "s") { + _eth = new PIEthernet(PIEthernet::TCP_Server); + piCout << "listen" << _eth->listen("127.0.0.1:1111"); + int cc = 0; + while (!PIKbdListener::exiting) { + if (cc != _eth->clientsCount()) { + piCout << "new client"; + _eth->clients().back()->startThreadedRead(); + cc++; + } + msleep(1); + } + } else { + _eth = new PIEthernet(PIEthernet::TCP_Client); + piCout << "connection" << _eth->connect("127.0.0.1:1111"); + _eth->send(PIString("0123456789101112").data(), 16); + while (!PIKbdListener::exiting) { + msleep(1); + } + } + delete _eth; + return 0; + + msg2105base msg; + msg.header.size = sizeof(msg); + msg.header.msg_id = 2105; + msg.msgTime = 1; + //PIKbdListener kbd; + //kbd.enableExitCapture(); + RC rc_; + PIEthernet eth; + CONNECT2(void, ullong, int, ð, threadedWriteEvent, &rc_, re); + eth.setParameter(PIEthernet::Broadcast); + eth.open("127.0.0.1:10211"); + eth.setSendAddress("234.0.2.1:10211"); + eth.joinMulticastGroup("234.0.2.1"); + eth.startThreadedWrite(); + for (int i = 0; i < 100000; ++i) { + PISystemTime tm = currentSystemTime(); + msg.type1kod = (i + 1) % 34; + msg.id = piRoundd(double(i) / 5. + 50); + if (i % 15 >= 10) msg.id += 10000; + msg.time_ns = tm.seconds; + msg.time_s = tm.nanoseconds; + msg.azimut = sin(float(i) / 20.) * 90; + msg.geo_width_PEC = sin(float(i) / 50.) * 90; + msg.geo_length_PEC = cos(float(i) / 50.) * 90; + piCout << "push to queue with id =" << eth.writeThreaded(&msg, sizeof(msg)); + piMSleep(50); + if (PIKbdListener::exiting) break; + } return 0;*/ - /*QApplication app(argc, argv); - PIFFT fft; - PIVector in; - in.resize(50*1000); - for (int i=400; i<404; i++) in[i] = complexd(1,0); - PITimer timer_; - fft.prepareFFT(in.size()); - timer_.reset(); - PIVector * out = fft.calcFFT(in); - cout << timer_.elapsed_m() << endl; - Graphic * g = new Graphic(); - QVector res; - fft.getAmplitude(); - for (int i=0; isize(); i++) res.append(QPointF(i,abs(out->at(i)))); - g->setGraphicData(res); - g->addGraphic("arg", Qt::darkBlue); - res.clear(); - for (int i=0; i< out->size(); i++) res.append(QPointF(i,arg(out->at(i)))); - g->setGraphicData(res, 1); - g->show(); - - return app.exec();*/ - + PISignals::setSlot(signalFunc); + //PISignals::grabSignals(PISignals::Interrupt); bool r_string = true, r_thread = true, r_mutex = true, r_timer = true, r_file = true, r_eval = true, r_event = true; bool succ = true; cout << "== PIP test program ==" << endl; diff --git a/pibitarray.h b/pibitarray.h index 807c237a..6fbe159a 100644 --- a/pibitarray.h +++ b/pibitarray.h @@ -22,7 +22,7 @@ #include "picontainers.h" -class PIBitArray { +class PIP_EXPORT PIBitArray { public: PIBitArray(const int & size = 0) {resize(size);} PIBitArray(uchar val) {resize(sizeof(val) * 8); data_[0] = val;} @@ -99,5 +99,6 @@ private: }; inline std::ostream & operator <<(std::ostream & s, const PIBitArray & ba) {for (uint i = 0; i < ba.bitSize(); ++i) {s << ba[i]; if (i % 8 == 7) s << ' ';} return s;} +inline PICout operator <<(PICout s, const PIBitArray & ba) {s.space(); s.setControl(0, true); for (uint i = 0; i < ba.bitSize(); ++i) {s << ba[i]; if (i % 8 == 7) s << ' ';} s.restoreControl(); return s;} #endif // PIBITARRAY_H diff --git a/pibytearray.h b/pibytearray.h index c6342006..05c4b6c3 100644 --- a/pibytearray.h +++ b/pibytearray.h @@ -90,12 +90,24 @@ private: PIVector nodes; }; -class PIByteArray: public PIVector { +class PIP_EXPORT PIByteArray: public PIVector { public: PIByteArray() {;} PIByteArray(const uint size) {resize(size);} PIByteArray(const void * data, const uint size) {for (uint i = 0; i < size; ++i) push_back(((uchar * )data)[i]);} + struct RawData { + friend PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v); + friend PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v); + public: + RawData(void * data, int size) {d = data; s = size;} + RawData(const void * data, const int size) {d = const_cast(data); s = size;} + RawData & operator =(const RawData & o) {d = o.d; s = o.s; return *this;} + private: + void * d; + int s; + }; + PIByteArray resized(int new_size) {PIByteArray tv(*this); tv.resize(new_size); return tv;} PIByteArray & convertToBase64(); @@ -146,42 +158,56 @@ private: }; -inline std::ostream & operator <<(std::ostream & s, const PIByteArray & ba) {for (uint i = 0; i < ba.size(); ++i) s << ba[i]; return s;} +inline std::ostream & operator <<(std::ostream & s, const PIByteArray & ba) {s << "{"; for (uint i = 0; i < ba.size(); ++i) {s << ba[i]; if (i < ba.size() - 1) s << ", ";} s << "}"; return s;} +inline PICout operator <<(PICout s, const PIByteArray & ba) {s.space(); s.setControl(0, true); s << "{"; for (uint i = 0; i < ba.size(); ++i) {s << ba[i]; if (i < ba.size() - 1) s << ", ";} s << "}"; s.restoreControl(); return s;} + +#define PBA_OPERATOR_TO int os = s.size_s(); s.enlarge(sizeof(v)); memcpy(s.data(os), &v, sizeof(v)); inline PIByteArray & operator <<(PIByteArray & s, uchar v) {s.push_back(v); return s;} -inline PIByteArray & operator <<(PIByteArray & s, const short & v) {for (uint i = 0; i < sizeof(v); ++i) s.push_back(((uchar * )&v)[i]); return s;} -inline PIByteArray & operator <<(PIByteArray & s, const int & v) {for (uint i = 0; i < sizeof(v); ++i) s.push_back(((uchar * )&v)[i]); return s;} -inline PIByteArray & operator <<(PIByteArray & s, const long & v) {for (uint i = 0; i < sizeof(v); ++i) s.push_back(((uchar * )&v)[i]); return s;} -inline PIByteArray & operator <<(PIByteArray & s, const llong & v) {for (uint i = 0; i < sizeof(v); ++i) s.push_back(((uchar * )&v)[i]); return s;} -inline PIByteArray & operator <<(PIByteArray & s, const ushort & v) {for (uint i = 0; i < sizeof(v); ++i) s.push_back(((uchar * )&v)[i]); return s;} -inline PIByteArray & operator <<(PIByteArray & s, const uint & v) {for (uint i = 0; i < sizeof(v); ++i) s.push_back(((uchar * )&v)[i]); return s;} -inline PIByteArray & operator <<(PIByteArray & s, const ulong & v) {for (uint i = 0; i < sizeof(v); ++i) s.push_back(((uchar * )&v)[i]); return s;} -inline PIByteArray & operator <<(PIByteArray & s, const ullong & v) {for (uint i = 0; i < sizeof(v); ++i) s.push_back(((uchar * )&v)[i]); return s;} -inline PIByteArray & operator <<(PIByteArray & s, const float & v) {for (uint i = 0; i < sizeof(v); ++i) s.push_back(((uchar * )&v)[i]); return s;} -inline PIByteArray & operator <<(PIByteArray & s, const double & v) {for (uint i = 0; i < sizeof(v); ++i) s.push_back(((uchar * )&v)[i]); return s;} +inline PIByteArray & operator <<(PIByteArray & s, const short v) {PBA_OPERATOR_TO return s;} +inline PIByteArray & operator <<(PIByteArray & s, const int v) {PBA_OPERATOR_TO return s;} +inline PIByteArray & operator <<(PIByteArray & s, const long & v) {PBA_OPERATOR_TO return s;} +inline PIByteArray & operator <<(PIByteArray & s, const llong & v) {PBA_OPERATOR_TO return s;} +inline PIByteArray & operator <<(PIByteArray & s, const ushort v) {PBA_OPERATOR_TO return s;} +inline PIByteArray & operator <<(PIByteArray & s, const uint v) {PBA_OPERATOR_TO return s;} +inline PIByteArray & operator <<(PIByteArray & s, const ulong & v) {PBA_OPERATOR_TO return s;} +inline PIByteArray & operator <<(PIByteArray & s, const ullong & v) {PBA_OPERATOR_TO return s;} +inline PIByteArray & operator <<(PIByteArray & s, const float v) {PBA_OPERATOR_TO return s;} +inline PIByteArray & operator <<(PIByteArray & s, const double & v) {PBA_OPERATOR_TO return s;} +inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) {int os = s.size_s(); s.enlarge(v.s); memcpy(s.data(os), v.d, v.s); return s;} template inline PIByteArray & operator <<(PIByteArray & s, const PIVector & v) {s << v.size_s(); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;} template inline PIByteArray & operator <<(PIByteArray & s, const PIList & v) {s << v.size_s(); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;} template inline PIByteArray & operator <<(PIByteArray & s, const PIDeque & v) {s << v.size_s(); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;} +template +inline PIByteArray & operator <<(PIByteArray & s, const T & v) {PBA_OPERATOR_TO return s;} -inline PIByteArray & operator >>(PIByteArray & s, uchar & v) {v = s.take_front(); return s;} -inline PIByteArray & operator >>(PIByteArray & s, short & v) {for (uint i = 0; i < sizeof(v); ++i) ((uchar * )&v)[i] = s.take_front(); return s;} -inline PIByteArray & operator >>(PIByteArray & s, int & v) {for (uint i = 0; i < sizeof(v); ++i) ((uchar * )&v)[i] = s.take_front(); return s;} -inline PIByteArray & operator >>(PIByteArray & s, long & v) {for (uint i = 0; i < sizeof(v); ++i) ((uchar * )&v)[i] = s.take_front(); return s;} -inline PIByteArray & operator >>(PIByteArray & s, llong & v) {for (uint i = 0; i < sizeof(v); ++i) ((uchar * )&v)[i] = s.take_front(); return s;} -inline PIByteArray & operator >>(PIByteArray & s, ushort & v) {for (uint i = 0; i < sizeof(v); ++i) ((uchar * )&v)[i] = s.take_front(); return s;} -inline PIByteArray & operator >>(PIByteArray & s, uint & v) {for (uint i = 0; i < sizeof(v); ++i) ((uchar * )&v)[i] = s.take_front(); return s;} -inline PIByteArray & operator >>(PIByteArray & s, ulong & v) {for (uint i = 0; i < sizeof(v); ++i) ((uchar * )&v)[i] = s.take_front(); return s;} -inline PIByteArray & operator >>(PIByteArray & s, ullong & v) {for (uint i = 0; i < sizeof(v); ++i) ((uchar * )&v)[i] = s.take_front(); return s;} -inline PIByteArray & operator >>(PIByteArray & s, float & v) {for (uint i = 0; i < sizeof(v); ++i) ((uchar * )&v)[i] = s.take_front(); return s;} -inline PIByteArray & operator >>(PIByteArray & s, double & v) {for (uint i = 0; i < sizeof(v); ++i) ((uchar * )&v)[i] = s.take_front(); return s;} +#undef PBA_OPERATOR_TO +#define PBA_OPERATOR_FROM memcpy(&v, s.data(), sizeof(v)); s.remove(0, sizeof(v)); + +inline PIByteArray & operator >>(PIByteArray & s, uchar & v) {assert(s.size() >= 1u); v = s.take_front(); return s;} +inline PIByteArray & operator >>(PIByteArray & s, short & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +inline PIByteArray & operator >>(PIByteArray & s, int & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +inline PIByteArray & operator >>(PIByteArray & s, long & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +inline PIByteArray & operator >>(PIByteArray & s, llong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +inline PIByteArray & operator >>(PIByteArray & s, ushort & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +inline PIByteArray & operator >>(PIByteArray & s, uint & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +inline PIByteArray & operator >>(PIByteArray & s, ulong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +inline PIByteArray & operator >>(PIByteArray & s, ullong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +inline PIByteArray & operator >>(PIByteArray & s, float & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +inline PIByteArray & operator >>(PIByteArray & s, double & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} +inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) {assert(s.size_s() >= v.s); memcpy(v.d, s.data(), v.s); s.remove(0, v.s); return s;} template inline PIByteArray & operator >>(PIByteArray & s, PIVector & v) {int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;} template inline PIByteArray & operator >>(PIByteArray & s, PIList & v) {int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;} template inline PIByteArray & operator >>(PIByteArray & s, PIDeque & v) {int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;} +template +inline PIByteArray & operator >>(PIByteArray & s, T & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;} + +#undef PBA_OPERATOR_FROM #endif // PIBYTEARRAY_H diff --git a/pichar.h b/pichar.h index 552acc51..ac5ba124 100644 --- a/pichar.h +++ b/pichar.h @@ -1,3 +1,6 @@ +/*! \file pichar.h + * \brief Unicode char +*/ /* PIP - Platform Independent Primitives Unicode char @@ -21,24 +24,41 @@ #define PICHAR_H #include "pibytearray.h" - -class PIChar +/*! \brief Unicode char + * \details This class is wrapper around \c "uint". + * There are many contructors and information functions; + */ +class PIP_EXPORT PIChar { friend class PIString; friend PIByteArray & operator <<(PIByteArray & s, const PIChar & v); friend PIByteArray & operator >>(PIByteArray & s, PIChar & v); public: + //! Contructs ascii symbol PIChar(const char c) {ch = c; ch &= 0xFF;} + + //! Contructs 2-bytes symbol PIChar(const short c) {ch = c; ch &= 0xFFFF;} - PIChar(const int c = 0) {ch = c;} + + //! Contructs 4-bytes symbol + PIChar(const int c) {ch = c;} + + //! Contructs ascii symbol PIChar(const uchar c) {ch = c; ch &= 0xFF;} + + //! Contructs 2-bytes symbol PIChar(const ushort c) {ch = c; ch &= 0xFFFF;} - PIChar(const uint c) {ch = c;} + + //! Default constructor. Contructs 4-bytes symbol + PIChar(const uint c = 0) {ch = c;} + + //! Contructs symbol from no more than 4 bytes of string PIChar(const char * c) {ch = *reinterpret_cast(c);} //inline operator const int() {return static_cast(ch);} //inline operator const char() {return toAscii();} + //! Copy operator PIChar & operator =(const char v) {ch = v; return *this;} /*inline PIChar & operator =(const short v) {ch = v; return *this;} inline PIChar & operator =(const int v) {ch = v; return *this;} @@ -46,6 +66,7 @@ public: inline PIChar & operator =(const ushort v) {ch = v; return *this;} inline PIChar & operator =(const uint v) {ch = v; return *this;}*/ + //! Compare operator bool operator ==(const PIChar & o) const {return strcmp(o.toCharPtr(), toCharPtr()) == 0;} /*inline bool operator ==(const PIChar & o) const {if (o.isAscii() ^ isAscii()) return false; if (isAscii()) return (o.toAscii() == toAscii()); @@ -57,6 +78,7 @@ public: inline bool operator ==(const ushort o) const {return (PIChar(o) == *this);} inline bool operator ==(const uint o) const {return (PIChar(o) == *this);}*/ + //! Compare operator bool operator !=(const PIChar & o) const {return !(o == *this);} /*inline bool operator !=(const char o) const {return (PIChar(o) != *this);} inline bool operator !=(const short o) const {return (PIChar(o) != *this);} @@ -65,62 +87,134 @@ public: inline bool operator !=(const ushort o) const {return (PIChar(o) != *this);} inline bool operator !=(const uint o) const {return (PIChar(o) != *this);}*/ + //! Compare operator bool operator >(const PIChar & o) const {return strcmp(o.toCharPtr(), toCharPtr()) < 0;} + + //! Compare operator bool operator <(const PIChar & o) const {return strcmp(o.toCharPtr(), toCharPtr()) > 0;} + + //! Compare operator bool operator >=(const PIChar & o) const {return strcmp(o.toCharPtr(), toCharPtr()) <= 0;} + + //! Compare operator bool operator <=(const PIChar & o) const {return strcmp(o.toCharPtr(), toCharPtr()) >= 0;} + //! Return \b true if symbol is digit ('0' to '9') bool isDigit() const {return isdigit(ch) != 0;} + + //! Return \b true if symbol is HEX digit ('0' to '9', 'a' to 'f', 'A' to 'F') bool isHex() const {return isxdigit(ch) != 0;} + + //! Return \b true if symbol is drawable (without space) bool isGraphical() const {return isgraph(ch) != 0;} + + //! Return \b true if symbol is control byte (< 32 or 127) bool isControl() const {return iscntrl(ch) != 0;} + + //! Return \b true if symbol is in lower case bool isLower() const {return islower(ch) != 0;} + + //! Return \b true if symbol is in upper case bool isUpper() const {return isupper(ch) != 0;} + + //! Return \b true if symbol is printable (with space) bool isPrint() const {return isprint(ch) != 0;} + + //! Return \b true if symbol is space or tab bool isSpace() const {return isspace(ch) != 0;} + + //! Return \b true if symbol is alphabetical letter bool isAlpha() const {return isalpha(ch) != 0;} + + //! Return \b true if symbol is ascii (< 128) bool isAscii() const {return isascii(ch) != 0;} - int toInt() const {return static_cast(ch);} - const wchar_t * toWCharPtr() const {return &ch;} + int toInt() const {return int(ch);} + const wchar_t * toWCharPtr() const {return reinterpret_cast(&ch);} + + //! Return as "char * " string const char * toCharPtr() const {return reinterpret_cast(&ch);} - wchar_t toWChar() const {return ch;} + + wchar_t toWChar() const {return wchar_t(ch);} char toAscii() const {return ch % 256;} int unicode16Code() const {wchar_t wc; if (mbtowc(&wc, toCharPtr(), 4) > 0) return wc; return 0;} //#ifdef WINDOWS // inline PIChar toUpper() const __attribute__ ((optimize(0))) {return PIChar(toupper(ch));} // inline PIChar toLower() const __attribute__ ((optimize(0))) {return PIChar(tolower(ch));} //#else + + //! Return symbol in upper case PIChar toUpper() const {return PIChar(toupper(ch));} + + //! Return symbol in lower case PIChar toLower() const {return PIChar(tolower(ch));} //#endif private: - wchar_t ch; + uint ch; }; + +//! Output operator to \c std::ostream inline std::ostream & operator <<(std::ostream & s, const PIChar & v) {s << v.toCharPtr(); return s;} +//! Output operator to \a PICout +inline PICout operator <<(PICout s, const PIChar & v) {s.space(); s.setControl(0, true); s << v.toCharPtr(); s.restoreControl(); return s;} + + +//! Write operator to \c PIByteArray inline PIByteArray & operator <<(PIByteArray & s, const PIChar & v) {s << uint(v.ch); return s;} + +//! Read operator from \c PIByteArray inline PIByteArray & operator >>(PIByteArray & s, PIChar & v) {uint i; s >> i; v.ch = wchar_t(i); return s;} + +//! Compare operator inline bool operator ==(const char v, const PIChar & c) {return (PIChar(v) == c);} + +//! Compare operator inline bool operator >(const char v, const PIChar & c) {return (PIChar(v) > c);} + +//! Compare operator inline bool operator <(const char v, const PIChar & c) {return (PIChar(v) < c);} + +//! Compare operator inline bool operator >=(const char v, const PIChar & c) {return (PIChar(v) >= c);} + +//! Compare operator inline bool operator <=(const char v, const PIChar & c) {return (PIChar(v) <= c);} + +//! Compare operator inline bool operator ==(const char * v, const PIChar & c) {return (PIChar(v) == c);} + +//! Compare operator inline bool operator >(const char * v, const PIChar & c) {return (PIChar(v) > c);} + +//! Compare operator inline bool operator <(const char * v, const PIChar & c) {return (PIChar(v) < c);} + +//! Compare operator inline bool operator >=(const char * v, const PIChar & c) {return (PIChar(v) >= c);} + +//! Compare operator inline bool operator <=(const char * v, const PIChar & c) {return (PIChar(v) <= c);} + +//! Compare operator inline bool operator ==(const int v, const PIChar & c) {return (PIChar(v) == c);} + +//! Compare operator inline bool operator >(const int v, const PIChar & c) {return (PIChar(v) > c);} + +//! Compare operator inline bool operator <(const int v, const PIChar & c) {return (PIChar(v) < c);} + +//! Compare operator inline bool operator >=(const int v, const PIChar & c) {return (PIChar(v) >= c);} + +//! Compare operator inline bool operator <=(const int v, const PIChar & c) {return (PIChar(v) <= c);} #endif // PICHAR_H diff --git a/picli.cpp b/picli.cpp index 81ccae40..07e766ba 100644 --- a/picli.cpp +++ b/picli.cpp @@ -69,7 +69,7 @@ void PICLI::parse() { _args_opt << cra; continue; } - piCout << "[PICli] Arguments overflow, \"" << cra << "\" ignored" << endl; + piCout << "[PICli] Arguments overflow, \"" << cra << "\" ignored"; } if (last == 0 ? false : last->has_value) { last->value = cra; diff --git a/picli.h b/picli.h index 8a9051e8..435a3310 100644 --- a/picli.h +++ b/picli.h @@ -22,7 +22,7 @@ #include "pistring.h" -class PICLI +class PIP_EXPORT PICLI { public: PICLI(int argc, char * argv[]); diff --git a/picodec.h b/picodec.h index 21ee8fa6..25baefdf 100644 --- a/picodec.h +++ b/picodec.h @@ -22,7 +22,7 @@ #include "piprocess.h" -class PICodec: private PIProcess +class PIP_EXPORT PICodec: private PIProcess { public: PICodec(): PIProcess() {setGrabOutput(true); tf = PIFile::openTemporary(PIIODevice::ReadWrite); tf.open();} diff --git a/piconfig.cpp b/piconfig.cpp index 48554566..2bcdc4f2 100644 --- a/piconfig.cpp +++ b/piconfig.cpp @@ -277,7 +277,7 @@ void PIConfig::addEntry(const PIString & name, const PIString & value, const PIS void PIConfig::setValue(const PIString & name, const PIString & value, const PIString & type, bool write) { Entry & e(getValue(name)); if (&e == &empty) { - addEntry(name, value, type); + addEntry(name, value, type, write); return; } e._value = value; @@ -376,10 +376,14 @@ void PIConfig::removeEntry(Branch & b, PIConfig::Entry * e) { void PIConfig::writeAll() { + //cout << this << " write < " << size() << endl; clear(); + //*this << "1234567894132456798\n"; return; //writeEntry(&root); buildFullNames(&root); Branch b = allLeaves(); + //for (int i = 0; i < b.size_s(); ++i) + // cout << b[i]->_name << " = " << b[i]->_value << endl; int j = 0; for (int i = 0; i < other.size_s(); ++i) { //cout << j << endl; @@ -387,25 +391,27 @@ void PIConfig::writeAll() { if (b[j]->_line == i) { b[j]->buildLine(); *this << b[j]->_all << '\n'; + //cout << this << " " << b[j]->_all << endl; ++j; } else { *this << other[i]; if (i < other.size_s() - 1) *this << '\n'; + //cout << this << " " << other[i] << endl; } } else { *this << other[i]; if (i < other.size_s() - 1) *this << '\n'; + //cout << this << " " << other[i] << endl; } - //cout << other[i] << endl; } flush(); readAll(); + //cout << this << " write > " << size() << endl; } void PIConfig::readAll() { root.clear(); - flush(); parse(); } diff --git a/piconfig.h b/piconfig.h index e0bf7abd..d80ea41f 100644 --- a/piconfig.h +++ b/piconfig.h @@ -49,17 +49,17 @@ Entry & getValue(const PIString & vname, const float def, bool * exist = 0) const {return getValue(vname, ftos(def), exist);} \ Entry & getValue(const PIString & vname, const double def, bool * exist = 0) const {return getValue(vname, dtos(def), exist);} -class PIConfig: public PIFile +class PIP_EXPORT PIConfig: public PIFile { friend class Entry; friend class Branch; public: PIConfig(const PIString & path, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite); - ~PIConfig() {piForeach (Entry * i, root._children) deleteEntry(i); close();} + ~PIConfig() {/*piForeach (Entry * i, root._children) deleteEntry(i); close();*/} class Entry; - class Branch: public PIVector { + class PIP_EXPORT Branch: public PIVector { friend class PIConfig; friend class Entry; friend std::ostream & operator <<(std::ostream & s, const Branch & v); @@ -90,7 +90,7 @@ public: }; - class Entry { + class PIP_EXPORT Entry { friend class PIConfig; friend class Branch; public: diff --git a/piconsole.cpp b/piconsole.cpp index 70d70414..509782fe 100644 --- a/piconsole.cpp +++ b/piconsole.cpp @@ -20,12 +20,15 @@ #include "piconsole.h" +extern PIMutex __PICout_mutex__; + + PIConsole::PIConsole(bool startNow, KBFunc slot): PIThread() { setPriority(piLow); needLockRun(true); ret_func = slot; num_format = 0; - cur_tab = width = height = pwidth = pheight = my = 0; + cur_tab = width = height = pwidth = pheight = max_y = 0; def_align = Nothing; #ifdef WINDOWS ulcoord.X = ulcoord.Y = 0; @@ -93,9 +96,11 @@ bool PIConsole::setTab(uint index) { return true; } lock(); + __PICout_mutex__.lock(); cur_tab = index; clearScreen(); fillLabels(); + __PICout_mutex__.unlock(); unlock(); return true; } @@ -135,6 +140,23 @@ bool PIConsole::setTabBindKey(const PIString & name, char bind_key) { void PIConsole::key_event(char key, void * t) { PIConsole * p = (PIConsole * )t; + int ct = p->cur_tab; + if (key == char(PIKbdListener::LeftArrow)) { + do { + ct--; + if (ct < 0) return; + } while (p->tabs[ct].key == 0); + p->setTab(ct); + return; + } + if (key == char(PIKbdListener::RightArrow)) { + do { + ct++; + if (ct >= p->tabs.size_s()) return; + } while (p->tabs[ct].key == 0); + p->setTab(ct); + return; + } for (uint i = 0; i < p->tabsCount(); ++i) { if (p->tabs[i].key == key) { p->setTab(i); @@ -148,7 +170,7 @@ void PIConsole::key_event(char key, void * t) { void PIConsole::stop(bool clear) { PIThread::stop(true); if (clear) clearScreen(); - moveTo(0, my + 4); + moveTo(0, max_y + 4); showCursor(); couts(fstr(Normal)); #ifdef WINDOWS @@ -273,9 +295,12 @@ void PIConsole::begin() { #ifdef WINDOWS SetConsoleMode(hOut, ENABLE_WRAP_AT_EOL_OUTPUT); #endif + max_y = 0; + __PICout_mutex__.lock(); clearScreen(); hideCursor(); fillLabels(); + __PICout_mutex__.unlock(); } @@ -292,6 +317,7 @@ void PIConsole::run() { width = ws.ws_col; height = ws.ws_row; #endif + __PICout_mutex__.lock(); if (pwidth != width || pheight != height) { clearScreen(); fillLabels(); @@ -304,7 +330,7 @@ void PIConsole::run() { PIVector & cvars(tabs[cur_tab].columns[i].variables); cx = col_wid * i; toUpperLeft(); - if (my < cvars.size()) my = cvars.size(); + if (max_y < cvars.size()) max_y = cvars.size(); j = 0; piForeachC (Variable & tv, cvars) { if (j > height - 3) continue; @@ -343,13 +369,19 @@ void PIConsole::run() { newLine(); } } +#ifdef WINDOWS + moveTo(0, max_y + 1); +#else + moveTo(0, max_y + 2); +#endif fflush(0); + __PICout_mutex__.unlock(); } void PIConsole::fillLabels() { if (!isRunning()) return; - uint cx, cy, my = 0, mx = 0, dx; + uint cx, cy, mx = 0, dx; #ifdef WINDOWS GetConsoleScreenBufferInfo(hOut, &sbi); width = sbi.srWindow.Right - sbi.srWindow.Left; @@ -360,6 +392,7 @@ void PIConsole::fillLabels() { width = ws.ws_col; height = ws.ws_row; #endif + max_y = 0; col_cnt = columns().size(); col_wid = (col_cnt > 0) ? width / col_cnt : width; for (uint i = 0; i < col_cnt; ++i) { @@ -378,7 +411,7 @@ void PIConsole::fillLabels() { toUpperLeft(); for (uint j = 0; j < cvars.size(); ++j) { if (int(j) > height - 3) continue; - if (my < j) my = j; + if (max_y < j) max_y = j; moveRight(cx); Variable & tv(cvars[j]); cvars[j].nx = cx; @@ -426,9 +459,9 @@ void PIConsole::fillLabels() { } } #ifdef WINDOWS - moveTo(0, my + 1); + moveTo(0, max_y + 1); #else - moveTo(0, my + 2); + moveTo(0, max_y + 2); #endif if (!tabs[cur_tab].status.isEmpty()) { printValue(tabs[cur_tab].status); @@ -446,7 +479,10 @@ void PIConsole::status() { ctab = &tabs[i]; if (ctab->key == 0) continue; printValue(ctab->key, PIConsole::White | PIConsole::Bold); - printValue(ctab->name + " ", PIConsole::Cyan | PIConsole::Inverse); + if (i == cur_tab) + printValue(ctab->name + " ", PIConsole::BackYellow | PIConsole::Black); + else + printValue(ctab->name + " ", PIConsole::Cyan | PIConsole::Inverse); printValue(" "); } newLine(); @@ -522,10 +558,10 @@ void PIConsole::addVariable(const PIString & name, const PIProtocol * ptr, int c addString("protocol " + name, col, format | PIConsole::Bold); addVariable("Rec - " + ptr->receiverDeviceName(), ptr->receiverDeviceState_ptr(), col, format); addVariable("Send - " + ptr->senderDeviceName(), ptr->senderDeviceState_ptr(), col, format); - addVariable("Sended count", ptr->sendCount_ptr(), col, format); addVariable("Received count", ptr->receiveCount_ptr(), col, format); addVariable("Invalid count", ptr->wrongCount_ptr(), col, format); addVariable("Missed count", ptr->missedCount_ptr(), col, format); + addVariable("Sended count", ptr->sendCount_ptr(), col, format); addVariable("Immediate Frequency, Hz", ptr->immediateFrequency_ptr(), col, format); addVariable("Integral Frequency, Hz", ptr->integralFrequency_ptr(), col, format); addVariable("Receive speed", ptr->receiveSpeed_ptr(), col, format); @@ -535,6 +571,17 @@ void PIConsole::addVariable(const PIString & name, const PIProtocol * ptr, int c addVariable("Disconnect Timeout, s", ptr->disconnectTimeout_ptr(), col, format); addVariable("Quality", ptr->quality_ptr(), col, format); } +void PIConsole::addVariable(const PIString & name, const PIDiagnostics * ptr, int col, PIFlags format) { + addString(name + " diagnostics", col, format | PIConsole::Bold); + addVariable("Received count", ptr->receiveCount_ptr(), col, format); + addVariable("Invalid count", ptr->wrongCount_ptr(), col, format); + addVariable("Sended count", ptr->sendCount_ptr(), col, format); + addVariable("Immediate Frequency, Hz", ptr->immediateFrequency_ptr(), col, format); + addVariable("Integral Frequency, Hz", ptr->integralFrequency_ptr(), col, format); + addVariable("Receive speed", ptr->receiveSpeed_ptr(), col, format); + addVariable("Send speed", ptr->sendSpeed_ptr(), col, format); + addVariable("Quality", ptr->quality_ptr(), col, format); +} void PIConsole::addVariable(const PIString & name, const PISystemMonitor * ptr, int col, PIFlags format) { addString("monitor " + name, col, format | PIConsole::Bold); addVariable("state", &(ptr->statistic().state), col, format); diff --git a/piconsole.h b/piconsole.h index 0b76408d..c8975af6 100644 --- a/piconsole.h +++ b/piconsole.h @@ -22,6 +22,7 @@ #include "pikbdlistener.h" #include "piprotocol.h" +#include "pidiagnostics.h" #include "pisystemmonitor.h" #ifndef WINDOWS # include @@ -32,8 +33,9 @@ /// void clearVariables(bool clearScreen = true) /// void start(bool wait = false) /// void stop(bool clear = false) -class PIConsole: public PIThread +class PIP_EXPORT PIConsole: public PIThread { + PIOBJECT(PIConsole) public: PIConsole(bool startNow = true, KBFunc slot = 0); ~PIConsole(); @@ -84,6 +86,7 @@ public: void addVariable(const PIString & name, const float * ptr, int column = 1, PIFlags format = PIConsole::Normal); void addVariable(const PIString & name, const double * ptr, int column = 1, PIFlags format = PIConsole::Normal); void addVariable(const PIString & name, const PIProtocol * ptr, int column = 1, PIFlags format = PIConsole::Normal); + void addVariable(const PIString & name, const PIDiagnostics * ptr, int column = 1, PIFlags format = PIConsole::Normal); void addVariable(const PIString & name, const PISystemMonitor * ptr, int column = 1, PIFlags format = PIConsole::Normal); void addBitVariable(const PIString & name, const void * ptr, int fromBit, int bitCount, int column = 1, PIFlags format = PIConsole::Normal); void addEmptyLine(int column = 1, uint count = 1); @@ -117,14 +120,14 @@ public: void setColumnAlignment(int col, Alignment align) {if (col < 0 || col >= columns().size_s()) return; column(col).alignment = align;} void setColumnAlignmentToAll(Alignment align) {piForeach (Tab & i, tabs) piForeach (Column & j, i.columns) j.alignment = align; fillLabels();} - EVENT_HANDLER0(PIConsole, void, clearVariables) {clearVariables(true);} - EVENT_HANDLER1(PIConsole, void, clearVariables, bool, clearScreen) {if (clearScreen && isRunning()) {toUpperLeft(); clearScreenLower();} columns().clear();} + EVENT_HANDLER0(void, clearVariables) {clearVariables(true);} + EVENT_HANDLER1(void, clearVariables, bool, clearScreen) {if (clearScreen && isRunning()) {toUpperLeft(); clearScreenLower();} columns().clear();} - EVENT_HANDLER0(PIConsole, void, waitForFinish) {WAIT_FOR_EXIT} - EVENT_HANDLER0(PIConsole, void, start) {start(false);} - EVENT_HANDLER1(PIConsole, void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();} - EVENT_HANDLER0(PIConsole, void, stop) {stop(false);} - EVENT_HANDLER1(PIConsole, void, stop, bool, clear); + EVENT_HANDLER0(void, waitForFinish) {WAIT_FOR_EXIT} + EVENT_HANDLER0(void, start) {start(false);} + EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();} + EVENT_HANDLER0(void, stop) {stop(false);} + EVENT_HANDLER1(void, stop, bool, clear); PIString fstr(PIFlags f); void enableExitCapture(char key = 'Q') {listener->enableExitCapture(key);} @@ -273,7 +276,7 @@ private: Alignment def_align; KBFunc ret_func; int width, height, pwidth, pheight, ret, col_wid, num_format; - uint my; + uint max_y; uint cur_tab, col_cnt; }; diff --git a/picontainers.h b/picontainers.h index 46a0957f..810533f8 100644 --- a/picontainers.h +++ b/picontainers.h @@ -1,6 +1,12 @@ +/*! \file picontainers.h + * \brief Generic containers based on STL + * + * This file declare all containers and useful macroses + * to use them +*/ /* PIP - Platform Independent Primitives - Generic containers, based on STL + Generic containers based on STL Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com This program is free software: you can redistribute it and/or modify @@ -22,6 +28,37 @@ #include "piincludes.h" +#ifdef DOXYGEN +/*! \def piForeach(i,c) + * \brief Macro for iterate any container + * \details Use this macros instead of standard "for" + * to get read/write access to each element of container. + * Pass direction is direct \n + * Example: \snippet picontainers.cpp foreach + */ +/*! \def piForeachC(i,c) + * \brief Macro for iterate any container only for read + * \details Use this macros instead of standard "for" + * to get read access to each element of container. + * Pass direction is direct \n + * Example: \snippet picontainers.cpp foreachC + */ +/*! \def piForeachR(i,c) + * \brief Macro for iterate any container with reverse direction + * \details Use this macros instead of standard "for" + * to get read/write access to each element of container. + * Pass direction is reverse \n + * Example: \snippet picontainers.cpp foreachR + */ +/*! \def piForeachCR(i,c) + * \brief Macro for iterate any container only for read with reverse direction + * \details Use this macros instead of standard "for" + * to get read access to each element of container. + * Pass direction is reverse \n + * Example: \snippet picontainers.cpp foreachCR + */ +#endif + #ifdef CC_GCC template @@ -126,42 +163,6 @@ template inline _PIForeachC * _PIForeachCastC(_PIForeachBase & c #define piForTimes(c) for(int _i##c = 0; _i##c < c; ++_i##c) -template -class PIFlags { -public: - PIFlags(): flags(0) {;} - PIFlags(Enum e): flags(e) {;} - PIFlags(const PIFlags & f): flags(f.flags) {;} - PIFlags(const int i): flags(i) {;} - PIFlags & setFlag(const PIFlags & f, bool on = true) {if (on) flags |= f.flags; else flags &= ~f.flags; return *this;} - PIFlags & setFlag(const Enum & e, bool on = true) {if (on) flags |= e; else flags &= ~e; return *this;} - PIFlags & setFlag(const int & i, bool on = true) {if (on) flags |= i; else flags &= ~i; return *this;} - void operator =(const PIFlags & f) {flags = f.flags;} - void operator =(const Enum & e) {flags = e;} - void operator =(const int & i) {flags = i;} - void operator |=(const PIFlags & f) {flags |= f.flags;} - void operator |=(const Enum & e) {flags |= e;} - void operator |=(const int i) {flags |= i;} - void operator &=(const PIFlags & f) {flags &= f.flags;} - void operator &=(const Enum & e) {flags &= e;} - void operator &=(const int i) {flags &= i;} - void operator ^=(const PIFlags & f) {flags ^= f.flags;} - void operator ^=(const Enum & e) {flags ^= e;} - void operator ^=(const int i) {flags ^= i;} - PIFlags operator |(PIFlags f) const {PIFlags tf(flags | f.flags); return tf;} - PIFlags operator |(Enum e) const {PIFlags tf(flags | e); return tf;} - PIFlags operator |(int i) const {PIFlags tf(flags | i); return tf;} - PIFlags operator &(PIFlags f) const {PIFlags tf(flags & f.flags); return tf;} - PIFlags operator &(Enum e) const {PIFlags tf(flags & e); return tf;} - PIFlags operator &(int i) const {PIFlags tf(flags & i); return tf;} - PIFlags operator ^(PIFlags f) const {PIFlags tf(flags ^ f.flags); return tf;} - PIFlags operator ^(Enum e) const {PIFlags tf(flags ^ e); return tf;} - PIFlags operator ^(int i) const {PIFlags tf(flags ^ i); return tf;} - bool operator [](Enum e) const {return (flags & e) == e;} - operator int() const {return flags;} -private: - int flags; -}; /* template class PIVector { @@ -269,7 +270,7 @@ public: bool operator ==(const PIVector & t) const {if (size_ != t.size_) return false; for (uint i = 0; i < size_; ++i) if (t[i] != data_[i]) return false; return true;} bool operator !=(const PIVector & t) const {if (size_ != t.size_) return true; for (uint i = 0; i < size_; ++i) if (t[i] != data_[i]) return true; return false;} - bool contain(const T & v) const {for (uint i = 0; i < size_; ++i) if (v == data_[i]) return true; return false;} + bool contains(const T & v) const {for (uint i = 0; i < size_; ++i) if (v == data_[i]) return true; return false;} T * data(int index = 0) {return &(data_[index]);} const T * data(int index = 0) const {return &(data_[index]);} @@ -370,35 +371,193 @@ private: uint size_, rsize_, os; }; */ + +/*! \brief Dynamic array for any type + * \details This class used to store dynamic array of any + * type of data. In memory data stored linear. You can insert + * item in any place of remove some items from any place. + * For quick add elements there is stream operator <<. + * This class based on std::vector, expanding his + * functionality. + */ template > -class PIVector: public vector { +class PIP_EXPORT PIVector: public vector { typedef PIVector _CVector; typedef vector _stlc; public: + //! Contructs an empty vector PIVector() {piMonitor.containers++;} + + //! Contructs vector with single element "value" PIVector(const Type & value) {piMonitor.containers++; _stlc::push_back(value);} + + //! Contructs vector with two elements "v0" and "v1" PIVector(const Type & v0, const Type & v1) {piMonitor.containers++; _stlc::push_back(v0); _stlc::push_back(v1);} + + //! Contructs vector with three elements "v0", "v1" and "v2" PIVector(const Type & v0, const Type & v1, const Type & v2) {piMonitor.containers++; _stlc::push_back(v0); _stlc::push_back(v1); _stlc::push_back(v2);} + + //! Contructs vector with four elements "v0", "v1", "v2" and "v3" PIVector(const Type & v0, const Type & v1, const Type & v2, const Type & v3) {piMonitor.containers++; _stlc::push_back(v0); _stlc::push_back(v1); _stlc::push_back(v2); _stlc::push_back(v3);} + + /*! \brief Contructs vector with size "size" filled elements "value" + * \details Example: \snippet picontainers.cpp PIVector::PIVector */ PIVector(uint size, const Type & value = Type()) {piMonitor.containers++; _stlc::resize(size, value);} ~PIVector() {piMonitor.containers--;} + + /*! \brief Read-only access to element by index "index" + * \details Example: \snippet picontainers.cpp PIVector::at_c + * \sa \a operator[] */ const Type & at(uint index) const {return (*this)[index];} + + /*! \brief Full access to element by index "index" + * \details Example: \snippet picontainers.cpp PIVector::at + * \sa \a operator[] */ Type & at(uint index) {return (*this)[index];} + + /*! \brief Read-only pointer to element by index "index" + * \details Example: \snippet picontainers.cpp PIVector::data_c */ const Type * data(uint index = 0) const {return &(*this)[index];} + + /*! \brief Pointer to element by index "index" + * \details Example: \snippet picontainers.cpp PIVector::data */ Type * data(uint index = 0) {return &(*this)[index];} + +#ifdef DOXYGEN + //! Elements count + uint size() const; +#endif + + //! Elements count int size_s() const {return static_cast(_stlc::size());} + + //! Return \c "true" if vector is empty, i.e. size = 0 bool isEmpty() const {return _stlc::empty();} + + //! Return \c "true" if vector has at least one element equal "t" + bool has(const Type & t) const {for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (t == *i) return true; return false;} + + //! Return how many times element "t" appears in vector + int etries(const Type & t) const {int ec = 0; for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (t == *i) ++ec; return ec;} typedef int (*CompareFunc)(const Type * , const Type * ); + + //! Standard compare function for type "Type". Return 0 if t0 = t1, -1 if t0 < t1 and 1 if t0 > t1. static int compare_func(const Type * t0, const Type * t1) {return (*t0) == (*t1) ? 0 : ((*t0) < (*t1) ? -1 : 1);} +#ifdef DOXYGEN + + /*! \brief Resize vector to size "size" + * \details Elements removed from end of vector if new size < old size, or added new elements = "new_type" if new size > old size.\n + * Example: \snippet picontainers.cpp PIVector::resize + * \sa \a size(), \a clear() */ + void resize(uint size, const Type & new_type = Type()); + + //! Increase vector size with "size" elements + PIVector & enlarge(uint size); + + //! Clear vector. Equivalent to call "resize(0)" + void clear(); + + /*! \brief Sort vector using quick sort algorithm and standard compare function + * \details Example: \snippet picontainers.cpp PIVector::sort_0 + * With custom compare function: \snippet picontainers.cpp PIVector::sort_1 */ + PIVector & sort(CompareFunc compare = compare_func) {qsort(&at(0), _stlc::size(), sizeof(Type), (int(*)(const void * , const void * ))compare); return *this;} + + /*! \brief Fill vector with elements "t" leave size is unchanged and return reference to vector + * \details Example: \snippet picontainers.cpp PIVector::fill */ + PIVector & fill(const Type & t) {_stlc::assign(_stlc::size(), t); return *this;} + + //! Last element of vector + Type & back(); + + //! Last element of vector + const Type & back() const; + + //! First element of vector + Type & front(); + + //! First element of vector + const Type & front() const; + + //! Add new element "t" at the end of vector and return reference to vector + PIVector & push_back(const Type & t); + + //! Add new element "t" at the beginning of vector and return reference to vector + PIVector & push_front(const Type & t) {_stlc::insert(_stlc::begin(), t); return *this;} + + //! Remove one element from the end of vector and return reference to vector + PIVector & pop_back(); + + //! Remove one element from the beginning of vector and return reference to vector + PIVector & pop_front() {_stlc::erase(_stlc::begin()); return *this;} + + //! Remove one element from the end of vector and return it + Type take_back() {Type t(_stlc::back()); _stlc::pop_back(); return t;} + + //! Remove one element from the beginning of vector and return it + Type take_front() {Type t(_stlc::front()); pop_front(); return t;} + + /*! \brief Remove one element by index "index" and return reference to vector + * \details Example: \snippet picontainers.cpp PIVector::remove_0 + * \sa \a removeOne(), \a removeAll() */ + PIVector & remove(uint index) {_stlc::erase(_stlc::begin() + index); return *this;} + + /*! \brief Remove "count" elements by first index "index" and return reference to vector + * \details Example: \snippet picontainers.cpp PIVector::remove_1 + * \sa \a removeOne(), \a removeAll() */ + PIVector & remove(uint index, uint count) {_stlc::erase(_stlc::begin() + index, _stlc::begin() + index + count); return *this;} + + /*! \brief Remove no more than one element equal "v" and return reference to vector + * \details Example: \snippet picontainers.cpp PIVector::removeOne + * \sa \a remove(), \a removeAll() */ + PIVector & removeOne(const Type & v) {for (typename _stlc::iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (v == *i) {_stlc::erase(i); return *this;} return *this;} + + /*! \brief Remove all elements equal "v" and return reference to vector + * \details Example: \snippet picontainers.cpp PIVector::removeAll + * \sa \a remove(), \a removeOne() */ */ + PIVector & removeAll(const Type & v) {for (typename _stlc::iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (v == *i) {_stlc::erase(i); --i;} return *this;} + + /*! \brief Insert element "t" after index "pos" and return reference to vector + * \details Example: \snippet picontainers.cpp PIVector::insert_0 */ + PIVector & insert(uint pos, const Type & t) {_stlc::insert(_stlc::begin() + pos, t); return *this;} + + /*! \brief Insert other vector "t" after index "pos" and return reference to vector + * \details Example: \snippet picontainers.cpp PIVector::insert_1 */ + PIVector & insert(uint pos, const PIVector & t) {_stlc::insert(_stlc::begin() + pos, t.begin(), t.end()); return *this;} + + /*! \brief Full access to element by index "index" + * \details Example: \snippet picontainers.cpp PIVector::() + * \sa \a at() */ + Type & operator [](uint index); + + /*! \brief Read-only access to element by index "index" + * \details Example: \snippet picontainers.cpp PIVector::()_c + * \sa \a at() */ + const Type & operator [](uint index) const; + + //! Add new element "t" at the end of vector and return reference to vector + PIVector & operator <<(const Type & t) {_stlc::push_back(t); return *this;} + + //! Add vector "t" at the end of vector and return reference to vector + PIVector & operator <<(const PIVector & t) {for (typename _stlc::const_iterator i = t.begin(); i != t.end(); i++) _stlc::push_back(*i); return *this;} + + //! Compare with vector "t" + bool operator ==(const PIVector & t) {for (uint i = 0; i < _stlc::size(); ++i) if (t[i] != at(i)) return false; return true;} + + //! Compare with vector "t" + bool operator !=(const PIVector & t) {for (uint i = 0; i < _stlc::size(); ++i) if (t[i] != at(i)) return true; return false;} + + bool contains(const Type & v) const {for (uint i = 0; i < _stlc::size(); ++i) if (v == at(i)) return true; return false;} + +#else + _CVector & enlarge(uint size_) {int ns = size_s() + size_; if (ns <= 0) _stlc::clear(); else _stlc::resize(ns); return *this;} _CVector & sort(CompareFunc compare = compare_func) {qsort(&at(0), _stlc::size(), sizeof(Type), (int(*)(const void * , const void * ))compare); return *this;} _CVector & fill(const Type & t) {_stlc::assign(_stlc::size(), t); return *this;} _CVector & pop_front() {_stlc::erase(_stlc::begin()); return *this;} _CVector & push_front(const Type & t) {_stlc::insert(_stlc::begin(), t); return *this;} Type take_front() {Type t(_stlc::front()); pop_front(); return t;} Type take_back() {Type t(_stlc::back()); _stlc::pop_back(); return t;} - _CVector & remove(uint num) {_stlc::erase(_stlc::begin() + num); return *this;} - _CVector & remove(uint num, uint count) {_stlc::erase(_stlc::begin() + num, _stlc::begin() + num + count); return *this;} - //_CVector & remove(const Type & t) {for (typename _stlc::iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (t == *i) {_stlc::erase(i); --i;} return *this;} + _CVector & remove(uint index) {_stlc::erase(_stlc::begin() + index); return *this;} + _CVector & remove(uint index, uint count) {_stlc::erase(_stlc::begin() + index, _stlc::begin() + index + count); return *this;} _CVector & removeOne(const Type & v) {for (typename _stlc::iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (v == *i) {_stlc::erase(i); return *this;} return *this;} _CVector & removeAll(const Type & v) {for (typename _stlc::iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (v == *i) {_stlc::erase(i); --i;} return *this;} _CVector & insert(uint pos, const Type & t) {_stlc::insert(_stlc::begin() + pos, t); return *this;} @@ -407,14 +566,24 @@ public: _CVector & operator <<(const _CVector & t) {for (typename _stlc::const_iterator i = t.begin(); i != t.end(); i++) _stlc::push_back(*i); return *this;} bool operator ==(const _CVector & t) {for (uint i = 0; i < _stlc::size(); ++i) if (t[i] != at(i)) return false; return true;} bool operator !=(const _CVector & t) {for (uint i = 0; i < _stlc::size(); ++i) if (t[i] != at(i)) return true; return false;} - bool contain(const Type & v) const {for (uint i = 0; i < _stlc::size(); ++i) if (v == at(i)) return true; return false;} + bool contains(const Type & v) const {for (uint i = 0; i < _stlc::size(); ++i) if (v == at(i)) return true; return false;} +#endif }; +/*! \brief Output operator for std::ostream + * \relates PIVector + * \details Example: \snippet picontainers.cpp PIVector::ostream<< */ template inline std::ostream & operator <<(std::ostream & s, const PIVector & v) {s << "{"; for (uint i = 0; i < v.size(); ++i) {s << v[i]; if (i < v.size() - 1) s << ", ";} s << "}"; return s;} +/*! \brief Output operator for PICout + * \relates PIVector + * \details Example: \snippet picontainers.cpp PIVector::PICout<< */ +template +inline PICout operator <<(PICout s, const PIVector & v) {s.space(); s.setControl(0, true); s << "{"; for (uint i = 0; i < v.size(); ++i) {s << v[i]; if (i < v.size() - 1) s << ", ";} s << "}"; s.restoreControl(); return s;} + template > -class PIList: public list { +class PIP_EXPORT PIList: public list { typedef PIList _CList; typedef list _stlc; public: @@ -431,16 +600,18 @@ public: Type * data(uint index = 0) {return &(*this)[index];} int size_s() const {return static_cast(_stlc::size());} bool isEmpty() const {return _stlc::empty();} + bool has(const Type & t) const {for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (t == *i) return true; return false;} + int etries(const Type & t) const {int ec = 0; for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (t == *i) ++ec; return ec;} _CList & fill(const Type & t) {_stlc::assign(_stlc::size(), t); return *this;} - _CList & remove(uint num) {_stlc::erase(_stlc::begin() + num); return *this;} - _CList & remove(uint num, uint count) {_stlc::erase(_stlc::begin() + num, _stlc::begin() + num + count); return *this;} + _CList & remove(uint index) {_stlc::erase(_stlc::begin() + index); return *this;} + _CList & remove(uint index, uint count) {_stlc::erase(_stlc::begin() + index, _stlc::begin() + index + count); return *this;} _CList & insert(uint pos, const Type & t) {_stlc::insert(_stlc::begin() + pos, t); return *this;} _CList & operator <<(const Type & t) {_stlc::push_back(t); return *this;} PIVector toVector() {PIVector v; for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) v << *i; return v;} }; template, typename Allocator = std::allocator > -class PISet: public set { +class PIP_EXPORT PISet: public set { typedef PISet _CSet; typedef set _stlc; public: @@ -452,15 +623,15 @@ public: ~PISet() {piMonitor.containers--;} int size_s() const {return static_cast(_stlc::size());} bool isEmpty() const {return _stlc::empty();} - _CSet & remove(uint num) {_stlc::erase(_stlc::begin() + num); return *this;} - _CSet & remove(uint num, uint count) {_stlc::erase(_stlc::begin() + num, _stlc::begin() + num + count); return *this;} + _CSet & remove(uint index) {_stlc::erase(_stlc::begin() + index); return *this;} + _CSet & remove(uint index, uint count) {_stlc::erase(_stlc::begin() + index, _stlc::begin() + index + count); return *this;} _CSet & operator <<(const Type & t) {_stlc::insert(t); return *this;} bool operator [](const Type & t) {return _stlc::find(t);} PIVector toVector() {PIVector v; for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) v << *i; return v;} }; template -class PIStack: public PIVector { +class PIP_EXPORT PIStack: public PIVector { typedef PIStack _CStack; public: PIStack() {;} @@ -476,7 +647,7 @@ public: }; template > -class PIDeque: public deque { +class PIP_EXPORT PIDeque: public deque { typedef PIDeque _CDeque; typedef deque _stlc; public: @@ -488,12 +659,14 @@ public: ~PIDeque() {piMonitor.containers--;} int size_s() const {return static_cast(_stlc::size());} bool isEmpty() const {return _stlc::empty();} + bool has(const Type & t) const {for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (t == *i) return true; return false;} + int etries(const Type & t) const {int ec = 0; for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) if (t == *i) ++ec; return ec;} _CDeque & operator <<(const Type & t) {_CDeque::push_back(t); return *this;} PIVector toVector() {PIVector v; for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); ++i) v << *i; return v;} }; template -class PIQueue: public PIDeque { +class PIP_EXPORT PIQueue: public PIDeque { typedef PIQueue _CQueue; public: PIQueue() {;} @@ -510,7 +683,7 @@ public: template -class PIPair { +class PIP_EXPORT PIPair { public: PIPair() {first = Type0(); second = Type1();} PIPair(const Type0 & value0, const Type1 & value1) {first = value0; second = value1;} @@ -519,21 +692,62 @@ public: }; template inline bool operator <(const PIPair & value0, const PIPair & value1) {return value0.first < value1.first;} +template +inline std::ostream & operator <<(std::ostream & s, const PIPair & v) {s << "(" << v.first << ", " << v.second << ")"; return s;} +template +inline PICout operator <<(PICout s, const PIPair & v) {s.space(); s.setControl(0, true); s << "(" << v.first << ", " << v.second << ")"; s.restoreControl(); return s;} template -class PIMap: public map { +class PIP_EXPORT PIMap: public map { typedef PIMap _CMap; typedef map _stlc; typedef std::pair _stlpair; public: PIMap() {;} PIMap(const Key & key_, const Type & value_) {insert(key_, value_);} - _CMap & insert(const Key & key_, const Type & value_) {_stlc::insert(std::pair(key_, value_)); return *this;} - _CMap & insert(PIPair entry_) {_stlc::insert(std::pair(entry_.first, entry_.second)); return *this;} + bool isEmpty() const {return _stlc::empty();} + bool contains(const Key & key_) const {return _stlc::count(key_) > 0;} + _CMap & insert(const Key & key_, const Type & value_) {_stlc::insert(_stlpair(key_, value_)); return *this;} + _CMap & insert(PIPair entry_) {_stlc::insert(_stlpair(entry_.first, entry_.second)); return *this;} Key key(Type value_) const {for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); i++) if (i->second == value_) return i->first; return Key();} - Type & value(Key key_) {return (*this)[key_];} - Type value(Key key_) const {return (*this)[key_];} + Type & value(const Key & key_) {typename _stlc::iterator it = _stlc::find(key_); if (it == _stlc::end()) it->second = Type(); return it->second;} + Type value(const Key & key_) const {return _stlc::find(key_)->second;} }; + +template +class PIP_EXPORT PIMultiMap: public multimap { + typedef PIMultiMap _CMultiMap; + typedef multimap _stlc; + typedef std::pair _stlpair; +public: + PIMultiMap() {;} + PIMultiMap(const Key & key_, const Type & value_) {insert(key_, value_);} + _CMultiMap & insert(const Key & key_, const Type & value_) {_stlc::insert(_stlpair(key_, value_)); return *this;} + _CMultiMap & insert(PIPair entry_) {_stlc::insert(_stlpair(entry_.first, entry_.second)); return *this;} + bool isEmpty() const {return _stlc::empty();} + bool contains(const Key & key_) const {return _stlc::count(key_) > 0;} + Key key(Type value_) const {for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); i++) if (i->second == value_) return i->first; return Key();} + PIVector keys(Type value_) const { + PIVector ret; + for (typename _stlc::const_iterator i = _stlc::begin(); i != _stlc::end(); i++) + if (i->second == value_) + ret << i->first; + return ret; + } + Type & value(const Key & key_) {return _stlc::find(key_)->second;} + Type value(const Key & key_) const {return _stlc::find(key_)->second;} + PIVector values(const Key & key_) const { + std::pair range = _stlc::equal_range(key_); + PIVector ret; + for (typename _stlc::const_iterator i = range.first; i != range.second; ++i) + ret << i->second; + return ret; + } + Type & operator [](const Key & key_) {if (!contains(key_)) return _stlc::insert(_stlpair(key_, Type()))->second; return _stlc::find(key_)->second;} + Type operator [](const Key & key_) const {return _stlc::find(key_)->second;} +}; + + #endif // PICONTAINERS_H diff --git a/picrc.h b/picrc.h index d855792f..4b0c08c0 100644 --- a/picrc.h +++ b/picrc.h @@ -23,7 +23,7 @@ #include "pistring.h" template -class uint_cl { +class PIP_EXPORT uint_cl { public: uint_cl() {for (int i = 0; i < L / 8; ++i) data_[i] = 0;} uint_cl(const uint_cl & v) {for (int i = 0; i < L / 8; ++i) data_[i] = v.data_[i];} @@ -160,7 +160,7 @@ inline std::ostream & operator <<(std::ostream & s, const uint_cl & v) {std:: template -class PICRC { +class PIP_EXPORT PICRC { public: PICRC(const uint_cl & poly) {poly_ = poly; reverse_poly = true; init_ = uint_cl(0).inversed(); out_ = uint_cl(0).inversed(); initTable();} PICRC(const uint_cl & poly, bool reverse, const uint_cl & initial, const uint_cl & out_xor) {poly_ = poly; reverse_poly = reverse; init_ = initial; out_ = out_xor; initTable();} diff --git a/pidir.h b/pidir.h index 81f1c13c..10af5142 100644 --- a/pidir.h +++ b/pidir.h @@ -26,7 +26,7 @@ #include #include -class PIDir +class PIP_EXPORT PIDir { public: PIDir(); diff --git a/piethernet.cpp b/piethernet.cpp index f906ce34..32f5b2bc 100644 --- a/piethernet.cpp +++ b/piethernet.cpp @@ -1,6 +1,6 @@ /* PIP - Platform Independent Primitives - Ethernet, UDP + Ethernet, UDP/TCP Broadcast/Multicast Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com This program is free software: you can redistribute it and/or modify @@ -47,7 +47,7 @@ PIEthernet::PIEthernet(PIEthernet::Type type, void * data, ReadRetFunc slot): PI sock = sock_s = -1; ret_func_ = slot; connected_ = false; - params = PIEthernet::ReuseAddress; + params = (type == UDP ? PIEthernet::ReuseAddress : 0); server_thread_.setData(this); setThreadedReadBufferSize(65536); if (type_ != UDP) init(); @@ -58,6 +58,7 @@ PIEthernet::PIEthernet(int sock_, PIString ip_port): PIIODevice("", ReadWrite) { piMonitor.ethernets++; setPriority(piHigh); type_ = TCP_Client; + path_ = ip_port; parseAddress(ip_port, &ip_s, &port_s); sock = sock_; sock_s = -1; @@ -80,22 +81,28 @@ PIEthernet::~PIEthernet() { bool PIEthernet::init() { //cout << "init " << type_ << endl; closeSocket(sock); - int st = 0; + int st = 0, pr = 0;; #ifdef WINDOWS - int flags = WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF; + int flags = 0; #else int so = 1; #endif - if (type_ == UDP) st = SOCK_DGRAM; - else st = SOCK_STREAM; + if (type_ == UDP) { + st = SOCK_DGRAM; + pr = IPPROTO_UDP; + } else { + st = SOCK_STREAM; + pr = IPPROTO_TCP; + } #ifdef WINDOWS + if (type_ == UDP) flags = WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF; if (params[ReuseAddress]) flags |= WSA_FLAG_OVERLAPPED; - sock = WSASocket(AF_INET, st, type_ == UDP ? IPPROTO_UDP : IPPROTO_TCP, NULL, 0, flags); + sock = WSASocket(AF_INET, st, pr, NULL, 0, flags); #else - sock = socket(AF_INET, st, type_ == UDP ? IPPROTO_UDP : IPPROTO_TCP); + sock = socket(AF_INET, st, pr); #endif if (sock == -1) { - piCout << "[PIEthernet] Cant`t create socket, " << EthErrorString() << endl; + piCout << "[PIEthernet] Cant`t create socket, " << ethErrorString(); return false; } #ifndef WINDOWS @@ -116,9 +123,11 @@ void PIEthernet::parseAddress(const PIString & ipp, PIString * ip, int * port) { bool PIEthernet::openDevice() { if (connected_) return true; - if (sock == -1) init(); + init(); if (sock == -1 || path_.isEmpty()) return false; parseAddress(path_, &ip_, &port_); + if (type_ != UDP) + return true; //cout << " bind to " << sock << ": " << (params[PIEthernet::Broadcast] ? "0.0.0.0" : path_) << ": " << port_ << " ..." <= 0) received(read_to, rs); + piCout << "eth" << path_ << "read return" << rs << errno; + if (rs <= 0) { + connected_ = false; + disconnected(rs < 0); + piCout << "eth" << path_ << "disconnected"; + } + if (rs > 0) received(read_to, rs); return rs; //return ::read(sock, read_to, max_size); default: break; @@ -313,10 +342,10 @@ int PIEthernet::read(void * read_to, int max_size) { int PIEthernet::write(const void * data, int max_size) { if (sock == -1) init(); if (sock == -1 || !isWriteable()) { - //piCout << "[PIEthernet] Can`t send to uninitialized socket" << endl; + //piCout << "[PIEthernet] Can`t send to uninitialized socket"; return -1; } - //piCout << "[PIEthernet] sending to " << ip_s << ":" << port_s << " " << max_size << " bytes" << endl; + //piCout << "[PIEthernet] sending to " << ip_s << ":" << port_s << " " << max_size << " bytes"; int ret = 0; switch (type_) { case TCP_SingleTCP: @@ -327,11 +356,14 @@ int PIEthernet::write(const void * data, int max_size) { #ifdef QNX addr_.sin_len = sizeof(addr_); #endif + //piCout << "connect SingleTCP" << ip_s << ":" << port_s << "..."; if (::connect(sock, (sockaddr * )&addr_, sizeof(addr_)) != 0) { - piCout << "[PIEthernet] Cant`t connect to " << ip_s << ":" << port_s << ", " << EthErrorString() << endl; + piCout << "[PIEthernet] Cant`t connect to " << ip_s << ":" << port_s << ", " << ethErrorString(); return -1; } - ret = ::write(sock, data, max_size); + //piCout << "ok, write SingleTCP" << int(data) << max_size << "bytes ..."; + ret = ::send(sock, (const char *)data, max_size, 0); + //piCout << "ok, ret" << ret; closeSocket(sock); init(); return ret; @@ -346,7 +378,7 @@ int PIEthernet::write(const void * data, int max_size) { return sendto(sock, data, max_size, 0, (sockaddr * )&saddr_, sizeof(saddr_)); #endif case TCP_Client: - return ::write(sock, data, max_size); + return ::send(sock, (const char *)data, max_size, 0); default: break; //return ::read(sock, read_to, max_size); } @@ -359,12 +391,13 @@ void PIEthernet::server_func(void * eth) { socklen_t slen = sizeof(client_addr); int s = accept(ce->sock, (sockaddr * )&client_addr, &slen); if (s == -1) { - piCout << "[PIEthernet] Cant`t accept new connection, " << EthErrorString() << endl; + piCout << "[PIEthernet] Cant`t accept new connection, " << ethErrorString(); return; } PIString ip(inet_ntoa(client_addr.sin_addr)); ip += ":" + PIString::fromNumber(htons(client_addr.sin_port)); ce->clients_ << new PIEthernet(s, ip); + ce->newConnection(ce->clients_.back()); //cout << "connected " << ip << endl; //char d[256]; //cout << " recv " << recv(s, d, 256, 0) << endl; @@ -375,7 +408,7 @@ void PIEthernet::server_func(void * eth) { PIStringList PIEthernet::interfaces() { #ifdef WINDOWS - piCout << "[PIEthernet] Not implemented on Windows, use \"PIEthernet::allAddresses\" instead" << endl; + piCout << "[PIEthernet] Not implemented on Windows, use \"PIEthernet::allAddresses\" instead"; return PIStringList(); #else # ifdef QNX @@ -434,7 +467,7 @@ PIStringList PIEthernet::interfaces() { PIString PIEthernet::interfaceAddress(const PIString & interface_) { #ifdef WINDOWS - piCout << "[PIEthernet] Not implemented on Windows, use \"PIEthernet::allAddresses\" instead" << endl; + piCout << "[PIEthernet] Not implemented on Windows, use \"PIEthernet::allAddresses\" instead"; return PIString(); #else struct ifreq ifr; @@ -459,14 +492,14 @@ PIStringList PIEthernet::allAddresses() { ulong ulOutBufLen = sizeof(IP_ADAPTER_INFO); pAdapterInfo = (IP_ADAPTER_INFO * ) HeapAlloc(GetProcessHeap(), 0, (sizeof (IP_ADAPTER_INFO))); if (pAdapterInfo == 0) { - piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo" << endl; + piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo"; return PIStringList(); } if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) { HeapFree(GetProcessHeap(), 0, (pAdapterInfo)); pAdapterInfo = (IP_ADAPTER_INFO *) HeapAlloc(GetProcessHeap(), 0, (ulOutBufLen)); if (pAdapterInfo == 0) { - piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo" << endl; + piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo"; return PIStringList(); } } @@ -482,7 +515,7 @@ PIStringList PIEthernet::allAddresses() { pAdapter = pAdapter->Next; } } else - piCout << "[PIEthernet] GetAdaptersInfo failed with error: " << ret << endl; + piCout << "[PIEthernet] GetAdaptersInfo failed with error: " << ret; if (pAdapterInfo) HeapFree(GetProcessHeap(), 0, (pAdapterInfo)); return al; @@ -490,6 +523,6 @@ PIStringList PIEthernet::allAddresses() { PIStringList il = interfaces(), al; piForeachC (PIString & i, il) al << interfaceAddress(i); - return al; + return al.removeStrings("0.0.0.0"); #endif } diff --git a/piethernet.h b/piethernet.h index 89fbfdd7..c75d3fa0 100644 --- a/piethernet.h +++ b/piethernet.h @@ -1,6 +1,6 @@ /* PIP - Platform Independent Primitives - Ethernet, UDP + Ethernet, UDP/TCP Broadcast/Multicast Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com This program is free software: you can redistribute it and/or modify @@ -24,8 +24,9 @@ #include "piiodevice.h" #include "piprocess.h" -class PIEthernet: public PIIODevice +class PIP_EXPORT PIEthernet: public PIIODevice { + PIOBJECT(PIEthernet) friend class PIPeer; public: // slot is any function format "bool (void*, uchar*, int)" @@ -35,7 +36,7 @@ public: enum Parameters {ReuseAddress = 0x1, Broadcast = 0x2}; PIEthernet(Type type = UDP, void * data = 0, ReadRetFunc slot = 0); - ~PIEthernet(); + virtual ~PIEthernet(); void setReadAddress(const PIString & ip, int port) {path_ = ip + ":" + PIString::fromNumber(port);} void setReadAddress(const PIString & ip_port) {path_ = ip_port;} @@ -61,8 +62,9 @@ public: bool joinMulticastGroup(const PIString & group); bool leaveMulticastGroup(const PIString & group); - bool connect(const PIString & ip, int port); - bool connect(const PIString & ip_port) {parseAddress(ip_port, &ip_c, &port_c); return connect(ip_c, port_c);} + bool connect(); + bool connect(const PIString & ip, int port) {path_ = ip + ":" + PIString::fromNumber(port); return connect();} + bool connect(const PIString & ip_port) {path_ = ip_port; return connect();} bool isConnected() const {return connected_;} bool listen(); @@ -73,9 +75,10 @@ public: int clientsCount() const {return clients_.size_s();} PIVector clients() {return clients_;} - bool send(const PIString & ip, int port, const void * data, int size) {ip_s = ip; port_s = port; return send(data, size);} - bool send(const PIString & ip_port, const void * data, int size) {parseAddress(ip_port, &ip_s, &port_s); return send(data, size);} - bool send(const void * data, int size) {return (write(data, size) == size);} + bool send(const PIString & ip, int port, const void * data, int size, bool threaded = false) {ip_s = ip; port_s = port; if (threaded) {writeThreaded(data, size); return true;} return send(data, size);} + bool send(const PIString & ip_port, const void * data, int size, bool threaded = false) {parseAddress(ip_port, &ip_s, &port_s); if (threaded) {writeThreaded(data, size); return true;} return send(data, size);} + bool send(const void * data, int size, bool threaded = false) {if (threaded) {writeThreaded(data, size); return true;} return (write(data, size) == size);} + bool send(const PIByteArray & ba, bool threaded = false) {if (threaded) {writeThreaded(ba); return true;} return (write(ba) == ba.size_s());} int read(void * read_to, int max_size); int write(const void * data, int max_size); @@ -84,6 +87,10 @@ public: static PIStringList interfaces(); static PIString interfaceAddress(const PIString & interface_); static PIStringList allAddresses(); + + EVENT1(newConnection, PIEthernet * , client) + EVENT0(connected) + EVENT1(disconnected, bool, withError) protected: PIEthernet(int sock, PIString ip_port); @@ -106,6 +113,7 @@ protected: PIString ip_, ip_s, ip_c; PIThread server_thread_; PIVector clients_; + PIQueue mcast_queue; #ifdef WINDOWS PIMap leafs; #endif @@ -115,7 +123,7 @@ protected: private: static void server_func(void * eth); - static std::string EthErrorString() { + static std::string ethErrorString() { #ifdef WINDOWS char * msg; int err = WSAGetLastError(); diff --git a/pievaluator.h b/pievaluator.h index 229ee3fc..38c4500b 100644 --- a/pievaluator.h +++ b/pievaluator.h @@ -72,7 +72,7 @@ namespace PIEvaluatorTypes { ⋀ & ⋁ | */ -class PIEvaluatorContent +class PIP_EXPORT PIEvaluatorContent { friend class PIEvaluator; public: @@ -108,7 +108,7 @@ private: }; -class PIEvaluator +class PIP_EXPORT PIEvaluator { public: PIEvaluator() {;} diff --git a/pifile.cpp b/pifile.cpp index 93f99a94..4587418f 100644 --- a/pifile.cpp +++ b/pifile.cpp @@ -32,7 +32,7 @@ bool PIFile::openDevice() { bool PIFile::closeDevice() { - if (!opened_) return true; + if (!opened_ || fd == 0) return true; return (fclose(fd) == 0); } @@ -104,7 +104,7 @@ void PIFile::resize(llong new_size, char fill_) { delete[] buff; return; } - piCout << "[PIFile] Downsize is not support yet :-(" << endl; + piCout << "[PIFile] Downsize is not support yet :-("; } diff --git a/pifile.h b/pifile.h index 694a8d3e..8133c03b 100644 --- a/pifile.h +++ b/pifile.h @@ -27,27 +27,29 @@ /// void clear() /// void resize(llong new_size, char fill = 0) /// void remove() -class PIFile: public PIIODevice +class PIP_EXPORT PIFile: public PIIODevice { + PIOBJECT(PIFile) public: PIFile(const PIString & path = PIString(), DeviceMode type = ReadWrite): PIIODevice(path, type) {setPrecision(5); openDevice();} + ~PIFile() {close();} //PIFile & operator =(const PIFile & f) {path_ = f.path_; type_ = f.type_; return *this;} - void flush() {fflush(fd);} - EVENT_HANDLER(PIFile, void, clear) {close(); fd = fopen(path_.data(), "w"); close(); open();} + void flush() {if (!opened_) fflush(fd);} + EVENT_HANDLER(void, clear) {close(); fd = fopen(path_.data(), "w"); if (fd != 0) fclose(fd); fd = 0; opened_ = false; open();} void seek(llong position) {if (!opened_) return; fseek(fd, position, SEEK_SET); clearerr(fd);} void seekToBegin() {if (!opened_) return; fseek(fd, 0, SEEK_SET); clearerr(fd);} void seekToEnd() {if (!opened_) return; fseek(fd, 0, SEEK_END); clearerr(fd);} void seekToLine(llong line) {if (!opened_) return; seekToBegin(); piForTimes (line) readLine(); clearerr(fd);} // line 0 - begin of file - EVENT_HANDLER1(PIFile, void, resize, llong, new_size) {resize(new_size, 0);} - EVENT_HANDLER2(PIFile, void, resize, llong, new_size, char, fill); + EVENT_HANDLER1(void, resize, llong, new_size) {resize(new_size, 0);} + EVENT_HANDLER2(void, resize, llong, new_size, char, fill); //void fill(char c) {stream.fill(c);} char readChar() {return (char)fgetc(fd);} PIString readLine(); llong readAll(void * data); PIByteArray readAll(bool forceRead = false); - EVENT_HANDLER0(PIFile, void, remove) {close(); std::remove(path_.data());} + EVENT_HANDLER0(void, remove) {close(); std::remove(path_.data());} void setPath(const PIString & path) {path_ = path; if (opened_) openDevice();} llong size(); @@ -56,11 +58,11 @@ public: bool isEmpty() {return (size() <= 0);} int precision() const {return prec;} - void setPrecision(int prec_) {prec = prec_; prec_str = "." + itos(prec_);} + void setPrecision(int prec_) {prec = prec_; if (prec >= 0) prec_str = "." + itos(prec_); else prec_str = "";} - int read(void * read_to, int max_size) {if (!canRead()) return -1; return fread(read_to, max_size, 1, fd);} - int write(const void * data, int max_size) {if (!canWrite()) return -1; return fwrite(data, max_size, 1, fd);} - PIFile & writeToBinLog(ushort id, const void * data, int size) {if (!isWriteable()) return *this; writeBinary(id).writeBinary((ushort)size); write(data, size); flush(); return *this;} + int read(void * read_to, int max_size) {if (!canRead() || fd == 0) return -1; return fread(read_to, max_size, 1, fd);} + int write(const void * data, int max_size) {if (!canWrite() || fd == 0) return -1; return fwrite(data, max_size, 1, fd);} + PIFile & writeToBinLog(ushort id, const void * data, int size) {if (!isWriteable() || fd == 0) return *this; writeBinary(id).writeBinary((ushort)size); write(data, size); flush(); return *this;} PIFile & writeBinary(const char v) {write(&v, sizeof(v)); return *this;} PIFile & writeBinary(const short v) {write(&v, sizeof(v)); return *this;} @@ -75,7 +77,9 @@ public: PIFile & writeBinary(const float v) {write(&v, sizeof(v)); return *this;} PIFile & writeBinary(const double v) {write(&v, sizeof(v)); return *this;} - PIFile & operator <<(const char & v) {if (!isWriteable()) return *this; write(&v, 1); return *this;} + PIFile & operator =(const PIFile & f) {path_ = f.path_; mode_ = f.mode_; return *this;} + + PIFile & operator <<(const char v) {if (!isWriteable()) return *this; write(&v, 1); return *this;} //PIFile & operator <<(const string & v) {write(v.c_str(), v.size()); return *this;} PIFile & operator <<(const PIString & v) {if (!isWriteable()) return *this; write(v.data(), v.lengthAscii()); return *this;} PIFile & operator <<(const PIByteArray & v) {if (!isWriteable()) return *this; write(v.data(), v.size()); return *this;} @@ -83,11 +87,11 @@ public: PIFile & operator <<(int v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%d", v); return *this;} PIFile & operator <<(long v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%ld", v); return *this;} PIFile & operator <<(llong v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%lld", v); return *this;} - PIFile & operator <<(uchar v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%c", v); return *this;} - PIFile & operator <<(ushort v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%hd", v); return *this;} - PIFile & operator <<(uint v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%d", v); return *this;} - PIFile & operator <<(ulong v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%ld", v); return *this;} - PIFile & operator <<(ullong v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%lld", v); return *this;} + PIFile & operator <<(uchar v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%u", int(v)); return *this;} + PIFile & operator <<(ushort v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%hu", v); return *this;} + PIFile & operator <<(uint v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%u", v); return *this;} + PIFile & operator <<(ulong v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%lu", v); return *this;} + PIFile & operator <<(ullong v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%llu", v); return *this;} PIFile & operator <<(float v) {if (!isWriteable()) return *this; ret = fprintf(fd, ("%" + prec_str + "f").c_str(), v); return *this;} PIFile & operator <<(double v) {if (!isWriteable()) return *this; ret = fprintf(fd, ("%" + prec_str + "lf").c_str(), v); return *this;} diff --git a/pigeometry.h b/pigeometry.h index 1536f7b0..a743b481 100644 --- a/pigeometry.h +++ b/pigeometry.h @@ -23,7 +23,7 @@ #include "pimath.h" template -class PIPoint { +class PIP_EXPORT PIPoint { public: Type x; Type y; @@ -55,7 +55,7 @@ template std::ostream & operator <<(std::ostream & s, const PIPoint & v) {s << '{' << v.x << ", " << v.y << '}'; return s;} template -class PIRect { +class PIP_EXPORT PIRect { public: Type x0; Type y0; diff --git a/piincludes.cpp b/piincludes.cpp index e149d432..7ddab3c7 100644 --- a/piincludes.cpp +++ b/piincludes.cpp @@ -18,6 +18,7 @@ */ #include "piincludes.h" +#include "pimutex.h" bool isPIInit = false; bool piDebug = true; @@ -29,3 +30,41 @@ lconv * currentLocale = std::localeconv(); #ifdef MAC_OS clock_serv_t __pi_mac_clock; #endif + +PIMutex __PICout_mutex__; + + +/*! \class PICout + * \brief Class for formatted output similar std::cout + * + * \section PICout_sec0 Synopsis + * This class provide many stream operators for output with some features. + * Output to PICout is thread-sequential, i.e. doesn`t mixed from parallel + * threads. + * + * \section PICout_sec1 Features + * - insertion spaces between entries + * - insertion new line at the end of output + * - strings are quoted + * - custom output operator can be easily written + * + * \section PICout_ex0 Example + * \snippet picout.cpp 0 + */ + + +PICout::PICout(PIFlags controls): fo_(true), cc_(false), co_(controls) { + __PICout_mutex__.lock(); +} + + +PICout::~PICout() { + if (cc_) return; + newLine(); + __PICout_mutex__.unlock(); +} + + +/*! \mainpage Title + * This is main page + */ diff --git a/piincludes.h b/piincludes.h index 5f7b3813..5cef4c1f 100644 --- a/piincludes.h +++ b/piincludes.h @@ -1,3 +1,9 @@ +/*! \file piincludes.h + * \brief Global includes of PIP + * + * This file include all needed STL and declare many useful + * macros and functions +*/ /* PIP - Platform Independent Primitives Global includes @@ -20,12 +26,58 @@ #ifndef PIINCLUDES_H #define PIINCLUDES_H -#define PIP_VERSION 0x000300 +//! Version of PIP in hex - 0x##(Major)##(Minor)##(Revision) +#define PIP_VERSION 0x000304 + +//! Major value of PIP version #define PIP_VERSION_MAJOR (PIP_VERSION & 0xFF0000) >> 16 + +//! Minor value of PIP version #define PIP_VERSION_MINOR (PIP_VERSION & 0xFF00) >> 8 + +//! Revision value of PIP version #define PIP_VERSION_REVISION PIP_VERSION & 0xFF + +//! Suffix of PIP version #define PIP_VERSION_SUFFIX "" +#ifdef DOXYGEN + +//! Macro is defined when compile-time debug is enabled +# define PIP_DEBUG + +//! Macro is defined when host is any Windows +# define WINDOWS + +//! Macro is defined when host is QNX +# define QNX + +//! Macro is defined when host is FreeBSD +# define FREE_BSD + +//! Macro is defined when host is Mac OS +# define MAC_OS + +//! Macro is defined when host is any Linux +# define LINUX + +//! Macro is defined when compiler is GCC or MinGW +# define CC_GCC + +//! Macro is defined when PIP is decided that host is support language +# define HAS_LOCALE + +//! Macro is defined when compiler is Visual Studio +# define CC_VC + +//! Macro is defined when compiler is unknown +# define CC_OTHER + +//! Macro is defined when PIP use "rt" library for timers implementation +# define PIP_TIMER_RT + +#endif + #if WIN32 || WIN64 || _WIN32 || _WIN64 || __WIN32__ || __WIN64__ # define WINDOWS #endif @@ -60,6 +112,13 @@ #else # define CC_OTHER #endif +#ifdef PIP_DEBUG +# undef NDEBUG +#else +# ifndef NDEBUG +# define NDEBUG +# endif +#endif #ifdef WINDOWS # ifdef CC_GCC @@ -69,6 +128,11 @@ # define typeof __typeof__ #endif +#include "pip_export.h" +#if defined(DOXYGEN) || defined(CC_GCC) +# undef PIP_EXPORT +# define PIP_EXPORT +#endif #include #ifdef CC_GCC # include @@ -90,6 +154,7 @@ #include #include #include +#include //#include #include #include @@ -153,7 +218,10 @@ extern char ** environ; extern PIMonitor piMonitor; +//! Macro used for infinite loop #define FOREVER for (;;) + +//! Macro used for infinite wait #define FOREVER_WAIT FOREVER msleep(1); typedef long long llong; @@ -175,6 +243,7 @@ using std::deque; using std::stack; using std::set; using std::map; +using std::multimap; using std::string; #ifndef QNX using std::wstring; @@ -188,15 +257,118 @@ typedef std::basic_string wstring; static locale_t currentLocale_t = 0; #endif +/*! \brief Templated function for swap two values + * \details Example:\n \snippet piincludes.cpp swap */ template inline void piSwap(T & f, T & s) {T t = f; f = s; s = t;} + +/*! \brief Templated function return round of float falue + * \details Round is the nearest integer value \n + * There is some macros: + * - \c piRoundf for "float" + * - \c piRoundd for "double" + * + * Example: + * \snippet piincludes.cpp round */ template inline int piRound(const T & v) {return int(v >= T(0.) ? v + T(0.5) : v - T(0.5));} + +/*! \brief Templated function return floor of float falue + * \details Floor is the largest integer that is not greater than value \n + * There is some macros: + * - \c piFloorf for "float" + * - \c piFloord for "double" + * + * Example: + * \snippet piincludes.cpp floor */ template inline int piFloor(const T & v) {return v < T(0) ? int(v) - 1 : int(v);} + +/*! \brief Templated function return ceil of float falue + * \details Ceil is the smallest integer that is not less than value \n + * There is some macros: + * - \c piCeilf for "float" + * - \c piCeild for "double" + * + * Example: + * \snippet piincludes.cpp ceil */ template inline int piCeil(const T & v) {return v < T(0) ? int(v) : int(v) + 1;} + +/*! \brief Templated function return absolute of numeric falue + * \details Absolute is the positive or equal 0 value \n + * There is some macros: + * - \c piAbss for "short" + * - \c piAbsi for "int" + * - \c piAbsl for "long" + * - \c piAbsll for "llong" + * - \c piAbsf for "float" + * - \c piAbsd for "double" + * + * Example: + * \snippet piincludes.cpp abs */ template inline T piAbs(const T & v) {return (v >= T(0) ? v : -v);} + +/*! \brief Templated function return minimum of two values + * \details There is some macros: + * - \c piMins for "short" + * - \c piMini for "int" + * - \c piMinl for "long" + * - \c piMinll for "llong" + * - \c piMinf for "float" + * - \c piMind for "double" + * + * Example: + * \snippet piincludes.cpp min2 */ template inline T piMin(const T & f, const T & s) {return (f > s) ? s : f;} + +/*! \brief Templated function return minimum of tree values + * \details There is some macros: + * - \c piMins for "short" + * - \c piMini for "int" + * - \c piMinl for "long" + * - \c piMinll for "llong" + * - \c piMinf for "float" + * - \c piMind for "double" + * + * Example: + * \snippet piincludes.cpp min3 */ template inline T piMin(const T & f, const T & s, const T & t) {return (f < s && f < t) ? f : ((s < t) ? s : t);} + +/*! \brief Templated function return maximum of two values + * \details There is some macros: + * - \c piMaxs for "short" + * - \c piMaxi for "int" + * - \c piMaxl for "long" + * - \c piMaxll for "llong" + * - \c piMaxf for "float" + * - \c piMaxd for "double" + * + * Example: + * \snippet piincludes.cpp max2 */ template inline T piMax(const T & f, const T & s) {return (f < s) ? s : f;} + +/*! \brief Templated function return maximum of tree values + * \details There is some macros: + * - \c piMaxs for "short" + * - \c piMaxi for "int" + * - \c piMaxl for "long" + * - \c piMaxll for "llong" + * - \c piMaxf for "float" + * - \c piMaxd for "double" + * + * Example: + * \snippet piincludes.cpp max3 */ template inline T piMax(const T & f, const T & s, const T & t) {return (f > s && f > t) ? f : ((s > t) ? s : t);} + +/*! \brief Templated function return clamped value + * \details Clamped is the not greater than "max" and not lesser than "min" value \n + * There is some macros: + * - \c piClamps for "short" + * - \c piClampi for "int" + * - \c piClampl for "long" + * - \c piClampll for "llong" + * - \c piClampf for "float" + * - \c piClampd for "double" + * + * Example: + * \snippet piincludes.cpp clamp */ template inline T piClamp(const T & v, const T & min, const T & max) {return (v > max ? max : (v < min ? min : v));} #define piRoundf piRound @@ -231,10 +403,11 @@ template inline T piClamp(const T & v, const T & min, const T & max) #define piClampd piClamp extern bool isPIInit; -extern bool piDebug; -extern string ifconfigPath; -#define piCout if (piDebug) cout +//! global variable enabling output to piCout +extern bool piDebug; + +extern string ifconfigPath; class PIInit { public: @@ -245,10 +418,8 @@ public: sigset_t ss; sigemptyset(&ss); sigaddset(&ss, SIGALRM); - if (pthread_sigmask(SIG_BLOCK, &ss, 0) == -1) { - //cout << "[PITimer] sigaction error: " << errorString() << endl; - //return 0; - } + sigprocmask(SIG_BLOCK, &ss, 0); + pthread_sigmask(SIG_BLOCK, &ss, 0); ifconfigPath = "/bin/ifconfig"; if (!fileExists(ifconfigPath)) { ifconfigPath = "/sbin/ifconfig"; @@ -305,8 +476,8 @@ inline double round(const double & v) {return floor(v + 0.5);} #endif inline ushort letobe_s(ushort v) {return v = (v << 8) | (v >> 8);} -inline bool atob(const string & str) { return str == "1" ? true : false;}; -inline string btos(const bool num) { return num ? "0" : "1";}; +inline bool atob(const string & str) {return str == "1" ? true : false;} +inline string btos(const bool num) {return num ? "0" : "1";} inline string itos(const int num) { char ch[256]; #ifndef CC_VC @@ -314,7 +485,7 @@ inline string itos(const int num) { #else sprintf_s(ch, 256, "%d", num); #endif - return string(ch); }; + return string(ch);} inline string ltos(const long num) { char ch[256]; #ifndef CC_VC @@ -322,23 +493,23 @@ inline string ltos(const long num) { #else sprintf_s(ch, 256, "%ld", num); #endif - return string(ch); }; + return string(ch);} inline string uitos(const uint num) { char ch[256]; #ifndef CC_VC - sprintf(ch, "%ud", num); + sprintf(ch, "%u", num); #else - sprintf_s(ch, 256, "%ud", num); + sprintf_s(ch, 256, "%u", num); #endif - return string(ch); }; + return string(ch);} inline string ultos(const ulong num) { char ch[256]; #ifndef CC_VC - sprintf(ch, "%lud", num); + sprintf(ch, "%lu", num); #else - sprintf_s(ch, 256, "%lud", num); + sprintf_s(ch, 256, "%lu", num); #endif - return string(ch); }; + return string(ch);} inline string ftos(const float num) { char ch[256]; #ifndef CC_VC @@ -346,7 +517,7 @@ inline string ftos(const float num) { #else sprintf_s(ch, 256, "%g", num); #endif - return string(ch); }; + return string(ch);} inline string dtos(const double num) { char ch[256]; #ifndef CC_VC @@ -354,9 +525,11 @@ inline string dtos(const double num) { #else sprintf_s(ch, 256, "%g", num); #endif - return string(ch); }; + return string(ch);} -#ifdef CC_VC +/*! \fn errorString() + * \brief Return readable error description in format "code - " */ +#ifdef WINDOWS inline string errorString() { char * msg; int err = GetLastError(); @@ -368,6 +541,259 @@ inline void errorClear() {errno = 0;} inline string errorString() {int e = errno; return "code " + itos(e) + " - " + string(strerror(e));} #endif +/// Return readable version of PIP inline string PIPVersion() {return itos(PIP_VERSION_MAJOR) + "." + itos(PIP_VERSION_MINOR) + "." + itos(PIP_VERSION_REVISION) + PIP_VERSION_SUFFIX;} +/*! \brief This class used as container for bit flags + * \details PIFlags is wrapper around \c "int". There are many + * bit-wise operators, native conversion to int and function + * to test flag. \n Example: + * \snippet piincludes.cpp flags + */ +template +class PIP_EXPORT PIFlags { +public: + //! Constructor with flags = 0 + PIFlags(): flags(0) {;} + //! Constructor with flags = Enum "e" + PIFlags(Enum e): flags(e) {;} + //! Constructor with flags = PIFlags "f" + PIFlags(const PIFlags & f): flags(f.flags) {;} + //! Constructor with flags = int "i" + PIFlags(const int i): flags(i) {;} + //! Set flags "f" to value "on" + PIFlags & setFlag(const PIFlags & f, bool on = true) {if (on) flags |= f.flags; else flags &= ~f.flags; return *this;} + //! Set flag "e" to value "on" + PIFlags & setFlag(const Enum & e, bool on = true) {if (on) flags |= e; else flags &= ~e; return *this;} + //! Set flag "i" to value "on" + PIFlags & setFlag(const int & i, bool on = true) {if (on) flags |= i; else flags &= ~i; return *this;} + //! copy operator + void operator =(const PIFlags & f) {flags = f.flags;} + //! copy operator + void operator =(const Enum & e) {flags = e;} + //! copy operator + void operator =(const int & i) {flags = i;} + //! compare operator + void operator ==(const PIFlags & f) {flags == f.flags;} + //! compare operator + void operator ==(const Enum & e) {flags == e;} + //! compare operator + void operator ==(const int i) {flags == i;} + //! compare operator + void operator !=(const PIFlags & f) {flags != f.flags;} + //! compare operator + void operator !=(const Enum & e) {flags != e;} + //! compare operator + void operator !=(const int i) {flags != i;} + //! compare operator + void operator >(const PIFlags & f) {flags > f.flags;} + //! compare operator + void operator >(const Enum & e) {flags > e;} + //! compare operator + void operator >(const int i) {flags > i;} + //! compare operator + void operator <(const PIFlags & f) {flags < f.flags;} + //! compare operator + void operator <(const Enum & e) {flags < e;} + //! compare operator + void operator <(const int i) {flags < i;} + //! compare operator + void operator >=(const PIFlags & f) {flags >= f.flags;} + //! compare operator + void operator >=(const Enum & e) {flags >= e;} + //! compare operator + void operator >=(const int i) {flags >= i;} + //! compare operator + void operator <=(const PIFlags & f) {flags <= f.flags;} + //! compare operator + void operator <=(const Enum & e) {flags <= e;} + //! compare operator + void operator <=(const int i) {flags <= i;} + //! Bit-wise AND operator + void operator &=(const PIFlags & f) {flags &= f.flags;} + //! Bit-wise AND operator + void operator &=(const Enum & e) {flags &= e;} + //! Bit-wise AND operator + void operator &=(const int i) {flags &= i;} + //! Bit-wise OR operator + void operator |=(const PIFlags & f) {flags |= f.flags;} + //! Bit-wise OR operator + void operator |=(const Enum & e) {flags |= e;} + //! Bit-wise OR operator + void operator |=(const int i) {flags |= i;} + //! Bit-wise XOR operator + void operator ^=(const PIFlags & f) {flags ^= f.flags;} + //! Bit-wise XOR operator + void operator ^=(const Enum & e) {flags ^= e;} + //! Bit-wise XOR operator + void operator ^=(const int i) {flags ^= i;} + //! Bit-wise AND operator + PIFlags operator &(PIFlags f) const {PIFlags tf(flags & f.flags); return tf;} + //! Bit-wise AND operator + PIFlags operator &(Enum e) const {PIFlags tf(flags & e); return tf;} + //! Bit-wise AND operator + PIFlags operator &(int i) const {PIFlags tf(flags & i); return tf;} + //! Bit-wise OR operator + PIFlags operator |(PIFlags f) const {PIFlags tf(flags | f.flags); return tf;} + //! Bit-wise OR operator + PIFlags operator |(Enum e) const {PIFlags tf(flags | e); return tf;} + //! Bit-wise OR operator + PIFlags operator |(int i) const {PIFlags tf(flags | i); return tf;} + //! Bit-wise XOR operator + PIFlags operator ^(PIFlags f) const {PIFlags tf(flags ^ f.flags); return tf;} + //! Bit-wise XOR operator + PIFlags operator ^(Enum e) const {PIFlags tf(flags ^ e); return tf;} + //! Bit-wise XOR operator + PIFlags operator ^(int i) const {PIFlags tf(flags ^ i); return tf;} + //! Test flag operator + bool operator [](Enum e) const {return (flags & e) == e;} + //! Implicity conversion to \c int + operator int() const {return flags;} +private: + int flags; +}; + +//! Macro used for conditional (piDebug) output to PICout +#define piCout if (piDebug) PICout() + +class PIMutex; +extern PIMutex __PICout_mutex__; + +//! \brief Namespace contains enums controlled PICout +namespace PICoutManipulators { + + //! \brief Enum contains special characters + enum PIP_EXPORT PICoutSpecialChar { + Null /*! Null-character, '\\0' */, + NewLine /*! New line character, '\\n' */, + Tab /*! Tab character, '\\t' */, + Esc /*! Escape character, '\\e' */, + Quote /*! Quote character, '"' */ + }; + + //! \brief Enum contains immediate action + enum PIP_EXPORT PICoutAction { + Flush /*! Flush the output */ + }; + + //! \brief Enum contains control of PICout + enum PIP_EXPORT PICoutControl { + AddNone /*! No controls */ = 0x0, + AddSpaces /*! Spaces will be appear after each output */ = 0x1, + AddNewLine /*! New line will be appear after all output */ = 0x2, + AddQuotes /*! Each string will be quoted */ = 0x4, + AddAll /*! All controls */ = 0xFFFFFFFF + }; +}; + +using namespace PICoutManipulators; + +typedef PIFlags PICoutControls; + +class PIP_EXPORT PICout { +public: + //! Default constructor with default features + PICout(PIFlags controls = AddSpaces | AddNewLine); + + PICout(const PICout & other): fo_(other.fo_), cc_(true), co_(other.co_) {;} + ~PICout(); + + //! Output operator for strings with "const char * " type + PICout operator <<(const char * v) {space(); quote(); std::cout << v; quote(); return *this;} + + //! Output operator for strings with "std::string" type + PICout operator <<(const string & v) {space(); quote(); std::cout << v; quote(); return *this;} + + //! Output operator for boolean values + PICout operator <<(const bool v) {space(); std::cout << v; return *this;} + + //! Output operator for "char" values + PICout operator <<(const char v) {space(); std::cout << v; return *this;} + + //! Output operator for "unsigned char" values + PICout operator <<(const uchar v) {space(); std::cout << ushort(v); return *this;} + + //! Output operator for "short" values + PICout operator <<(const short v) {space(); std::cout << v; return *this;} + + //! Output operator for "unsigned short" values + PICout operator <<(const ushort v) {space(); std::cout << v; return *this;} + + //! Output operator for "int" values + PICout operator <<(const int v) {space(); std::cout << v; return *this;} + + //! Output operator for "unsigned int" values + PICout operator <<(const uint v) {space(); std::cout << v; return *this;} + + //! Output operator for "long" values + PICout operator <<(const long v) {space(); std::cout << v; return *this;} + + //! Output operator for "unsigned long" values + PICout operator <<(const ulong v) {space(); std::cout << v; return *this;} + + //! Output operator for "long long" values + PICout operator <<(const llong v) {space(); std::cout << v; return *this;} + + //! Output operator for "unsigned long long" values + PICout operator <<(const ullong v) {space(); std::cout << v; return *this;} + + //! Output operator for "float" values + PICout operator <<(const float v) {space(); std::cout << v; return *this;} + + //! Output operator for "double" values + PICout operator <<(const double v) {space(); std::cout << v; return *this;} + + //! Output operator for \a PICoutSpecialChar values + PICout operator <<(const PICoutSpecialChar v) { + switch (v) { + case Null: std::cout << char(0); + case NewLine: std::cout << '\n'; + case Tab: std::cout << '\t'; + case Esc: std::cout << '\e'; + case Quote: std::cout << '"'; + }; + return *this; + } + + //! Do some action + PICout operator <<(const PICoutAction v) { + switch (v) { + case Flush: std::cout << std::flush; + }; + return *this; + } + + //! Set control flag "c" is "on" state + void setControl(PICoutControl c, bool on = true) {co_.setFlag(c, on);} + + //! Set control flags "c" and if "save" exec \a saveControl() + void setControl(PICoutControls c, bool save = false) {if (save) saveControl(); co_ = c;} + + //! Save control flags to internal stack \sa \a restoreControl() + void saveControl() {cos_.push(co_);} + + //! Restore control flags from internal stack \sa \a saveControl() + void restoreControl() {if (!cos_.empty()) {co_ = cos_.top(); cos_.pop();}} + + /*! \brief Conditional put space character to output + * \details If it is not a first output and control \a AddSpaces is set + * space character is put \sa \a quote(), \a newLine() */ + inline void space() {if (!fo_ && co_[AddSpaces]) std::cout << ' '; fo_ = false;} + + /*! \brief Conditional put quote character to output + * \details If control \a AddQuotes is set + * quote character is put \sa \a space(), \a newLine() */ + inline void quote() {if (co_[AddQuotes]) std::cout << '"'; fo_ = false;} + + /*! \brief Conditional put new line character to output + * \details If control \a AddNewLine is set + * new line character is put \sa \a space(), \a quote() */ + inline void newLine() {if (co_[AddNewLine]) std::cout << std::endl; fo_ = false;} + +private: + bool fo_, cc_; + PICoutControls co_; + std::stack cos_; +}; + #endif // PIINCLUDES_H diff --git a/piiodevice.cpp b/piiodevice.cpp index 41912d9b..3e0a4843 100644 --- a/piiodevice.cpp +++ b/piiodevice.cpp @@ -20,6 +20,45 @@ #include "piiodevice.h" +/*! \class PIIODevice + * \brief Base class for input/output classes + * + * \section PIIODevice_sec0 Synopsis + * This class provide open/close logic, threaded read and virtual input/output + * functions \a read() and \a write(). You should implement pure virtual + * function \a openDevice() in your subclass. + * + * \section PIIODevice_sec1 Open and close + * PIIODevice have boolean variable indicated open status. Returns of functions + * \a openDevice() and \a closeDevice() change this variable. + * + * \section PIIODevice_sec2 Threaded read + * PIIODevice based on PIThread, so it`s overload \a run() to exec \a read() + * in background thread. If read is successful virtual function \a threadedRead() + * is executed. Default implementation of this function execute external static + * function set by \a setThreadedReadSlot() with data set by \a setThreadedReadData(). + * Extrenal static function should have format \n + * bool func_name(void * Threaded_read_data, uchar * readed_data, int readed_size)\n + * Threaded read starts with function \a startThreadedRead(). + * + * \section PIIODevice_sec3 Internal buffer + * PIIODevice have internal buffer for threaded read, and \a threadedRead() function + * receive pointer to this buffer in first argument. You can adjust size of this buffer + * by function \a setThreadedReadBufferSize() \n + * Default size of this buffer is 4096 bytes + * + * \section PIIODevice_sec4 Reopen + * When threaded read is begin its call \a open() if device is closed. While threaded + * read running PIIODevice check if device opened every read and if not call \a open() + * every reopen timeout if reopen enabled. Reopen timeout is set by \a setReopenTimeout(), + * reopen enable is set by \a setReopenEnabled(). + * + * \section PIIODevice_ex0 Example + * \snippet piiodevice.cpp 0 + */ + + +//! Constructs a empty PIIODevice PIIODevice::PIIODevice(): PIThread() { mode_ = ReadOnly; opened_ = init_ = thread_started_ = false; @@ -27,12 +66,18 @@ PIIODevice::PIIODevice(): PIThread() { reopen_timeout_ = 1000; ret_func_ = 0; ret_data_ = 0; + tri = 0; buffer_tr.resize(4096); CONNECT2(void, void * , int, &timer, timeout, this, check_start); + CONNECT(void, &write_thread, started, this, write_func); init(); } +/*! \brief Constructs a PIIODevice with path and mode + * \param path path to device + * \param type mode for open + * \param initNow init or not in constructor */ PIIODevice::PIIODevice(const PIString & path, PIIODevice::DeviceMode type, bool initNow): PIThread() { path_ = path; mode_ = type; @@ -41,8 +86,10 @@ PIIODevice::PIIODevice(const PIString & path, PIIODevice::DeviceMode type, bool reopen_timeout_ = 1000; ret_func_ = 0; ret_data_ = 0; + tri = 0; buffer_tr.resize(4096); CONNECT2(void, void * , int, &timer, timeout, this, check_start); + CONNECT(void, &write_thread, started, this, write_func); if (initNow) init(); } @@ -56,6 +103,21 @@ void PIIODevice::check_start(void * data, int delim) { } +void PIIODevice::write_func() { + while (!write_thread.isStopping()) { + while (!write_queue.isEmpty()) { + if (write_thread.isStopping()) return; + write_thread.lock(); + PIPair item(write_queue.dequeue()); + write_thread.unlock(); + int ret = write(item.first); + threadedWriteEvent(item.second, ret); + } + msleep(1); + } +} + + void PIIODevice::terminate() { thread_started_ = false; if (!isInitialized()) return; @@ -103,4 +165,14 @@ void PIIODevice::run() { return; } threadedRead(buffer_tr.data(), readed_); + threadedReadEvent(buffer_tr.data(), readed_); +} + + +ullong PIIODevice::writeThreaded(const PIByteArray & data) { + write_thread.lock(); + write_queue.enqueue(PIPair(data, tri)); + ++tri; + write_thread.unlock(); + return tri - 1; } diff --git a/piiodevice.h b/piiodevice.h index bc8b7181..47692c7f 100644 --- a/piiodevice.h +++ b/piiodevice.h @@ -1,3 +1,6 @@ +/*! \file piiodevice.h + * \brief Abstract input/output device +*/ /* PIP - Platform Independent Primitives Abstract input/output device @@ -25,36 +28,59 @@ // function executed from threaded read, pass ThreadedReadData, readedData, sizeOfData typedef bool (*ReadRetFunc)(void * , uchar * , int ); -/// events: -/// void opened() -/// void closed() -/// -/// handlers: -/// bool open() -/// bool open(const PIString & path) -/// bool open(const DeviceMode & type) -/// bool open(const PIString & path, const DeviceMode & type) -/// bool close() -/// bool initialize() -/// void flush() -class PIIODevice: public PIThread { +// events: +// void opened() +// void closed() +// +// handlers: +// bool open() +// bool open(const PIString & path) +// bool open(const DeviceMode & type) +// bool open(const PIString & path, const DeviceMode & type) +// bool close() +// bool initialize() +// void flush() + +class PIP_EXPORT PIIODevice: public PIThread +{ + PIOBJECT(PIIODevice) public: PIIODevice(); - enum DeviceMode {ReadOnly = 0x01, WriteOnly = 0x02, ReadWrite = 0x03}; + //! \brief Open modes for PIIODevice + enum DeviceMode { + ReadOnly /*! Device can only read */ = 0x01, + WriteOnly /*! Device can only write */ = 0x02, + ReadWrite /*! Device can both read and write */ = 0x03 + }; PIIODevice(const PIString & path, DeviceMode type = ReadWrite, bool initNow = true); - virtual ~PIIODevice() {if (opened_) {closeDevice(); if (!opened_) closed();}} - + virtual ~PIIODevice() {stop(); write_thread.stop(); if (opened_) {closeDevice(); if (!opened_) closed();}} + //! Current open mode of device DeviceMode mode() const {return mode_;} + + //! Current path of device PIString path() const {return path_;} + + //! return \b true if mode is ReadOnly or ReadWrite bool isReadable() const {return (mode_ & ReadOnly);} + + //! return \b true if mode is WriteOnly or ReadWrite bool isWriteable() const {return (mode_ & WriteOnly);} + bool isInitialized() const {return init_;} + + //! return \b true if device is successfully opened bool isOpened() const {return opened_;} + + //! return \b true if device is closed bool isClosed() const {return !opened_;} + + //! return \b true if device can read \b now bool canRead() const {return opened_ && (mode_ & ReadOnly);} + + //! return \b true if device can write \b now bool canWrite() const {return opened_ && (mode_ & WriteOnly);} @@ -74,34 +100,83 @@ public: int threadedReadBufferSize() const {return buffer_tr.size_s();} const uchar * threadedReadBuffer() const {return buffer_tr.data();} + bool isThreadedRead() const {return isRunning();} void startThreadedRead() {if (!isRunning()) start();} void startThreadedRead(ReadRetFunc func) {ret_func_ = func; if (!isRunning()) start();} - - EVENT_HANDLER(PIIODevice, bool, open) {if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;} - EVENT_HANDLER1(PIIODevice, bool, open, const PIString &, _path) {path_ = _path; if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;} - EVENT_HANDLER1(PIIODevice, bool, open, const DeviceMode &, _type) {mode_ = _type; if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;} - EVENT_HANDLER2(PIIODevice, bool, open, const PIString &, _path, const DeviceMode &, _type) {path_ = _path; mode_ = _type; if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;} - EVENT_HANDLER(PIIODevice, bool, close) {opened_ = !closeDevice(); if (!opened_) closed(); return !opened_;} - EVENT_HANDLER(PIIODevice, bool, initialize) {init_ = init(); return init_;} - - // Flush device - EVENT_VHANDLER(PIIODevice, void, flush) {;} - - EVENT(PIIODevice, opened) - EVENT(PIIODevice, closed) + + bool isThreadedWrite() const {return write_thread.isRunning();} + void startThreadedWrite() {if (!write_thread.isRunning()) write_thread.startOnce();} + void stopThreadedWrite() {write_thread.stop();} + void clearThreadedWriteQueue() {write_thread.lock(); write_queue.clear(); write_thread.unlock();} // Read from device to "read_to" maximum "max_size" bytes, return readed bytes count - virtual int read(void * read_to, int max_size) {piCout << "[PIIODevice] \"read\" not implemented!" << endl; return -2;} + virtual int read(void * read_to, int max_size) {piCout << "[PIIODevice] \"read\" not implemented!"; return -2;} // Write to device "data" maximum "max_size" bytes, return written bytes count - virtual int write(const void * data, int max_size) {piCout << "[PIIODevice] \"write\" not implemented!" << endl; return -2;} + virtual int write(const void * data, int max_size) {piCout << "[PIIODevice] \"write\" not implemented!"; return -2;} // Read from device maximum "max_size" bytes and return them as PIByteArray PIByteArray read(int max_size) {buffer_in.resize(max_size); int ret = read(buffer_in.data(), max_size); if (ret < 0) return PIByteArray(); return buffer_in.resized(ret);} int write(const PIByteArray & data) {return write(data.data(), data.size_s());} + + ullong writeThreaded(const void * data, int max_size) {return writeThreaded(PIByteArray(data, uint(max_size)));} + ullong writeThreaded(const PIByteArray & data); + EVENT_HANDLER(bool, open) {if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;} + EVENT_HANDLER1(bool, open, const PIString &, _path) {path_ = _path; if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;} + EVENT_HANDLER1(bool, open, const DeviceMode &, _type) {mode_ = _type; if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;} + EVENT_HANDLER2(bool, open, const PIString &, _path, const DeviceMode &, _type) {path_ = _path; mode_ = _type; if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;} + EVENT_HANDLER(bool, close) {opened_ = !closeDevice(); if (!opened_) closed(); return !opened_;} + EVENT_HANDLER(bool, initialize) {init_ = init(); return init_;} + + EVENT_VHANDLER(void, flush) {;} + + EVENT(opened) + EVENT(closed) + EVENT2(threadedReadEvent, uchar * , readed, int, size) + EVENT2(threadedWriteEvent, ullong, id, int, written_size) + +//! \handlers +//! \{ + + //! \fn bool open() + //! \brief Open device + + //! \fn bool open(const PIString & path) + //! \brief Open device with path "path" + + //! \fn bool open(const DeviceMode & mode) + //! \brief Open device with mode "mode" + + //! \fn bool open(const PIString & path, const DeviceMode & mode) + //! \brief Open device with path "path" and mode "mode" + +//! \} +//! \vhandlers +//! \{ + + //! \fn void flush() + //! \brief Immediate write all buffers + +//! \} +//! \events +//! \{ + + //! \fn void opened() + //! \brief Raise if succesfull open + + //! \fn void closed() + //! \brief Raise if succesfull close + + //! \fn void threadedReadEvent(uchar * readed, int size) + //! \brief Raise if read thread succesfull read some data + + //! \fn void threadedWriteEvent(ullong id, int written_size) + //! \brief Raise if write thread succesfull write some data of queue item with id "id" + +//! \} protected: // Function executed before first openDevice() or from constructor @@ -124,14 +199,18 @@ protected: void * ret_data_; private: - EVENT_HANDLER2(PIIODevice, void, check_start, void * , data, int, delim); + EVENT_HANDLER2(void, check_start, void * , data, int, delim); + EVENT_HANDLER(void, write_func); void begin(); void run(); void end() {terminate();} PITimer timer; + PIThread write_thread; PIByteArray buffer_in, buffer_tr; + PIQueue > write_queue; + ullong tri; int readed_; }; diff --git a/pikbdlistener.cpp b/pikbdlistener.cpp index 3fc84153..cd364a95 100644 --- a/pikbdlistener.cpp +++ b/pikbdlistener.cpp @@ -42,8 +42,8 @@ PIKbdListener::PIKbdListener(KBFunc slot, void * data_): PIThread() { void PIKbdListener::begin() { //cout << "list begin" << endl; #ifdef WINDOWS - SetConsoleMode(hIn, ENABLE_PROCESSED_INPUT); GetConsoleMode(hIn, &tmode); + SetConsoleMode(hIn, ENABLE_PROCESSED_INPUT); #else struct termios term; tcgetattr(0, &term); @@ -55,17 +55,68 @@ void PIKbdListener::begin() { void PIKbdListener::run() { + rc = 0; + char lc = 0; #ifdef WINDOWS - ReadConsole(hIn, &rc, 1, &ret, 0); + INPUT_RECORD ir; + ReadConsoleInput(hIn, &ir, 1, &ret); + if (ir.EventType == KEY_EVENT) { + KEY_EVENT_RECORD ker = ir.Event.KeyEvent; + if (ker.bKeyDown) { + bool ctrl = ((ker.dwControlKeyState & LEFT_CTRL_PRESSED) || (ker.dwControlKeyState & RIGHT_CTRL_PRESSED)); + //cout << "key " << int(ker.wVirtualKeyCode) << endl; + switch (ker.wVirtualKeyCode) { + case 37: ret = 1; lc = (ctrl ? CtrlLeftArrow : LeftArrow); break; + case 38: ret = 1; lc = (ctrl ? CtrlUpArrow : UpArrow); break; + case 39: ret = 1; lc = (ctrl ? CtrlRightArrow : RightArrow); break; + case 40: ret = 1; lc = (ctrl ? CtrlDownArrow : DownArrow); break; + default: ret = 1; lc = ker.uChar.AsciiChar; break; + } + if (lc == 0) return; + } else return; + } else return; + /*if (lc == 0) { + ReadConsole(hIn, &rc, 1, &ret, 0); + //cout << "read console" << endl; + lc = char(rc); + }*/ + /*if (ret < 0 || ret > 3) return; + lc = char(((uchar * )&rc)[ret - 1]); + for (int i = 0; i < ret; ++i) + cout << std::hex << int(((uchar * )&rc)[i]) << ' '; + cout << endl << std::hex << rc << endl;*/ #else - ret = read(0, &rc, 1); + ret = read(0, &rc, 4); + if (ret < 0 || ret > 3) return; + lc = char(((uchar * )&rc)[ret - 1]); + //for (int i = 0; i < ret; ++i) + // cout << std::hex << int(((uchar * )&rc)[i]) << ' '; + //cout << endl << std::hex << rc << endl; + if (((char * )&rc)[0] == '\e' && ret == 3) { + if (((char * )&rc)[1] == '[') { + switch (((char * )&rc)[2]) { + case 'A': lc = UpArrow; break; // up + case 'B': lc = DownArrow; break; // down + case 'C': lc = RightArrow; break; // right + case 'D': lc = LeftArrow; break; // left + } + } + } + if (((char * )&rc)[0] == '5' && ret == 2) { + switch (((char * )&rc)[1]) { + case 'A': lc = CtrlUpArrow; break; // up + case 'B': lc = CtrlDownArrow; break; // down + case 'C': lc = CtrlRightArrow; break; // right + case 'D': lc = CtrlLeftArrow; break; // left + } + } #endif - if (exit_enabled && rc == exit_key) { + if (exit_enabled && ret == 1 && lc == exit_key) { PIKbdListener::exiting = true; return; } - keyPressed(rc, data); - if (ret_func != 0 && ret > 0) ret_func(rc, data); + keyPressed(lc, data); + if (ret_func != 0 && ret > 0) ret_func(lc, data); } diff --git a/pikbdlistener.h b/pikbdlistener.h index 9d122477..508439e3 100644 --- a/pikbdlistener.h +++ b/pikbdlistener.h @@ -35,25 +35,38 @@ typedef void (*KBFunc)(char, void * ); /// handlers: /// void enableExitCapture(char key = 'Q') /// void setActive(bool yes = true) -class PIKbdListener: public PIThread { +class PIP_EXPORT PIKbdListener: public PIThread +{ + PIOBJECT(PIKbdListener) friend class PIConsole; public: + enum SpecialSymbol { + UpArrow = -1, + DownArrow = -2, + RightArrow = -3, + LeftArrow = -4, + CtrlUpArrow = -5, + CtrlDownArrow = -6, + CtrlRightArrow = -7, + CtrlLeftArrow = -8 + }; + // slot is any function format "void (char, void * )" PIKbdListener(KBFunc slot = 0, void * data = 0); ~PIKbdListener() {terminate(); end();} void setData(void * data_) {data = data_;} void setSlot(KBFunc slot_) {ret_func = slot_;} - EVENT_HANDLER(PIKbdListener, void, enableExitCapture) {enableExitCapture('Q');} - EVENT_HANDLER1(PIKbdListener, void, enableExitCapture, char, key) {exit_enabled = true; exit_key = key;} + EVENT_HANDLER( void, enableExitCapture) {enableExitCapture('Q');} + EVENT_HANDLER1(void, enableExitCapture, char, key) {exit_enabled = true; exit_key = key;} void disableExitCapture() {exit_enabled = false;} bool exitCaptured() const {return exit_enabled;} char exitKey() const {return exit_key;} bool isActive() {return is_active;} - EVENT_HANDLER(PIKbdListener, void, setActive) {setActive(true);} - EVENT_HANDLER1(PIKbdListener, void, setActive, bool, yes); + EVENT_HANDLER(void, setActive) {setActive(true);} + EVENT_HANDLER1(void, setActive, bool, yes); - EVENT2(PIKbdListener, keyPressed, char, key, void * , data) + EVENT2(keyPressed, char, key, void * , data) static bool exiting; @@ -61,6 +74,8 @@ private: void begin(); void run(); void end(); + + void raiseSpecial(); KBFunc ret_func; char exit_key; @@ -71,7 +86,7 @@ private: void * hIn; DWORD smode, tmode; #else - char rc; + int rc; int ret; struct termios sterm, tterm; #endif diff --git a/pimath.h b/pimath.h index 94838ddd..2a4a7cbf 100644 --- a/pimath.h +++ b/pimath.h @@ -96,16 +96,18 @@ inline double fromDb(double val) {return pow(10., val / 10.);} inline double toRad(double deg) {return deg * M_PI_180;} inline double toDeg(double rad) {return rad * M_180_PI;} -inline PIVector abs(const PIVector &v) { +inline PIVector abs(const PIVector & v) { PIVector result; result.resize(v.size()); - for(uint i=0; i abs(const PIVector &v) { +inline PIVector abs(const PIVector & v) { PIVector result; result.resize(v.size()); - for(uint i=0; i -class PIMathVectorT { +class PIP_EXPORT PIMathVectorT { typedef PIMathVectorT _CVector; public: PIMathVectorT() {resize(Size);} @@ -139,7 +141,7 @@ public: Type angleCos(const _CVector & v) const {Type tv = v.length() * length(); return (tv == Type(0) ? Type(0) : ((*this) ^ v) / tv);} Type angleSin(const _CVector & v) const {Type tv = angleCos(v); return sqrt(Type(1) - tv * tv);} Type angleRad(const _CVector & v) const {return acos(angleCos(v));} - Type angleDeg(const _CVector & v) const {return toGrad(acos(angleCos(v)));} + Type angleDeg(const _CVector & v) const {return toDeg(acos(angleCos(v)));} _CVector projection(const _CVector & v) {Type tv = v.length(); return (tv == Type(0) ? _CVector() : v * (((*this) ^ v) / tv));} _CVector & normalize() {Type tv = length(); if (tv == Type(1)) return *this; PIMV_FOR(i, 0) c[i] /= tv; return *this;} _CVector normalized() {_CVector tv(*this); tv.normalize(); return tv;} @@ -207,7 +209,7 @@ typedef PIMathVectorT<4u, double> PIMathVectorT4d; #define PIMM_FOR_R(v) for (uint v = 0; v < Rows; ++v) template -class PIMathMatrixT { +class PIP_EXPORT PIMathMatrixT { typedef PIMathMatrixT _CMatrix; typedef PIMathMatrixT _CMatrixI; typedef PIMathVectorT _CMCol; @@ -417,7 +419,7 @@ class PIMathMatrix; #define PIMV_FOR(v, s) for (uint v = s; v < size_; ++v) template -class PIMathVector { +class PIP_EXPORT PIMathVector { typedef PIMathVector _CVector; public: PIMathVector(const uint size = 3) {resize(size);} @@ -440,7 +442,7 @@ public: Type angleCos(const _CVector & v) const {Type tv = v.length() * length(); return (tv == Type(0) ? Type(0) : ((*this) ^ v) / tv);} Type angleSin(const _CVector & v) const {Type tv = angleCos(v); return sqrt(Type(1) - tv * tv);} Type angleRad(const _CVector & v) const {return acos(angleCos(v));} - Type angleDeg(const _CVector & v) const {return toGrad(acos(angleCos(v)));} + Type angleDeg(const _CVector & v) const {return toDeg(acos(angleCos(v)));} _CVector projection(const _CVector & v) {Type tv = v.length(); return (tv == Type(0) ? _CVector() : v * (((*this) ^ v) / tv));} _CVector & normalize() {Type tv = length(); if (tv == Type(1)) return *this; PIMV_FOR(i, 0) c[i] /= tv; return *this;} _CVector normalized() {_CVector tv(*this); tv.normalize(); return tv;} @@ -499,7 +501,7 @@ typedef PIMathVector PIMathVectord; #define PIMM_FOR_R(v) for (uint v = 0; v < rows_; ++v) template -class PIMathMatrix { +class PIP_EXPORT PIMathMatrix { typedef PIMathMatrix _CMatrix; typedef PIMathVector _CMCol; typedef PIMathVector _CMRow; @@ -716,7 +718,7 @@ struct TransferFunction { // Для задания передаточной фу // Эйлера // Рунге-Кутта 4-го порядка // Адамса-Бэшфортса-Моултона 2, 3, 4 порядков -class Solver +class PIP_EXPORT Solver { public: enum Method {Global = -1, @@ -774,7 +776,7 @@ private: -class PIFFT +class PIP_EXPORT PIFFT { public: PIFFT(); @@ -827,7 +829,7 @@ private: }; -class PIStatistic { +class PIP_EXPORT PIStatistic { public: PIStatistic(); bool calculate(const PIVector &val); diff --git a/pimonitor.h b/pimonitor.h index 34aab13a..95f4f8e9 100644 --- a/pimonitor.h +++ b/pimonitor.h @@ -20,7 +20,14 @@ #ifndef PIMONITOR_H #define PIMONITOR_H -class PIMonitor +#include "pip_export.h" + +#if defined(DOXYGEN) || defined(__GNUC__) +# undef PIP_EXPORT +# define PIP_EXPORT +#endif + +class PIP_EXPORT PIMonitor { public: PIMonitor(); diff --git a/pimultiprotocol.h b/pimultiprotocol.h index c045de1b..362fd357 100644 --- a/pimultiprotocol.h +++ b/pimultiprotocol.h @@ -64,12 +64,12 @@ public: PIRepeater(const PIString & config, const PIString & name) { PIConfig conf(config, PIIODevice::ReadOnly); if (!conf.isOpened()) { - piCout << "[PIRepeater \"" << name << "\"] Can`t open \"" << config << "\"!" << endl; + piCout << "[PIRepeater \"" << name << "\"] Can`t open \"" << config << "\"!"; return; } PIConfig::Entry & b(conf.getValue(name)); if (b.childCount() != 2) { - piCout << "[PIRepeater \"" << name << "\"] \"" << config << "\" should consist 2 nodes!" << endl; + piCout << "[PIRepeater \"" << name << "\"] \"" << config << "\" should consist 2 nodes!"; return; } addProtocol(config, b.child(0)->fullName()); diff --git a/pimutex.h b/pimutex.h index 43d5930e..b7c68bdd 100644 --- a/pimutex.h +++ b/pimutex.h @@ -21,11 +21,11 @@ #define PIMUTEX_H #include "piincludes.h" -#ifdef CC_GCC -#include +#ifndef WINDOWS +# include #endif -class PIMutex +class PIP_EXPORT PIMutex { public: #ifndef WINDOWS @@ -59,7 +59,8 @@ private: }; -class PIMutexLocker + +class PIP_EXPORT PIMutexLocker { public: PIMutexLocker(PIMutex * m): mutex(m) {mutex->lock();} diff --git a/piobject.h b/piobject.h index 8005898f..58cc2185 100644 --- a/piobject.h +++ b/piobject.h @@ -1,3 +1,8 @@ +/*! \file piobject.h + * \brief Base object + * + * This file declare PIObject class and associated macros +*/ /* PIP - Platform Independent Primitives Object, base class of some PIP classes, provide EVENT -> EVENT_HANDLER mechanism @@ -22,31 +27,166 @@ #include "pistring.h" -/// declare event handler \"event\" inside class \"obj\" with name \"name\", ret name() -#define EVENT_HANDLER0(obj, ret, name) static ret __stat_eh_##name##__(void * o) {return ((obj*)o)->name();} ret name() -#define EVENT_HANDLER1(obj, ret, name, a0, n0) static ret __stat_eh_##name##__(void * o, a0 n0) {return ((obj*)o)->name(n0);} ret name(a0 n0) -#define EVENT_HANDLER2(obj, ret, name, a0, n0, a1, n1) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1) {return ((obj*)o)->name(n0, n1);} ret name(a0 n0, a1 n1) -#define EVENT_HANDLER3(obj, ret, name, a0, n0, a1, n1, a2, n2) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2) {return ((obj*)o)->name(n0, n1, n2);} ret name(a0 n0, a1 n1, a2 n2) -#define EVENT_HANDLER4(obj, ret, name, a0, n0, a1, n1, a2, n2, a3, n3) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2, a3 n3) {return ((obj*)o)->name(n0, n1, n2, n3);} ret name(a0 n0, a1 n1, a2 n2, a3 n3) + +#ifdef DOXYGEN + + +/// \relatesalso PIObject \brief you should use this macro after class declaration to use EVENT and EVENT_HANDLER +#define PIOBJECT(name) + + +/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\", ret name() +#define EVENT_HANDLER0(ret, name) ret name() + +/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\", ret name(type0 var0) +#define EVENT_HANDLER1(ret, name, type0, var0) ret name(type0 var0) + +/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\", ret name(type0 var0, type1 var1) +#define EVENT_HANDLER2(ret, name, type0, var0, type1, var1) ret name(type0 var0, type1 var1) + +/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\", ret name(type0 var0, type1 var1, type2 var2) +#define EVENT_HANDLER3(ret, name, type0, var0, type1, var1, type2, var2) ret name(type0 var0, type1 var1, type2 var2) + +/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\", ret name(type0 var0, type1 var1, type2 var2, type3 var3) +#define EVENT_HANDLER4(ret, name, type0, var0, type1, var1, type2, var2, type3, var3) ret name(type0 var0, type1 var1, type2 var2, type3 var3) + +/// \relatesalso PIObject \brief EVENT_HANDLER is synonym of EVENT_HANDLER0 #define EVENT_HANDLER EVENT_HANDLER0 -/// declare virtual event handler \"event\" inside class \"obj\" with name \"name\", virtual ret name() -#define EVENT_VHANDLER0(obj, ret, name) static ret __stat_eh_##name##__(void * o) {return ((obj*)o)->name();} virtual ret name() -#define EVENT_VHANDLER1(obj, ret, name, a0, n0) static ret __stat_eh_##name##__(void * o, a0 n0) {return ((obj*)o)->name(n0);} virtual ret name(a0 n0) -#define EVENT_VHANDLER2(obj, ret, name, a0, n0, a1, n1) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1) {return ((obj*)o)->name(n0, n1);} virtual ret name(a0 n0, a1 n1) -#define EVENT_VHANDLER3(obj, ret, name, a0, n0, a1, n1, a2, n2) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2) {return ((obj*)o)->name(n0, n1, n2);} virtual ret name(a0 n0, a1 n1, a2 n2) -#define EVENT_VHANDLER4(obj, ret, name, a0, n0, a1, n1, a2, n2, a3, n3) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2, a3 n3) {return ((obj*)o)->name(n0, n1, n2, n3);} virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3) + +/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\", virtual ret name() +#define EVENT_VHANDLER0(ret, name) virtual ret name() + +/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\", virtual ret name(type0 var0) +#define EVENT_VHANDLER1(ret, name, type0, var0) virtual ret name(type0 var0) + +/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\", virtual ret name(type0 var0, type1 var1) +#define EVENT_VHANDLER2(ret, name, type0, var0, type1, var1) virtual ret name(type0 var0, type1 var1) + +/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\", virtual ret name(type0 var0, type1 var1, type2 var2) +#define EVENT_VHANDLER3(ret, name, type0, var0, type1, var1, type2, var2) virtual ret name(type0 var0, type1 var1, type2 var2) + +/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\", virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3) +#define EVENT_VHANDLER4(ret, name, type0, var0, type1, var1, type2, var2, type3, var3) virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3) + +/// \relatesalso PIObject \brief EVENT_VHANDLER is synonym of EVENT_VHANDLER0 #define EVENT_VHANDLER EVENT_VHANDLER0 -/// declare event \"event\" inside class \"obj\" with name \"name\", void name(); -#define EVENT0(obj, name) EVENT_HANDLER0(obj, void, name) {PIObject::raiseEvent(this, #name);} -#define EVENT1(obj, name, a0, n0) EVENT_HANDLER1(obj, void, name, a0, n0) {PIObject::raiseEvent(this, #name, n0);} -#define EVENT2(obj, name, a0, n0, a1, n1) EVENT_HANDLER2(obj, void, name, a0, n0, a1, n1) {PIObject::raiseEvent(this, #name, n0, n1);} -#define EVENT3(obj, name, a0, n0, a1, n1, a2, n2) EVENT_HANDLER3(obj, void, name, a0, n0, a1, n1, a2, n2) {PIObject::raiseEvent(this, #name, n0, n1, n2);} -#define EVENT4(obj, name, a0, n0, a1, n1, a2, n2, a3, n3) EVENT_HANDLER4(obj, void, name, a0, n0, a1, n1, a2, n2, a3, n3) {PIObject::raiseEvent(this, #name, n0, n1, n2, n3);} + +/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(); +#define EVENT0(name) void name(); + +/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0); +#define EVENT1(name, type0, var0) void name(type0 var0); + +/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1); +#define EVENT2(name, type0, var0, type1, var1) void name(type0 var0, type1 var1); + +/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1, type2 var2); +#define EVENT3(name, type0, var0, type1, var1, type2, var2) void name(type0 var0, type1 var1, type2 var2); + +/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1, type2 var2, type3 var3); +#define EVENT4(name, type0, var0, type1, var1, type2, var2, type3, var3) void name(type0 var0, type1 var1, type2 var2, type3 var3); + +/// \relatesalso PIObject \brief EVENT is synonym of EVENT0 +#define EVENT EVENT0 + + +#define RAISE_EVENT0(src, event) +#define RAISE_EVENT1(src, event, v0) +#define RAISE_EVENT2(src, event, v0, v1) +#define RAISE_EVENT3(src, event, v0, v1, v2) +#define RAISE_EVENT4(src, event, v0, v1, v2, v3) +#define RAISE_EVENT RAISE_EVENT0 + + +/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" from object \"dest\" with check of event and handler exists +#define CONNECT0(ret, src, event, dest, handler) + +/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" from object \"dest\" with check of event and handler exists +#define CONNECT1(ret, type0, src, event, dest, handler) + +/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" from object \"dest\" with check of event and handler exists +#define CONNECT2(ret, type0, type1, src, event, dest, handler) + +/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" from object \"dest\" with check of event and handler exists +#define CONNECT3(ret, type0, type1, type2, src, event, dest, handler) + +/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" from object \"dest\" with check of event and handler exists +#define CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler) + +/// \relatesalso PIObject \brief CONNECT is synonym of CONNECT0 +#define CONNECT CONNECT0 + + +/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" from object \"dest\" without check of event exists +#define WEAK_CONNECT0(ret, src, event, dest, handler) + +/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" from object \"dest\" without check of event exists +#define WEAK_CONNECT1(ret, type0, src, event, dest, handler) + +/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" from object \"dest\" without check of event exists +#define WEAK_CONNECT2(ret, type0, type1, src, event, dest, handler) + +/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" from object \"dest\" without check of event exists +#define WEAK_CONNECT3(ret, type0, type1, type2, src, event, dest, handler) + +/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" from object \"dest\" without check of event exists +#define WEAK_CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler) + +/// \relatesalso PIObject \brief WEAK_CONNECT is synonym of WEAK_CONNECT0 +#define WEAK_CONNECT WEAK_CONNECT0 + + +/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" from object \"dest\" +#define DISCONNECT0(ret, src, event, dest, handler) + +/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" from object \"dest\" +#define DISCONNECT1(ret, type0, src, event, dest, handler) + +/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" from object \"dest\" +#define DISCONNECT2(ret, type0, type1, src, event, dest, handler) + +/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" from object \"dest\" +#define DISCONNECT3(ret, type0, type1, type2, src, event, dest, handler) + +/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" from object \"dest\" +#define DISCONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler) + +/// \relatesalso PIObject \brief DISCONNECT is synonym of DISCONNECT0 +#define DISCONNECT DISCONNECT0 + + +/// \relatesalso PIObject \brief Returns pointer to events handler \"handler\" +#define HANDLER(handler) + + +#else + + +#define PIOBJECT(obj) typedef obj __PIObject__; + +#define EVENT_HANDLER0(ret, name) static ret __stat_eh_##name##__(void * o) {return ((__PIObject__*)o)->name();} ret name() +#define EVENT_HANDLER1(ret, name, a0, n0) static ret __stat_eh_##name##__(void * o, a0 n0) {return ((__PIObject__*)o)->name(n0);} ret name(a0 n0) +#define EVENT_HANDLER2(ret, name, a0, n0, a1, n1) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1) {return ((__PIObject__*)o)->name(n0, n1);} ret name(a0 n0, a1 n1) +#define EVENT_HANDLER3(ret, name, a0, n0, a1, n1, a2, n2) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2) {return ((__PIObject__*)o)->name(n0, n1, n2);} ret name(a0 n0, a1 n1, a2 n2) +#define EVENT_HANDLER4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2, a3 n3) {return ((__PIObject__*)o)->name(n0, n1, n2, n3);} ret name(a0 n0, a1 n1, a2 n2, a3 n3) +#define EVENT_HANDLER EVENT_HANDLER0 + +#define EVENT_VHANDLER0(ret, name) static ret __stat_eh_##name##__(void * o) {return ((__PIObject__*)o)->name();} virtual ret name() +#define EVENT_VHANDLER1(ret, name, a0, n0) static ret __stat_eh_##name##__(void * o, a0 n0) {return ((__PIObject__*)o)->name(n0);} virtual ret name(a0 n0) +#define EVENT_VHANDLER2(ret, name, a0, n0, a1, n1) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1) {return ((__PIObject__*)o)->name(n0, n1);} virtual ret name(a0 n0, a1 n1) +#define EVENT_VHANDLER3(ret, name, a0, n0, a1, n1, a2, n2) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2) {return ((__PIObject__*)o)->name(n0, n1, n2);} virtual ret name(a0 n0, a1 n1, a2 n2) +#define EVENT_VHANDLER4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2, a3 n3) {return ((__PIObject__*)o)->name(n0, n1, n2, n3);} virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3) +#define EVENT_VHANDLER EVENT_VHANDLER0 + +#define EVENT0(name) EVENT_HANDLER0(void, name) {PIObject::raiseEvent(this, #name);} +#define EVENT1(name, a0, n0) EVENT_HANDLER1(void, name, a0, n0) {PIObject::raiseEvent(this, #name, n0);} +#define EVENT2(name, a0, n0, a1, n1) EVENT_HANDLER2(void, name, a0, n0, a1, n1) {PIObject::raiseEvent(this, #name, n0, n1);} +#define EVENT3(name, a0, n0, a1, n1, a2, n2) EVENT_HANDLER3(void, name, a0, n0, a1, n1, a2, n2) {PIObject::raiseEvent(this, #name, n0, n1, n2);} +#define EVENT4(name, a0, n0, a1, n1, a2, n2, a3, n3) EVENT_HANDLER4(void, name, a0, n0, a1, n1, a2, n2, a3, n3) {PIObject::raiseEvent(this, #name, n0, n1, n2, n3);} #define EVENT EVENT0 -/// raise event \"event\" from object \"src\" #define RAISE_EVENT0(src, event) (src)->event(); #define RAISE_EVENT1(src, event, v0) (src)->event(v0); #define RAISE_EVENT2(src, event, v0, v1) (src)->event(v0, v1); @@ -54,31 +194,62 @@ #define RAISE_EVENT4(src, event, v0, v1, v2, v3) (src)->event(v0, v1, v2, v3); #define RAISE_EVENT RAISE_EVENT0 -/// connect event \"event\" from object \"src\" to event handler \"handler\" from object \"dst\" with check of event and handler exists -#define CONNECT0(ret, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*))(&(dst)->__stat_eh_##handler##__), (void*)(void(*)(void*))(&(src)->__stat_eh_##event##__)); -#define CONNECT1(ret, a0, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0))(&(dst)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0))(&(src)->__stat_eh_##event##__)); -#define CONNECT2(ret, a0, a1, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1))(&(dst)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1))(&(src)->__stat_eh_##event##__)); -#define CONNECT3(ret, a0, a1, a2, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1, a2))(&(dst)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1, a2))(&(src)->__stat_eh_##event##__)); -#define CONNECT4(ret, a0, a1, a2, a3, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dst)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1, a2, a3))(&(src)->__stat_eh_##event##__)); +#define CONNECT0(ret, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*))(&(src)->__stat_eh_##event##__)); +#define CONNECT1(ret, a0, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0))(&(src)->__stat_eh_##event##__)); +#define CONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1))(&(src)->__stat_eh_##event##__)); +#define CONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1, a2))(&(src)->__stat_eh_##event##__)); +#define CONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1, a2, a3))(&(src)->__stat_eh_##event##__)); #define CONNECT CONNECT0 -/// connect event \"event\" from object \"src\" to event handler \"handler\" from object \"dst\" without check of event exists -#define WEAK_CONNECT0(ret, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*))(&(dst)->__stat_eh_##handler##__)); -#define WEAK_CONNECT1(ret, a0, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0))(&(dst)->__stat_eh_##handler##__)); -#define WEAK_CONNECT2(ret, a0, a1, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1))(&(dst)->__stat_eh_##handler##__)); -#define WEAK_CONNECT3(ret, a0, a1, a2, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1, a2))(&(dst)->__stat_eh_##handler##__)); -#define WEAK_CONNECT4(ret, a0, a1, a2, a3, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dst)->__stat_eh_##handler##__)); +#define WEAK_CONNECT0(ret, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__)); +#define WEAK_CONNECT1(ret, a0, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__)); +#define WEAK_CONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__)); +#define WEAK_CONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__)); +#define WEAK_CONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piConnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__)); #define WEAK_CONNECT WEAK_CONNECT0 -/// piDisconnect event \"event\" from object \"src\" from event handler \"handler\" from object \"dst\" -#define DISCONNECT0(ret, src, event, dst, handler) PIObject::piDisconnect(src, #event, dst, (void*)(ret(*)(void*))(&(dst)->__stat_eh_##handler##__)); -#define DISCONNECT1(ret, a0, src, event, dst, handler) PIObject::piDisconnect(src, #event, dst, (void*)(ret(*)(void*, a0))(&(dst)->__stat_eh_##handler##__)); -#define DISCONNECT2(ret, a0, a1, src, event, dst, handler) PIObject::piDisconnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1))(&(dst)->__stat_eh_##handler##__)); -#define DISCONNECT3(ret, a0, a1, a2, src, event, dst, handler) PIObject::piDisconnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1, a2))(&(dst)->__stat_eh_##handler##__)); -#define DISCONNECT4(ret, a0, a1, a2, a3, src, event, dst, handler) PIObject::piDisconnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dst)->__stat_eh_##handler##__)); +#define DISCONNECT0(ret, src, event, dest, handler) PIObject::piDisconnect(src, #event, dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__)); +#define DISCONNECT1(ret, a0, src, event, dest, handler) PIObject::piDisconnect(src, #event, dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__)); +#define DISCONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piDisconnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__)); +#define DISCONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piDisconnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__)); +#define DISCONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piDisconnect(src, #event, dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__)); #define DISCONNECT DISCONNECT0 -class PIObject +#define HANDLER(handler) __stat_eh_##handler##__ + +#endif + +typedef void (*Handler)(void * ); + +/** \brief This is base class for any classes which use events -> handlers mechanism. + * \details + * \section PIObject_sec0 Events and Event handlers + * %PIObject provide notification mechanism similar Qt but implemented + * on language capabilities without any special preprocessors or compilers. + * Any class inherits PIObject should use macro \a PIOBJECT() immediate + * after declaration to proper compile. + * + * Event is a some abstract event that can be raised at any time. + * Event is a function but declared with special macro \a EVENT(). + * To raise event simply execute event function. + * + * Event handler is a function but declared with special macro + * \a EVENT_HANDLER(). You can use event handlers as ordinary functions. + * + * Main goal of this mechanism is perform abstract connections between + * various objects. This functionality provide macro \a CONNECT() which + * connect some event of first object to some event handler or event of + * second object. Each event can be connected any times to any event handlers. + * + * Example: \snippet piobject.cpp main + * Result: + * \code{.cpp} + * handler B: 2 , 0.5 + * handler A: event to handler + * handler A: event to event + * \endcode + */ +class PIP_EXPORT PIObject { friend class PIObjectManager; public: @@ -133,7 +304,7 @@ public: slots_.insert(NamedFunction(func, name, PIStringList(typeid(T0).name(), typeid(T1).name(), typeid(T2).name(), typeid(T3).name())), name); } */ - /// Direct connect + // / Direct connect static void piConnect(PIObject * src, const PIString & sig, void * dest, void * ev_h) {src->connections << Connection(ev_h, 0, sig, dest);} static void piConnect(PIObject * src, const PIString & sig, void * dest, void * ev_h, void * e_h) {src->connections << Connection(ev_h, e_h, sig, dest);} static void piDisconnect(PIObject * src, const PIString & sig, void * dest, void * ev_h) { @@ -145,6 +316,25 @@ public: } } } + static void piDisconnect(PIObject * src, const PIString & sig, void * dest) { + for (int i = 0; i < src->connections.size_s(); ++i) { + Connection & cc(src->connections[i]); + if (cc.event == sig && cc.dest == dest) { + src->connections.remove(i); + i--; + } + } + } + static void piDisconnect(PIObject * src, const PIString & sig) { + for (int i = 0; i < src->connections.size_s(); ++i) { + Connection & cc(src->connections[i]); + if (cc.event == sig) { + src->connections.remove(i); + i--; + } + } + } + static void piDisconnect(PIObject * src) {src->connections.clear();} //static void piConnect(PIObject & src, const PIString & sig, PIObject * dest, void * ev_h) {src.connections << Connection(ev_h, sig, dest);} //static void piConnect(PIObject * src, const PIString & sig, PIObject & dest, void * ev_h) {src->connections << Connection(ev_h, sig, &dest);} //static void piConnect(PIObject & src, const PIString & sig, PIObject & dest, void * ev_h) {src.connections << Connection(ev_h, sig, &dest);} @@ -164,7 +354,7 @@ public: return PIObject::piConnect(src, event, dest, handler, force); }*/ - /// Raise events + // / Raise events static void raiseEvent(PIObject * sender, const PIString & event) { for (int j = 0; j < sender->connections.size_s(); ++j) { Connection & i(sender->connections[j]); @@ -226,7 +416,7 @@ public: destObject->raiseEvent(name, v0, v1, v2, v3); } */ - /// Raise events through manager + // / Raise events through manager static void raiseEvent(const PIString & destObject, const PIString & name) { PIObject * dest = findByName(destObject); if (dest == 0) { diff --git a/pip.h b/pip.h index bd1fb55b..d354cd9f 100644 --- a/pip.h +++ b/pip.h @@ -29,3 +29,4 @@ #include "pisystemmonitor.h" #include "pipeer.h" #include "picrc.h" +#include "pistatemachine.h" diff --git a/pip.pro b/pip.pro index 5731c7c9..19e49c2e 100644 --- a/pip.pro +++ b/pip.pro @@ -1,66 +1,83 @@ -###################################################################### -# Automatically generated by qmake (2.01a) ?? ???. 5 22:55:18 2011 -###################################################################### - -TEMPLATE = app -TARGET = pip_test -DEPENDPATH += . -INCLUDEPATH += . -QT -= core gui -LIBS = -lpthread -lrt - -# Input -HEADERS += pibitarray.h \ - pibytearray.h \ - pichar.h \ - picli.h \ - picodec.h \ - piconfig.h \ - piconsole.h \ - picontainers.h \ - pidir.h \ - piethernet.h \ - pievaluator.h \ - pifile.h \ - pigeometry.h \ - piincludes.h \ - pikbdlistener.h \ - pimath.h \ - pimonitor.h \ - pimultiprotocol.h \ - pimutex.h \ - piobject.h \ - pip.h \ - piprocess.h \ - piprotocol.h \ - piserial.h \ - pisignals.h \ - pistring.h \ - pisystemmonitor.h \ - pithread.h \ - pitimer.h \ - pivariable.h -SOURCES += main.cpp \ - pibytearray.cpp \ - picli.cpp \ - picodec.cpp \ - piconfig.cpp \ - piconsole.cpp \ - pidir.cpp \ - piethernet.cpp \ - pievaluator.cpp \ - pifile.cpp \ - pikbdlistener.cpp \ - pimath.cpp \ - pimonitor.cpp \ - pimultiprotocol.cpp \ - piobject.cpp \ - piprocess.cpp \ - piprotocol.cpp \ - piserial.cpp \ - pisignals.cpp \ - pistring.cpp \ - pisystemmonitor.cpp \ - pithread.cpp \ - pitimer.cpp \ - pivariable.cpp +###################################################################### +# Automatically generated by qmake (2.01a) ?? ???. 5 22:55:18 2011 +###################################################################### + +TEMPLATE = lib +TARGET = pip +DEPENDPATH += . +INCLUDEPATH += . +QT -= core gui +CONFIG -= qt +CONFIG += dll +VERSION = 0.3.4 + +# Input +HEADERS += \ + pivariable.h \ + pitimer.h \ + pithread.h \ + pisystemtests.h \ + pisystemmonitor.h \ + pistring.h \ + pisignals.h \ + piserial.h \ + piprotocol.h \ + piprocess.h \ + pipeer.h \ + pipacketextractor.h \ + pip.h \ + piobject.h \ + pimutex.h \ + pimultiprotocol.h \ + pimonitor.h \ + pimath.h \ + pikbdlistener.h \ + piiodevice.h \ + piincludes.h \ + pigeometry.h \ + pifile.h \ + pievaluator.h \ + piethernet.h \ + pidir.h \ + picrc.h \ + picontainers.h \ + piconsole.h \ + piconfig.h \ + picodec.h \ + picli.h \ + pichar.h \ + pibytearray.h \ + pibitarray.h +SOURCES += main.cpp \ + pivariable.cpp \ + pitimer.cpp \ + pithread.cpp \ + pisystemtests.cpp \ + pisystemmonitor.cpp \ + pistring.cpp \ + pisignals.cpp \ + piserial.cpp \ + piprotocol.cpp \ + piprocess.cpp \ + pipeer.cpp \ + pipacketextractor.cpp \ + piobject.cpp \ + pimonitor.cpp \ + pimath.cpp \ + pikbdlistener.cpp \ + piiodevice.cpp \ + piincludes.cpp \ + pifile.cpp \ + pievaluator.cpp \ + piethernet.cpp \ + pidir.cpp \ + piconsole.cpp \ + piconfig.cpp \ + picodec.cpp \ + picli.cpp \ + pibytearray.cpp +win32 { + LIBS += -lws2_32 -lIphlpapi +} else { + LIBS = -lpthread -lrt +} diff --git a/pipacketextractor.h b/pipacketextractor.h index a293caa6..ade0ad30 100644 --- a/pipacketextractor.h +++ b/pipacketextractor.h @@ -26,7 +26,7 @@ // Pass data, recHeaderPtr, received_data, recHeaderSize. Return true if packet is correct nor return false. typedef bool (*HeaderCheckFunc)(void * , uchar * , uchar * , int ); -class PIPacketExtractor: public PIIODevice +class PIP_EXPORT PIPacketExtractor: public PIIODevice { public: PIPacketExtractor(PIIODevice * device_ = 0, void * recHeaderPtr = 0, int recHeaderSize = 0, int recDataSize = 0); diff --git a/pipeer.h b/pipeer.h index db39a9b1..698000df 100644 --- a/pipeer.h +++ b/pipeer.h @@ -22,8 +22,9 @@ #include "piethernet.h" -class PIPeer: public PIEthernet +class PIP_EXPORT PIPeer: public PIEthernet { + PIOBJECT(PIPeer) struct PeerInfo; friend PIByteArray & operator <<(PIByteArray & s, const PIPeer::PeerInfo & v); friend PIByteArray & operator >>(PIByteArray & s, PIPeer::PeerInfo & v); @@ -37,7 +38,7 @@ protected: bool threadedRead(uchar * readed, int size); private: - EVENT_HANDLER2(PIPeer, void, timerEvent, void * , data, int, delim); + EVENT_HANDLER2(void, timerEvent, void * , data, int, delim); static bool func_readed(void * peer, uchar * data, int size); struct PeerInfo { diff --git a/piprocess.cpp b/piprocess.cpp index 4d944be6..537a8c54 100644 --- a/piprocess.cpp +++ b/piprocess.cpp @@ -141,12 +141,12 @@ void PIProcess::run() { WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); } else - piCout << "[PIProcess] \"CreateProcess\" error, " << errorString() << endl; + piCout << "[PIProcess] \"CreateProcess\" error, " << errorString(); #else //cout << "exec " << tf_in << ", " << tf_out << ", " << tf_err << endl; if (execve(str.c_str(), a, e) < 0) - piCout << "[PIProcess] \"execve\" error, " << errorString() << endl; + piCout << "[PIProcess] \"execve\" error, " << errorString(); } else { msleep(1); //cout << "wait" << endl; diff --git a/piprocess.h b/piprocess.h index aa1ea544..a3ddf923 100644 --- a/piprocess.h +++ b/piprocess.h @@ -40,11 +40,12 @@ /// bool exec(const PIString & program, const PIStringList & args) /// void terminate() /// bool waitForFinish(int timeout_msecs = 60000) -class PIProcess: private PIThread +class PIP_EXPORT PIProcess: private PIThread { + PIOBJECT(PIProcess) public: PIProcess(); - ~PIProcess(); + virtual ~PIProcess(); int exitCode() const {return exit_code;} #ifdef WINDOWS @@ -65,18 +66,18 @@ public: PIString workingDirectory() const {return wd;} void setWorkingDirectory(const PIString & path) {wd = path;} void resetWorkingDirectory() {wd.clear();} - EVENT_HANDLER1(PIProcess, void, exec, const PIString & , program) {args.clear(); args << program; exec_();} - EVENT_HANDLER2(PIProcess, void, exec, const PIString & , program, const PIString & , arg) {args.clear(); args << program << arg; exec_();} - EVENT_HANDLER3(PIProcess, void, exec, const PIString & , program, const PIString & , arg1, const PIString & , arg2) {args.clear(); args << program << arg1 << arg2; exec_();} - EVENT_HANDLER4(PIProcess, void, exec, const PIString & , program, const PIString & , arg1, const PIString & , arg2, const PIString & , arg3) {args.clear(); args << program << arg1 << arg2 << arg3; exec_();} - EVENT_HANDLER2(PIProcess, void, exec, const PIString & , program, const PIStringList & , args_) {args << program << args_; exec_();} + EVENT_HANDLER1(void, exec, const PIString & , program) {args.clear(); args << program; exec_();} + EVENT_HANDLER2(void, exec, const PIString & , program, const PIString & , arg) {args.clear(); args << program << arg; exec_();} + EVENT_HANDLER3(void, exec, const PIString & , program, const PIString & , arg1, const PIString & , arg2) {args.clear(); args << program << arg1 << arg2; exec_();} + EVENT_HANDLER4(void, exec, const PIString & , program, const PIString & , arg1, const PIString & , arg2, const PIString & , arg3) {args.clear(); args << program << arg1 << arg2 << arg3; exec_();} + EVENT_HANDLER2(void, exec, const PIString & , program, const PIStringList & , args_) {args << program << args_; exec_();} #ifdef WINDOWS - EVENT_HANDLER(PIProcess, void, terminate) {if (is_exec) if (!TerminateProcess(pi.hProcess, 0)) return; pi.dwProcessId = 0;} + EVENT_HANDLER(void, terminate) {if (is_exec) if (!TerminateProcess(pi.hProcess, 0)) return; pi.dwProcessId = 0;} #else - EVENT_HANDLER(PIProcess, void, terminate) {if (is_exec) kill(pid, SIGKILL); pid = 0;} + EVENT_HANDLER(void, terminate) {if (is_exec) kill(pid, SIGKILL); pid = 0;} #endif - EVENT_HANDLER(PIProcess, bool, waitForFinish) {return waitForFinish(60000);} - EVENT_HANDLER1(PIProcess, bool, waitForFinish, int, timeout_msecs) {return PIThread::waitForFinish(timeout_msecs);} + EVENT_HANDLER(bool, waitForFinish) {return waitForFinish(60000);} + EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs) {return PIThread::waitForFinish(timeout_msecs);} PIByteArray readOutput() {f_out.open(PIIODevice::ReadOnly); return f_out.readAll();} PIByteArray readError() {f_err.open(PIIODevice::ReadOnly); return f_err.readAll();} @@ -92,8 +93,8 @@ public: static int currentPID() {return getpid();} #endif - EVENT1(PIProcess, execStarted, PIString, program) - EVENT2(PIProcess, execFinished, PIString, program, int, exit_code) + EVENT1(execStarted, PIString, program) + EVENT2(execFinished, PIString, program, int, exit_code) private: virtual void run(); diff --git a/piprotocol.cpp b/piprotocol.cpp index 5889313e..51a00db7 100644 --- a/piprotocol.cpp +++ b/piprotocol.cpp @@ -26,7 +26,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re PIObject::setName(name); PIConfig conf(config, PIIODevice::ReadOnly); if (!conf.isOpened()) { - piCout << "[PIProtocol \"" << name << "\"] Can`t open \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Can`t open \"" << config << "\"!"; devReceiverState = devSenderState = "Config error"; return; } @@ -41,7 +41,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re /// receiver section if (rb.isEntryExists("ip") && rb.isEntryExists("device")) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous receiver type in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous receiver type in \"" << config << "\"!"; devReceiverState = "Config error"; return; } @@ -50,7 +50,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) dev = gdev; if (gok && ok && (dev != gdev)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous receiver type in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous receiver type in \"" << config << "\"!"; devReceiverState = "Config error"; return; } @@ -59,7 +59,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) ps = gps; if (gok && ok && (ps != gps)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive port in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive port in \"" << config << "\"!"; devReceiverState = "Config error"; return; } @@ -74,7 +74,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) flag = gflag; if (gok && ok && (flag != gflag)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectEnabled\" flag in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectEnabled\" flag in \"" << config << "\"!"; devReceiverState = "Config error"; return; } @@ -85,18 +85,18 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) freq = gfreq; if (gok && ok && (freq != gfreq)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectTimeout\" value in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectTimeout\" value in \"" << config << "\"!"; devReceiverState = "Config error"; return; } eth->setReopenTimeout(freq * 1000); } if (recDataPtr == 0) - piCout << "[PIProtocol \"" << name << "\"] Warning: null receive data pointer!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Warning: null receive data pointer!"; if (recDataSize == 0) - piCout << "[PIProtocol \"" << name << "\"] Warning: null receive data size!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Warning: null receive data size!"; } else { - piCout << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".receiver.port\" or \"" << name << ".port\" in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".receiver.port\" or \"" << name << ".port\" in \"" << config << "\"!"; devReceiverState = "Config error"; return; } @@ -106,7 +106,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) dev = gdev; if (gok && ok && (dev != gdev)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous receiver type in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous receiver type in \"" << config << "\"!"; devReceiverState = "Config error"; return; } @@ -115,7 +115,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) ps = gps; if (gok && ok && (ps != gps)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive \"speed\" in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive \"speed\" in \"" << config << "\"!"; devReceiverState = "Config error"; return; } @@ -124,7 +124,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) flag = gflag; if (gok && ok && (flag != gflag)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive \"parity\" in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive \"parity\" in \"" << config << "\"!"; devReceiverState = "Config error"; return; } @@ -135,7 +135,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) flag = gflag; if (gok && ok && (flag != gflag)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive \"twoStopBits\" parity in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive \"twoStopBits\" parity in \"" << config << "\"!"; devReceiverState = "Config error"; return; } @@ -154,7 +154,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) ps = gps; if (gok && ok && (ps != gps)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive \"vtime\" in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive \"vtime\" in \"" << config << "\"!"; devReceiverState = "Config error"; return; } @@ -162,11 +162,11 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re } has_dev = true; if (recDataPtr == 0) - piCout << "[PIProtocol \"" << name << "\"] Warning: null receive data pointer!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Warning: null receive data pointer!"; if (recDataSize == 0) - piCout << "[PIProtocol \"" << name << "\"] Warning: null receive data size!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Warning: null receive data size!"; } else { - piCout << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".receiver.speed\" or \"" << name << ".speed\" in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".receiver.speed\" or \"" << name << ".speed\" in \"" << config << "\"!"; devReceiverState = "Config error"; return; } @@ -176,7 +176,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) history_write_rec = ghist; if (gok && ok && (history_write_rec != ghist)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous receiver history in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous receiver history in \"" << config << "\"!"; devReceiverState = "Config error"; return; } @@ -187,7 +187,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re history_id_rec = rb.getValue("historyID", 0, &ok); if (!ok) { history_id_rec = protName.toByteArray().checksumCRC16(); - piCout << "[PIProtocol \"" << name << "\"] Warning: no receiver history ID defined, write with ID = " << history_id_rec << endl; + piCout << "[PIProtocol \"" << name << "\"] Warning: no receiver history ID defined, write with ID = " << history_id_rec; } history_file_rec.open(history_path_rec, PIIODevice::WriteOnly); } @@ -196,21 +196,21 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re gfreq = b.getValue("frequency", -1.f, &gok); if (gok && !ok) freq = gfreq; if (gok && ok && (freq != gfreq)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous expected frequency in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous expected frequency in \"" << config << "\"!"; devReceiverState = "Config error"; return; } if (freq > 0.f && !has_dev) - piCout << "[PIProtocol \"" << name << "\"] Warning: no receiver device and not null expected frequency!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Warning: no receiver device and not null expected frequency!"; float tm = b.getValue("disconnectTimeout", 3.f); if (tm <= 0.f) - piCout << "[PIProtocol \"" << name << "\"] Warning: diconnect timeout <= 0 s!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Warning: diconnect timeout <= 0 s!"; timeout_ = (tm < 0.f) ? 0.f : tm; setExpectedFrequency(freq); /// sender section if (sb.isEntryExists("ip") && sb.isEntryExists("device")) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender type in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender type in \"" << config << "\"!"; devSenderState = "Config error"; return; } @@ -220,7 +220,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) dev = gdev; if (gok && ok && (dev != gdev)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender type in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender type in \"" << config << "\"!"; devSenderState = "Config error"; return; } @@ -229,7 +229,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) ps = gps; if (gok && ok && (ps != gps)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous send port in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous send port in \"" << config << "\"!"; devSenderState = "Config error"; return; } @@ -243,7 +243,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) flag = gflag; if (gok && ok && (flag != gflag)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectEnabled\" flag in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectEnabled\" flag in \"" << config << "\"!"; devReceiverState = "Config error"; return; } @@ -254,18 +254,18 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) freq = gfreq; if (gok && ok && (freq != gfreq)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectTimeout\" value in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectTimeout\" value in \"" << config << "\"!"; devReceiverState = "Config error"; return; } eth->setReopenTimeout(freq * 1000); } if (sendDataPtr_ == 0) - piCout << "[PIProtocol \"" << name << "\"] Warning: null send data pointer!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Warning: null send data pointer!"; if (sendDataSize_ == 0) - piCout << "[PIProtocol \"" << name << "\"] Warning: null send data size!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Warning: null send data size!"; } else { - piCout << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".sender.port\" or \"" << name << ".port\" in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".sender.port\" or \"" << name << ".port\" in \"" << config << "\"!"; devSenderState = "Config error"; return; } @@ -275,7 +275,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) dev = gdev; if (gok && ok && (dev != gdev)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender type in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender type in \"" << config << "\"!"; devSenderState = "Config error"; return; } @@ -284,7 +284,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) ps = gps; if (gok && ok && (ps != gps)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous send \"speed\" in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous send \"speed\" in \"" << config << "\"!"; devSenderState = "Config error"; return; } @@ -293,7 +293,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) flag = gflag; if (gok && ok && (flag != gflag)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous send \"parity\" in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous send \"parity\" in \"" << config << "\"!"; devSenderState = "Config error"; return; } @@ -304,14 +304,14 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re if (ok || gok) { if (gok && !ok) flag = gflag; if (gok && ok && (flag != gflag)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous send \"twoStopBits\" parity in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous send \"twoStopBits\" parity in \"" << config << "\"!"; devSenderState = "Config error"; return; } pp.setFlag(PISerial::TwoStopBits, flag); } } else { - piCout << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".sender.speed\" or \"" << name << ".speed\" in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".sender.speed\" or \"" << name << ".speed\" in \"" << config << "\"!"; devSenderState = "Config error"; return; } @@ -322,16 +322,16 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re ser->setParameters(pp); has_dev = true; if (sendDataPtr_ == 0) - piCout << "[PIProtocol \"" << name << "\"] Warning: null send data pointer!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Warning: null send data pointer!"; if (sendDataSize_ == 0) - piCout << "[PIProtocol \"" << name << "\"] Warning: null send data size!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Warning: null send data size!"; } history_write_send = sb.getValue("writeHistory", false, &ok); ghist = b.getValue("writeHistory", false, &gok); if (ok || gok) { if (gok && !ok) history_write_send = ghist; if (gok && ok && (history_write_send != ghist)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender history in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender history in \"" << config << "\"!"; devSenderState = "Config error"; return; } @@ -342,7 +342,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re history_id_send = sb.getValue("historyID", 0, &ok); if (!ok) { history_id_send = protName.toByteArray().checksumCRC16() + 1; - piCout << "[PIProtocol \"" << name << "\"] Warning: no sender history ID defined, write with ID = " << history_id_send << endl; + piCout << "[PIProtocol \"" << name << "\"] Warning: no sender history ID defined, write with ID = " << history_id_send; } history_file_send.open(history_path_send, PIIODevice::WriteOnly); } @@ -351,12 +351,12 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re gfreq = b.getValue("frequency", -1.f, &gok); if (gok && !ok) freq = gfreq; if (gok && ok && (freq != gfreq)) { - piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender frequency in \"" << config << "\"!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender frequency in \"" << config << "\"!"; devSenderState = "Config error"; return; } if (freq > 0.f && !has_dev) - piCout << "[PIProtocol \"" << name << "\"] Warning: no sender device and not null send frequency!" << endl; + piCout << "[PIProtocol \"" << name << "\"] Warning: no sender device and not null send frequency!"; setSenderFrequency(freq); headerPtr = (uchar * )recHeaderPtr; @@ -643,7 +643,7 @@ void PIProtocol::calc_diag() { else if (good_percents > 20.f && good_percents <= 80.f) diag = PIProtocol::Average; else diag = PIProtocol::Good; if (diag != net_diag) { - qualityChanged(net_diag, diag); + qualityChanged(diag, net_diag); net_diag = diag; } } diff --git a/piprotocol.h b/piprotocol.h index 9bd60ad9..10afed2a 100644 --- a/piprotocol.h +++ b/piprotocol.h @@ -29,7 +29,7 @@ class PIProtocol; -class PIMultiProtocolBase +class PIP_EXPORT PIMultiProtocolBase { friend class PIProtocol; public: @@ -65,12 +65,12 @@ typedef void (*ReceiveFunc)(void * ); /// void stop() /// void send() /// void send(const void * data, int size, bool direct = false) -class PIProtocol: public PIObject +class PIP_EXPORT PIProtocol: public PIObject { + PIOBJECT(PIProtocol) friend class PIMultiProtocolBase; friend class PIMultiProtocol; enum Type {None, Serial, Ethernet}; - public: PIProtocol(): PIObject() {init();} PIProtocol(const PIString & config, const PIString & name, void * recHeaderPtr = 0, int recHeaderSize = 0, @@ -79,9 +79,9 @@ public: enum Quality {Unknown = 1, Failure = 2, Bad = 3, Average = 4, Good = 5}; - EVENT_HANDLER0(PIProtocol, void, startReceive) {startReceive(-1.f);} - EVENT_HANDLER1(PIProtocol, void, startReceive, float, exp_frequency); // if "frequency = -1" used last passed value - EVENT_HANDLER0(PIProtocol, void, stopReceive); + EVENT_HANDLER0(void, startReceive) {startReceive(-1.f);} + EVENT_HANDLER1(void, startReceive, float, exp_frequency); // if "frequency = -1" used last passed value + EVENT_HANDLER0(void, stopReceive); void setExpectedFrequency(float frequency); // for connection quality diagnostic void setReceiverDevice(const PIString & device, PISerial::Speed speed, bool force = false); // for Serial void setReceiverData(void * dataPtr, int dataSize) {this->dataPtr = (uchar * )dataPtr; this->dataSize = dataSize; packet_ext->setPacketData(headerPtr, headerSize, dataSize);} @@ -91,9 +91,9 @@ public: void setReceiveSlot(ReceiveFunc slot) {ret_func = slot;} float expectedFrequency() const {return exp_freq;} - EVENT_HANDLER0(PIProtocol, void, startSend) {startSend(-1.f);} // if "frequency = -1" used last passed value - EVENT_HANDLER1(PIProtocol, void, startSend, float, frequency); // if "frequency = -1" used last passed value - EVENT_HANDLER0(PIProtocol, void, stopSend) {sendTimer->stop(); senderStopped();} + EVENT_HANDLER0(void, startSend) {startSend(-1.f);} // if "frequency = -1" used last passed value + EVENT_HANDLER1(void, startSend, float, frequency); // if "frequency = -1" used last passed value + EVENT_HANDLER0(void, stopSend) {sendTimer->stop(); senderStopped();} void setSenderFrequency(float frequency) {send_freq = frequency;} void setSenderDevice(const PIString & device, PISerial::Speed speed, bool force = false); // for Serial void setSenderData(void * dataPtr, int dataSize) {sendDataPtr = (uchar * )dataPtr; sendDataSize = dataSize;} @@ -103,11 +103,11 @@ public: void setSenderParameters(PIFlags parameters) {if (type_send == PIProtocol::Serial) ser->setParameters(parameters);} // for Serial float senderFrequency() const {return send_freq;} - EVENT_HANDLER0(PIProtocol, void, start) {startReceive(); startSend();} - EVENT_HANDLER0(PIProtocol, void, stop) {stopReceive(); stopSend();} - EVENT_HANDLER0(PIProtocol, void, send); - EVENT_HANDLER2(PIProtocol, void, send, const void *, data, int, size) {send(data, size, false);} - EVENT_HANDLER3(PIProtocol, void, send, const void *, data, int, size, bool, direct); + EVENT_HANDLER0(void, start) {startReceive(); startSend();} + EVENT_HANDLER0(void, stop) {stopReceive(); stopSend();} + EVENT_HANDLER0(void, send); + EVENT_HANDLER2(void, send, const void *, data, int, size) {send(data, size, false);} + EVENT_HANDLER3(void, send, const void *, data, int, size, bool, direct); void setName(const PIString & name) {protName = name; PIObject::setName(name);} PIString name() const {return protName;} @@ -161,12 +161,12 @@ public: PIPacketExtractor * packetExtractor() {return packet_ext;} PIByteArray lastHeader() {return packet_ext->lastHeader();} - EVENT0(PIProtocol, receiverStarted) - EVENT0(PIProtocol, receiverStopped) - EVENT0(PIProtocol, senderStarted) - EVENT0(PIProtocol, senderStopped) - EVENT1(PIProtocol, received, bool, validate_is_ok) - EVENT2(PIProtocol, qualityChanged, PIProtocol::Quality, old_quality, PIProtocol::Quality, new_quality) + EVENT0(receiverStarted) + EVENT0(receiverStopped) + EVENT0(senderStarted) + EVENT0(senderStopped) + EVENT1(received, bool, validate_is_ok) + EVENT2(qualityChanged, PIProtocol::Quality, new_quality, PIProtocol::Quality, old_quality) protected: virtual bool receive(uchar * data, int size) {if (dataPtr != 0) memcpy(dataPtr, data, size); return true;} // executed when raw data received, break if 'false' return diff --git a/piserial.cpp b/piserial.cpp index 2370c5e1..cefef69b 100644 --- a/piserial.cpp +++ b/piserial.cpp @@ -67,14 +67,14 @@ bool PISerial::setPin(int number, bool on) { case 3: return setST(on); break; case 4: return setDTR(on); break; case 5: - piCout << "[PISerial] Pin number 5 is ground" << endl; + piCout << "[PISerial] Pin number 5 is ground"; return false; case 6: return setDSR(on); break; case 7: return setRTS(on); break; case 8: return setCTS(on); break; case 9: return setRNG(on); break; default: - piCout << "[PISerial] Pin number " << number << " doesn`t exists!" << endl; + piCout << "[PISerial] Pin number " << number << " doesn`t exists!"; return false; } return false; @@ -93,7 +93,7 @@ bool PISerial::isPin(int number) const { case 8: return isCTS(); break; case 9: return isRNG(); break; default: - piCout << "[PISerial] Pin number " << number << " doesn`t exists!" << endl; + piCout << "[PISerial] Pin number " << number << " doesn`t exists!"; return false; } return false; @@ -103,7 +103,7 @@ bool PISerial::isPin(int number) const { bool PISerial::setBit(int bit, bool on, const PIString & bname) { #ifndef WINDOWS if (fd < 0) { - piCout << "[PISerial] set" << bname << " error: \"" << path_ << "\" is not opened!" << endl; + piCout << "[PISerial] set" << bname << " error: \"" << path_ << "\" is not opened!"; return false; } if (ioctl(fd, on ? TIOCMBIS : TIOCMBIC, &bit) < 0) { @@ -112,7 +112,7 @@ bool PISerial::setBit(int bit, bool on, const PIString & bname) { } return true; #else - piCout << "[PISerial] set" << bname << " doesn`t implemented on Windows, sorry :-(" << endl; + piCout << "[PISerial] set" << bname << " doesn`t implemented on Windows, sorry :-("; return false; #endif } @@ -121,7 +121,7 @@ bool PISerial::setBit(int bit, bool on, const PIString & bname) { bool PISerial::isBit(int bit, const PIString & bname) const { #ifndef WINDOWS if (fd < 0) { - piCout << "[PISerial] is" << bname << " error: \"" << path_ << "\" is not opened!" << endl; + piCout << "[PISerial] is" << bname << " error: \"" << path_ << "\" is not opened!"; return false; } int ret = 0; @@ -129,7 +129,7 @@ bool PISerial::isBit(int bit, const PIString & bname) const { piCout << "[PISerial] is" << bname << " error: " << errorString(); return ret & bit; #else - piCout << "[PISerial] set" << bname << " doesn`t implemented on Windows, sorry :-(" << endl; + piCout << "[PISerial] set" << bname << " doesn`t implemented on Windows, sorry :-("; return false; #endif } @@ -301,7 +301,7 @@ bool PISerial::openDevice() { if (isWriteable()) {ds |= GENERIC_WRITE; sm |= FILE_SHARE_WRITE;} hCom = CreateFileA(path_.data(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0); if(hCom == INVALID_HANDLE_VALUE) { - piCout << "[PISerial] Unable to open \"" << path_ << "\"" << endl; + piCout << "[PISerial] Unable to open \"" << path_ << "\""; return false; } fd = 0; @@ -312,7 +312,7 @@ bool PISerial::openDevice() { times.WriteTotalTimeoutConstant = 1; times.WriteTotalTimeoutMultiplier = 0; if (SetCommTimeouts(hCom, ×) == -1) { - piCout << "[PISerial] Unable to set timeouts for \"" << path_ << "\"" << endl; + piCout << "[PISerial] Unable to set timeouts for \"" << path_ << "\""; CloseHandle(hCom); fd = -1; return false; @@ -330,7 +330,7 @@ bool PISerial::openDevice() { } desc.StopBits = params[PISerial::TwoStopBits] ? TWOSTOPBITS : ONESTOPBIT; if (SetCommState(hCom, &desc) == -1) { - piCout << "[PISerial] Unable to set comm state for \"" << path_ << "\"" << endl; + piCout << "[PISerial] Unable to set comm state for \"" << path_ << "\""; CloseHandle(hCom); fd = -1; return false; @@ -345,7 +345,7 @@ bool PISerial::openDevice() { //cout << "init ser " << path_ << " mode " << om << " param " << params << endl; fd = ::open(path_.data(), O_NOCTTY | om); if(fd == -1) { - piCout << "[PISerial] Unable to open \"" << path_ << "\"" << endl; + piCout << "[PISerial] Unable to open \"" << path_ << "\""; return false; } @@ -371,20 +371,20 @@ bool PISerial::openDevice() { fcntl(fd, F_SETFL, 0); if(tcsetattr(fd, TCSANOW, &desc) < 0) { - piCout << "[PISerial] Can`t set attributes for \"" << path_ << "\"" << endl; + piCout << "[PISerial] Can`t set attributes for \"" << path_ << "\""; ::close(fd); return false; } - //piCout << "[PISerial] Initialized " << path_ << endl; + //piCout << "[PISerial] Initialized " << path_; #endif return true; } int PISerial::write(const void * data, int max_size, bool wait) { - //piCout << "[PISerial] send " << max_size << ": " << PIString((char*)data, max_size) << endl; + //piCout << "[PISerial] send " << max_size << ": " << PIString((char*)data, max_size); if (fd == -1 || !canWrite()) { - //piCout << "[PISerial] Can`t write to uninitialized COM" << endl; + //piCout << "[PISerial] Can`t write to uninitialized COM"; return -1; } #ifdef WINDOWS @@ -402,6 +402,6 @@ int PISerial::write(const void * data, int max_size, bool wait) { if (wait) tcdrain(fd); #endif return (int)wrote; - //piCout << "[PISerial] Error while sending" << endl; - //piCout << "[PISerial] Wrote " << wrote << " bytes in " << path_ << endl; + //piCout << "[PISerial] Error while sending"; + //piCout << "[PISerial] Wrote " << wrote << " bytes in " << path_; } diff --git a/piserial.h b/piserial.h index 4e00e2d8..dd0e9a7e 100644 --- a/piserial.h +++ b/piserial.h @@ -29,7 +29,7 @@ # ifndef B50 # define B50 0000001 # endif -# ifndef B50 +# ifndef B75 # define B75 0000002 # endif # ifndef B1500000 @@ -83,8 +83,11 @@ # define B3500000 3500000 # define B4000000 4000000 #endif +#ifndef CRTSCTS +# define CRTSCTS 020000000000 +#endif -class PISerial: public PIIODevice { +class PIP_EXPORT PISerial: public PIIODevice { public: // slot is any function format "bool (void*, uchar*, int)" // slot_header is any function format "bool (void*, uchar*, uchar*, int)" diff --git a/pisignals.h b/pisignals.h index b1e9ec3d..3cd8c872 100644 --- a/pisignals.h +++ b/pisignals.h @@ -23,7 +23,7 @@ #include "picontainers.h" #include -class PISignals +class PIP_EXPORT PISignals { public: enum Signal { diff --git a/pistring.cpp b/pistring.cpp index bbd1721e..51179ac7 100644 --- a/pistring.cpp +++ b/pistring.cpp @@ -20,6 +20,41 @@ #include "pistring.h" +/*! \class PIString + * \brief String class + * \details PIP use this class for use string information. + * + * \section PIString_sec0 Synopsis + * This class based on \a PIVector to store information. + * String is a sequence of \a PIChar and can contain multibyte + * symbols. Therefore real memory size of string is symbols count * 4. + * String can be constucted from many types of data and can be converted + * to many types. There are man operators and handly functions to use + * string as you wish. + * + * \section PIString_sec1 To/from data convertions + * Most common constructor is \a PIString(const char * str), where "str" + * is null-terminated string, e.g. \c "string". This is 7 chars with last char = 0. + * Also you can constructs \a PIString from single \a PIChar, \a PIByteArray, + * other \a PIString or sequency of the same characters with custom length.\n \n + * This class has implicit conversions to const char * and + * \c std::string. Also there are functions to make same convertions: + * * \a data() - to const char * , + * * \a stdString() - to \c std::string, + * * \a toByteArray() - to \a PIByteArray. + * + * \section PIString_sec2 Numeric operations + * You can get symbolic representation of any numeric value with function + * \a setNumber(any integer value, int base = 10, bool * ok = 0). Default + * arguments are set for decimal base system, but you can choose any system + * from 2 to 40. There are the same static functions \a fromNumber(), that + * returns \a PIString. \n + * Also there is function \a setReadableSize() which is set human-readable + * size in bytes, Kb, Mb, Gb or Pb. Static analog is \a readableSize(). + * + */ + + const char PIString::toBaseN[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', @@ -346,25 +381,24 @@ int PIString::lengthAscii() const { const char * PIString::data() const { - PIByteArray & d_(*(const_cast(&data_))); - d_.clear(); + data_.clear(); int wc; uchar tc; for (int i = 0, j = 0; i < size_s(); ++i) { wc = at(i).toInt(); while (tc = wc & 0xFF, tc) { - d_.push_back(uchar(tc)); ++j; + data_.push_back(uchar(tc)); ++j; wc >>= 8; } /*if (at(i).isAscii()) - d_.push_back(uchar(at(i).toAscii())); + data_.push_back(uchar(at(i).toAscii())); else { - d_.push_back((at(i).toCharPtr()[0])); ++j; - d_.push_back((at(i).toCharPtr()[1])); + data_.push_back((at(i).toCharPtr()[0])); ++j; + data_.push_back((at(i).toCharPtr()[1])); }*/ } - d_.push_back(uchar('\0')); - return (const char * )d_.data(); + data_.push_back(uchar('\0')); + return (const char * )data_.data(); } @@ -439,25 +473,29 @@ llong PIString::toLLong() const { } */ -PIString & PIString::setReadableSize(long bytes) { +PIString & PIString::setReadableSize(llong bytes) { clear(); if (bytes < 1024) {*this += (PIString::fromNumber(bytes) + " B"); return *this;} double fres = bytes / 1024.; - long res = bytes / 1024; + llong res = bytes / 1024; fres -= res; - if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(int(fres * 10)).left(1) + " kB"); return *this;} + if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " kB"); return *this;} fres = res / 1024.; res /= 1024; fres -= res; - if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(int(fres * 10)).left(1) + " MB"); return *this;} + if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " MB"); return *this;} fres = res / 1024.; res /= 1024; fres -= res; - if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(int(fres * 10)).left(1) + " GB"); return *this;} + if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " GB"); return *this;} fres = res / 1024.; res /= 1024; fres -= res; - *this += (PIString::fromNumber(res) + "." + PIString::fromNumber(int(fres * 10)).left(1) + " PB"); + if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " TB"); return *this;} + fres = res / 1024.; + res /= 1024; + fres -= res; + *this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " PB"); return *this; } @@ -476,6 +514,7 @@ inline char chrLwr(char c) { } + PIStringList& PIStringList::removeDuplicates() { PIStringList l; PIString s; diff --git a/pistring.h b/pistring.h index 35e12a7b..03b679b2 100644 --- a/pistring.h +++ b/pistring.h @@ -1,3 +1,8 @@ +/*! \file pistring.h + * \brief String + * + * This file declare string and string list classes +*/ /* PIP - Platform Independent Primitives String @@ -26,13 +31,14 @@ class PIStringList; -class PIString: public PIVector +class PIP_EXPORT PIString: public PIVector { public: - PIString() {piMonitor.strings++; piMonitor.containers--;} + //! Contructs an empty string + PIString() {reserve(256); piMonitor.strings++; piMonitor.containers--;} //inline PIString & operator +=(const char c) {push_back(c); return *this;} - PIString & operator +=(const PIChar c) {push_back(c); return *this;} + PIString & operator +=(const PIChar & c) {push_back(c); return *this;} PIString & operator +=(const char * str); PIString & operator +=(const wchar_t * str); PIString & operator +=(const string & str) {appendFromChars(str.c_str(), str.length()); return *this;} @@ -43,107 +49,335 @@ public: #endif //PIString(const char c) {*this += c;} - PIString(const PIChar c) {reserve(256); piMonitor.strings++; piMonitor.containers--; *this += c;} + + //! Contructs string with single symbol "c" + PIString(const PIChar & c) {reserve(256); piMonitor.strings++; piMonitor.containers--; *this += c;} + + /*! \brief Contructs string from c-string "str" + * \details "str" should be null-terminated\n + * Example: \snippet pistring.cpp PIString(char * ) */ PIString(const char * str) {reserve(256); piMonitor.strings++; piMonitor.containers--; *this += str;} + + /*! \brief Contructs string from \c wchar_t c-string "str" + * \details "str" should be null-terminated\n + * Example: \snippet pistring.cpp PIString(wchar_t * ) */ PIString(const wchar_t * str) {reserve(256); piMonitor.strings++; piMonitor.containers--; *this += str;} + + //! Contructs string from std::string "str" PIString(const string & str) {reserve(256); piMonitor.strings++; piMonitor.containers--; *this += str;} -#ifdef HAS_LOCALE + + #ifdef HAS_LOCALE PIString(const wstring & str) {reserve(256); piMonitor.strings++; piMonitor.containers--; *this += str;} #endif + + //! Contructs string from byte array "ba" PIString(const PIByteArray & ba) {reserve(256); piMonitor.strings++; piMonitor.containers--; *this += ba;} + + /*! \brief Contructs string from "len" characters of buffer "str" + * \details Example: \snippet pistring.cpp PIString(char * , int) */ PIString(const char * str, const int len) {reserve(256); piMonitor.strings++; piMonitor.containers--; *this += string(str, len);} + + /*! \brief Contructs string as sequence of characters "c" of buffer with length "len" + * \details Example: \snippet pistring.cpp PIString(int, char) */ PIString(const int len, const char c) {reserve(256); piMonitor.strings++; piMonitor.containers--; for (int i = 0; i < len; ++i) push_back(c);} + + /*! \brief Contructs string as sequence of symbols "c" of buffer with length "len" + * \details Example: \snippet pistring.cpp PIString(int, PIChar) */ PIString(const int len, const PIChar & c) {reserve(256); piMonitor.strings++; piMonitor.containers--; for (int i = 0; i < len; ++i) push_back(c);} + + //! Contructs string from other string "str" PIString(const PIString & str) {reserve(256); piMonitor.strings++; piMonitor.containers--; *this += str;} + ~PIString() {piMonitor.strings--; piMonitor.containers++;} + + /*! \brief Return c-string representation of string + * \details Converts content of string to c-string and return + * pointer to first char. This buffer is valid until new convertion + * or execution \a data() or \a toByteArray().\n + * Example: \snippet pistring.cpp PIString::char* */ operator const char*() {return data();} + + //! Return std::string representation of string operator const string() {if (size() == 0) return string(); string s; for (int i = 0; i < length(); ++i) s.push_back(at(i).toAscii()); return s;} + + //! Return symbol at index "pos" PIChar operator [](const int pos) const {return at(pos);} + + //! Return const reference symbol at index "pos" PIChar & operator [](const int pos) {return at(pos);} + //! Compare operator bool operator ==(const PIString & str) const; + + //! Compare operator bool operator ==(const PIChar c) const {return *this == PIString(c);} //inline bool operator ==(const char c) const {return *this == PIString(c);} + + //! Compare operator bool operator ==(const char * str) const {return *this == PIString(str);} + + //! Compare operator bool operator ==(const string & str) const {return *this == PIString(str);} + + //! Compare operator bool operator !=(const PIString & str) const; + + //! Compare operator bool operator !=(const PIChar c) const {return *this != PIString(c);} //inline bool operator !=(const char c) const {return *this != PIString(c);} + + //! Compare operator bool operator !=(const char * str) const {return *this != PIString(str);} + + //! Compare operator bool operator !=(const string & str) const {return *this != PIString(str);} + + //! Compare operator bool operator <(const PIString & str) const; + + //! Compare operator bool operator <(const PIChar c) const {return *this < PIString(c);} //inline bool operator <(const char c) const {return *this < PIString(c);} + + //! Compare operator bool operator <(const char * str) const {return *this < PIString(str);} + + //! Compare operator bool operator <(const string & str) const {return *this < PIString(str);} + + //! Compare operator bool operator >(const PIString & str) const; + + //! Compare operator bool operator >(const PIChar c) const {return *this > PIString(c);} //inline bool operator >(const char c) const {return *this > PIString(c);} + + //! Compare operator bool operator >(const char * str) const {return *this > PIString(str);} + + //! Compare operator bool operator >(const string & str) const {return *this > PIString(str);} + + //! Compare operator bool operator <=(const PIString & str) const {return !(*this > str);} + + //! Compare operator bool operator <=(const PIChar c) const {return *this <= PIString(c);} //inline bool operator <=(const char c) const {return *this <= PIString(c);} + + //! Compare operator bool operator <=(const char * str) const {return *this <= PIString(str);} + + //! Compare operator bool operator <=(const string & str) const {return *this <= PIString(str);} + + //! Compare operator bool operator >=(const PIString & str) const {return !(*this < str);} + + //! Compare operator bool operator >=(const PIChar c) const {return *this >= PIString(c);} //inline bool operator >=(const char c) const {return *this >= PIString(c);} + + //! Compare operator bool operator >=(const char * str) const {return *this >= PIString(str);} + + //! Compare operator bool operator >=(const string & str) const {return *this >= PIString(str);} + + /*! \brief Append string "str" at the end of string + * \details Example: \snippet pistring.cpp PIString::<<(PIString) */ PIString & operator <<(const PIString & str) {*this += str; return *this;} //inline PIString & operator <<(const char c) {*this += c; return *this;} - PIString & operator <<(const PIChar c) {*this += c; return *this;} + + /*! \brief Append symbol "c" at the end of string + * \details Example: \snippet pistring.cpp PIString::<<(PIChar) */ + PIString & operator <<(const PIChar & c) {*this += c; return *this;} + + /*! \brief Append c-string "str" at the end of string + * \details Example: \snippet pistring.cpp PIString::<<(char * ) */ PIString & operator <<(const char * str) {*this += str; return *this;} + + /*! \brief Append \c wchar_t c-string "str" at the end of string + * \details Example: \snippet pistring.cpp PIString::<<(wchar_t * ) */ PIString & operator <<(const wchar_t * str) {*this += str; return *this;} + + //! Append std::string "str" at the end of string PIString & operator <<(const string & str) {*this += str; return *this;} + + /*! \brief Append string representation of "num" at the end of string + * \details Example: \snippet pistring.cpp PIString::<<(int) */ PIString & operator <<(const int & num) {*this += PIString::fromNumber(num); return *this;} + + /*! \brief Append string representation of "num" at the end of string + * \details Example: \snippet pistring.cpp PIString::<<(int) */ PIString & operator <<(const short & num) {*this += PIString::fromNumber(num); return *this;} + + /*! \brief Append string representation of "num" at the end of string + * \details Example: \snippet pistring.cpp PIString::<<(int) */ PIString & operator <<(const long & num) {*this += PIString::fromNumber(num); return *this;} + + /*! \brief Append string representation of "num" at the end of string + * \details Example: \snippet pistring.cpp PIString::<<(int) */ PIString & operator <<(const float & num) {*this += PIString::fromNumber(num); return *this;} + + /*! \brief Append string representation of "num" at the end of string + * \details Example: \snippet pistring.cpp PIString::<<(int) */ PIString & operator <<(const double & num) {*this += PIString::fromNumber(num); return *this;} + + /*! \brief Return part of string from symbol at index "start" and maximum length "len" + * \details All variants demonstrated in example: \snippet pistring.cpp PIString::mid + * \sa \a left(), \a right() */ PIString mid(const int start, const int len = -1) const; + + /*! \brief Return part of string from left and maximum length "len" + * \details Example: \snippet pistring.cpp PIString::left + * \sa \a mid(), \a right() */ PIString left(const int len) const {return len <= 0 ? PIString() : mid(0, len);} + + /*! \brief Return part of string from right and maximum length "len" + * \details Example: \snippet pistring.cpp PIString::right + * \sa \a mid(), \a left() */ PIString right(const int len) const {return len <= 0 ? PIString() : mid(size() - len, len);} + + /*! \brief Remove part of string from symbol as index "start" and maximum length "len" + * and return this string + * \details All variants demonstrated in example: \snippet pistring.cpp PIString::cutMid + * \sa \a cutLeft(), \a cutRight() */ PIString & cutMid(const int start, const int len); + + /*! \brief Remove part of string from left and maximum length "len" and return this string + * \details Example: \snippet pistring.cpp PIString::cutLeft + * \sa \a cutMid(), \a cutRight() */ PIString & cutLeft(const int len) {return len <= 0 ? *this : cutMid(0, len);} + + /*! \brief Remove part of string from right and maximum length "len" and return this string + * \details Example: \snippet pistring.cpp PIString::cutRight + * \sa \a cutMid(), \a cutLeft() */ PIString & cutRight(const int len) {return len <= 0 ? *this : cutMid(size() - len, len);} + + /*! \brief Remove spaces at the start and at the end of string and return this string + * \details Example: \snippet pistring.cpp PIString::trim + * \sa \a trimmed() */ PIString & trim(); + + /*! \brief Return copy of this string without spaces at the start and at the end + * \details Example: \snippet pistring.cpp PIString::trimmed + * \sa \a trim() */ PIString trimmed() const; + + /*! \brief Replace part of string from index "from" and maximum length "len" + * with string "with" and return this string + * \details Example: \snippet pistring.cpp PIString::replace_0 + * \sa \a replaced(), \a replaceAll() */ PIString & replace(const int from, const int count, const PIString & with); + + /*! \brief Replace part copy of this string from index "from" and maximum length "len" + * with string "with" and return copied string + * \details Example: \snippet pistring.cpp PIString::replaced_0 + * \sa \a replace(), \a replaceAll() */ PIString replaced(const int from, const int count, const PIString & with) const {PIString str(*this); str.replace(from, count, with); return str;} + + /*! \brief Replace first founded substring "what" with string "with" and return this string + * \details If "ok" is not null, it set to "true" if something was replaced\n + * Example: \snippet pistring.cpp PIString::replace_1 + * \sa \a replaced(), \a replaceAll() */ PIString & replace(const PIString & what, const PIString & with, bool * ok = 0); + + /*! \brief Replace first founded substring "what" with string "with" and return copied string + * \details If "ok" is not null, it set to "true" if something was replaced\n + * Example: \snippet pistring.cpp PIString::replaced_1 + * \sa \a replaced(), \a replaceAll() */ PIString replaced(const PIString & what, const PIString & with, bool * ok = 0) const {PIString str(*this); str.replace(what, with, ok); return str;} + + /*! \brief Replace all founded substrings "what" with strings "with" and return this string + * \details Example: \snippet pistring.cpp PIString::replaceAll + * \sa \a replace(), \a replaced() */ PIString & replaceAll(const PIString & what, const PIString & with); PIString replaceAll(const PIString & what, const PIString & with) const {PIString str(*this); str.replaceAll(what, with); return str;} + + /*! \brief Insert symbol "c" after index "index" and return this string + * \details Example: \snippet pistring.cpp PIString::insert_0 */ PIString & insert(const int index, const PIChar & c) {PIVector::insert(index, c); return *this;} + + /*! \brief Insert symbol "c" after index "index" and return this string + * \details Example: \snippet pistring.cpp PIString::insert_1 */ PIString & insert(const int index, const char & c) {return insert(index, PIChar(c));} + + /*! \brief Insert string "str" after index "index" and return this string + * \details Example: \snippet pistring.cpp PIString::insert_2 */ PIString & insert(const int index, const PIString & str); + + /*! \brief Insert string "str" after index "index" and return this string + * \details Example: \snippet pistring.cpp PIString::insert_2 */ PIString & insert(const int index, const char * c) {return insert(index, PIString(c));} + + /*! \brief Enlarge string to length "len" by addition sequence of symbols + * "c" at the end of string, and return this string + * \details Example: \snippet pistring.cpp PIString::expandRightTo + * \sa \a expandLeftTo() */ PIString & expandRightTo(const int len, const PIChar & c) {if (len > length()) resize(len, c); return *this;} + + /*! \brief Enlarge string to length "len" by addition sequence of symbols + * "c" at the beginning of string, and return this string + * \details Example: \snippet pistring.cpp PIString::expandLeftTo + * \sa \a expandRightTo() */ PIString & expandLeftTo(const int len, const PIChar & c) {if (len > length()) insert(0, PIString(len - length(), c)); return *this;} + + /*! \brief Reverse string and return this string + * \details Example: \snippet pistring.cpp PIString::reverse + * \sa \a reversed() */ PIString & reverse() {PIString str(*this); clear(); piForeachR (const PIChar & c, str) push_back(c); return *this;} + + /*! \brief Reverse copy of this string and return it + * \details Example: \snippet pistring.cpp PIString::reversed + * \sa \a reverse() */ PIString reversed() const {PIString str(*this); str.reverse(); return str;} //const char * data() {return convertToStd().c_str();} + + + /*! \brief Return real bytes count of this string + * \details It`s equivalent length os char sequence + * returned by function \a data() \n + * Example: \snippet pistring.cpp PIString::lengthAscii + * \sa \a data() */ int lengthAscii() const; + + /*! \brief Return \c char * representation of this string + * \details This function fill buffer by sequence + * of chars. Minimum length of this buffer is count + * of symbols. Returned \c char * is valid until next + * execution of this function.\n + * Example: \snippet pistring.cpp PIString::data + * \sa \a lengthAscii() */ const char * data() const; + + //! \brief Return \c std::string representation of this string const string stdString() const {return convertToStd();} #ifdef HAS_LOCALE wstring stdWString() const {return convertToWString();} #endif + + //! \brief Return \a PIByteArray contains \a data() of this string PIByteArray toByteArray() const {const char * d = data(); return PIByteArray(d, lengthAscii());} + + /*! \brief Split string with delimiter "delim" to \a PIStringList and return it + * \details Example: \snippet pistring.cpp PIString::split */ PIStringList split(const PIString & delim) const; + + //! \brief Convert each symbol in copyed string to upper case and return it PIString toUpperCase() const; + + //! \brief Convert each symbol in copyed string to lower case and return it PIString toLowerCase() const; #ifdef HAS_LOCALE PIString toNativeDecimalPoints() const {PIString s(*this); if (currentLocale == 0) return s; return s.replaceAll(".", currentLocale->decimal_point);} @@ -151,60 +385,199 @@ public: PIString toNativeDecimalPoints() const {PIString s(*this); return s;} #endif + + //! \brief Search substring "str" from symbol at index "start" and return first occur position + //! \details Example: \snippet pistring.cpp PIString::find int find(const char str, const int start = 0) const; + + //! \brief Search substring "str" from symbol at index "start" and return first occur position + //! \details Example: \snippet pistring.cpp PIString::find int find(const PIString str, const int start = 0) const; + + //! \brief Search substring "str" from symbol at index "start" and return first occur position + //! \details Example: \snippet pistring.cpp PIString::find int find(const char * str, const int start = 0) const {return find(PIString(str), start);} + + //! \brief Search substring "str" from symbol at index "start" and return first occur position + //! \details Example: \snippet pistring.cpp PIString::find int find(const string str, const int start = 0) const {return find(PIString(str), start);} + + //! \brief Search substring "str" from symbol at index "start" and return last occur position + //! \details Example: \snippet pistring.cpp PIString::findLast int findLast(const char str, const int start = 0) const; + + //! \brief Search substring "str" from symbol at index "start" and return last occur position + //! \details Example: \snippet pistring.cpp PIString::findLast int findLast(const PIString str, const int start = 0) const; + + //! \brief Search substring "str" from symbol at index "start" and return last occur position + //! \details Example: \snippet pistring.cpp PIString::findLast int findLast(const char * str, const int start = 0) const {return findLast(PIString(str), start);} + + //! \brief Search substring "str" from symbol at index "start" and return last occur position + //! \details Example: \snippet pistring.cpp PIString::findLast int findLast(const string str, const int start = 0) const {return findLast(PIString(str), start);} + + //! \brief Return symbols length of string int length() const {return size();} + + //! \brief Return \c true if string is empty, i.e. length = 0 bool isEmpty() const {return (size() == 0 || *this == "");} + + //! \brief Return \c true if string equal "true" or "on" or positive numeric value bool toBool() const {PIString s(*this); if (atof(s.toNativeDecimalPoints().data()) > 0. || s.trimmed().toLowerCase() == "true" || s.trimmed().toLowerCase() == "on") return true; return false;} + + //! \brief Return \c char numeric value of string char toChar() const; + + //! \brief Return \c short numeric value of string in base "base" + //! \details Example: \snippet pistring.cpp PIString::toNumber short toShort(int base = -1, bool * ok = 0) const {return short(toNumberBase(*this, base, ok));} + + //! \brief Return \c ushort numeric value of string in base "base" + //! \details Example: \snippet pistring.cpp PIString::toNumber ushort toUShort(int base = -1, bool * ok = 0) const {return ushort(toNumberBase(*this, base, ok));} + + //! \brief Return \c int numeric value of string in base "base" + //! \details Example: \snippet pistring.cpp PIString::toNumber int toInt(int base = -1, bool * ok = 0) const {return int(toNumberBase(*this, base, ok));} + + //! \brief Return \c uint numeric value of string in base "base" + //! \details Example: \snippet pistring.cpp PIString::toNumber uint toUInt(int base = -1, bool * ok = 0) const {return uint(toNumberBase(*this, base, ok));} + + //! \brief Return \c long numeric value of string in base "base" + //! \details Example: \snippet pistring.cpp PIString::toNumber long toLong(int base = -1, bool * ok = 0) const {return long(toNumberBase(*this, base, ok));} + + //! \brief Return \c ulong numeric value of string in base "base" + //! \details Example: \snippet pistring.cpp PIString::toNumber ulong toULong(int base = -1, bool * ok = 0) const {return ulong(toNumberBase(*this, base, ok));} + + //! \brief Return \c llong numeric value of string in base "base" + //! \details Example: \snippet pistring.cpp PIString::toNumber llong toLLong(int base = -1, bool * ok = 0) const {return toNumberBase(*this, base, ok);} + + //! \brief Return \c ullong numeric value of string in base "base" + //! \details Example: \snippet pistring.cpp PIString::toNumber ullong toULLong(int base = -1, bool * ok = 0) const {return ullong(toNumberBase(*this, base, ok));} + + //! \brief Return \c float numeric value of string + //! \details Example: \snippet pistring.cpp PIString::toFloat float toFloat() const {PIString s(*this); return (float)atof(s.toNativeDecimalPoints().data());} + + //! \brief Return \c double numeric value of string + //! \details Example: \snippet pistring.cpp PIString::toFloat double toDouble() const {PIString s(*this); return atof(s.toNativeDecimalPoints().data());} + + //! \brief Return \c ldouble numeric value of string + //! \details Example: \snippet pistring.cpp PIString::toFloat ldouble toLDouble() const {PIString s(*this); return atof(s.toNativeDecimalPoints().data());} //inline PIString & setNumber(const char value) {clear(); *this += itos(value); return *this;} + + //! \brief Set string content to numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::setNumber PIString & setNumber(const short value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} + + //! \brief Set string content to numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::setNumber PIString & setNumber(const ushort value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} + + //! \brief Set string content to numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::setNumber PIString & setNumber(const int value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} + + //! \brief Set string content to numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::setNumber PIString & setNumber(const uint value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} + + //! \brief Set string content to numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::setNumber PIString & setNumber(const long value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} + + //! \brief Set string content to numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::setNumber PIString & setNumber(const ulong value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} - PIString & setNumber(const llong value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} - PIString & setNumber(const ullong value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} + + //! \brief Set string content to numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::setNumber + PIString & setNumber(const llong & value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} + + //! \brief Set string content to numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::setNumber + PIString & setNumber(const ullong & value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} + + //! \brief Set string content to numeric representation of "value" + //! \details Example: \snippet pistring.cpp PIString::setFloat PIString & setNumber(const float value) {clear(); *this += ftos(value); return *this;} - PIString & setNumber(const double value) {clear(); *this += dtos(value); return *this;} - PIString & setNumber(const ldouble value) {clear(); *this += dtos(value); return *this;} - PIString & setReadableSize(long bytes); + + //! \brief Set string content to numeric representation of "value" + //! \details Example: \snippet pistring.cpp PIString::setFloat + PIString & setNumber(const double & value) {clear(); *this += dtos(value); return *this;} + + //! \brief Set string content to numeric representation of "value" + //! \details Example: \snippet pistring.cpp PIString::setFloat + PIString & setNumber(const ldouble & value) {clear(); *this += dtos(value); return *this;} + + //! \brief Set string content to human readable size in B/kB/MB/GB/TB + //! \details Example: \snippet pistring.cpp PIString::setReadableSize + PIString & setReadableSize(llong bytes); //inline static PIString fromNumber(const char value) {return PIString(itos(value));} + + //! \brief Return string contains numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::fromNumber static PIString fromNumber(const short value, int base = 10, bool * ok = 0) {return fromNumberBase(llong(value), base, ok);} + + //! \brief Return string contains numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::fromNumber static PIString fromNumber(const ushort value, int base = 10, bool * ok = 0) {return fromNumberBase(llong(value), base, ok);} + + //! \brief Return string contains numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::fromNumber static PIString fromNumber(const int value, int base = 10, bool * ok = 0) {return fromNumberBase(llong(value), base, ok);} + + //! \brief Return string contains numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::fromNumber static PIString fromNumber(const uint value, int base = 10, bool * ok = 0) {return fromNumberBase(llong(value), base, ok);} + + //! \brief Return string contains numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::fromNumber static PIString fromNumber(const long value, int base = 10, bool * ok = 0) {return fromNumberBase(llong(value), base, ok);} + + //! \brief Return string contains numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::fromNumber static PIString fromNumber(const ulong value, int base = 10, bool * ok = 0) {return fromNumberBase(llong(value), base, ok);} - static PIString fromNumber(const llong value, int base = 10, bool * ok = 0) {return fromNumberBase(value, base, ok);} - static PIString fromNumber(const ullong value, int base = 10, bool * ok = 0) {return fromNumberBase(llong(value), base, ok);} + + //! \brief Return string contains numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::fromNumber + static PIString fromNumber(const llong & value, int base = 10, bool * ok = 0) {return fromNumberBase(value, base, ok);} + + //! \brief Return string contains numeric representation of "value" in base "base" + //! \details Example: \snippet pistring.cpp PIString::fromNumber + static PIString fromNumber(const ullong & value, int base = 10, bool * ok = 0) {return fromNumberBase(llong(value), base, ok);} + + //! \brief Return string contains numeric representation of "value" + //! \details Example: \snippet pistring.cpp PIString::fromFloat static PIString fromNumber(const float value) {return PIString(ftos(value));} - static PIString fromNumber(const double value) {return PIString(dtos(value));} - static PIString fromNumber(const ldouble value) {return PIString(dtos(value));} + + //! \brief Return string contains numeric representation of "value" + //! \details Example: \snippet pistring.cpp PIString::fromFloat + static PIString fromNumber(const double & value) {return PIString(dtos(value));} + + //! \brief Return string contains numeric representation of "value" + //! \details Example: \snippet pistring.cpp PIString::fromFloat + static PIString fromNumber(const ldouble & value) {return PIString(dtos(value));} + + //! \brief Return "true" or "false" static PIString fromBool(const bool value) {return PIString(value ? "true" : "false");} - static PIString readableSize(long bytes) {PIString s; s.setReadableSize(bytes); return s;} + + //! \brief Return string contains human readable size in B/kB/MB/GB/TB + //! \details Example: \snippet pistring.cpp PIString::readableSize + static PIString readableSize(llong bytes) {PIString s; s.setReadableSize(bytes); return s;} private: static const char toBaseN[]; @@ -254,45 +627,92 @@ private: wstring convertToWString() const {wstring s; for (int i = 0; i < length(); ++i) s.push_back(at(i).toWChar()); return s;} #endif - PIByteArray data_; + mutable PIByteArray data_; //string std_string; //wstring std_wstring; }; + +//! \relatesalso PIString \brief Output operator to std::ostream (cout) inline std::ostream & operator <<(std::ostream & s, const PIString & v) {for (int i = 0; i < v.length(); ++i) s << v[i]; return s;} + +//! \relatesalso PIString \brief Input operator from std::istream (cin) inline std::istream & operator >>(std::istream & s, PIString & v) {string ss; s >> ss; v << PIString(ss); return s;} +//! \relatesalso PIString \relatesalso PICout \brief Output operator to PICout +inline PICout operator <<(PICout s, const PIString & v) {s.space(); s.quote(); s.setControl(0, true); for (int i = 0; i < v.length(); ++i) s << v[i]; s.restoreControl(); s.quote(); return s;} + + +//! \relatesalso PIString \relatesalso PIByteArray \brief Output operator to PIByteArray inline PIByteArray & operator <<(PIByteArray & s, const PIString & v) {s << v.size_s(); for (int i = 0; i < v.length(); ++i) s << v[i]; return s;} + +//! \relatesalso PIString \relatesalso PIByteArray \brief Input operator from PIByteArray inline PIByteArray & operator >>(PIByteArray & s, PIString & v) {int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;} + +//! \relatesalso PIString \brief Return concatenated string inline PIString operator +(const PIString & str, const PIString & f) {PIString s(str); s += f; return s;} //inline PIString operator +(const PIString & f, const char c) {PIString s(f); s.push_back(c); return s;} + +//! \relatesalso PIString \brief Return concatenated string inline PIString operator +(const PIString & f, const char * str) {PIString s(f); s += str; return s;} + +//! \relatesalso PIString \brief Return concatenated string inline PIString operator +(const PIString & f, const string & str) {PIString s(f); s += str; return s;} //inline PIString operator +(const char c, const PIString & f) {return PIString(c) + f;} + +//! \relatesalso PIString \brief Return concatenated string inline PIString operator +(const char * str, const PIString & f) {return PIString(str) + f;} + +//! \relatesalso PIString \brief Return concatenated string inline PIString operator +(const string & str, const PIString & f) {return PIString(str) + f;} inline char chrUpr(char c); inline char chrLwr(char c); -class PIStringList: public PIVector + +/*!\brief Strings array class + * \details This class is based on \a PIVector and + * expand it functionality. */ +class PIP_EXPORT PIStringList: public PIVector { public: + + //! Contructs empty strings list PIStringList() {;} + + //! Contructs strings list with one string "str" PIStringList(const PIString & str) {push_back(str);} + + //! Contructs empty strings list with strings "s0" and "s1" PIStringList(const PIString & s0, const PIString & s1) {push_back(s0); push_back(s1);} + + //! Contructs empty strings list with strings "s0", "s1" and "s2" PIStringList(const PIString & s0, const PIString & s1, const PIString & s2) {push_back(s0); push_back(s1); push_back(s2);} + + //! Contructs empty strings list with strings "s0", "s1", "s2" and "s3" PIStringList(const PIString & s0, const PIString & s1, const PIString & s2, const PIString & s3) {push_back(s0); push_back(s1); push_back(s2); push_back(s3);} + + //! \brief Join all strings in one with delimiter "delim" and return it + //! \details Example: \snippet pistring.cpp PIStringList::join PIString join(const PIString & delim) const {PIString s; for (uint i = 0; i < size(); ++i) {s += at(i); if (i < size() - 1) s += delim;} return s;} + + //! \brief Remove all strings equal "value" and return this + //! \details Example: \snippet pistring.cpp PIStringList::removeStrings PIStringList & removeStrings(const PIString & value) {for (uint i = 0; i < size(); ++i) {if (at(i) == value) {remove(i); --i;}} return *this;} + PIStringList & remove(uint num) {PIVector::remove(num); return *this;} PIStringList & remove(uint num, uint count) {PIVector::remove(num, count); return *this;} + + //! \brief Remove duplicated strings and return this + //! \details Example: \snippet pistring.cpp PIStringList::removeDuplicates PIStringList & removeDuplicates(); + + //! Return sum of lengths of all strings uint contentSize() {uint s = 0; for (uint i = 0; i < size(); ++i) s += at(i).size(); return s;} PIStringList & operator <<(const PIString & str) {push_back(str); return *this;} @@ -308,6 +728,10 @@ public: }; +//! \relatesalso PIStringList \brief Output operator to std::ostream (cout) inline std::ostream & operator <<(std::ostream & s, const PIStringList & v) {s << "{"; for (uint i = 0; i < v.size(); ++i) {s << '\"' << v[i] << '\"'; if (i < v.size() - 1) s << ", ";} s << "}"; return s;} +//! \relatesalso PIStringList \relatesalso PICout \brief Output operator to PICout +inline PICout operator <<(PICout s, const PIStringList & v) {s.space(); s.setControl(0, true); s << "{"; for (uint i = 0; i < v.size(); ++i) {s << '\"' << v[i] << '\"'; if (i < v.size() - 1) s << ", ";} s << "}"; s.restoreControl(); return s;} + #endif // PISTRING_H diff --git a/pisystemmonitor.cpp b/pisystemmonitor.cpp index b880ac0c..774bbfc6 100644 --- a/pisystemmonitor.cpp +++ b/pisystemmonitor.cpp @@ -42,7 +42,7 @@ bool PISystemMonitor::startOnProcess(int pID) { file.open("/proc/" + PIString::fromNumber(pID_) + "/stat", PIIODevice::ReadOnly); filem.open("/proc/" + PIString::fromNumber(pID_) + "/statm", PIIODevice::ReadOnly); if (!file.isOpened()) { - piCout << "[PISystemMonitor] Can`t find process with ID = " << pID_ << "!" << endl; + piCout << "[PISystemMonitor] Can`t find process with ID = " << pID_ << "!"; return false; } cycle = -1; diff --git a/pisystemmonitor.h b/pisystemmonitor.h index 2f013092..51ed5068 100644 --- a/pisystemmonitor.h +++ b/pisystemmonitor.h @@ -23,7 +23,7 @@ #include "pithread.h" #include "piprocess.h" -class PISystemMonitor: public PIThread +class PIP_EXPORT PISystemMonitor: public PIThread { public: PISystemMonitor(); diff --git a/pisystemtests.h b/pisystemtests.h index 1c8e4539..eea34196 100644 --- a/pisystemtests.h +++ b/pisystemtests.h @@ -23,9 +23,9 @@ #include "piconfig.h" namespace PISystemTests { - extern long time_resolution_ns; - extern long time_elapsed_ns; - extern long usleep_offset_us; + PIP_EXPORT extern long time_resolution_ns; + PIP_EXPORT extern long time_elapsed_ns; + PIP_EXPORT extern long usleep_offset_us; class PISystemTestReader { public: diff --git a/pithread.cpp b/pithread.cpp index b9e97860..9ff6b122 100644 --- a/pithread.cpp +++ b/pithread.cpp @@ -31,6 +31,36 @@ void piUSleep(int usecs) { } +/*! \class PIThread + * \brief Thread class + * \details This class allow you exec your code in separate thread. + * + * \section PIThread_sec0 Synopsis + * Multithread . + * + * \section PIThread_sec1 To/from data convertions + * Most common constructor is \a PIThread(const char * str), where "str" + * is null-terminated string, e.g. \c "string". This is 7 chars with last char = 0. + * Also you can constructs \a PIThread from single \a PIChar, \a PIByteArray, + * other \a PIThread or sequency of the same characters with custom length.\n \n + * This class has implicit conversions to const char * and + * \c std::string. Also there are functions to make same convertions: + * * \a data() - to const char * , + * * \a stdString() - to \c std::string, + * * \a toByteArray() - to \a PIByteArray. + * + * \section PIThread_sec2 Numeric operations + * You can get symbolic representation of any numeric value with function + * \a setNumber(any integer value, int base = 10, bool * ok = 0). Default + * arguments are set for decimal base system, but you can choose any system + * from 2 to 40. There are the same static functions \a fromNumber(), that + * returns \a PIThread. \n + * Also there is function \a setReadableSize() which is set human-readable + * size in bytes, Kb, Mb, Gb or Pb. Static analog is \a readableSize(). + * + */ + + PIThread::PIThread(void * data, ThreadFunc func, bool startNow, int timer_delay): PIObject() { piMonitor.threads++; data_ = data; @@ -58,12 +88,14 @@ PIThread::~PIThread() { #ifndef WINDOWS pthread_cancel(thread); #else + TerminateThread(thread, 0); CloseHandle(thread); #endif } bool PIThread::start(int timer_delay) { + if (running) return false; terminating = running = false; timer = timer_delay; #ifndef WINDOWS @@ -88,6 +120,7 @@ bool PIThread::start(int timer_delay) { bool PIThread::startOnce() { + if (running) return false; terminating = running = false; #ifndef WINDOWS pthread_attr_t attr; @@ -110,13 +143,13 @@ bool PIThread::startOnce() { } -void PIThread::terminate(bool hard) { +void PIThread::terminate() { if (thread == 0) return; running = false; #ifndef WINDOWS - if (hard) kill((ullong)thread, SIGKILL); - else pthread_cancel(thread); + pthread_cancel(thread); #else + TerminateThread(thread, 0); CloseHandle(thread); #endif thread = 0; @@ -125,6 +158,10 @@ void PIThread::terminate(bool hard) { void * PIThread::thread_function(void * t) { +#ifndef WINDOWS + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0); +#endif PIThread & ct = *((PIThread * )t); ct.running = true; ct.begin(); @@ -150,6 +187,10 @@ void * PIThread::thread_function(void * t) { void * PIThread::thread_function_once(void * t) { +#ifndef WINDOWS + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0); +#endif PIThread & ct = *((PIThread * )t); ct.running = true; ct.begin(); diff --git a/pithread.h b/pithread.h index d9f109e0..0de14501 100644 --- a/pithread.h +++ b/pithread.h @@ -1,3 +1,8 @@ +/*! \file pithread.h + * \brief Thread + * + * This file declare thread class and some wait functions +*/ /* PIP - Platform Independent Primitives Thread @@ -24,86 +29,188 @@ #include "pimutex.h" #include "piobject.h" -#ifdef WINDOWS -inline void msleep(int msecs) {Sleep(msecs);} +#ifdef DOXYGEN +//! \brief Sleep for "msecs" milliseconds +void msleep(int msecs); #else +# ifdef WINDOWS +inline void msleep(int msecs) {Sleep(msecs);} +# else inline void msleep(int msecs) {usleep(msecs * 1000);} +# endif #endif + +/*! \brief Precise sleep for "usecs" microseconds + * \details This function consider \c "usleep" offset + * on QNX/Linux/Mac, which is calculated with + * \a pip_sys_test program. If there is correct + * offset value in system config, this function + * wait \b exactly "usecs" microseconds. */ void piUSleep(int usecs); // on !Windows consider constant "usleep" offset + +/*! \brief Precise sleep for "msecs" milliseconds + * \details This function exec \a piUSleep (msecs * 1000). */ inline void piMSleep(int msecs) {piUSleep(msecs * 1000);} // on !Windows consider constant "usleep" offset typedef void (*ThreadFunc)(void * ); -/// events: -/// void started() -/// void stopped() -/// -/// handlers: -/// bool start(int timer_delay = -1) -/// bool start(ThreadFunc func, int timer_delay = -1) -/// bool startOnce() -/// bool startOnce(ThreadFunc func) -/// void stop(bool wait = false) -/// void terminate(bool hard = false) -/// bool waitForStart(int timeout_msecs = -1) -/// bool waitForFinish(int timeout_msecs = -1) -/// void lock() -/// void unlock() -class PIThread: public PIObject { + +class PIP_EXPORT PIThread: public PIObject +{ + PIOBJECT(PIThread) public: PIThread(void * data, ThreadFunc func, bool startNow = false, int timer_delay = -1); PIThread(bool startNow = false, int timer_delay = -1); virtual ~PIThread(); -#ifdef QNX +#ifdef DOXYGEN + //! Priority of thread + enum Priority {piHighest /** Highest */, + piHigh /** High */, + piNormal /** Normal, default */, + piLow /** Low */, + piLowerst /** Lowest */ + }; +#else +# ifdef QNX enum Priority {piHighest = 12, piHigh = 11, piNormal = 10, piLow = 9, piLowerst = 8 }; -#else +# else enum Priority {piHighest = -2, piHigh = -1, piNormal = 0, piLow = 1, piLowerst = 2 }; +# endif #endif - //bool start(int timer_delay = -1); - EVENT_HANDLER0(PIThread, bool, start) {return start(-1);} - EVENT_HANDLER1(PIThread, bool, start, int, timer_delay); - EVENT_HANDLER1(PIThread, bool, start, ThreadFunc, func) {ret_func = func; return start(-1);} - EVENT_HANDLER2(PIThread, bool, start, ThreadFunc, func, int, timer_delay) {ret_func = func; return start(timer_delay);} - EVENT_HANDLER0(PIThread, bool, startOnce); - EVENT_HANDLER1(PIThread, bool, startOnce, ThreadFunc, func) {ret_func = func; return startOnce();} - EVENT_HANDLER0(PIThread, void, stop) {stop(false);} - EVENT_HANDLER1(PIThread, void, stop, bool, wait) {terminating = true; if (wait) waitForFinish();} - EVENT_HANDLER0(PIThread, void, terminate) {terminate(false);} - EVENT_HANDLER1(PIThread, void, terminate, bool, hard); + EVENT_HANDLER0(bool, start) {return start(-1);} + EVENT_HANDLER1(bool, start, int, timer_delay); + EVENT_HANDLER1(bool, start, ThreadFunc, func) {ret_func = func; return start(-1);} + EVENT_HANDLER2(bool, start, ThreadFunc, func, int, timer_delay) {ret_func = func; return start(timer_delay);} + EVENT_HANDLER0(bool, startOnce); + EVENT_HANDLER1(bool, startOnce, ThreadFunc, func) {ret_func = func; return startOnce();} + EVENT_HANDLER0(void, stop) {stop(false);} + EVENT_HANDLER1(void, stop, bool, wait) {terminating = true; if (wait) waitForFinish();} + EVENT_HANDLER0(void, terminate); + + //! \brief Set common data passed to external function void setData(void * d) {data_ = d;} + + //! \brief Set external function that will be executed after every \a run() void setSlot(ThreadFunc func) {ret_func = func;} + + //! \brief Set priority of thread void setPriority(PIThread::Priority prior); + + //! \brief Return priority of thread PIThread::Priority priority() const {return priority_;} + + //! \brief Return \c true if thread is running bool isRunning() const {return running;} - EVENT_HANDLER0(PIThread, bool, waitForFinish) {return waitForFinish(-1);} - EVENT_HANDLER1(PIThread, bool, waitForFinish, int, timeout_msecs); - EVENT_HANDLER0(PIThread, bool, waitForStart) {return waitForStart(-1);} - EVENT_HANDLER1(PIThread, bool, waitForStart, int, timeout_msecs); + + bool isStopping() const {return running && terminating;} + + EVENT_HANDLER0(bool, waitForStart) {return waitForStart(-1);} + EVENT_HANDLER1(bool, waitForStart, int, timeout_msecs); + EVENT_HANDLER0(bool, waitForFinish) {return waitForFinish(-1);} + EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs); + + //! \brief Set necessity of lock every \a run with internal mutex void needLockRun(bool need) {lockRun = need;} - EVENT_HANDLER0(PIThread, void, lock) {mutex_.lock();} - EVENT_HANDLER0(PIThread, void, unlock) {mutex_.unlock();} + EVENT_HANDLER0(void, lock) {mutex_.lock();} + EVENT_HANDLER0(void, unlock) {mutex_.unlock();} + + //! \brief Return internal mutex PIMutex & mutex() {return mutex_;} - EVENT(PIThread, started) - EVENT(PIThread, stopped) + EVENT(started) + EVENT(stopped) + +//! \handlers +//! \{ + + /** \fn bool start(int timer_delay = -1) + * \brief Start thread + * \details Start execution of \a run() in internal loop with + * "timer_delay" delay in milliseconds. If "timer_delay" <= 0 + * there is no delay in loop. Thread also exec external function + * set by \a setSlot() if it`s not null + * + * \return \c false if thread already started or can`t start thread */ + + /** \fn bool start(ThreadFunc func, int timer_delay = -1) + * \brief Start thread + * \details Overloaded function. Set external function "func" before start + * + * \return \c false if thread already started or can`t start thread */ + + /** \fn bool startOnce() + * \brief Start thread without internal loop + * \details Start execution of \a run() once. Thread also exec + * external function set by \a setSlot() if it`s not null + * + * \return \c false if thread already started or can`t start thread */ + + /** \fn bool startOnce(ThreadFunc func) + * \brief Start thread without internal loop + * \details Overloaded function. Set external function "func" before start + * + * \return \c false if thread already started or can`t start thread */ + + /** \fn void stop(bool wait = false) + * \brief Stop thread + * \details Stop execution of thread and wait for it finish + * if "wait" is \c true. This function can block for infinite + * time if "wait" is \c true and any of thread function is + * busy forever */ + + /** \fn void terminate() + * \brief Strongly stop thread + * \details Stop execution of thread immediately */ + + /** \fn bool waitForStart(int timeout_msecs = -1) + * \brief Wait for thread start + * \details This function block until thread finish for "timeout_msecs" + * or forever if "timeout_msecs" < 0 + * + * \return \c false if timeout is exceeded */ + + /** \fn bool waitForFinish(int timeout_msecs = -1) + * \brief Wait for thread finish + * \details This function block until thread start for "timeout_msecs" + * or forever if "timeout_msecs" < 0 + * + * \return \c false if timeout is exceeded */ + + //! \fn void lock() + //! \brief Lock internal mutex + + //! \fn void unlock() + //! \brief Unlock internal mutex + +//! \} +//! \events +//! \{ + + //! \fn void started() + //! \brief Raise on thread start + + //! \fn void stopped() + //! \brief Raise on thread stop + +//! \} protected: static void * thread_function(void * t); static void * thread_function_once(void * t); - virtual void begin() {;} // executed at start - virtual void run() {;} // main loop executed with "timer_delay" timeout - virtual void end() {;} // executed at finish + virtual void begin() {;} + virtual void run() {;} + virtual void end() {;} volatile bool terminating, running, lockRun; int timer, policy; diff --git a/pitimer.cpp b/pitimer.cpp index da90d0c2..400ee637 100644 --- a/pitimer.cpp +++ b/pitimer.cpp @@ -20,6 +20,73 @@ #include "pitimer.h" #include "pisystemtests.h" +bool operator ==(const PITime & t0, const PITime & t1) { + return (t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds); +} +bool operator <(const PITime & t0, const PITime & t1) { + if (t0.hours == t1.hours) { + if (t0.minutes == t1.minutes) { + return t0.seconds < t1.seconds; + } else return t0.minutes < t1.minutes; + } else return t0.hours < t1.hours; +} +bool operator >(const PITime & t0, const PITime & t1) { + if (t0.hours == t1.hours) { + if (t0.minutes == t1.minutes) { + return t0.seconds > t1.seconds; + } else return t0.minutes > t1.minutes; + } else return t0.hours > t1.hours; +} + +bool operator ==(const PIDate & t0, const PIDate & t1) { + return (t0.year == t1.year && t0.month == t1.month && t0.day == t1.day); +} +bool operator <(const PIDate & t0, const PIDate & t1) { + if (t0.year == t1.year) { + if (t0.month == t1.month) { + return t0.day < t1.day; + } else return t0.month < t1.month; + } else return t0.year < t1.year; +} +bool operator >(const PIDate & t0, const PIDate & t1) { + if (t0.year == t1.year) { + if (t0.month == t1.month) { + return t0.day > t1.day; + } else return t0.month > t1.month; + } else return t0.year > t1.year; +} + +bool operator ==(const PIDateTime & t0, const PIDateTime & t1) { + return (t0.year == t1.year && t0.month == t1.month && t0.day == t1.day && + t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds); +} +bool operator <(const PIDateTime & t0, const PIDateTime & t1) { + if (t0.year == t1.year) { + if (t0.month == t1.month) { + if (t0.day == t1.day) { + if (t0.hours == t1.hours) { + if (t0.minutes == t1.minutes) { + return t0.seconds < t1.seconds; + } else return t0.minutes < t1.minutes; + } else return t0.hours < t1.hours; + } else return t0.day < t1.day; + } else return t0.month < t1.month; + } else return t0.year < t1.year; +} +bool operator >(const PIDateTime & t0, const PIDateTime & t1) { + if (t0.year == t1.year) { + if (t0.month == t1.month) { + if (t0.day == t1.day) { + if (t0.hours == t1.hours) { + if (t0.minutes == t1.minutes) { + return t0.seconds > t1.seconds; + } else return t0.minutes > t1.minutes; + } else return t0.hours > t1.hours; + } else return t0.day > t1.day; + } else return t0.month > t1.month; + } else return t0.year > t1.year; +} + #ifdef PIP_TIMER_RT PITimer::TimerPool * pool = 0; @@ -34,17 +101,20 @@ PITimer::PITimer(TimerEvent slot, void * data_, bool threaded_) #endif ret_func = slot; data = data_; + running_ = false; + interval_ = 0.; #ifdef PIP_TIMER_RT piMonitor.timers++; ti = -1; threaded = threaded_; - running = false; memset(&se, 0, sizeof(se)); se.sigev_notify = SIGEV_THREAD; se.sigev_value.sival_ptr = this; se.sigev_notify_function = PITimer::timer_event; se.sigev_notify_attributes = 0; lockRun = false; +#else + deferred_ = false; #endif reset(); } @@ -58,17 +128,20 @@ PITimer::PITimer(bool threaded_) #endif ret_func = 0; data = 0; + running_ = false; + interval_ = 0.; #ifdef PIP_TIMER_RT piMonitor.timers++; ti = -1; threaded = threaded_; - running = false; memset(&se, 0, sizeof(se)); se.sigev_notify = SIGEV_THREAD; se.sigev_value.sival_ptr = this; se.sigev_notify_function = PITimer::timer_event; se.sigev_notify_attributes = 0; lockRun = false; +#else + deferred_ = false; #endif reset(); } @@ -84,14 +157,15 @@ PITimer::~PITimer() { #ifdef PIP_TIMER_RT void PITimer::start(double msecs) { - if (ti != -1 || msecs < 0 || running) return; + if (ti != -1 || msecs < 0 || running_) return; + interval_ = msecs; if (!threaded) { ticks = int(msecs); if (pool == 0) pool = new TimerPool(); pool->add(this); //cout << "not threaded timer start " << msecs << " msecs\n"; if (!pool->isRunning()) pool->start(); - running = true; + running_ = true; return; } spec.it_interval.tv_nsec = ((int)(msecs * 1000) % 1000000) * 1000; @@ -100,16 +174,17 @@ void PITimer::start(double msecs) { ti = timer_create(CLOCK_REALTIME, &se, &timer); //cout << "***create timer " << msecs << " msecs\n"; if (ti == -1) { - piCout << "[PITimer] Can`t create timer for " << msecs << " msecs: " << errorString() << endl; + piCout << "[PITimer] Can`t create timer for " << msecs << " msecs: " << errorString(); return; } timer_settime(timer, 0, &spec, 0); - running = true; + running_ = true; } void PITimer::deferredStart(double interval_msecs, double delay_msecs) { - if (ti != -1 || interval_msecs < 0 || running) return; + if (ti != -1 || interval_msecs < 0 || running_) return; + interval_ = interval_msecs; spec.it_interval.tv_nsec = ((int)(interval_msecs * 1000) % 1000000) * 1000; spec.it_interval.tv_sec = (time_t)(interval_msecs / 1000); spec.it_value.tv_nsec = ((int)(delay_msecs * 1000) % 1000000) * 1000; @@ -117,16 +192,17 @@ void PITimer::deferredStart(double interval_msecs, double delay_msecs) { ti = timer_create(CLOCK_REALTIME, &se, &timer); //cout << "***create timer\n"; if (ti == -1) { - piCout << "[PITimer] Can`t create timer for " << interval_msecs << " msecs: " << errorString() << endl; + piCout << "[PITimer] Can`t create timer for " << interval_msecs << " msecs: " << errorString(); return; } timer_settime(timer, 0, &spec, 0); - running = true; + running_ = true; } void PITimer::deferredStart(double interval_msecs, const PIDateTime & start_datetime) { - if (ti != -1 || interval_msecs < 0 || running) return; + if (ti != -1 || interval_msecs < 0 || running_) return; + interval_ = interval_msecs; spec.it_interval.tv_nsec = ((int)(interval_msecs * 1000) % 1000000) * 1000; spec.it_interval.tv_sec = (time_t)(interval_msecs / 1000); struct tm dtm; @@ -142,11 +218,11 @@ void PITimer::deferredStart(double interval_msecs, const PIDateTime & start_date ti = timer_create(CLOCK_REALTIME, &se, &timer); //cout << "***create timer\n"; if (ti == -1) { - piCout << "[PITimer] Can`t create timer for " << interval_msecs << " msecs: " << errorString() << endl; + piCout << "[PITimer] Can`t create timer for " << interval_msecs << " msecs: " << errorString(); return; } timer_settime(timer, TIMER_ABSTIME, &spec, 0); - running = true; + running_ = true; } @@ -170,7 +246,7 @@ void PITimer::TimerPool::begin() { sa.sa_handler = empty_handler; sigemptyset(&sa.sa_mask); if (sigaction(SIGALRM, &sa, 0) == -1) { - piCout << "[PITimer] sigaction error: " << errorString() << endl; + piCout << "[PITimer] sigaction error: " << errorString(); stop(); return; }*/ @@ -184,12 +260,12 @@ void PITimer::TimerPool::begin() { spec.it_value = spec.it_interval; //cout << "***create pool timer\n"; if (timer_create(CLOCK_REALTIME, &se, &timer) == -1) { - piCout << "[PITimer] Can`t create timer for pool: " << errorString() << endl; + piCout << "[PITimer] Can`t create timer for pool: " << errorString(); stop(); return; } if (timer_settime(timer, 0, &spec, 0) == -1) { - piCout << "[PITimer] Can`t set timer for pool: " << errorString() << endl; + piCout << "[PITimer] Can`t set timer for pool: " << errorString(); stop(); return; } @@ -221,8 +297,8 @@ void PITimer::TimerPool::run() { void PITimer::stop() { - if (!running) return; - running = false; + if (!running_) return; + running_ = false; if (!threaded) { if (pool != 0) { pool->remove(this); @@ -231,12 +307,13 @@ void PITimer::stop() { } if (ti != -1) timer_delete(timer); ti = -1; + interval_ = 0.; } void PITimer::timer_event(sigval e) { PITimer * ct = (PITimer * )e.sival_ptr; - if (!ct->running) return; + if (!ct->running_) return; if (ct->lockRun) ct->lock(); if (ct->ret_func != 0) ct->ret_func(ct->data, 1); ct->timeout(ct->data, 1); @@ -255,12 +332,12 @@ void PITimer::timer_event(sigval e) { bool PITimer::waitForFinish(int timeout_msecs) { if (timeout_msecs < 0) { - while (running) + while (running_) msleep(1); return true; } int cnt = 0; - while (running && cnt < timeout_msecs) { + while (running_ && cnt < timeout_msecs) { msleep(1); ++cnt; } @@ -270,18 +347,65 @@ bool PITimer::waitForFinish(int timeout_msecs) { #else void PITimer::start(double msecs) { - if (msecs < 0 || running) return; + if (msecs < 0 || running_) return; + interval_ = msecs; inc_time = PISystemTime::fromMilliseconds(msecs); st_time = currentSystemTime() + inc_time; + deferred_ = false; + running_ = true; PIThread::start(); } +void PITimer::deferredStart(double interval_msecs, double delay_msecs) { + //piCout << "defStart exec with" << delay_msecs << interval_msecs; + if (interval_msecs < 0 || running_) return; + interval_ = interval_msecs; + PISystemTime cst = currentSystemTime(); + inc_time = PISystemTime::fromMilliseconds(interval_msecs); + st_time = currentSystemTime() + PISystemTime::fromMilliseconds(delay_msecs); + if (st_time < cst) st_time = cst; + running_ = deferred_ = true; + PIThread::start(); + //piCout << "timer start def"; +} + + +void PITimer::deferredStart(double interval_msecs, const PIDateTime & start_datetime) { + //piCout << "defStart exec to" << start_datetime.toString() << interval_msecs; + if (interval_msecs < 0 || running_) return; + interval_ = interval_msecs; + PISystemTime cst = currentSystemTime(); + inc_time = PISystemTime::fromMilliseconds(interval_msecs); + st_time = start_datetime.toSystemTime(); + if (st_time < cst) st_time = cst; + running_ = deferred_ = true; + PIThread::start(); + //piCout << "timer start def"; +} + + void PITimer::run() { - if (!running) return; + if (!running_) return; + while (deferred_) { + PISystemTime tst = st_time - currentSystemTime(); + if (tst.seconds > 0) { + piMSleep(100); + if (!running_) return; + continue; + } + if (tst.nanoseconds > 100000000) { + piMSleep(100); + if (!running_) return; + continue; + } + tst.sleep(); + deferred_ = false; + if (!running_) return; + } (st_time - currentSystemTime()).sleep(); st_time += inc_time; - if (lockRun) lock(); + //if (lockRun) lock(); if (ret_func != 0) ret_func(data, 1); timeout(data, 1); tick(data, 1); @@ -293,7 +417,7 @@ void PITimer::run() { timeout(data, i.delim); tick(data, i.delim); } - if (lockRun) unlock(); + //if (lockRun) unlock(); } #endif @@ -524,7 +648,7 @@ PISystemTime currentSystemTime() { } -PIString PITime::toString(const PIString & format) { +PIString PITime::toString(const PIString & format) const { PIString ts = format; ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0')); ts.replace("h", PIString::fromNumber(hours)); @@ -532,11 +656,14 @@ PIString PITime::toString(const PIString & format) { ts.replace("m", PIString::fromNumber(minutes)); ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0')); ts.replace("s", PIString::fromNumber(seconds)); + ts.replace("zzz", PIString::fromNumber(milliseconds).expandLeftTo(3, '0')); + ts.replace("zz", PIString::fromNumber(milliseconds).expandLeftTo(2, '0')); + ts.replace("z", PIString::fromNumber(milliseconds)); return ts; } -PIString PIDate::toString(const PIString & format) { +PIString PIDate::toString(const PIString & format) const { PIString ts = format; ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0')); ts.replace("yy", PIString::fromNumber(year).right(2)); @@ -549,14 +676,8 @@ PIString PIDate::toString(const PIString & format) { } -PIString PIDateTime::toString(const PIString & format) { +PIString PIDateTime::toString(const PIString & format) const { PIString ts = format; - ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0')); - ts.replace("h", PIString::fromNumber(hours)); - ts.replace("mm", PIString::fromNumber(minutes).expandLeftTo(2, '0')); - ts.replace("m", PIString::fromNumber(minutes)); - ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0')); - ts.replace("s", PIString::fromNumber(seconds)); ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0')); ts.replace("yy", PIString::fromNumber(year).right(2)); ts.replace("y", PIString::fromNumber(year).right(1)); @@ -564,10 +685,45 @@ PIString PIDateTime::toString(const PIString & format) { ts.replace("M", PIString::fromNumber(month)); ts.replace("dd", PIString::fromNumber(day).expandLeftTo(2, '0')); ts.replace("d", PIString::fromNumber(day)); + ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0')); + ts.replace("h", PIString::fromNumber(hours)); + ts.replace("mm", PIString::fromNumber(minutes).expandLeftTo(2, '0')); + ts.replace("m", PIString::fromNumber(minutes)); + ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0')); + ts.replace("s", PIString::fromNumber(seconds)); + ts.replace("zzz", PIString::fromNumber(milliseconds).expandLeftTo(3, '0')); + ts.replace("zz", PIString::fromNumber(milliseconds).expandLeftTo(2, '0')); + ts.replace("z", PIString::fromNumber(milliseconds)); return ts; } +time_t PIDateTime::toSecondSinceEpoch() const { + tm pt; + pt.tm_sec = seconds; + pt.tm_min = minutes; + pt.tm_hour = hours; + pt.tm_mday = day; + pt.tm_mon = month - 1; + pt.tm_year = year - 1900; + return mktime(&pt); +} + + +PIDateTime PIDateTime::fromSecondSinceEpoch(const time_t sec) { + tm * pt = localtime(&sec); + PIDateTime dt; + dt.seconds = pt->tm_sec; + dt.minutes = pt->tm_min; + dt.hours = pt->tm_hour; + dt.day = pt->tm_mday; + dt.month = pt->tm_mon + 1; + dt.year = pt->tm_year + 1900; + return dt; + +} + + PIString time2string(const PITime & time, const PIString & format) { PIString ts = format; ts.replace("hh", PIString::fromNumber(time.hours).expandLeftTo(2, '0')); diff --git a/pitimer.h b/pitimer.h index 10c9d7a2..9359ccbd 100644 --- a/pitimer.h +++ b/pitimer.h @@ -28,7 +28,7 @@ typedef void (*TimerEvent)(void * , int ); -class PISystemTime { +class PIP_EXPORT PISystemTime { public: PISystemTime() {seconds = nanoseconds = 0;} PISystemTime(long s, long ns) {seconds = s; nanoseconds = ns; checkOverflows();} @@ -71,29 +71,65 @@ private: inline PIByteArray & operator <<(PIByteArray & s, const PISystemTime & v) {s << v.seconds << v.nanoseconds; return s;} inline PIByteArray & operator >>(PIByteArray & s, PISystemTime & v) {s >> v.seconds >> v.nanoseconds; return s;} -struct PITime { +struct PIP_EXPORT PITime { + PITime() {hours = minutes = seconds = milliseconds = 0;} + int milliseconds; int seconds; int minutes; int hours; - PIString toString(const PIString & format = "h:mm:ss"); + PIString toString(const PIString & format = "h:mm:ss") const; }; +PIP_EXPORT bool operator ==(const PITime & t0, const PITime & t1); +PIP_EXPORT bool operator <(const PITime & t0, const PITime & t1); +PIP_EXPORT bool operator >(const PITime & t0, const PITime & t1); +inline bool operator !=(const PITime & t0, const PITime & t1) {return !(t0 == t1);} +inline bool operator <=(const PITime & t0, const PITime & t1) {return !(t0 > t1);} +inline bool operator >=(const PITime & t0, const PITime & t1) {return !(t0 < t1);} -struct PIDate { +struct PIP_EXPORT PIDate { + PIDate() {year = month = day = 0;} int day; int month; int year; - PIString toString(const PIString & format = "d.MM.yyyy"); + PIString toString(const PIString & format = "d.MM.yyyy") const; }; +PIP_EXPORT bool operator ==(const PIDate & t0, const PIDate & t1); +PIP_EXPORT bool operator <(const PIDate & t0, const PIDate & t1); +PIP_EXPORT bool operator >(const PIDate & t0, const PIDate & t1); +inline bool operator !=(const PIDate & t0, const PIDate & t1) {return !(t0 == t1);} +inline bool operator <=(const PIDate & t0, const PIDate & t1) {return !(t0 > t1);} +inline bool operator >=(const PIDate & t0, const PIDate & t1) {return !(t0 < t1);} -struct PIDateTime { +struct PIP_EXPORT PIDateTime { + PIDateTime() {year = month = day = hours = minutes = seconds = 0;} + PIDateTime(const PITime & time) {year = month = day = 0; hours = time.hours; minutes = time.minutes; seconds = time.seconds; milliseconds = time.milliseconds;} + PIDateTime(const PIDate & date) {year = date.year; month = date.month; day = date.day; hours = minutes = seconds = milliseconds = 0;} + PIDateTime(const PIDate & date, const PITime & time) {year = date.year; month = date.month; day = date.day; hours = time.hours; minutes = time.minutes; seconds = time.seconds; milliseconds = time.milliseconds;} + int milliseconds; int seconds; int minutes; int hours; int day; int month; int year; - PIString toString(const PIString & format = "h:mm:ss d.MM.yyyy"); + PIDateTime normalized() const {return PIDateTime::fromSecondSinceEpoch(toSecondSinceEpoch());} + void normalize() {*this = normalized();} + PIString toString(const PIString & format = "h:mm:ss d.MM.yyyy") const; + time_t toSecondSinceEpoch() const; + PISystemTime toSystemTime() const {return PISystemTime(int(toSecondSinceEpoch()), milliseconds * 1000000);} + void operator +=(const PIDateTime & d1) {year += d1.year; month += d1.month; day += d1.day; hours += d1.hours; minutes += d1.minutes; seconds += d1.seconds; normalize();} + void operator -=(const PIDateTime & d1) {year -= d1.year; month -= d1.month; day -= d1.day; hours -= d1.hours; minutes -= d1.minutes; seconds -= d1.seconds; normalize();} + static PIDateTime fromSecondSinceEpoch(const time_t sec); + static PIDateTime fromSystemTime(const PISystemTime & st) {PIDateTime dt = fromSecondSinceEpoch(st.seconds); dt.milliseconds = piClampi(st.nanoseconds / 1000000, 0, 999); return dt;} }; +inline PIDateTime operator +(const PIDateTime & d0, const PIDateTime & d1) {PIDateTime td = d0; td += d1; return td.normalized();} +inline PIDateTime operator -(const PIDateTime & d0, const PIDateTime & d1) {PIDateTime td = d0; td -= d1; return td.normalized();} +PIP_EXPORT bool operator ==(const PIDateTime & t0, const PIDateTime & t1); +PIP_EXPORT bool operator <(const PIDateTime & t0, const PIDateTime & t1); +PIP_EXPORT bool operator >(const PIDateTime & t0, const PIDateTime & t1); +inline bool operator !=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 == t1);} +inline bool operator <=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 > t1);} +inline bool operator >=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 < t1);} /// events: /// void timeout(void * data, int delimiter) @@ -108,13 +144,14 @@ struct PIDateTime { /// void clearDelimiters() /// void lock() /// void unlock() -class PITimer +class PIP_EXPORT PITimer #ifndef PIP_TIMER_RT : public PIThread #else : public PIObject #endif { + PIOBJECT(PITimer) public: PITimer(TimerEvent slot = 0, void * data = 0, bool threaded = true); PITimer(bool threaded); @@ -122,53 +159,53 @@ public: void setData(void * data_) {data = data_;} void setSlot(TimerEvent slot) {ret_func = slot;} + double interval() const {return interval_;} #ifndef PIP_TIMER_RT # ifdef WINDOWS - EVENT_HANDLER0(PITimer, void, reset) {t_st = GetCurrentTime();} - EVENT_HANDLER1(PIThread, bool, start, int, timer_delay) {start(double(timer_delay)); return true;} - EVENT_HANDLER1(PITimer, void, start, double, msecs); + EVENT_HANDLER0(void, reset) {t_st = GetCurrentTime();} # elif defined(MAC_OS) - EVENT_HANDLER0(PITimer, void, reset) {clock_get_time(__pi_mac_clock, &t_st);} - EVENT_HANDLER1(PIThread, bool, start, int, timer_delay) {start(double(timer_delay)); return true;} - EVENT_HANDLER1(PITimer, void, start, double, msecs); + EVENT_HANDLER0(void, reset) {clock_get_time(__pi_mac_clock, &t_st);} # else - EVENT_HANDLER0(PITimer, void, reset) {clock_gettime(0, &t_st);} - EVENT_HANDLER1(PIThread, bool, start, int, timer_delay) {start(double(timer_delay)); return true;} - EVENT_HANDLER1(PITimer, void, start, double, msecs); + EVENT_HANDLER0(void, reset) {clock_gettime(0, &t_st);} # endif + EVENT_HANDLER1(bool, start, int, timer_delay) {start(double(timer_delay)); return true;} + EVENT_HANDLER1(void, start, double, msecs); + EVENT_HANDLER0(void, stop) {running_ = false;} + EVENT_HANDLER2(void, deferredStart, double, interval_msecs, double, delay_msecs); + EVENT_HANDLER2(void, deferredStart, double, interval_msecs, const PIDateTime &, start_datetime); #else - EVENT_HANDLER0(PITimer, void, reset) {clock_gettime(0, &t_st);} - EVENT_HANDLER1(PITimer, void, start, double, msecs); - EVENT_HANDLER2(PITimer, void, deferredStart, double, interval_msecs, double, delay_msecs); - EVENT_HANDLER2(PITimer, void, deferredStart, double, interval_msecs, const PIDateTime &, start_datetime); - EVENT_HANDLER0(PITimer, void, stop); - EVENT_HANDLER0(PITimer, bool, waitForFinish) {return waitForFinish(-1);} - EVENT_HANDLER1(PITimer, bool, waitForFinish, int, timeout_msecs); - bool isRunning() const {return running;} + EVENT_HANDLER0(void, reset) {clock_gettime(0, &t_st);} + EVENT_HANDLER1(void, start, double, msecs); + EVENT_HANDLER2(void, deferredStart, double, interval_msecs, double, delay_msecs); + EVENT_HANDLER2(void, deferredStart, double, interval_msecs, const PIDateTime &, start_datetime); + EVENT_HANDLER0(void, stop); + EVENT_HANDLER0(bool, waitForFinish) {return waitForFinish(-1);} + EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs); + bool isRunning() const {return running_;} void needLockRun(bool need) {lockRun = need;} - EVENT_HANDLER0(PITimer, void, lock) {mutex_.lock();} - EVENT_HANDLER0(PITimer, void, unlock) {mutex_.unlock();} + EVENT_HANDLER0(void, lock) {mutex_.lock();} + EVENT_HANDLER0(void, unlock) {mutex_.unlock();} #endif void addDelimiter(int delim, TimerEvent slot = 0) {ret_funcs << TimerSlot(slot, delim);} void removeDelimiter(int delim) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].delim == delim) {ret_funcs.remove(i); i--;}} void removeDelimiter(TimerEvent slot) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].slot == slot) {ret_funcs.remove(i); i--;}} void removeDelimiter(int delim, TimerEvent slot) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].slot == slot && ret_funcs[i].delim == delim) {ret_funcs.remove(i); i--;}} - EVENT_HANDLER0(PITimer, void, clearDelimiters) {ret_funcs.clear();} + EVENT_HANDLER0(void, clearDelimiters) {ret_funcs.clear();} double elapsed_n(); // nanoseconds double elapsed_u(); // microseconds - double elapsed_m(); // miliseconds + double elapsed_m(); // milliseconds double elapsed_s(); // seconds double reset_time_n(); // nanoseconds double reset_time_u(); // microseconds - double reset_time_m(); // miliseconds + double reset_time_m(); // milliseconds double reset_time_s(); // seconds PISystemTime reset_time(); static double elapsed_system_n(); // nanoseconds static double elapsed_system_u(); // microseconds - static double elapsed_system_m(); // miliseconds + static double elapsed_system_m(); // milliseconds static double elapsed_system_s(); // seconds @@ -200,7 +237,7 @@ public: int ticks; #endif - EVENT2(PITimer, timeout, void * , data, int, delimiter) + EVENT2(timeout, void * , data, int, delimiter) protected: virtual void tick(void * data, int delimiter) {;} @@ -208,10 +245,12 @@ protected: private: #ifndef PIP_TIMER_RT void run(); + void end() {interval_ = 0.;} PISystemTime st_time, inc_time; + bool deferred_; #else - bool running, threaded; + bool threaded; volatile bool lockRun; PIMutex mutex_; int ti; @@ -219,6 +258,8 @@ private: timer_t timer; sigevent se; #endif + bool running_; + double interval_; #ifdef WINDOWS long @@ -246,12 +287,12 @@ private: extern PITimer::TimerPool * pool; #endif -PITime currentTime(); -PIDate currentDate(); -PIDateTime currentDateTime(); -PISystemTime currentSystemTime(); -PIString time2string(const PITime & time, const PIString & format = "h:mm:ss"); // obsolete, use PITime.toString() instead -PIString date2string(const PIDate & date, const PIString & format = "d.MM.yyyy"); // obsolete, use PITime.toString() instead -PIString datetime2string(const PIDateTime & datetime, const PIString & format = "h:mm:ss d.MM.yyyy"); // obsolete, use PIDateTime.toString() instead +PIP_EXPORT PITime currentTime(); +PIP_EXPORT PIDate currentDate(); +PIP_EXPORT PIDateTime currentDateTime(); +PIP_EXPORT PISystemTime currentSystemTime(); +PIP_EXPORT PIString time2string(const PITime & time, const PIString & format = "h:mm:ss"); // obsolete, use PITime.toString() instead +PIP_EXPORT PIString date2string(const PIDate & date, const PIString & format = "d.MM.yyyy"); // obsolete, use PITime.toString() instead +PIP_EXPORT PIString datetime2string(const PIDateTime & datetime, const PIString & format = "h:mm:ss d.MM.yyyy"); // obsolete, use PIDateTime.toString() instead #endif // PITIMER_H diff --git a/pivariable.h b/pivariable.h index 6f20de90..08fc51e8 100644 --- a/pivariable.h +++ b/pivariable.h @@ -22,11 +22,11 @@ #include "piconfig.h" -class PIVariant { +class PIP_EXPORT PIVariant { friend class PIVariable; public: enum Type {Bool, Char, Short, Int, Long, LLong, UChar, UShort, UInt, ULong, ULLong, Float, Double, LDouble, String, StringList}; - + PIVariant() {setValue(0.);} PIVariant(const char * v) {setValue(v);} PIVariant(const bool & v) {setValue(v);} @@ -45,7 +45,7 @@ public: PIVariant(const ldouble & v) {setValue(v);} PIVariant(const PIString & v) {setValue(v);} PIVariant(const PIStringList & v) {setValue(v);} - + inline void setValue(const char * v) {setValue(PIString(v));} inline void setValue(const bool & v) {type = PIVariant::Bool; vBool = v;} inline void setValue(const char & v) {type = PIVariant::Char; vChar = v;} @@ -92,7 +92,7 @@ public: inline void operator =(const ldouble & v) {type = PIVariant::LDouble; vLDouble = v;} inline void operator =(const PIString & v) {type = PIVariant::String; vString = v;} inline void operator =(const PIStringList & v) {type = PIVariant::StringList; vStringList = v;} - + bool operator ==(const PIVariant & v) const; inline bool operator !=(const PIVariant & v) const {return !(*this == v);} @@ -115,25 +115,25 @@ public: }; PIString vString; PIStringList vStringList; - + static PIVariant readFromString(const PIString & s); - + private: static PIVariant::Type fromString(const PIString & str); static PIString toString(const PIVariant::Type & var); static uint variableSize(const PIVariant::Type & var); static double variableValue(const char * var_ptr, const PIVariant::Type & var); - + }; inline std::ostream & operator <<(std::ostream & s, const PIVariant & v) {s << v.typeName() << ": " << v.stringValue(); return s;} -class PIVariable { +class PIP_EXPORT PIVariable { public: PIVariable() {;} PIVariable(const PIString & str) {setVariable(str);} ~PIVariable() {;} - + void setVariable(const PIString & str); void writeVariable(char * dest); inline void readVariable(const char * var_ptr) {value_ = PIVariant::variableValue((char * )((long)var_ptr + offset), type_);} @@ -143,37 +143,37 @@ public: inline void setName(const PIString & str) {name_ = str;} inline double value() const {return value_;} inline void setValue(const double & val) {value_ = val;} - + int offset; - + private: PIVariant::Type type_; uint size_; PIString name_; double value_; - + }; -/* +/* * PIStruct is abstract structure, described by *.conf file with format of each line: * " = # ". * e.g. "pi = double #f 3.1418" - * + * * You can write or read binary content of this struct * by functions "writeData" and "readData", e.g. * "char * data = new char[struct.size()]; * struct.writeData(data);" - * + * * Access to each variable in struct is looks like * "double value = struct["pi"].value();" */ -class PIStruct { +class PIP_EXPORT PIStruct { public: PIStruct() {;} PIStruct(const PIString & str) {parseFile(str);} - + void parseFile(const PIString & file); void readData(const char * data); void writeData(char * data); @@ -184,17 +184,12 @@ public: inline void setName(const PIString & str) {name_ = str;} inline PIVariable & operator[](const uint & index) {return vars[index];} inline PIVariable & operator[](const PIString & name) {for (uint i = 0; i < vars.size(); ++i) if (vars[i].name() == name) return vars[i];} - + private: uint size_; PIString name_; PIVector vars; - + }; #endif // PIVARIABLE_H - -#/** PhEDIT attribute block -#-11:16777215 -#0:7338:monospace10:-3:-3:0 -#** PhEDIT attribute block ends (-0000117)**/