463 lines
15 KiB
C++
463 lines
15 KiB
C++
/*
|
|
PIP - Platform Independent Primitives
|
|
Global includes
|
|
Copyright (C) 2013 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#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__;
|
|
|
|
|
|
#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, "");
|
|
#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
|
|
|
|
|
|
PICout::PICout(PIFlags<PICoutControl> 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: std::cout << std::flush; break;
|
|
case PICoutManipulators::Backspace:
|
|
#ifdef WINDOWS
|
|
GetConsoleScreenBufferInfo(hOut, &sbi);
|
|
coord = sbi.dwCursorPosition;
|
|
coord.X = piMax<int>(0, int(coord.X) - 1);
|
|
SetConsoleCursorPosition(hOut, coord);
|
|
printf(" ");
|
|
SetConsoleCursorPosition(hOut, coord);
|
|
#else
|
|
printf("\e[1D \e[1D");
|
|
#endif
|
|
break;
|
|
case PICoutManipulators::ShowCursor:
|
|
#ifdef WINDOWS
|
|
GetConsoleCursorInfo(hOut, &curinfo);
|
|
curinfo.bVisible = true;
|
|
SetConsoleCursorInfo(hOut, &curinfo);
|
|
#else
|
|
printf("\e[?25h");
|
|
#endif
|
|
break;
|
|
case PICoutManipulators::HideCursor:
|
|
#ifdef WINDOWS
|
|
GetConsoleCursorInfo(hOut, &curinfo);
|
|
curinfo.bVisible = false;
|
|
SetConsoleCursorInfo(hOut, &curinfo);
|
|
#else
|
|
printf("\e[?25l");
|
|
#endif
|
|
break;
|
|
case PICoutManipulators::ClearScreen:
|
|
#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 PINUMERICCOUT if (cnb_ == 10) std::cout << v; else std::cout << PIString::fromNumber(v, cnb_);
|
|
|
|
PICout PICout::operator <<(const uchar v) {space(); if (cnb_ == 10) std::cout << ushort(v); else std::cout << 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(); std::cout << v; return *this;}
|
|
|
|
PICout PICout::operator <<(const double v) {space(); std::cout << v; return *this;}
|
|
|
|
PICout PICout::operator <<(const void * v) {space(); std::cout << "0x" << PIString::fromNumber(ullong(v), 16); return *this;}
|
|
|
|
PICout PICout::operator <<(const PIObject * v) {space(); std::cout << v->className() << "*(" << "0x" << PIString::fromNumber(ullong(v), 16) << ", \"" << v->name() << "\")"; return *this;}
|
|
|
|
#undef PINUMERICCOUT
|
|
|
|
|
|
void PICout::applyFormat(PICoutFormat f) {
|
|
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
|
|
}
|
|
|
|
|
|
/*! \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 more 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)
|
|
* * 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)
|
|
* * command-line arguments parser (\a PICLI)
|
|
* * math evaluator (\a PIEvaluator)
|
|
* * peering net node (\a PIPeer)
|
|
* * process (\a PIProcess)
|
|
* * state machine (\a PIStateMachine)
|
|
* \n \n Basic using of PIP described at page \ref using_basic */
|
|
|
|
|
|
/*! \page using_basic Getting started
|
|
* Many novice programmers are solved many common task with system integrity: output to console,
|
|
* keyboard buttons press detecting, working with serial ports, ethernet or files, and many other.
|
|
* These tasks can solve this library, and code, based only on PIP will be compile and work
|
|
* similar on many systems: Windows, any Linux, Red Hat, FreeBSD, MacOS X and QNX.
|
|
* Typical application on PIP looks like this: \n
|
|
\code{.cpp}
|
|
#include <pip.h>
|
|
|
|
|
|
// declare key press handler
|
|
void key_event(char key, void * );
|
|
|
|
|
|
PIConsole console(false, key_event); // don`t start now, key handler is "key_event"
|
|
|
|
|
|
// some vars
|
|
int i = 2, j = 3;
|
|
|
|
|
|
// implicit key press handler
|
|
void key_event(char key, void * ) {
|
|
switch (key) {
|
|
case '-':
|
|
i--;
|
|
break;
|
|
case '+':
|
|
i++;
|
|
break;
|
|
case '(':
|
|
j--;
|
|
break;
|
|
case ')':
|
|
j++;
|
|
break;
|
|
};
|
|
};
|
|
|
|
|
|
class MainClass: public PITimer {
|
|
PIOBJECT(MainClass)
|
|
public:
|
|
MainClass() {}
|
|
protected:
|
|
void tick(void * data, int delimiter) {
|
|
piCout << "timer tick";
|
|
// timer tick
|
|
}
|
|
};
|
|
|
|
|
|
MainClass main_class;
|
|
|
|
|
|
int main(int argc, char * argv[]) {
|
|
// enabling auto-detection of exit button press, by default 'Q' (shift+q)
|
|
console.enableExitCapture();
|
|
|
|
// if we want to parse command-line arguments
|
|
PICLI cli(argc, argv);
|
|
cli.addArgument("console"); // "-c" or "--console"
|
|
cli.addArgument("debug"); // "-d" or "--debug"
|
|
|
|
// enabling or disabling global debug flag
|
|
piDebug = cli.hasArgument("debug");
|
|
|
|
// configure console
|
|
console.addTab("first tab", '1');
|
|
console.addString("PIP console", 1, PIConsole::Bold);
|
|
console.addVariable("int var (i)", &i, 1);
|
|
console.addVariable("int green var (j)", &j, 1, PIConsole::Green);
|
|
console.addString("'-' - i--", 2);
|
|
console.addString("'+' - i++", 2);
|
|
console.addString("'(' - j--", 2);
|
|
console.addString("')' - j++", 2);
|
|
console.addTab("second tab", '2');
|
|
console.addString("col 1", 1);
|
|
console.addString("col 2", 2);
|
|
console.addString("col 3", 3);
|
|
console.setTab("first tab");
|
|
|
|
// start output to console if "console" argument exists
|
|
if (cli.hasArgument("console"))
|
|
console.start();
|
|
|
|
// start main class, e.g. 40 Hz
|
|
main_class.start(25.);
|
|
|
|
// wait for 'Q' press, independently if console is started or not
|
|
console.waitForFinish();
|
|
|
|
return 0;
|
|
};
|
|
\endcode
|
|
* This code demonstrates simple interactive configurable program, which can be started with console
|
|
* display or not, and with debug or not. \b MainClass is central class that also can be inherited from
|
|
* \a PIThread and reimplement \a run() function.
|
|
* \n Many PIP classes has events and event handlers, which can be connected one to another.
|
|
* Details you can see at \a PIObject reference page (\ref PIObject_sec0).
|
|
* \n To configure your program from file use \a PIConfig.
|
|
* \n If you want more information see \ref using_advanced */
|
|
|
|
|
|
/*! \page using_advanced Advanced using
|
|
* Sorry, creativity crisis xD
|
|
*/
|