Files
pip/piincludes.cpp

464 lines
15 KiB
C++

/*
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 <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, "");
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
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(); if (v == 0) std::cout << "PIObject*(0x0)"; else 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
*/