/* PIP - Platform Independent Primitives Global includes Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "piincludes.h" #include "piconsole.h" bool isPIInit = false; bool piDebug = true; string ifconfigPath; PIInit piInit; lconv * currentLocale = #ifdef ANDROID 0; #else std::localeconv(); #endif #ifdef HAS_LOCALE static locale_t currentLocale_t = 0; #endif #ifdef MAC_OS clock_serv_t __pi_mac_clock; #endif PIMutex __PICout_mutex__; PIString __PICout_string__; #ifdef WINDOWS FILETIME __pi_ftjan1970; long long __pi_perf_freq = -1; PINtSetTimerResolution setTimerResolutionAddr = 0; #endif PIInit::PIInit() { if (isPIInit) return; isPIInit = true; #ifndef WINDOWS sigset_t ss; sigemptyset(&ss); sigaddset(&ss, SIGALRM); sigprocmask(SIG_BLOCK, &ss, 0); pthread_sigmask(SIG_BLOCK, &ss, 0); ifconfigPath = "/bin/ifconfig"; if (!fileExists(ifconfigPath)) { ifconfigPath = "/sbin/ifconfig"; if (!fileExists(ifconfigPath)) { ifconfigPath = "/usr/bin/ifconfig"; if (!fileExists(ifconfigPath)) { ifconfigPath = "/usr/sbin/ifconfig"; if (!fileExists(ifconfigPath)) { ifconfigPath = ""; } } } } #else // WinSock inint WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); // Timers init SYSTEMTIME jan1970 = {1970, 1, 4, 1, 0, 14, 15, 0}; SystemTimeToFileTime(&jan1970, &__pi_ftjan1970); LARGE_INTEGER pf; pf.QuadPart = -1; if (QueryPerformanceFrequency(&pf) != 0) __pi_perf_freq = pf.QuadPart; if (__pi_perf_freq == 0) __pi_perf_freq = -1; // Sleep precision init ntlib = LoadLibrary("ntdll.dll"); if (ntlib) setTimerResolutionAddr = (PINtSetTimerResolution)GetProcAddress(ntlib, "NtSetTimerResolution"); /*if (setTimerResolution) setTimerResolutionAddr(1, TRUE, &prev_res);*/ #endif //piDebug = true; #ifdef HAS_LOCALE //cout << "has locale" << endl; if (currentLocale_t != 0) { freelocale(currentLocale_t); currentLocale_t = 0; } currentLocale_t = newlocale(LC_ALL, setlocale(LC_ALL, ""), 0); #else setlocale(LC_ALL, ""); setlocale(LC_NUMERIC, "C"); #endif #ifdef MAC_OS host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &__pi_mac_clock); #endif } PIInit::~PIInit() { #ifdef WINDOWS WSACleanup(); //if (setTimerResolution) setTimerResolutionAddr(prev_res, TRUE, &prev_res); if (ntlib) FreeLibrary(ntlib); #endif #ifdef MAC_OS mach_port_deallocate(mach_task_self(), __pi_mac_clock); #endif //if (currentLocale_t != 0) freelocale(currentLocale_t); } #ifdef WINDOWS void * PICout::hOut = 0; WORD PICout::dattr = 0; DWORD PICout::smode = 0; #endif bool PICout::buffer_ = false; PICout::PICout(PIFlags controls): fo_(true), cc_(false), fc_(false), cnb_(10), co_(controls) { #ifdef WINDOWS if (hOut == 0) { hOut = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO sbi; GetConsoleScreenBufferInfo(hOut, &sbi); dattr = sbi.wAttributes; } attr_ = dattr; #endif __PICout_mutex__.lock(); } PICout::~PICout() { if (fc_) applyFormat(PICoutManipulators::Default); if (cc_) return; newLine(); __PICout_mutex__.unlock(); } PICout PICout::operator <<(const PICoutAction v) { #ifdef WINDOWS CONSOLE_SCREEN_BUFFER_INFO sbi; COORD coord; CONSOLE_CURSOR_INFO curinfo; #endif switch (v) { case PICoutManipulators::Flush: if (!PICout::buffer_) std::cout << std::flush; break; case PICoutManipulators::Backspace: if (!PICout::buffer_) { #ifdef WINDOWS GetConsoleScreenBufferInfo(hOut, &sbi); coord = sbi.dwCursorPosition; coord.X = piMax(0, int(coord.X) - 1); SetConsoleCursorPosition(hOut, coord); printf(" "); SetConsoleCursorPosition(hOut, coord); #else printf("\e[1D \e[1D"); #endif } break; case PICoutManipulators::ShowCursor: if (!PICout::buffer_) { #ifdef WINDOWS GetConsoleCursorInfo(hOut, &curinfo); curinfo.bVisible = true; SetConsoleCursorInfo(hOut, &curinfo); #else printf("\e[?25h"); #endif } break; case PICoutManipulators::HideCursor: if (!PICout::buffer_) { #ifdef WINDOWS GetConsoleCursorInfo(hOut, &curinfo); curinfo.bVisible = false; SetConsoleCursorInfo(hOut, &curinfo); #else printf("\e[?25l"); #endif } break; case PICoutManipulators::ClearScreen: if (!PICout::buffer_) { #ifdef WINDOWS /// TODO !!! /*GetConsoleCursorInfo(hOut, &curinfo); curinfo.bVisible = false; SetConsoleCursorInfo(hOut, &curinfo); SetConsoleCursorPosition(hOut, ulcoord); FillConsoleOutputAttribute(hOut, dattr, width * (height + 1), ulcoord, &written); FillConsoleOutputCharacter(hOut, ' ', width * (height + 1), ulcoord, &written);*/ #else printf("\e[H\e[J"); #endif } break; case PICoutManipulators::SaveContol: saveControl(); break; case PICoutManipulators::RestoreControl: restoreControl(); break; default: break; }; return *this; } #define PICOUTTOTARGET(v) {if (PICout::buffer_) __PICout_string__ << (v); else std::cout << (v);} #define PINUMERICCOUT if (cnb_ == 10) PICOUTTOTARGET(v) else PICOUTTOTARGET(PIString::fromNumber(v, cnb_)) PICout PICout::operator <<(const char * v) {space(); quote(); PICOUTTOTARGET(v) quote(); return *this;} PICout PICout::operator <<(const string & v) {space(); quote(); PICOUTTOTARGET(v) quote(); return *this;} PICout PICout::operator <<(const bool v) {space(); if (v) PICOUTTOTARGET("true") else PICOUTTOTARGET("false") return *this;} PICout PICout::operator <<(const char v) {space(); PICOUTTOTARGET(v) return *this;} PICout PICout::operator <<(const uchar v) {space(); if (cnb_ == 10) PICOUTTOTARGET(ushort(v)) else PICOUTTOTARGET(PIString::fromNumber(v, cnb_)) return *this;} PICout PICout::operator <<(const short int v) {space(); PINUMERICCOUT return *this;} PICout PICout::operator <<(const ushort v) {space(); PINUMERICCOUT return *this;} PICout PICout::operator <<(const int v) {space(); PINUMERICCOUT return *this;} PICout PICout::operator <<(const uint v) {space(); PINUMERICCOUT return *this;} PICout PICout::operator <<(const long v) {space(); PINUMERICCOUT return *this;} PICout PICout::operator <<(const ulong v) {space(); PINUMERICCOUT return *this;} PICout PICout::operator <<(const llong v) {space(); PINUMERICCOUT return *this;} PICout PICout::operator <<(const ullong v) {space(); PINUMERICCOUT return *this;} PICout PICout::operator <<(const float v) {space(); PICOUTTOTARGET(v) return *this;} PICout PICout::operator <<(const double v) {space(); PICOUTTOTARGET(v) return *this;} PICout PICout::operator <<(const void * v) {space(); PICOUTTOTARGET("0x") PICOUTTOTARGET(PIString::fromNumber(ullong(v), 16)) return *this;} PICout PICout::operator <<(const PIObject * v) { space(); if (v == 0) PICOUTTOTARGET("PIObject*(0x0)") else { PICOUTTOTARGET(v->className()) PICOUTTOTARGET("*(0x") PICOUTTOTARGET(PIString::fromNumber(ullong(v), 16)) PICOUTTOTARGET(", \"") PICOUTTOTARGET(v->name()) PICOUTTOTARGET("\")") } return *this; } PICout PICout::operator <<(const PICoutSpecialChar v) { switch (v) { case Null: if (PICout::buffer_) __PICout_string__ << PIChar(0); else std::cout << char(0); break; case NewLine: if (PICout::buffer_) __PICout_string__ << "\n"; else std::cout << '\n'; fo_ = true; break; case Tab: if (PICout::buffer_) __PICout_string__ << "\t"; else std::cout << '\t'; break; case Esc: #ifdef CC_VC if (PICout::buffer_) __PICout_string__ << PIChar(27); else std::cout << char(27); #else if (PICout::buffer_) __PICout_string__ << "\e"; else std::cout << '\e'; #endif break; case Quote: if (PICout::buffer_) __PICout_string__ << "\""; else std::cout << '"'; break; }; return *this; } #undef PICOUTTOTARGET #undef PINUMERICCOUT PICout & PICout::space() { if (!fo_ && co_[AddSpaces]) { if (PICout::buffer_) __PICout_string__ << " "; else std::cout << ' '; } fo_ = false; return *this; } PICout & PICout::quote() { if (co_[AddQuotes]) { if (PICout::buffer_) __PICout_string__ << "\""; else std::cout << '"'; } fo_ = false; return *this; } PICout & PICout::newLine() { if (co_[AddNewLine]) { if (PICout::buffer_) __PICout_string__ << "\n"; else std::cout << std::endl; } fo_ = false; return *this; } void PICout::applyFormat(PICoutFormat f) { if (PICout::buffer_) return; fc_ = true; #ifdef WINDOWS static int mask_fore = ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); static int mask_back = ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); switch (f) { case Bin: case Oct: case Dec: case Hex: break; case PICoutManipulators::Bold: attr_ |= FOREGROUND_INTENSITY; break; case PICoutManipulators::Underline: attr_ |= COMMON_LVB_UNDERSCORE; break; case PICoutManipulators::Black: attr_ = (attr_ & mask_fore); break; case PICoutManipulators::Red: attr_ = (attr_ & mask_fore) | FOREGROUND_RED; break; case PICoutManipulators::Green: attr_ = (attr_ & mask_fore) | FOREGROUND_GREEN; break; case PICoutManipulators::Blue: attr_ = (attr_ & mask_fore) | FOREGROUND_BLUE; break; case PICoutManipulators::Yellow: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN; break; case PICoutManipulators::Magenta: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_BLUE; break; case PICoutManipulators::Cyan: attr_ = (attr_ & mask_fore) | FOREGROUND_GREEN | FOREGROUND_BLUE; break; case PICoutManipulators::White: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break; case PICoutManipulators::BackBlack: attr_ = (attr_ & mask_back); break; case PICoutManipulators::BackRed: attr_ = (attr_ & mask_back) | BACKGROUND_RED; break; case PICoutManipulators::BackGreen: attr_ = (attr_ & mask_back) | BACKGROUND_GREEN; break; case PICoutManipulators::BackBlue: attr_ = (attr_ & mask_back) | BACKGROUND_BLUE; break; case PICoutManipulators::BackYellow: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN; break; case PICoutManipulators::BackMagenta: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_BLUE; break; case PICoutManipulators::BackCyan: attr_ = (attr_ & mask_back) | BACKGROUND_GREEN | BACKGROUND_BLUE; break; case PICoutManipulators::BackWhite: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break; case PICoutManipulators::Default: attr_ = dattr; break; default: break; } SetConsoleTextAttribute(hOut, attr_); #else switch (f) { case Bin: case Oct: case Dec: case Hex: break; case PICoutManipulators::Bold: printf("\e[1m"); break; case PICoutManipulators::Faint: printf("\e[2m"); break; case PICoutManipulators::Italic: printf("\e[3m"); break; case PICoutManipulators::Underline: printf("\e[4m"); break; case PICoutManipulators::Blink: printf("\e[5m"); break; case PICoutManipulators::Black: printf("\e[30m"); break; case PICoutManipulators::Red: printf("\e[31m"); break; case PICoutManipulators::Green: printf("\e[32m"); break; case PICoutManipulators::Blue: printf("\e[34m"); break; case PICoutManipulators::Yellow: printf("\e[33m"); break; case PICoutManipulators::Magenta: printf("\e[35m"); break; case PICoutManipulators::Cyan: printf("\e[36m"); break; case PICoutManipulators::White: printf("\e[37m"); break; case PICoutManipulators::BackBlack: printf("\e[40m"); break; case PICoutManipulators::BackRed: printf("\e[41m"); break; case PICoutManipulators::BackGreen: printf("\e[42m"); break; case PICoutManipulators::BackBlue: printf("\e[44m"); break; case PICoutManipulators::BackYellow: printf("\e[43m"); break; case PICoutManipulators::BackMagenta: printf("\e[45m"); break; case PICoutManipulators::BackCyan: printf("\e[46m"); break; case PICoutManipulators::BackWhite: printf("\e[47m"); break; case PICoutManipulators::Default: printf("\e[0m"); break; default: break; } #endif } bool PICout::setBufferActive(bool on, bool clear) { PIMutexLocker ml(__PICout_mutex__); bool ret = PICout::buffer_; if (clear) __PICout_string__.clear(); PICout::buffer_ = on; return ret; } bool PICout::isBufferActive() { return PICout::buffer_; } PIString PICout::buffer(bool clear) { PIMutexLocker ml(__PICout_mutex__); PIString ret = __PICout_string__; if (clear) __PICout_string__.clear(); return ret; } void PICout::clearBuffer() { PIMutexLocker ml(__PICout_mutex__); __PICout_string__.clear(); } /*! \class PICout * \brief Class for formatted output similar std::cout * * \section PICout_sec0 Synopsis * This class provide many stream operators for output with some features. * Output to PICout is thread-sequential, i.e. doesn`t mixed from parallel * threads. * * \section PICout_sec1 Features * - insertion spaces between entries * - insertion new line at the end of output * - strings are quoted * - custom output operator can be easily written * * \section PICout_ex0 Usage * \snippet picout.cpp 0 * * \section PICout_ex1 Writing your own output operator * \snippet picout.cpp own */ /*! \mainpage What is PIP * PIP - Platform-Independent Primitives - is crossplatform library for C++ developers. * It is wrap around STL and pure C++. This library can help developers write non-GUI * projects much more quickly, efficiently and customizable than on pure C++. * Library contains many classes, some of them are pure abstract, some classes * can be used as they are, some classes should be inherited to new classes. * PIP provide classes: * * direct output to console (\a PICout) * * containers (\a PIVector, \a PIList, \a PIMap, \a PIStack) * * byte array (\a PIByteArray) * * string (\a PIString, \a PIStringList) * * base object (events and handlers) (\a PIObject) * * thread (\a PIThread) * * timer (\a PITimer) * * console (information output) (\a PIConsole) * * stand-alone * * server * * client * * i/o devices * * base class (\a PIIODevice) * * file (\a PIFile) * * serial port (\a PISerial) * * ethernet (\a PIEthernet) * * USB (\a PIUSB) * * packets extractor (\a PIPacketExtractor) * * binary log (\a PIBinaryLog) * * connection quality diagnotic (\a PIDiagnostics) * * command-line arguments parser (\a PICLI) * * math evaluator (\a PIEvaluator) * * peering net node (\a PIPeer) * * process (\a PIProcess) * * state machine (\a PIStateMachine) * \n \n Basic using of PIP described at page \ref using_basic */ /*! \page using_basic Getting started * Many novice programmers are solved many common task with system integrity: output to console, * keyboard buttons press detecting, working with serial ports, ethernet or files, and many other. * These tasks can solve this library, and code, based only on PIP will be compile and work * similar on many systems: Windows, any Linux, Red Hat, FreeBSD, MacOS X and QNX. * Typical application on PIP looks like this: \n \code{.cpp} #include // declare key press handler void key_event(char key, void * ); PIConsole console(false, key_event); // don`t start now, key handler is "key_event" // some vars int i = 2, j = 3; // implicit key press handler void key_event(char key, void * ) { switch (key) { case '-': i--; break; case '+': i++; break; case '(': j--; break; case ')': j++; break; }; }; class MainClass: public PITimer { PIOBJECT(MainClass) public: MainClass() {} protected: void tick(void * data, int delimiter) { piCout << "timer tick"; // timer tick } }; MainClass main_class; int main(int argc, char * argv[]) { // enabling auto-detection of exit button press, by default 'Q' (shift+q) console.enableExitCapture(); // if we want to parse command-line arguments PICLI cli(argc, argv); cli.addArgument("console"); // "-c" or "--console" cli.addArgument("debug"); // "-d" or "--debug" // enabling or disabling global debug flag piDebug = cli.hasArgument("debug"); // configure console console.addTab("first tab", '1'); console.addString("PIP console", 1, PIConsole::Bold); console.addVariable("int var (i)", &i, 1); console.addVariable("int green var (j)", &j, 1, PIConsole::Green); console.addString("'-' - i--", 2); console.addString("'+' - i++", 2); console.addString("'(' - j--", 2); console.addString("')' - j++", 2); console.addTab("second tab", '2'); console.addString("col 1", 1); console.addString("col 2", 2); console.addString("col 3", 3); console.setTab("first tab"); // start output to console if "console" argument exists if (cli.hasArgument("console")) console.start(); // start main class, e.g. 40 Hz main_class.start(25.); // wait for 'Q' press, independently if console is started or not console.waitForFinish(); return 0; }; \endcode * This code demonstrates simple interactive configurable program, which can be started with console * display or not, and with debug or not. \b MainClass is central class that also can be inherited from * \a PIThread and reimplement \a run() function. * \n Many PIP classes has events and event handlers, which can be connected one to another. * Details you can see at \a PIObject reference page (\ref PIObject_sec0). * \n To configure your program from file use \a PIConfig. * \n If you want more information see \ref using_advanced */ /*! \page using_advanced Advanced using * Sorry, creativity crisis xD */