Init
This commit is contained in:
parent
693e47744a
commit
24afc71c1a
19 changed files with 5366 additions and 0 deletions
48
Makefile
Normal file
48
Makefile
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
IDIR=include
|
||||||
|
SRCDIR=src
|
||||||
|
ODIR=obj
|
||||||
|
ODIR_SHARED=obj_so
|
||||||
|
|
||||||
|
NAME = libztd
|
||||||
|
|
||||||
|
CC=g++
|
||||||
|
CXXFLAGS= -I$(IDIR) -Wall -pedantic -std=c++17
|
||||||
|
ifeq ($(DEBUG),true)
|
||||||
|
CXXFLAGS += -g
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(shell mkdir -p $(ODIR))
|
||||||
|
$(shell mkdir -p $(ODIR_SHARED))
|
||||||
|
|
||||||
|
# automatically finds .h and .hpp
|
||||||
|
DEPS = $(shell if [ -n "$(ls $(IDIR))" ] ; then ls $(IDIR)/*.hpp $(IDIR)/*.h 2>/dev/null ; fi)
|
||||||
|
|
||||||
|
# automatically finds .c and .cpp and makes the corresponding .o rule
|
||||||
|
OBJ = $(shell ls $(SRCDIR)/*.cpp $(SRCDIR)/*.c 2>/dev/null | sed 's|\.cpp|.o|g;s|\.c|.o|g;s|$(SRCDIR)/|$(ODIR)/|g')
|
||||||
|
|
||||||
|
# automatically finds .c and .cpp and makes the corresponding .o rule
|
||||||
|
OBJ_SHARED = $(shell ls $(SRCDIR)/*.cpp $(SRCDIR)/*.c 2>/dev/null | sed 's|\.cpp|.o|g;s|\.c|.o|g;s|$(SRCDIR)/|$(ODIR_SHARED)/|g')
|
||||||
|
|
||||||
|
|
||||||
|
$(ODIR)/%.o: $(SRCDIR)/%.c $(DEPS)
|
||||||
|
$(CC) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(ODIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
|
||||||
|
$(CC) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(ODIR_SHARED)/%.o: $(SRCDIR)/%.c $(DEPS)
|
||||||
|
$(CC) $(CXXFLAGS) -fPIC -o $@ $<
|
||||||
|
|
||||||
|
$(ODIR_SHARED)/%.o: $(SRCDIR)/%.cpp $(DEPS)
|
||||||
|
$(CC) $(CXXFLAGS) -fPIC -c -o $@ $<
|
||||||
|
|
||||||
|
all: static shared
|
||||||
|
|
||||||
|
static: $(OBJ)
|
||||||
|
ar rcs libztd.a $^
|
||||||
|
|
||||||
|
shared: $(OBJ_SHARED)
|
||||||
|
$(CC) -shared -o libztd.so $^
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm $(ODIR)/*.o $(ODIR_SHARED)/*.o
|
||||||
12
README.md
Normal file
12
README.md
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
# ztd
|
||||||
|
|
||||||
|
zawz's standard C++ library. Tools for easier coding
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
``make static`` for a static build
|
||||||
|
``make shared`` for a shared build
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
Use ``doxygen`` to generate HTML documentation files
|
||||||
120
include/zcolor.hpp
Normal file
120
include/zcolor.hpp
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
#ifndef ZCOLOR_HPP
|
||||||
|
#define ZCOLOR_HPP
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define BOLD "\033[0;02m"
|
||||||
|
#define ITALIC "\033[0;03m"
|
||||||
|
#define UNDERLINE "\033[0;04m"
|
||||||
|
#define BLINK "\033[0;05m"
|
||||||
|
#define STRIKE "\033[0;09m"
|
||||||
|
|
||||||
|
#define BOLD_ITALIC "\033[1;03m"
|
||||||
|
#define BOLD_UNDERLINE "\033[1;04m"
|
||||||
|
#define BOLD_BLINK "\033[1;05m"
|
||||||
|
#define BOLD_STRIKE "\033[1;09m"
|
||||||
|
|
||||||
|
#define COLOR_RESET "\033[0;0m"
|
||||||
|
|
||||||
|
//! Number of predefined colors
|
||||||
|
#define COLOR_COUNT 19
|
||||||
|
|
||||||
|
/*! @file zcolor.hpp
|
||||||
|
* @brief Color management
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace ztd
|
||||||
|
{
|
||||||
|
//! ANSI color management
|
||||||
|
/*! C++ Class for easy ANSI color management and display
|
||||||
|
*/
|
||||||
|
class color
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Enumeration of preset colors
|
||||||
|
/*!
|
||||||
|
* Values: none, white, gray, black, red, green, orange, blue, magenta, cyan,
|
||||||
|
* b_white, b_lightgray, b_gray, b_red, b_green, b_yellow, b_blue, b_magenta, b_cyan
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
enum color_name {
|
||||||
|
none=0,
|
||||||
|
white=1,
|
||||||
|
gray=2,
|
||||||
|
black=3,
|
||||||
|
red=4,
|
||||||
|
green=5,
|
||||||
|
orange=6,
|
||||||
|
blue=7,
|
||||||
|
magenta=8,
|
||||||
|
cyan=9,
|
||||||
|
//bold
|
||||||
|
b_white=10,
|
||||||
|
b_lightgray=11,
|
||||||
|
b_gray=12,
|
||||||
|
b_red=13,
|
||||||
|
b_green=14,
|
||||||
|
b_yellow=15,
|
||||||
|
b_blue=16,
|
||||||
|
b_magenta=17,
|
||||||
|
b_cyan=18
|
||||||
|
};
|
||||||
|
|
||||||
|
//! String color names
|
||||||
|
/*!
|
||||||
|
Values "none", "white", "gray", "black", "red", "green", "orange", "blue", "magenta", "cyan",
|
||||||
|
* "b_white", "b_lightgray", "b_gray", "b_red", "b_green", "b_yellow", "b_blue", "b_magenta", "b_cyan"
|
||||||
|
*/
|
||||||
|
static const char* color_name_index[COLOR_COUNT];
|
||||||
|
|
||||||
|
static const char* color_index[COLOR_COUNT];
|
||||||
|
|
||||||
|
static const char* getColorCode(const unsigned int index);
|
||||||
|
//!Get color code with of enum
|
||||||
|
/*! @return Returns corresponding color code to the input enum color\n
|
||||||
|
* Returns color none in case of failure
|
||||||
|
@see color_name
|
||||||
|
*/
|
||||||
|
static const char* getColorCode(color_name cm);
|
||||||
|
//!Get color code with of string
|
||||||
|
/*! @return Returns corresponding color code to the input string name\n
|
||||||
|
* Returns color none in case of failure
|
||||||
|
@see color_name_index
|
||||||
|
*/
|
||||||
|
static const char* getColorCode(const std::string& str);
|
||||||
|
|
||||||
|
//! @brief Constructor
|
||||||
|
color();
|
||||||
|
//! @brief Constructor with initial value
|
||||||
|
color(color_name cm);
|
||||||
|
//! @brief Constructor with initial value
|
||||||
|
color(const std::string& name);
|
||||||
|
|
||||||
|
//!Set color corresponding to enum value
|
||||||
|
/*!
|
||||||
|
Color set to none in case of failure
|
||||||
|
@see color_name
|
||||||
|
*/
|
||||||
|
void setColor(color_name cm);
|
||||||
|
//!Set color with string name
|
||||||
|
/*!
|
||||||
|
Color set to none in case of failure
|
||||||
|
@see color_name_index
|
||||||
|
*/
|
||||||
|
void setColor(const std::string& name);
|
||||||
|
|
||||||
|
//! Get color code
|
||||||
|
/*! @return color in ANSI code
|
||||||
|
*/
|
||||||
|
const char* code() const;
|
||||||
|
|
||||||
|
//! Stored ansi color code
|
||||||
|
std::string color_code;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Insert color code to stream
|
||||||
|
inline std::ostream& operator<<(std::ostream& st, const color& c) { return st << c.code(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //ZCOLOR_HPP
|
||||||
394
include/zfiledat.hpp
Normal file
394
include/zfiledat.hpp
Normal file
|
|
@ -0,0 +1,394 @@
|
||||||
|
#ifndef ZFILEDAT_HPP
|
||||||
|
#define ZFILEDAT_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
|
/*! @file zfiledat.hpp
|
||||||
|
* @brief Storing and reading data
|
||||||
|
*
|
||||||
|
* Easily organize data in a JSON-like file format
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace ztd
|
||||||
|
{
|
||||||
|
class filedat;
|
||||||
|
class chunkdat;
|
||||||
|
class format_error;
|
||||||
|
|
||||||
|
//! @brief Abstract data storing object
|
||||||
|
/*! Used for inheritance and type classing.
|
||||||
|
<b> Not for external use </b>
|
||||||
|
*/
|
||||||
|
class chunk_abstract
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! @brief Type of data
|
||||||
|
/*! Values: none , string , map , list
|
||||||
|
*/
|
||||||
|
enum typeEnum { none, string, map, list};
|
||||||
|
|
||||||
|
//! @brief Get type of chunk
|
||||||
|
typeEnum type();
|
||||||
|
|
||||||
|
chunk_abstract();
|
||||||
|
virtual ~chunk_abstract();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typeEnum m_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief String data storing class
|
||||||
|
/*!
|
||||||
|
Back-end of string data chunk.
|
||||||
|
<b> Not for external use </b>
|
||||||
|
*/
|
||||||
|
class chunk_string : public chunk_abstract
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! @brief String data
|
||||||
|
std::string val;
|
||||||
|
|
||||||
|
chunk_string();
|
||||||
|
virtual ~chunk_string();
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief Map data storing class
|
||||||
|
/*!
|
||||||
|
Back-end of map data chunk.
|
||||||
|
<b> Not for external use </b>
|
||||||
|
*/
|
||||||
|
class chunk_map : public chunk_abstract
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! @brief Mapped data
|
||||||
|
std::map<std::string, chunkdat*> values;
|
||||||
|
|
||||||
|
chunk_map();
|
||||||
|
virtual ~chunk_map();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief String data storing class
|
||||||
|
/*!
|
||||||
|
Back-end of list data chunk.
|
||||||
|
<b> Not for external use </b>
|
||||||
|
*/
|
||||||
|
class chunk_list : public chunk_abstract
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! @brief List data
|
||||||
|
std::vector<chunkdat*> list;
|
||||||
|
|
||||||
|
chunk_list();
|
||||||
|
virtual ~chunk_list();
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief Chunk data object
|
||||||
|
/*!
|
||||||
|
Object containing a chunk of data\n
|
||||||
|
Either string, map, or list
|
||||||
|
*/
|
||||||
|
class chunkdat
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! @brief Constructor
|
||||||
|
chunkdat();
|
||||||
|
//! @brief Constructor with initial value
|
||||||
|
chunkdat(const char* in);
|
||||||
|
//! @brief Constructor with initial value
|
||||||
|
chunkdat(std::string const& in);
|
||||||
|
chunkdat(const char* in, const int in_size, int offset=0, filedat* data=nullptr);
|
||||||
|
chunkdat(std::string const& in, int offset=0, filedat* data=nullptr);
|
||||||
|
//! @brief Constructor with copy
|
||||||
|
chunkdat(chunkdat const& in);
|
||||||
|
//dtor
|
||||||
|
~chunkdat();
|
||||||
|
|
||||||
|
//! @brief Clear contents
|
||||||
|
void clear();
|
||||||
|
//! @brief Type of the stored data
|
||||||
|
chunk_abstract::typeEnum type() const;
|
||||||
|
//! @brief get pointer to chunk_abstract
|
||||||
|
inline chunk_abstract* getp() const { return m_achunk; }
|
||||||
|
//! @brief Size of list. -1 if not a list
|
||||||
|
int listSize() const;
|
||||||
|
//! @brief Get pointer to parent (debug)
|
||||||
|
inline filedat* parent() const { return m_parent; }
|
||||||
|
//! @brief Get data offset (debug)
|
||||||
|
inline int offset() const { return m_offset; }
|
||||||
|
|
||||||
|
|
||||||
|
//! @brief Set data
|
||||||
|
/*!
|
||||||
|
@param in C string data
|
||||||
|
@param in_size Size of the string data
|
||||||
|
@param offset Used for debugging
|
||||||
|
@param data Used for debugging
|
||||||
|
*/
|
||||||
|
void set(const char* in, const int in_size, int offset=0, filedat* parent=nullptr);
|
||||||
|
//! @brief Set data
|
||||||
|
/*!
|
||||||
|
@param in String data
|
||||||
|
@param offset Used for debugging
|
||||||
|
@param data Used for debuggingy
|
||||||
|
*/
|
||||||
|
inline void set(std::string const& in, int offset=0, filedat* data=nullptr) { this->set(in.c_str(), in.size(), offset, data); }
|
||||||
|
|
||||||
|
//! @brief Copy chunk's data
|
||||||
|
inline void set(chunkdat const& in) { this->set(in.strval(), in.offset(), in.parent()); } // TODO
|
||||||
|
|
||||||
|
//! @brief Get string value of data
|
||||||
|
/*!
|
||||||
|
@param alignment Number of initial aligners
|
||||||
|
@param aligner String to use for aligning sub-chunks
|
||||||
|
@return String value of the whole chunk data
|
||||||
|
*/
|
||||||
|
std::string strval(unsigned int alignment=0, std::string const& aligner="\t") const;
|
||||||
|
|
||||||
|
void addToMap(std::string const& name, chunkdat const& val);
|
||||||
|
void addToMap(std::vector<std::pair<std::string, chunkdat>> const& vec);
|
||||||
|
void addToList(chunkdat const& val);
|
||||||
|
void addToList(std::vector<chunkdat> const& vec);
|
||||||
|
//! @brief Add keyed data to map chunk
|
||||||
|
/*!
|
||||||
|
@param name Key of the data
|
||||||
|
@param val Data
|
||||||
|
*/
|
||||||
|
inline void add(std::string const& name, chunkdat const& val) { addToMap(name, val); }
|
||||||
|
//! @brief Add multiple keyed data to map chunk
|
||||||
|
/*!
|
||||||
|
@param vec Vector of pairs of keys and data
|
||||||
|
*/
|
||||||
|
inline void add(std::vector<std::pair<std::string, chunkdat>> const& vec) { addToMap(vec); }
|
||||||
|
//! @brief Append data to end of list
|
||||||
|
/*!
|
||||||
|
@param val Data to add
|
||||||
|
*/
|
||||||
|
inline void add(chunkdat const& val) { addToList(val); }
|
||||||
|
//! @brief Append list of data to end of list
|
||||||
|
/*!
|
||||||
|
@param vec Vector of data to add
|
||||||
|
*/
|
||||||
|
inline void add(std::vector<chunkdat> const& vec) { addToList(vec); }
|
||||||
|
// void concatenate(chunkdat const& chk); //concatenates chunks
|
||||||
|
|
||||||
|
//! @brief Create a copy of the chunk
|
||||||
|
inline chunkdat copy() const { return chunkdat(*this); }
|
||||||
|
//! @brief Create a pointed copy of the chunk
|
||||||
|
inline chunkdat* pcopy() const { return new chunkdat(*this); }
|
||||||
|
|
||||||
|
//! @brief Reference to subchunk of map
|
||||||
|
/*!
|
||||||
|
Throws format_error exception when operation fails
|
||||||
|
@param a Key of the subchunk data
|
||||||
|
@return Reference to the subchunk in question
|
||||||
|
*/
|
||||||
|
chunkdat& subChunkRef(std::string const& a) const;
|
||||||
|
//! @brief Reference to subchunk of list
|
||||||
|
/*!
|
||||||
|
Throws format_error exception when operation fails
|
||||||
|
@param a Position of subchunk data in list
|
||||||
|
@return Reference to the subchunk in question
|
||||||
|
*/
|
||||||
|
chunkdat& subChunkRef(const unsigned int a) const;
|
||||||
|
//! @brief Pointer to subchunk of map
|
||||||
|
/*!
|
||||||
|
@param a Key of the subchunk data
|
||||||
|
@return Reference to the subchunk in question\n
|
||||||
|
nullptr if operation failed
|
||||||
|
*/
|
||||||
|
chunkdat* subChunkPtr(std::string const& a) const;
|
||||||
|
//! @brief Pointer to subchunk of list
|
||||||
|
/*!
|
||||||
|
@param a Position of subchunk data in list
|
||||||
|
@return Reference to the subchunk in question\n
|
||||||
|
nullptr if operation failed
|
||||||
|
*/
|
||||||
|
chunkdat* subChunkPtr(const unsigned int a) const;
|
||||||
|
|
||||||
|
//! @brief Reference to subchunk of map
|
||||||
|
/*!
|
||||||
|
@see subChunkRef(std::string const& a) const
|
||||||
|
*/
|
||||||
|
inline chunkdat& operator[](std::string const& a) const { return subChunkRef(a); }
|
||||||
|
//! @brief Reference to subchunk of Map
|
||||||
|
/*!
|
||||||
|
@see subChunkRef(const unsigned int a) const
|
||||||
|
*/
|
||||||
|
inline chunkdat& operator[](const unsigned int a) const { return subChunkRef(a); }
|
||||||
|
//! @brief Copy contents of chunk
|
||||||
|
inline chunkdat& operator=(chunkdat const& a) { set(a); return *this; }
|
||||||
|
//! @brief add() and return *this
|
||||||
|
inline chunkdat& operator+=(std::pair<std::string, chunkdat> const& a) { add(a.first, a.second); return *this; }
|
||||||
|
//! @brief add() and return *this
|
||||||
|
inline chunkdat& operator+=(std::vector<std::pair<std::string, chunkdat>> const& a) { add(a); return *this; }
|
||||||
|
//! @brief add() and return *this
|
||||||
|
inline chunkdat& operator+=(chunkdat const& a) { add(a); return *this; }
|
||||||
|
//! @brief add() and return *this
|
||||||
|
inline chunkdat& operator+=(std::vector<chunkdat> const& a) { add(a); return *this; }
|
||||||
|
// inline bool operator*=(chunkdat const& a) { concatenate(a); }
|
||||||
|
|
||||||
|
//add operator+ and operator*
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
filedat* m_parent;
|
||||||
|
int m_offset;
|
||||||
|
|
||||||
|
chunk_abstract* m_achunk;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief File data object
|
||||||
|
/*!
|
||||||
|
Object for importing, reading, altering and writing of file data\n
|
||||||
|
*/
|
||||||
|
class filedat
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! @brief Constructor
|
||||||
|
filedat();
|
||||||
|
//! @brief Constructor with initial file path
|
||||||
|
filedat(std::string const& in);
|
||||||
|
virtual ~filedat();
|
||||||
|
|
||||||
|
//! @brief Get current file path
|
||||||
|
inline std::string filePath() const { return m_filePath; }
|
||||||
|
//! @brief Set file path
|
||||||
|
inline void setFilePath(std::string const& in) { m_filePath=in; }
|
||||||
|
|
||||||
|
//! @brief Test wether file can be read
|
||||||
|
bool readTest() const;
|
||||||
|
|
||||||
|
//! @brief Import file data
|
||||||
|
/*!
|
||||||
|
Throws format_error exceptions if errors are encountered while reading
|
||||||
|
@param path Will set this as file path if not empty
|
||||||
|
*/
|
||||||
|
void import_file(const std::string& path="");
|
||||||
|
//! @brief Import data from stdin
|
||||||
|
/*!
|
||||||
|
Throws format_error exceptions if errors are encountered while reading
|
||||||
|
*/
|
||||||
|
void import_stdin();
|
||||||
|
//! @brief Import data from string
|
||||||
|
/*!
|
||||||
|
Throws format_error exceptions if errors are encountered while reading
|
||||||
|
*/
|
||||||
|
void import_string(const std::string& data);
|
||||||
|
//! @brief Export data to file
|
||||||
|
/*!
|
||||||
|
@param path Will set this as file path if not empty
|
||||||
|
@param aligner String used to align subchunks
|
||||||
|
*/
|
||||||
|
bool export_file(std::string const& path="", std::string const& aligner="\t") const;
|
||||||
|
|
||||||
|
//! @brief Clear contents of data
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
//! @brief Get string value of data
|
||||||
|
/*!
|
||||||
|
@param aligner String used to align subchunks
|
||||||
|
*/
|
||||||
|
std::string strval(std::string const& aligner="\t") const;
|
||||||
|
|
||||||
|
//! @brief Get reference to chunk data
|
||||||
|
inline chunkdat& data() const { return *m_dataChunk; }
|
||||||
|
//! @brief Get pointer to chunk data
|
||||||
|
inline chunkdat* pdata() const { return m_dataChunk; }
|
||||||
|
|
||||||
|
//! @brief Set data
|
||||||
|
/*!
|
||||||
|
Throws format_error exceptions if errors are encountered
|
||||||
|
@see chunkdat::set(chunkdat const& a)
|
||||||
|
*/
|
||||||
|
inline void set_data(chunkdat const& in) { m_dataChunk->set(in); }
|
||||||
|
|
||||||
|
//! @brief Imported data as is. Used for debugging
|
||||||
|
inline const std::string& im_data() const { return m_data; }
|
||||||
|
//! @brief Imported data as is. Used for debugging
|
||||||
|
inline const char* im_c_data() const { return m_data.c_str(); }
|
||||||
|
|
||||||
|
//! @brief Reference to subchunk
|
||||||
|
//! @see chunkdat::operator[](std::string const &a) const
|
||||||
|
inline chunkdat& operator[](const std::string& index) { return m_dataChunk->subChunkRef(index); }
|
||||||
|
//! @brief Reference to subchunk
|
||||||
|
//! @see chunkdat::operator[](const unsigned int a) const
|
||||||
|
inline chunkdat& operator[](const unsigned int index) { return m_dataChunk->subChunkRef(index); }
|
||||||
|
|
||||||
|
//! @brief add data and return *this
|
||||||
|
//! @see chunkdat::operator+=(std::pair<std::string, chunkdat> const& a)
|
||||||
|
inline filedat& operator+=(std::pair<std::string, chunkdat> const& a) { *m_dataChunk += a; return *this; }
|
||||||
|
//! @brief add data and return *this
|
||||||
|
//! @see chunkdat::operator+=(std::vector<std::pair<std::string, chunkdat>> const& a)
|
||||||
|
inline filedat& operator+=(std::vector<std::pair<std::string, chunkdat>> const& a) { *m_dataChunk += a; return *this; }
|
||||||
|
//! @brief add data and return *this
|
||||||
|
//! @see chunkdat::operator+=(chunkdat const& a)
|
||||||
|
inline filedat& operator+=(chunkdat const& a) { *m_dataChunk += a; return *this; }
|
||||||
|
//! @brief add() and return *this
|
||||||
|
//! @see chunkdat::operator+=(std::vector<chunkdat> const& a)
|
||||||
|
inline filedat& operator+=(std::vector<chunkdat> const& a) { *m_dataChunk += a; return *this; }
|
||||||
|
|
||||||
|
//! @brief set_data() and return *this
|
||||||
|
//! @see chunkdat::operator+=(std::vector<chunkdat> const& a)
|
||||||
|
inline filedat& operator=(chunkdat const& a) { set_data(a); return *this; }
|
||||||
|
|
||||||
|
//! @brief Is a read char
|
||||||
|
static bool isRead(char in);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//functions
|
||||||
|
void generateChunk();
|
||||||
|
//attributes
|
||||||
|
std::string m_filePath;
|
||||||
|
std::string m_data;
|
||||||
|
chunkdat* m_dataChunk;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief Data format exception
|
||||||
|
/*!
|
||||||
|
Thrown when errors are encountered when manipulating data chunks
|
||||||
|
*/
|
||||||
|
class format_error : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! @brief Conctructor
|
||||||
|
inline format_error(const std::string& what, const std::string& origin, const std::string& data, int where) { desc=what; index=where; filename=origin; sdat=data; }
|
||||||
|
|
||||||
|
//! @brief Error message
|
||||||
|
inline const char * what () const throw () {return desc.c_str();}
|
||||||
|
//! @brief Origin of the data, name of imported file, otherwise empty if generated
|
||||||
|
inline const char * origin() const throw () {return filename.c_str();}
|
||||||
|
//! @brief Data causing the exception
|
||||||
|
inline const char * data() const throw () {return sdat.c_str();}
|
||||||
|
//! @brief Where the error is located in the data
|
||||||
|
inline const int where () const throw () {return index;}
|
||||||
|
private:
|
||||||
|
std::string desc;
|
||||||
|
int index;
|
||||||
|
std::string filename;
|
||||||
|
std::string sdat;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& stream, chunkdat const& a) { return stream << a.strval(); }
|
||||||
|
inline std::ostream& operator<<(std::ostream& stream, filedat const& a) { return stream << a.strval(); }
|
||||||
|
|
||||||
|
void printErrorIndex(const char* in, const int index, const std::string& message, const std::string& origin);
|
||||||
|
//! @brief Print exception to console
|
||||||
|
/*!
|
||||||
|
If origin is known, displays location and discriminating line\n
|
||||||
|
If origin is unknown, displays whole data up to discriminating line
|
||||||
|
*/
|
||||||
|
void printFormatException(format_error& exc);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ZFILEDAT_HPP
|
||||||
146
include/zoptions.hpp
Normal file
146
include/zoptions.hpp
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
#ifndef ZOPTIONS_H
|
||||||
|
#define ZOPTIONS_H
|
||||||
|
|
||||||
|
//DUPLICATES NOT HANDLED: takes last one
|
||||||
|
//NO ORDER: no way to know options order
|
||||||
|
//RETURNS TRANSITIONAL STATE IF ERROR
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
/*! @file zoptions.hpp
|
||||||
|
* @brief CLI option reading and processing
|
||||||
|
*
|
||||||
|
* Easy managing of POSIX/GNU style options
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
namespace ztd
|
||||||
|
{
|
||||||
|
//! @brief Option exception
|
||||||
|
/*!
|
||||||
|
Thrown when errors are encountered during processing of options
|
||||||
|
*/
|
||||||
|
class option_error : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! @brief option error types
|
||||||
|
enum error_type { unknown_option, takes_no_arg, missing_arg};
|
||||||
|
|
||||||
|
//! @brief Conctructor
|
||||||
|
option_error(error_type type, const std::string& option);
|
||||||
|
|
||||||
|
//! @brief Type of error
|
||||||
|
inline error_type type() { return errtype; }
|
||||||
|
//! @brief Error message
|
||||||
|
inline const char * what () const throw () {return msg.c_str();}
|
||||||
|
//! @brief Subject of said error
|
||||||
|
inline const char * option () const throw () {return opt.c_str();}
|
||||||
|
private:
|
||||||
|
error_type errtype;
|
||||||
|
std::string opt;
|
||||||
|
std::string msg;
|
||||||
|
};
|
||||||
|
//! @brief Convert argc/argv into vector<std::string>
|
||||||
|
std::vector<std::string> argVector(int argc, char** argv);
|
||||||
|
|
||||||
|
//! @brief Single option object
|
||||||
|
/*! Definition of a GNU/POSIX style option
|
||||||
|
*/
|
||||||
|
class option
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/* CTOR/DTOR */
|
||||||
|
//ctors
|
||||||
|
option();
|
||||||
|
//! @brief Create a char defined option
|
||||||
|
option(char c, bool arg=false, std::string helptext="", std::string argname="arg");
|
||||||
|
//! @brief Create a string defined option
|
||||||
|
option(std::string const& str, bool arg=false, std::string helptext="", std::string argname="arg");
|
||||||
|
//! @brief Create a char and string defined option
|
||||||
|
option(char c, std::string const& str, bool arg=false, std::string helptext="", std::string argname="arg");
|
||||||
|
//! @brief Create copy
|
||||||
|
option(const option& opt);
|
||||||
|
|
||||||
|
/* FUNCTIONS */
|
||||||
|
|
||||||
|
//! @brief Print option's help
|
||||||
|
/*!
|
||||||
|
@param leftpad Put @a leftpad spaces at start of the line
|
||||||
|
@param rightpad Help text starts at column @a leftpad + @a rightpad
|
||||||
|
*/
|
||||||
|
void print_help(int leftpad, int rightpad) const;
|
||||||
|
|
||||||
|
/* PROPERTIES */
|
||||||
|
|
||||||
|
bool shortDef; // has a char definition
|
||||||
|
char charName;
|
||||||
|
|
||||||
|
bool longDef; // has a string definition
|
||||||
|
std::string strName;
|
||||||
|
|
||||||
|
bool takesArgument; // option takes an argument
|
||||||
|
|
||||||
|
std::string help_text; // text to display in print_help
|
||||||
|
std::string arg_name; // name of the argument to display in print_help
|
||||||
|
|
||||||
|
/* PROCESSING STATUS */
|
||||||
|
|
||||||
|
//! @brief Option was activated
|
||||||
|
bool activated; // option was activated
|
||||||
|
|
||||||
|
//! @brief Option's argument
|
||||||
|
std::string argument; // argument of the option
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief Set of POSIX/GNU style options
|
||||||
|
/*!
|
||||||
|
Process arguments through it to extract options
|
||||||
|
*/
|
||||||
|
class option_set
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*CREATION FUNCTIONS*/
|
||||||
|
//! @brief Add option to the set
|
||||||
|
inline void add(option opt) { m_options.push_back(opt); }
|
||||||
|
|
||||||
|
/*PRINT FUNCTIONS*/
|
||||||
|
//! @brief Print help for the full option set
|
||||||
|
/*!
|
||||||
|
Output order follows option creation order
|
||||||
|
@param leftpad Put @a leftpad spaces at start of the line
|
||||||
|
@param rightpad Help text starts at column @a leftpad + @a rightpad
|
||||||
|
*/
|
||||||
|
void print_help(int leftpad=2, int rightpad=25) const;
|
||||||
|
|
||||||
|
/*QUERY FUNCTIONS*/
|
||||||
|
//! @brief Find char option
|
||||||
|
option* find(char c);
|
||||||
|
//! @brief Find string option
|
||||||
|
option* find(std::string const& str);
|
||||||
|
|
||||||
|
/*PROCESSING FUNCTIONS*/
|
||||||
|
//! @brief Process arguments through the option set
|
||||||
|
/*!
|
||||||
|
If errors are encountered, exceptions option_error are thrown
|
||||||
|
@param arguments vector of string containing arguments and options
|
||||||
|
@return Leftover arguments that are not options\n
|
||||||
|
*/
|
||||||
|
std::vector<std::string> process(std::vector<std::string> arguments);
|
||||||
|
//! @brief Process arguments through the option set
|
||||||
|
/*!
|
||||||
|
calls process(std::vector<std::string> arguments)
|
||||||
|
*/
|
||||||
|
inline std::vector<std::string> process(int argc, char** argv) { return this->process(ztd::argVector(argc, argv)); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<option> m_options;
|
||||||
|
};
|
||||||
|
|
||||||
|
} //ztd
|
||||||
|
|
||||||
|
#endif //ZOPTIONS_H
|
||||||
42
include/zshell.hpp
Normal file
42
include/zshell.hpp
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef ZSHELL_HPP
|
||||||
|
#define ZSHELL_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/*! \file zshell.hpp
|
||||||
|
* @brief Shell functionality and interaction
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace ztd
|
||||||
|
{
|
||||||
|
//! @brief Execute a shell command and retrieve its output
|
||||||
|
/*!
|
||||||
|
@param command Shell command to execute
|
||||||
|
@param to_console Output to console
|
||||||
|
@return Output of the command
|
||||||
|
@see <a href="https://linux.die.net/man/3/systeml">system(), pclose()</a>
|
||||||
|
*/
|
||||||
|
std::string sh(const std::string& command, bool to_console=false);
|
||||||
|
|
||||||
|
//! @brief popen C function with added pid functionality
|
||||||
|
/*!
|
||||||
|
@param pid Pointer to an @a int in which the process's pid will be stored
|
||||||
|
@see <a href="http://man7.org/linux/man-pages/man3/popen.3.html">popen(), pclose()</a>
|
||||||
|
*/
|
||||||
|
FILE* popen2(const char* command, const char* type, int* pid);
|
||||||
|
//! @brief pclose C function with added pid functionality
|
||||||
|
/*!
|
||||||
|
@param pid Pid of the opened process
|
||||||
|
@see <a href="http://man7.org/linux/man-pages/man3/popen.3.html">popen(), pclose()</a>
|
||||||
|
*/
|
||||||
|
int pclose2(FILE* fp, pid_t pid);
|
||||||
|
|
||||||
|
// class shell
|
||||||
|
// {
|
||||||
|
// public:
|
||||||
|
// private:
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //ZSHELL_HPP
|
||||||
224
include/zsocket.hpp
Normal file
224
include/zsocket.hpp
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
#ifndef SOCKET_H
|
||||||
|
#define SOCKET_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// #include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#include <mutex> // std::mutex, std::unique_lock
|
||||||
|
#include <condition_variable> // std::condition_variable
|
||||||
|
|
||||||
|
|
||||||
|
/*! @file zsocket.hpp
|
||||||
|
* @brief Manage network sockets
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace ztd
|
||||||
|
{
|
||||||
|
//! @brief Main socket abstract object
|
||||||
|
/*! Abstract object, doesn't work on its own. Provides operations and templates for child classes. \n \n
|
||||||
|
Provides automatic background data reading with parallel_on() \n
|
||||||
|
Wait for reading of data with wait_data() \n
|
||||||
|
Retrieve data with retrieve() \n
|
||||||
|
*/
|
||||||
|
class socket_abstract
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
socket_abstract();
|
||||||
|
virtual ~socket_abstract();
|
||||||
|
|
||||||
|
//! @brief Get the socket's file descriptor
|
||||||
|
inline int fd() { return m_fd; }
|
||||||
|
//! @brief Valid connection established, data can be sent and/or recieved
|
||||||
|
inline bool operational() { return m_operational; }
|
||||||
|
//! @brief Close connection
|
||||||
|
void close_socket();
|
||||||
|
|
||||||
|
//! @brief Send string data
|
||||||
|
bool send_string(std::string const& text);
|
||||||
|
//! @brief Recieve string data
|
||||||
|
std::string read_string();
|
||||||
|
//! @brief Send byte data
|
||||||
|
/*! @param data Array of bytes
|
||||||
|
@param size Size of the array
|
||||||
|
@return @a True if successful, @a False otherwise
|
||||||
|
*/
|
||||||
|
bool send_data(uint8_t *data, uint32_t size);
|
||||||
|
//! @brief Send byte data
|
||||||
|
/*! @param data Pre-allocated array of bytes
|
||||||
|
@param size Pointer to size of data array. Number of bytes read stored to pointed location if successful reading
|
||||||
|
@return @a True if successful, @a False otherwise
|
||||||
|
*/
|
||||||
|
bool read_data(uint8_t *data, uint32_t *size);
|
||||||
|
|
||||||
|
//! @brief State of automatic parallel data reading
|
||||||
|
inline bool parallel() { return m_parallel; }
|
||||||
|
//! @brief Turn on automatic parallel data reading
|
||||||
|
/*! Socket has to be operational. \n Read data stored for later use with retrieve()
|
||||||
|
@param bufferSize size of the reading buffer
|
||||||
|
*/
|
||||||
|
void parallel_on(uint32_t bufferSize=256);
|
||||||
|
//! @brief Turn off automatic parallel data reading
|
||||||
|
void parallelOff();
|
||||||
|
//! @brief Forcibly kill automatic parallel data reading
|
||||||
|
void killParallel();
|
||||||
|
|
||||||
|
inline std::vector<std::vector<uint8_t>>& data() { return m_dataSet; }
|
||||||
|
//! @brief Data is available
|
||||||
|
/*! Parallel reading enabled
|
||||||
|
*/
|
||||||
|
inline bool data_available() { return m_dataSet.size() > 0; }
|
||||||
|
//! @brief Retrieve pending data (parallel reading)
|
||||||
|
std::vector<uint8_t> retrieve();
|
||||||
|
|
||||||
|
inline std::condition_variable& cv() { return m_cv; }
|
||||||
|
inline std::mutex& mtx() { return m_mtx; }
|
||||||
|
//! @brief Wait until data is recieved (parallel reading)
|
||||||
|
void wait_data();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void parallel_reading(socket_abstract *s, uint32_t bufferSize);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int m_fd;
|
||||||
|
bool m_operational;
|
||||||
|
|
||||||
|
bool m_parallel;
|
||||||
|
std::thread *m_thread;
|
||||||
|
std::vector<std::vector<uint8_t>> m_dataSet;
|
||||||
|
std::condition_variable m_cv;
|
||||||
|
std::mutex m_mtx;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief TCP socket abstract object
|
||||||
|
/*! Abstract object, doesn't work on its own. Provides operations and templates for child classes
|
||||||
|
*/
|
||||||
|
class tcpsocket_abstract : public socket_abstract
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
tcpsocket_abstract();
|
||||||
|
virtual ~tcpsocket_abstract();
|
||||||
|
|
||||||
|
//! @brief Init socket for IPv4 TCP
|
||||||
|
bool init_ipv4();
|
||||||
|
//! @brief Init socket for IPv6 TCP
|
||||||
|
bool init_ipv6();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief TCP server
|
||||||
|
/*! Does not provide an operational socket, use tcpsocket_server_instance for a connection to a client \n \ny
|
||||||
|
Run init_ipv4() then listen_ipv4() to open the server on ipv4 \n
|
||||||
|
Run init_ipv6() then listen_ipv6() to open the server on IPv6
|
||||||
|
*/
|
||||||
|
class tcpsocket_server : public tcpsocket_abstract
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
tcpsocket_server();
|
||||||
|
virtual ~tcpsocket_server();
|
||||||
|
|
||||||
|
//! @brief Server is open
|
||||||
|
inline bool is_open() { return m_listening; }
|
||||||
|
//! @brief Listening port. 0 if not open
|
||||||
|
inline uint16_t port() { return m_port; }
|
||||||
|
|
||||||
|
inline struct sockaddr_in addr() { return m_servaddr; }
|
||||||
|
|
||||||
|
//! @brief Open server for IPv4
|
||||||
|
/*! @param port Listening port, != 0
|
||||||
|
@param backlog Backlog value
|
||||||
|
@return @a True if successful, @a False otherwise
|
||||||
|
*/
|
||||||
|
bool listen_ipv4(uint16_t port, int backlog=5);
|
||||||
|
|
||||||
|
//! @brief Open server for IPv6
|
||||||
|
/*! @param port Listening port, != 0
|
||||||
|
@param backlog Backlog value
|
||||||
|
@return @a True if successful, @a False otherwise
|
||||||
|
*/
|
||||||
|
bool listen_ipv6(uint16_t port, int backlog=5);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_listening;
|
||||||
|
uint16_t m_port;
|
||||||
|
struct sockaddr_in m_servaddr;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief Instance for TCP server
|
||||||
|
/*! Instance of a TCP connection to a client. Can send/read data. Refer to socket_abstract methods
|
||||||
|
*/
|
||||||
|
class tcpsocket_server_instance : public socket_abstract
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! @brief Constructor.
|
||||||
|
/*! @param server Pointer to parent TCP server
|
||||||
|
*/
|
||||||
|
tcpsocket_server_instance(tcpsocket_server *server);
|
||||||
|
virtual ~tcpsocket_server_instance();
|
||||||
|
|
||||||
|
//! @brief Wait for a client connection.
|
||||||
|
/*! Socket becomes operational if connection successful
|
||||||
|
@return @a True if a valid connection is established, @a False otherwise
|
||||||
|
*/
|
||||||
|
bool accept_connection();
|
||||||
|
|
||||||
|
inline struct sockaddr_in client() { return m_cliaddr; }
|
||||||
|
//! @brief Get client address
|
||||||
|
char* client_address();
|
||||||
|
//! @brief Get client port
|
||||||
|
uint16_t client_port();
|
||||||
|
|
||||||
|
private:
|
||||||
|
tcpsocket_server *m_server;
|
||||||
|
struct sockaddr_in m_cliaddr;
|
||||||
|
|
||||||
|
socklen_t m_clilen;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @brief TCP client
|
||||||
|
/*! Can send/read data. Refer to socket_abstract methods \n
|
||||||
|
Run init_ipv4() then connect_ipv4() for an operational IPv4 connection \n
|
||||||
|
Run init_ipv6() then connect_ipv6() for an operational IPv6 connection
|
||||||
|
*/
|
||||||
|
class tcpsocket_client : public tcpsocket_abstract
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
tcpsocket_client();
|
||||||
|
virtual ~tcpsocket_client();
|
||||||
|
|
||||||
|
//! @brief Connect to an IPv4 TCP server
|
||||||
|
/*! @param addr IPv4 string address of the target server
|
||||||
|
@param port Port of the target server
|
||||||
|
@return @a True if successful, @a False otherwise
|
||||||
|
*/
|
||||||
|
bool connect_ipv4(std::string const& addr, uint16_t port);
|
||||||
|
//! @brief Connect to an IPv6 TCP server
|
||||||
|
/*! @param addr IPv6 string address of the target server
|
||||||
|
@param port Port of the target server
|
||||||
|
@return @a True if successful, @a False otherwise
|
||||||
|
*/
|
||||||
|
bool connect_ipv6(std::string const& addr, uint16_t port);
|
||||||
|
|
||||||
|
//! @brief String address of target server
|
||||||
|
inline std::string addr() { return m_addr; }
|
||||||
|
//! @brief Port of target server
|
||||||
|
inline uint16_t port() { return m_port; }
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct hostent *m_server;
|
||||||
|
struct sockaddr_in m_servaddr;
|
||||||
|
std::string m_addr;
|
||||||
|
uint16_t m_port;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SOCKET_H
|
||||||
40
include/zthread.hpp
Normal file
40
include/zthread.hpp
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef ZTHREAD_HPP
|
||||||
|
#define ZTHREAD_HPP
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
/*! \file zthread.hpp
|
||||||
|
* @brief Thread management
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace ztd
|
||||||
|
{
|
||||||
|
//! @brief Coordinated thread pool
|
||||||
|
class thread_pool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~thread_pool();
|
||||||
|
//! @brief Join and delete all threads of the pool
|
||||||
|
void join();
|
||||||
|
|
||||||
|
//! @brief Detach all threads of the pool
|
||||||
|
void detach();
|
||||||
|
|
||||||
|
//! @brief Delete all threads of the pool
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
//! @brief Instanciate new thread
|
||||||
|
template <class Fn, class... Args>
|
||||||
|
void thread(Fn&& fn, Args&&... args)
|
||||||
|
{
|
||||||
|
m_threads.push_back(new std::thread(fn, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::thread*> m_threads;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ZTHREAD_HPP
|
||||||
53
include/ztime.hpp
Normal file
53
include/ztime.hpp
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
#ifndef ZTIME_HPP
|
||||||
|
#define ZTIME_HPP
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
/*! @file ztime.hpp
|
||||||
|
* @brief Time measuring and managing
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace ztd
|
||||||
|
{
|
||||||
|
//! Measure time intervals
|
||||||
|
/*! Class for quick and easy time measurement
|
||||||
|
*/
|
||||||
|
class timer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
timer();
|
||||||
|
|
||||||
|
//! Get measured time
|
||||||
|
/*!
|
||||||
|
If the timer was stopped, returns the time between start and stop\n
|
||||||
|
If the timer is still running, returns time between start and now
|
||||||
|
@return
|
||||||
|
In seconds, µs granularity
|
||||||
|
*/
|
||||||
|
double time() const;
|
||||||
|
|
||||||
|
//! Start the timer
|
||||||
|
/*!
|
||||||
|
If the timer was already running, resets the timer to this point
|
||||||
|
*/
|
||||||
|
void start();
|
||||||
|
//! Stop the timer
|
||||||
|
/*!
|
||||||
|
Store time difference
|
||||||
|
@return
|
||||||
|
@b true if timer was running, @b false otherwise
|
||||||
|
*/
|
||||||
|
bool stop();
|
||||||
|
|
||||||
|
//! Reset the timer
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_stopped;
|
||||||
|
double m_sec;
|
||||||
|
struct timeval m_start, m_end;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ZTIME_HPP
|
||||||
33
include/zwait.hpp
Normal file
33
include/zwait.hpp
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef ZWAIT_HPP
|
||||||
|
#define ZWAIT_HPP
|
||||||
|
|
||||||
|
#include <mutex> // std::mutex, std::unique_lock
|
||||||
|
#include <condition_variable> // std::condition_variable
|
||||||
|
|
||||||
|
/*! \file zwait.hpp
|
||||||
|
* @brief Thread stalling and waiting
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace ztd
|
||||||
|
{
|
||||||
|
//! @brief Thread waiting object
|
||||||
|
class wait_pool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! Wait until notified
|
||||||
|
void wait();
|
||||||
|
|
||||||
|
//! Notify one instance of wait()
|
||||||
|
void notify_one();
|
||||||
|
|
||||||
|
//! Notify all instances of wait()
|
||||||
|
void notify_all();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::condition_variable m_cv;
|
||||||
|
std::mutex m_mtx;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //ZWAIT_HPP
|
||||||
102
src/zcolor.cpp
Normal file
102
src/zcolor.cpp
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
#include "zcolor.hpp"
|
||||||
|
|
||||||
|
const char* ztd::color::color_name_index[COLOR_COUNT] = {
|
||||||
|
"none",
|
||||||
|
"white",
|
||||||
|
"gray",
|
||||||
|
"black",
|
||||||
|
"red",
|
||||||
|
"green",
|
||||||
|
"orange",
|
||||||
|
"blue",
|
||||||
|
"magenta",
|
||||||
|
"cyan",
|
||||||
|
//bold
|
||||||
|
"b_white",
|
||||||
|
"b_lightgray",
|
||||||
|
"b_gray",
|
||||||
|
"b_red",
|
||||||
|
"b_green",
|
||||||
|
"b_yellow",
|
||||||
|
"b_blue",
|
||||||
|
"b_magenta",
|
||||||
|
"b_cyan"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* ztd::color::color_index[COLOR_COUNT] = {
|
||||||
|
COLOR_RESET, //none
|
||||||
|
"\033[0;37m", //white
|
||||||
|
"\033[0;02m", //gray
|
||||||
|
"\033[0;30m", //black
|
||||||
|
"\033[0;31m", //red
|
||||||
|
"\033[0;32m", //green
|
||||||
|
"\033[0;33m", //orange
|
||||||
|
"\033[0;34m", //blue
|
||||||
|
"\033[0;35m", //magenta
|
||||||
|
"\033[0;36m", //cyan
|
||||||
|
// BOLD
|
||||||
|
"\033[1;37m", //bold white
|
||||||
|
"\033[1;02m", //bold light gray
|
||||||
|
"\033[1;30m", //bold gray
|
||||||
|
"\033[1;31m", //bold red
|
||||||
|
"\033[1;32m", //bold green
|
||||||
|
"\033[1;33m", //bold yellow
|
||||||
|
"\033[1;34m", //bold blue
|
||||||
|
"\033[1;35m", //bold magenta
|
||||||
|
"\033[1;36m" //bold cyan
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* ztd::color::getColorCode(const unsigned int index)
|
||||||
|
{
|
||||||
|
if( index < 0 || index >= COLOR_COUNT)
|
||||||
|
return COLOR_RESET;
|
||||||
|
else
|
||||||
|
return ztd::color::color_index[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ztd::color::getColorCode(ztd::color::color_name cm)
|
||||||
|
{
|
||||||
|
return ztd::color::color_index[(int) cm];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ztd::color::getColorCode(const std::string& str)
|
||||||
|
{
|
||||||
|
for(unsigned int i=0; i<COLOR_COUNT ; i++)
|
||||||
|
{
|
||||||
|
if(color_name_index[i] == str)
|
||||||
|
{
|
||||||
|
return getColorCode(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return COLOR_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::color::color()
|
||||||
|
{
|
||||||
|
setColor(none);
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::color::color(ztd::color::color_name cm)
|
||||||
|
{
|
||||||
|
setColor(cm);
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::color::color(const std::string& name)
|
||||||
|
{
|
||||||
|
setColor(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::color::setColor(ztd::color::color_name cm)
|
||||||
|
{
|
||||||
|
color_code=getColorCode(cm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::color::setColor(const std::string& name)
|
||||||
|
{
|
||||||
|
color_code=getColorCode(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ztd::color::code() const
|
||||||
|
{
|
||||||
|
return color_code.c_str();
|
||||||
|
}
|
||||||
889
src/zfiledat.cpp
Normal file
889
src/zfiledat.cpp
Normal file
|
|
@ -0,0 +1,889 @@
|
||||||
|
#include "zfiledat.hpp"
|
||||||
|
|
||||||
|
// Function code
|
||||||
|
bool ztd::filedat::isRead(char in)
|
||||||
|
{
|
||||||
|
return in>=33 && in<=126;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string repeatString(const std::string& str, const unsigned int n)
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
for(unsigned int i=0 ; i<n ; i++)
|
||||||
|
ret += str;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ztd::printErrorIndex(const char* in, const int index, const std::string& message, const std::string& origin)
|
||||||
|
{
|
||||||
|
int i=0, j=0; // j: last newline
|
||||||
|
int line=1; //n: line #
|
||||||
|
int in_size=strlen(in);
|
||||||
|
if(index >= 0)
|
||||||
|
{
|
||||||
|
while(i < in_size && i < index)
|
||||||
|
{
|
||||||
|
if(in[i] == '\n')
|
||||||
|
{
|
||||||
|
line++;
|
||||||
|
j=i+1;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
while(i < in_size && in[i]!='\n')
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(origin != "")
|
||||||
|
{
|
||||||
|
std::cerr << origin << ": Error\nLine " << line << " col " << index-j+1 << ": " << message << std::endl;
|
||||||
|
std::cerr << std::string(in+j, i-j) << std::endl;
|
||||||
|
std::cerr << repeatString(" ", index-j) << '^' << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "Format Error: " << message << std::endl;
|
||||||
|
if(index >= 0)
|
||||||
|
{
|
||||||
|
std::cerr << std::string(in, i) << std::endl;
|
||||||
|
std::cerr << repeatString(" ", index-j) << '^' << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
std::cerr << in << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::printFormatException(ztd::format_error& exc)
|
||||||
|
{
|
||||||
|
ztd::printErrorIndex(exc.data(), exc.where(), exc.what(), exc.origin());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ztd::filedat::filedat()
|
||||||
|
{
|
||||||
|
m_dataChunk = new ztd::chunkdat();
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::filedat::filedat(std::string const& in)
|
||||||
|
{
|
||||||
|
m_dataChunk = new ztd::chunkdat();
|
||||||
|
m_filePath=in;
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::filedat::~filedat()
|
||||||
|
{
|
||||||
|
if(m_dataChunk!=nullptr)
|
||||||
|
delete m_dataChunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::filedat::clear()
|
||||||
|
{
|
||||||
|
m_data="";
|
||||||
|
if(m_dataChunk!=nullptr)
|
||||||
|
{
|
||||||
|
delete m_dataChunk;
|
||||||
|
m_dataChunk = new ztd::chunkdat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ztd::filedat::readTest() const
|
||||||
|
{
|
||||||
|
std::ifstream stream(m_filePath);
|
||||||
|
if(!stream)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::filedat::import_file(const std::string& path)
|
||||||
|
{
|
||||||
|
if(path != "")
|
||||||
|
m_filePath=path;
|
||||||
|
std::ifstream st(m_filePath);
|
||||||
|
if(!st)
|
||||||
|
throw std::runtime_error("Cannot read file '" + m_filePath + '\'');
|
||||||
|
|
||||||
|
this->clear();
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
while(st)
|
||||||
|
{
|
||||||
|
getline(st, line);
|
||||||
|
m_data += (line + '\n');
|
||||||
|
}
|
||||||
|
this->generateChunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::filedat::import_stdin()
|
||||||
|
{
|
||||||
|
m_filePath="stdin";
|
||||||
|
this->clear();
|
||||||
|
std::string line;
|
||||||
|
while(std::cin)
|
||||||
|
{
|
||||||
|
getline(std::cin, line);
|
||||||
|
m_data += (line + '\n');
|
||||||
|
}
|
||||||
|
this->generateChunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::filedat::import_string(const std::string& data)
|
||||||
|
{
|
||||||
|
this->clear();
|
||||||
|
m_data=data;
|
||||||
|
m_filePath="";
|
||||||
|
this->generateChunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ztd::filedat::export_file(std::string const& path, std::string const& aligner) const
|
||||||
|
{
|
||||||
|
std::ofstream stream;
|
||||||
|
if(path=="")
|
||||||
|
stream.open(m_filePath);
|
||||||
|
else
|
||||||
|
stream.open(path);
|
||||||
|
if(!stream)
|
||||||
|
return false;
|
||||||
|
stream << this->strval(aligner);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ztd::filedat::strval(std::string const& aligner) const
|
||||||
|
{
|
||||||
|
if(m_dataChunk == nullptr)
|
||||||
|
return "";
|
||||||
|
else
|
||||||
|
return m_dataChunk->strval(0, aligner);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::filedat::generateChunk()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(m_dataChunk != nullptr)
|
||||||
|
delete m_dataChunk;
|
||||||
|
m_dataChunk = new ztd::chunkdat(m_data.c_str(), m_data.size(), 0, this);
|
||||||
|
}
|
||||||
|
catch(ztd::format_error& e)
|
||||||
|
{
|
||||||
|
throw ztd::format_error(e.what(), m_filePath, m_data, e.where());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string _getname(const char* in, const int in_size, int* start, int* val_size, int* end)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
|
||||||
|
*start = in_size; //default no value
|
||||||
|
*end = in_size; //default end
|
||||||
|
*val_size=0; //default no value
|
||||||
|
|
||||||
|
while(i<in_size)
|
||||||
|
{
|
||||||
|
if(i+1<in_size && in[i] == '/' && in[i+1] == '/')
|
||||||
|
while(i<in_size && in[i] != '\n')
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if(ztd::filedat::isRead(in[i]))
|
||||||
|
break;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if(i >= in_size) //ends without value
|
||||||
|
return "";
|
||||||
|
|
||||||
|
int j=i; //name start
|
||||||
|
while(i<in_size && in[i] != '=') //skip to =
|
||||||
|
i++;
|
||||||
|
if(i >= in_size) //no =
|
||||||
|
throw ztd::format_error("Tag has no value", "", std::string(in, in_size), j);
|
||||||
|
|
||||||
|
if(i == j) //nothing preceding =
|
||||||
|
throw ztd::format_error("Value has no tag", "", std::string(in, in_size), i);
|
||||||
|
|
||||||
|
int k=i-1; //name end
|
||||||
|
while( !ztd::filedat::isRead(in[k]) )
|
||||||
|
k--;
|
||||||
|
std::string name=std::string(in+j, k-j+1);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
while(i < in_size && !ztd::filedat::isRead(in[i]))
|
||||||
|
i++;
|
||||||
|
if(i >= in_size) //no value
|
||||||
|
{
|
||||||
|
*start=i;
|
||||||
|
*val_size=0;
|
||||||
|
*end=i;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
if(in[i] == '\"') //"" val
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
*start=i; //value starts
|
||||||
|
j=0; //size
|
||||||
|
while(i+j < in_size && in[i+j]!='\"')
|
||||||
|
{
|
||||||
|
if(in[i]+j=='\\')
|
||||||
|
j++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if(i+j >= in_size) // no closing "
|
||||||
|
throw ztd::format_error("Double quote does not close", "", std::string(in, in_size), i-1);
|
||||||
|
*val_size=j;
|
||||||
|
*end=i+j+1;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
if(in[i] == '\'') //"" val
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
*start=i; //value starts
|
||||||
|
j=0; //size
|
||||||
|
while(i+j < in_size && in[i+j]!='\'')
|
||||||
|
{
|
||||||
|
if(in[i]+j=='\\')
|
||||||
|
j++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if(i+j >= in_size) // no closing '
|
||||||
|
throw ztd::format_error("Single quote does not close", "", std::string(in, in_size), i-1);
|
||||||
|
*val_size=j;
|
||||||
|
*end=i+j+1;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
if(in[i] == '{')
|
||||||
|
{
|
||||||
|
*start=i;
|
||||||
|
j=1;
|
||||||
|
int counter=0;
|
||||||
|
while( i+j < in_size && !( counter == 0 && in[i+j]=='}') )
|
||||||
|
{
|
||||||
|
if(i+j+1<in_size && in[i+j] == '/' && in[i+j+1] == '/')
|
||||||
|
while(i+j<in_size && in[i+j] != '\n')
|
||||||
|
j++;
|
||||||
|
if(in[i+j]=='\\')
|
||||||
|
j++;
|
||||||
|
if(in[i+j]=='{')
|
||||||
|
counter++;
|
||||||
|
if(in[i+j]=='}')
|
||||||
|
counter--;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if(i+j >= in_size) //reached end without closing
|
||||||
|
throw ztd::format_error("Brace does not close", "", std::string(in, in_size), i);
|
||||||
|
j++;
|
||||||
|
*val_size=j;
|
||||||
|
*end=i+j;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
if(in[i] == '[')
|
||||||
|
{
|
||||||
|
*start=i;
|
||||||
|
j=1;
|
||||||
|
int counter=0;
|
||||||
|
while( i+j < in_size && !( counter == 0 && in[i+j]==']') )
|
||||||
|
{
|
||||||
|
if(i+j+1<in_size && in[i+j] == '/' && in[i+j+1] == '/')
|
||||||
|
while(i+j<in_size && in[i+j] != '\n')
|
||||||
|
j++;
|
||||||
|
if(in[i+j]=='\\')
|
||||||
|
j++;
|
||||||
|
if(in[i+j]=='[')
|
||||||
|
counter++;
|
||||||
|
if(in[i+j]==']')
|
||||||
|
counter--;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if(i+j >= in_size) //reached end without closing
|
||||||
|
throw ztd::format_error("Bracket does not close", "", std::string(in, in_size), i);
|
||||||
|
j++;
|
||||||
|
*val_size=j;
|
||||||
|
*end=i+j;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
{ // no encapsulation: go to end of line
|
||||||
|
*start=i; //value starts
|
||||||
|
j=0; //size
|
||||||
|
while(i+j < in_size && in[i+j]!='\n')
|
||||||
|
{
|
||||||
|
if(in[i]+j=='\\')
|
||||||
|
j++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
while( !ztd::filedat::isRead(in[i+j]) )
|
||||||
|
j--;
|
||||||
|
*val_size=j+1;
|
||||||
|
*end=i+j+1;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string _getlist(const char* in, const int in_size, int* start, int* end)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
std::string ret;
|
||||||
|
|
||||||
|
while(i<in_size)
|
||||||
|
{
|
||||||
|
if(i+1<in_size && in[i] == '/' && in[i+1] == '/')
|
||||||
|
while(i<in_size && in[i] != '\n')
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if(ztd::filedat::isRead(in[i]))
|
||||||
|
break;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*start=i;
|
||||||
|
if(i >= in_size) //ends without value
|
||||||
|
{
|
||||||
|
*end = in_size;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if(in[i] == ',') //value is empty
|
||||||
|
{
|
||||||
|
*end=i+1;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int j=0;
|
||||||
|
if(in[i] == '\"') //"" val
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
j=0; //size
|
||||||
|
while(i+j < in_size && in[i+j]!='\"')
|
||||||
|
{
|
||||||
|
if(in[i]+j=='\\')
|
||||||
|
j++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if(i+j >= in_size) // no closing "
|
||||||
|
throw ztd::format_error("Double quote does not close", "", std::string(in, in_size), i-1);
|
||||||
|
ret = std::string(in+i, j);
|
||||||
|
*end=i+j+1;
|
||||||
|
}
|
||||||
|
else if(in[i] == '\'') //"" val
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
j=0; //size
|
||||||
|
while(i+j < in_size && in[i+j]!='\'')
|
||||||
|
{
|
||||||
|
if(in[i]+j=='\\')
|
||||||
|
j++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if(i+j >= in_size) // no closing '
|
||||||
|
throw ztd::format_error("Single quote does not close", "", std::string(in, in_size), i-1);
|
||||||
|
ret = std::string(in+i, j);
|
||||||
|
*end=i+j+1;
|
||||||
|
}
|
||||||
|
else if(in[i] == '{')
|
||||||
|
{
|
||||||
|
j=1;
|
||||||
|
int counter=0;
|
||||||
|
while( i+j < in_size && !( counter == 0 && in[i+j]=='}') )
|
||||||
|
{
|
||||||
|
if(i+j+1<in_size && in[i+j] == '/' && in[i+j+1] == '/')
|
||||||
|
while(i+j<in_size && in[i+j] != '\n')
|
||||||
|
j++;
|
||||||
|
if(in[i+j]=='\\')
|
||||||
|
j++;
|
||||||
|
if(in[i+j]=='{')
|
||||||
|
counter++;
|
||||||
|
if(in[i+j]=='}')
|
||||||
|
counter--;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if(i+j >= in_size) //reached end without closing
|
||||||
|
throw ztd::format_error("Brace does not close", "", std::string(in, in_size), i);
|
||||||
|
j++;
|
||||||
|
ret = std::string(in+i, j);
|
||||||
|
*end=i+j;
|
||||||
|
}
|
||||||
|
else if(in[i] == '[')
|
||||||
|
{
|
||||||
|
j=1;
|
||||||
|
int counter=0;
|
||||||
|
while( i+j < in_size && !( counter == 0 && in[i+j]==']') )
|
||||||
|
{
|
||||||
|
if(i+j+1<in_size && in[i+j] == '/' && in[i+j+1] == '/')
|
||||||
|
while(i+j<in_size && in[i+j] != '\n')
|
||||||
|
j++;
|
||||||
|
if(in[i+j]=='\\')
|
||||||
|
j++;
|
||||||
|
if(in[i+j]=='[')
|
||||||
|
counter++;
|
||||||
|
if(in[i+j]==']')
|
||||||
|
counter--;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if(i+j >= in_size) //reached end without closing
|
||||||
|
throw ztd::format_error("Bracket does not close", "", std::string(in, in_size), i);
|
||||||
|
j++;
|
||||||
|
ret = std::string(in+i, j);
|
||||||
|
*end=i+j;
|
||||||
|
}
|
||||||
|
else // no encapsulation: go to next ,
|
||||||
|
{
|
||||||
|
j=0; //size
|
||||||
|
while(i+j < in_size && in[i+j]!=',')
|
||||||
|
{
|
||||||
|
if(in[i+j]=='\\')
|
||||||
|
j++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if(i+j < in_size)
|
||||||
|
{
|
||||||
|
while( !ztd::filedat::isRead(in[i+j]) )
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
ret = std::string(in+i,j);
|
||||||
|
*end=i+j;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = *end;
|
||||||
|
while(i < in_size && !ztd::filedat::isRead(in[i]))
|
||||||
|
i++;
|
||||||
|
if( i>= in_size ) //last char
|
||||||
|
{
|
||||||
|
*end=i;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else if(in[i] ==',') //comma as expected
|
||||||
|
{
|
||||||
|
*end=i+1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else //Unexpected char
|
||||||
|
throw ztd::format_error("Expecting comma", "", std::string(in, in_size), i);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::chunkdat::set(const char* in, const int in_size, int offset, filedat* parent)
|
||||||
|
{
|
||||||
|
this->clear(); //reset everything
|
||||||
|
this->m_parent=parent;
|
||||||
|
this->m_offset=offset;
|
||||||
|
|
||||||
|
int i=0;
|
||||||
|
|
||||||
|
while(i<in_size && !ztd::filedat::isRead(in[i])) //skip unread char
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if(i >= in_size) //empty: make an empty strval
|
||||||
|
{
|
||||||
|
ztd::chunk_string* cv = new ztd::chunk_string();
|
||||||
|
m_achunk=cv;
|
||||||
|
cv->val = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if( in[i] == '{')
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
int val_end=in_size-1;
|
||||||
|
while(!ztd::filedat::isRead(in[val_end])) //skip unread char
|
||||||
|
val_end--;
|
||||||
|
if(in[val_end] != '}')
|
||||||
|
throw ztd::format_error("Expecting closing brace", "", std::string(in, in_size), val_end+1);
|
||||||
|
|
||||||
|
ztd::chunk_map* tch = new ztd::chunk_map();
|
||||||
|
m_achunk = tch;
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
std::string val;
|
||||||
|
while(i < val_end)
|
||||||
|
{
|
||||||
|
int start=0;
|
||||||
|
int _size=0;
|
||||||
|
int end=0;
|
||||||
|
|
||||||
|
while(!ztd::filedat::isRead(in[i]))
|
||||||
|
i++;
|
||||||
|
|
||||||
|
std::string newstr=std::string(in+i, val_end-i);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
name = _getname(newstr.c_str(), newstr.size(), &start, &_size, &end);
|
||||||
|
val = newstr.substr(start, _size);
|
||||||
|
}
|
||||||
|
catch(ztd::format_error& e)
|
||||||
|
{
|
||||||
|
throw ztd::format_error(e.what(), "", std::string(in, in_size), e.where()+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( name == "" ) //no more values
|
||||||
|
break;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ztd::chunkdat* chk = new ztd::chunkdat(val.c_str(),val.size(), offset + start+i, m_parent);
|
||||||
|
if(!tch->values.insert( std::make_pair(name, chk ) ).second)
|
||||||
|
{
|
||||||
|
delete chk;
|
||||||
|
throw ztd::format_error("Key '" + name + "' already present", "", std::string(in, in_size), 0 - start );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(ztd::format_error& e)
|
||||||
|
{
|
||||||
|
throw ztd::format_error(e.what(), "", std::string(in, in_size), e.where() + start + i );
|
||||||
|
}
|
||||||
|
|
||||||
|
i += end;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if( in[i] == '[')
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
int val_end=in_size-1;
|
||||||
|
while(!ztd::filedat::isRead(in[val_end])) //skip unread char
|
||||||
|
val_end--;
|
||||||
|
if(in[val_end] != ']')
|
||||||
|
throw ztd::format_error("Expecting closing bracket", "", std::string(in, in_size), val_end+1);
|
||||||
|
|
||||||
|
ztd::chunk_list* tch = new ztd::chunk_list();
|
||||||
|
m_achunk = tch;
|
||||||
|
|
||||||
|
int end=0,start=0;
|
||||||
|
while( i < val_end )
|
||||||
|
{
|
||||||
|
std::string val;
|
||||||
|
std::string newstr=std::string(in+i, val_end-i);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
val = _getlist(newstr.c_str(), newstr.size(), &start, &end);
|
||||||
|
}
|
||||||
|
catch(ztd::format_error& e)
|
||||||
|
{
|
||||||
|
throw ztd::format_error(e.what(), "", std::string(in, in_size), e.where()+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tch->list.push_back(new ztd::chunkdat(val.c_str(),val.size(), offset + start+i, m_parent) );
|
||||||
|
}
|
||||||
|
catch(ztd::format_error& e)
|
||||||
|
{
|
||||||
|
throw ztd::format_error(e.what(), "", std::string(in, in_size), e.where() + start + i );
|
||||||
|
}
|
||||||
|
|
||||||
|
i+=end;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
else // string value
|
||||||
|
{
|
||||||
|
int val_end=in_size;
|
||||||
|
val_end--;
|
||||||
|
while(!ztd::filedat::isRead(in[val_end])) //skip unread char
|
||||||
|
val_end--;
|
||||||
|
|
||||||
|
ztd::chunk_string* tch = new ztd::chunk_string();
|
||||||
|
m_achunk = tch;
|
||||||
|
|
||||||
|
tch->val = std::string(in+i,val_end-i+1);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::chunkdat::addToMap(std::string const& name, chunkdat const& val)
|
||||||
|
{
|
||||||
|
if(this->type()==ztd::chunk_abstract::map)
|
||||||
|
{
|
||||||
|
ztd::chunk_map* cp = dynamic_cast<chunk_map*>(m_achunk);
|
||||||
|
ztd::chunkdat* chk = new ztd::chunkdat(val);
|
||||||
|
if( !cp->values.insert( std::make_pair(name,chk) ).second )
|
||||||
|
{
|
||||||
|
delete chk;
|
||||||
|
throw ztd::format_error("Key '" + name + "' already present", "", this->strval(), -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(this->type() == ztd::chunk_abstract::none)
|
||||||
|
{
|
||||||
|
ztd::chunk_map* cp = new ztd::chunk_map();
|
||||||
|
m_achunk=cp;
|
||||||
|
cp->values.insert(std::make_pair(name , new ztd::chunkdat(val)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw ztd::format_error("Cannot add keys to non-map chunks", "", this->strval(), -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::chunkdat::addToMap(std::vector<std::pair<std::string, chunkdat>> const& vec)
|
||||||
|
{
|
||||||
|
for(auto it : vec)
|
||||||
|
this->addToMap(it.first, it.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::chunkdat::addToList(chunkdat const& val)
|
||||||
|
{
|
||||||
|
if(this->type()==ztd::chunk_abstract::list)
|
||||||
|
{
|
||||||
|
ztd::chunk_list* lp = dynamic_cast<chunk_list*>(m_achunk);
|
||||||
|
lp->list.push_back(new ztd::chunkdat(val));
|
||||||
|
}
|
||||||
|
else if(this->type() == ztd::chunk_abstract::none)
|
||||||
|
{
|
||||||
|
ztd::chunk_list* lp = new ztd::chunk_list();
|
||||||
|
m_achunk=lp;
|
||||||
|
lp->list.push_back(new ztd::chunkdat(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw ztd::format_error("Cannot add elements to non-list chunks", "", this->strval(), -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::chunkdat::addToList(std::vector<chunkdat> const& vec)
|
||||||
|
{
|
||||||
|
for(auto it : vec)
|
||||||
|
this->addToList(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ztd::chunkdat::strval(unsigned int alignment, std::string const& aligner) const
|
||||||
|
{
|
||||||
|
if(this->type()==ztd::chunk_abstract::string)
|
||||||
|
{
|
||||||
|
ztd::chunk_string* vp = dynamic_cast<chunk_string*>(m_achunk);
|
||||||
|
return vp->val;
|
||||||
|
}
|
||||||
|
else if(this->type()==ztd::chunk_abstract::map)
|
||||||
|
{
|
||||||
|
ztd::chunk_map* cp = dynamic_cast<chunk_map*>(m_achunk);
|
||||||
|
std::string ret="{\n";
|
||||||
|
for(auto it : cp->values)
|
||||||
|
{
|
||||||
|
ret += repeatString(aligner,alignment+1);
|
||||||
|
ret += it.first;
|
||||||
|
ret += '=';
|
||||||
|
if(it.second!=nullptr)
|
||||||
|
ret += it.second->strval(alignment+1, aligner);
|
||||||
|
ret += '\n';
|
||||||
|
}
|
||||||
|
ret += repeatString(aligner, alignment);
|
||||||
|
ret += '}';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else if(this->type()==ztd::chunk_abstract::list)
|
||||||
|
{
|
||||||
|
ztd::chunk_list* lp = dynamic_cast<chunk_list*>(m_achunk);
|
||||||
|
std::string ret="[\n";
|
||||||
|
for(auto it : lp->list)
|
||||||
|
{
|
||||||
|
ret += repeatString(aligner, alignment+1);
|
||||||
|
if(it!=nullptr)
|
||||||
|
ret += it->strval(alignment+1, aligner);
|
||||||
|
ret += ",\n";
|
||||||
|
}
|
||||||
|
ret.erase(ret.end()-2);
|
||||||
|
ret += repeatString(aligner, alignment);
|
||||||
|
ret += ']';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int ztd::chunkdat::listSize() const
|
||||||
|
{
|
||||||
|
if(this->type() != ztd::chunk_abstract::list)
|
||||||
|
return -1;
|
||||||
|
ztd::chunk_list* cl = dynamic_cast<chunk_list*>(m_achunk);
|
||||||
|
return cl->list.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::chunkdat* ztd::chunkdat::subChunkPtr(std::string const& in) const
|
||||||
|
{
|
||||||
|
if(this->type()==ztd::chunk_abstract::map)
|
||||||
|
{
|
||||||
|
ztd::chunk_map* dc = dynamic_cast<chunk_map*>(m_achunk);
|
||||||
|
auto fi = dc->values.find(in);
|
||||||
|
if(fi == dc->values.end()) //none found
|
||||||
|
return nullptr;
|
||||||
|
return fi->second;
|
||||||
|
}
|
||||||
|
else //not a chunk
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::chunkdat* ztd::chunkdat::subChunkPtr(const unsigned int a) const
|
||||||
|
{
|
||||||
|
if(this->type()==ztd::chunk_abstract::list)
|
||||||
|
{
|
||||||
|
ztd::chunk_list* cl = dynamic_cast<chunk_list*>(m_achunk);
|
||||||
|
if(a >= cl->list.size()) //outside of range
|
||||||
|
return nullptr;
|
||||||
|
return cl->list[a];
|
||||||
|
}
|
||||||
|
else //not a list
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::chunkdat& ztd::chunkdat::subChunkRef(std::string const& in) const
|
||||||
|
{
|
||||||
|
if(this->type()!=ztd::chunk_abstract::map)
|
||||||
|
{
|
||||||
|
if(m_parent != nullptr)
|
||||||
|
{
|
||||||
|
throw ztd::format_error("chunkdat isn't a map", m_parent->filePath(), m_parent->im_data(), m_offset );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw ztd::format_error("chunkdat isn't a map", "", this->strval(), -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ztd::chunk_map* dc = dynamic_cast<chunk_map*>(m_achunk);
|
||||||
|
auto fi = dc->values.find(in);
|
||||||
|
if(fi == dc->values.end())
|
||||||
|
{
|
||||||
|
if(m_parent != nullptr)
|
||||||
|
{
|
||||||
|
throw ztd::format_error("Map doesn't have '" + in + "' flag", m_parent->filePath(), m_parent->im_data(), m_offset );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw ztd::format_error("Map doesn't have '" + in + "' flag", "", this->strval(), -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *fi->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::chunkdat& ztd::chunkdat::subChunkRef(const unsigned int a) const
|
||||||
|
{
|
||||||
|
if(this->type()!=ztd::chunk_abstract::list)
|
||||||
|
{
|
||||||
|
if(m_parent != nullptr)
|
||||||
|
{
|
||||||
|
throw ztd::format_error("chunkdat isn't a list", m_parent->filePath(), m_parent->im_data(), m_offset );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw ztd::format_error("chunkdat isn't a list", "", this->strval(), -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ztd::chunk_list* cl = dynamic_cast<chunk_list*>(m_achunk);
|
||||||
|
if(a >= cl->list.size())
|
||||||
|
{
|
||||||
|
if(m_parent != nullptr)
|
||||||
|
{
|
||||||
|
throw ztd::format_error("List size is below " + std::to_string(a), m_parent->filePath(), m_parent->im_data(), m_offset );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw ztd::format_error("List size is below " + std::to_string(a), "", this->strval(), -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *cl->list[a];
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::chunkdat::chunkdat()
|
||||||
|
{
|
||||||
|
m_achunk=nullptr;
|
||||||
|
}
|
||||||
|
ztd::chunkdat::chunkdat(const char* in)
|
||||||
|
{
|
||||||
|
m_achunk=nullptr;
|
||||||
|
set(in, strlen(in), 0, nullptr);
|
||||||
|
}
|
||||||
|
ztd::chunkdat::chunkdat(std::string const& in)
|
||||||
|
{
|
||||||
|
m_achunk=nullptr;
|
||||||
|
set(in, 0, nullptr);
|
||||||
|
}
|
||||||
|
ztd::chunkdat::chunkdat(const char* in, const int in_size, int offset, filedat* data)
|
||||||
|
{
|
||||||
|
m_achunk=nullptr;
|
||||||
|
set(in, in_size, offset, data);
|
||||||
|
}
|
||||||
|
ztd::chunkdat::chunkdat(std::string const& in, int offset, filedat* data)
|
||||||
|
{
|
||||||
|
m_achunk=nullptr;
|
||||||
|
set(in, offset, data);
|
||||||
|
}
|
||||||
|
ztd::chunkdat::chunkdat(chunkdat const& in)
|
||||||
|
{
|
||||||
|
m_achunk=nullptr;
|
||||||
|
set(in);
|
||||||
|
}
|
||||||
|
ztd::chunkdat::~chunkdat()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::chunkdat::clear()
|
||||||
|
{
|
||||||
|
if(m_achunk!=nullptr)
|
||||||
|
delete m_achunk;
|
||||||
|
m_achunk=nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::chunk_abstract::typeEnum ztd::chunkdat::type() const
|
||||||
|
{
|
||||||
|
if(m_achunk!=nullptr)
|
||||||
|
return m_achunk->type();
|
||||||
|
else
|
||||||
|
return ztd::chunk_abstract::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::chunk_abstract::chunk_abstract()
|
||||||
|
{
|
||||||
|
m_type=ztd::chunk_abstract::none;
|
||||||
|
}
|
||||||
|
ztd::chunk_abstract::typeEnum ztd::chunk_abstract::type()
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
ztd::chunk_abstract::~chunk_abstract()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::chunk_string::chunk_string()
|
||||||
|
{
|
||||||
|
m_type=ztd::chunk_abstract::string;
|
||||||
|
}
|
||||||
|
ztd::chunk_string::~chunk_string()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::chunk_map::chunk_map()
|
||||||
|
{
|
||||||
|
m_type=ztd::chunk_abstract::map;
|
||||||
|
}
|
||||||
|
ztd::chunk_map::~chunk_map()
|
||||||
|
{
|
||||||
|
for(auto it : values)
|
||||||
|
{
|
||||||
|
if(it.second != nullptr)
|
||||||
|
delete it.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::chunk_list::chunk_list()
|
||||||
|
{
|
||||||
|
m_type=ztd::chunk_abstract::list;
|
||||||
|
}
|
||||||
|
ztd::chunk_list::~chunk_list()
|
||||||
|
{
|
||||||
|
for(auto it : list)
|
||||||
|
{
|
||||||
|
if(it!=nullptr)
|
||||||
|
delete it;
|
||||||
|
}
|
||||||
|
}
|
||||||
256
src/zoptions.cpp
Normal file
256
src/zoptions.cpp
Normal file
|
|
@ -0,0 +1,256 @@
|
||||||
|
#include "zoptions.hpp"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
ztd::option_error::option_error(error_type type, const std::string& option)
|
||||||
|
{
|
||||||
|
opt=option;
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case unknown_option : msg = "Unkown option: " + opt; break;
|
||||||
|
case takes_no_arg : msg = "Option " + opt + " doesn't take an argument"; break;
|
||||||
|
case missing_arg : msg = "Option " + opt + " needs an argument"; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ztd::argVector(int argc, char** argv)
|
||||||
|
{
|
||||||
|
std::vector<std::string> out;
|
||||||
|
for(int i=1;i<argc; i++)
|
||||||
|
{
|
||||||
|
out.push_back(std::string(argv[i]));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::option::option()
|
||||||
|
{
|
||||||
|
shortDef=false;
|
||||||
|
longDef=false;
|
||||||
|
takesArgument=false;
|
||||||
|
activated=false;
|
||||||
|
charName=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::option::option(char c, bool arg, std::string helptext, std::string argname)
|
||||||
|
{
|
||||||
|
//char
|
||||||
|
shortDef=true;
|
||||||
|
charName=c;
|
||||||
|
//string
|
||||||
|
longDef=false;
|
||||||
|
strName="";
|
||||||
|
//arg
|
||||||
|
takesArgument=arg;
|
||||||
|
arg_name=argname;
|
||||||
|
//help
|
||||||
|
help_text=helptext;
|
||||||
|
//init
|
||||||
|
activated=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::option::option(std::string const& str, bool arg, std::string helptext, std::string argname)
|
||||||
|
{
|
||||||
|
//char
|
||||||
|
shortDef=false;
|
||||||
|
charName=0;
|
||||||
|
//string
|
||||||
|
longDef=true;
|
||||||
|
strName=str;
|
||||||
|
//arg
|
||||||
|
takesArgument=arg;
|
||||||
|
arg_name=argname;
|
||||||
|
//help
|
||||||
|
help_text=helptext;
|
||||||
|
//init
|
||||||
|
activated=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::option::option(char c, std::string const& str, bool arg, std::string helptext, std::string argname)
|
||||||
|
{
|
||||||
|
//char
|
||||||
|
shortDef=true;
|
||||||
|
charName=c;
|
||||||
|
//string
|
||||||
|
longDef=true;
|
||||||
|
strName=str;
|
||||||
|
//arg
|
||||||
|
takesArgument=arg;
|
||||||
|
arg_name=argname;
|
||||||
|
//help
|
||||||
|
help_text=helptext;
|
||||||
|
//init
|
||||||
|
activated=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::option::option(const option& opt)
|
||||||
|
{
|
||||||
|
//char
|
||||||
|
shortDef=opt.shortDef;
|
||||||
|
charName=opt.charName;
|
||||||
|
//string
|
||||||
|
longDef=opt.longDef;
|
||||||
|
strName=opt.strName;
|
||||||
|
//arg
|
||||||
|
takesArgument=opt.takesArgument;
|
||||||
|
arg_name=opt.arg_name;
|
||||||
|
//help
|
||||||
|
help_text=opt.help_text;
|
||||||
|
//init
|
||||||
|
activated=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::option::print_help(int leftpad, int rightpad) const
|
||||||
|
{
|
||||||
|
//prepadding
|
||||||
|
printf("%*s", -1*leftpad, "");
|
||||||
|
|
||||||
|
//short def
|
||||||
|
if(this->shortDef)
|
||||||
|
{
|
||||||
|
printf("-%c ", this->charName);
|
||||||
|
rightpad -= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
//longdef
|
||||||
|
if(this->longDef)
|
||||||
|
{
|
||||||
|
printf("--%s ", this->strName.c_str());
|
||||||
|
rightpad -= 3 + this->strName.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
//argument
|
||||||
|
if(this->takesArgument)
|
||||||
|
{
|
||||||
|
printf(" <%s>", arg_name.c_str());
|
||||||
|
rightpad -= arg_name.size() + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%*s%s", -1*rightpad, "", help_text.c_str());
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::option_set::print_help(int leftpad, int rightpad) const
|
||||||
|
{
|
||||||
|
for(auto it : this->m_options)
|
||||||
|
it.print_help(leftpad,rightpad);
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::option* ztd::option_set::find(char c)
|
||||||
|
{
|
||||||
|
for( auto it=m_options.begin() ; it!=m_options.end() ; it++ )
|
||||||
|
{
|
||||||
|
if((*it).shortDef && (*it).charName == c)
|
||||||
|
return &(*it);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::option* ztd::option_set::find(std::string const& str)
|
||||||
|
{
|
||||||
|
for( auto it=m_options.begin() ; it!=m_options.end() ; it++ )
|
||||||
|
{
|
||||||
|
if((*it).longDef && (*it).strName == str)
|
||||||
|
return &(*it);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ztd::option_set::process(std::vector<std::string> arguments)
|
||||||
|
{
|
||||||
|
std::vector<std::string> out;
|
||||||
|
unsigned int i=0;
|
||||||
|
for( auto it = arguments.begin(); it!=arguments.end() ; it++ )
|
||||||
|
{
|
||||||
|
if( (*it).size()>0 && (*it)[0]=='-' )
|
||||||
|
{
|
||||||
|
if((*it).size()>1 && (*it)[1]=='-')
|
||||||
|
{
|
||||||
|
std::size_t eqn=(*it).find('=');
|
||||||
|
if(eqn == std::string::npos)
|
||||||
|
{
|
||||||
|
ztd::option* popt = this->find( (*it).substr(2,eqn-2) );
|
||||||
|
if(popt == nullptr)
|
||||||
|
{
|
||||||
|
throw ztd::option_error(ztd::option_error::unknown_option, "--" + (*it).substr(2,eqn-2));
|
||||||
|
}
|
||||||
|
if(popt->takesArgument)
|
||||||
|
{
|
||||||
|
if( ++it == arguments.end() ) //finishes here
|
||||||
|
{
|
||||||
|
throw ztd::option_error(ztd::option_error::missing_arg, "--" + popt->strName);
|
||||||
|
}
|
||||||
|
popt->activated = true;
|
||||||
|
popt->argument = (*it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
popt->activated = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ztd::option* popt = this->find( (*it).substr(2,eqn-2) );
|
||||||
|
if(popt == nullptr)
|
||||||
|
{
|
||||||
|
throw ztd::option_error(ztd::option_error::unknown_option, "--" +(*it).substr(2,eqn-2));
|
||||||
|
}
|
||||||
|
if(!popt->takesArgument)
|
||||||
|
{
|
||||||
|
throw ztd::option_error(ztd::option_error::takes_no_arg, "--" + popt->strName);
|
||||||
|
}
|
||||||
|
popt->argument = (*it).substr(eqn+1,(*it).size()-eqn-1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i=1;
|
||||||
|
ztd::option* popt=nullptr;
|
||||||
|
bool tstop=false;
|
||||||
|
while( !tstop && it!=arguments.end() && (*it).size()>i )
|
||||||
|
{
|
||||||
|
popt=this->find((*it)[i]);
|
||||||
|
if(popt==nullptr) //not found: error
|
||||||
|
{
|
||||||
|
throw ztd::option_error(ztd::option_error::unknown_option, std::string("-") + (*it)[i] );
|
||||||
|
}
|
||||||
|
if(popt->takesArgument) //no argument
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
if((*it).size()<=i) //finishes here
|
||||||
|
{
|
||||||
|
if( ++it == arguments.end() )
|
||||||
|
{
|
||||||
|
throw ztd::option_error(ztd::option_error::missing_arg, std::string("-") + popt->charName );
|
||||||
|
}
|
||||||
|
popt->activated = true;
|
||||||
|
popt->argument = (*it);
|
||||||
|
tstop = true;
|
||||||
|
}
|
||||||
|
else //continue
|
||||||
|
{
|
||||||
|
if( (*it)[i] != '=') //incorrect
|
||||||
|
{
|
||||||
|
throw ztd::option_error(ztd::option_error::missing_arg, std::string("-") + popt->charName );
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
popt->argument = (*it).substr(i , (*it).size()-i );
|
||||||
|
popt->activated = true;
|
||||||
|
tstop=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //no argument
|
||||||
|
popt->activated = true;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.push_back(*it);
|
||||||
|
}
|
||||||
|
if(it == arguments.end())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
96
src/zshell.cpp
Normal file
96
src/zshell.cpp
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
#include "zshell.hpp"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
std::string ztd::sh(const std::string& command, bool to_console)
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
FILE *stream = popen(command.c_str(), "r");
|
||||||
|
char* buff = NULL;
|
||||||
|
size_t buff_size = 0;
|
||||||
|
while (getline(&buff, &buff_size, stream) > 0)
|
||||||
|
{
|
||||||
|
if(to_console)
|
||||||
|
{
|
||||||
|
printf("%s", buff);
|
||||||
|
}
|
||||||
|
ret += buff;
|
||||||
|
}
|
||||||
|
pclose(stream);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* ztd::popen2(const char* command, const char* type, int* pid)
|
||||||
|
{
|
||||||
|
const int READ=0, WRITE=1;
|
||||||
|
pid_t child_pid;
|
||||||
|
int fd[2];
|
||||||
|
pipe(fd);
|
||||||
|
|
||||||
|
if((child_pid = fork()) == -1)
|
||||||
|
{
|
||||||
|
perror("fork");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* child process */
|
||||||
|
if (child_pid == 0)
|
||||||
|
{
|
||||||
|
if ( index(type, 'r') != NULL )
|
||||||
|
{
|
||||||
|
close(fd[READ]); //Close the READ end of the pipe since the child's fd is write-only
|
||||||
|
dup2(fd[WRITE], 1); //Redirect stdout to pipe
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
close(fd[WRITE]); //Close the WRITE end of the pipe since the child's fd is read-only
|
||||||
|
dup2(fd[READ], 0); //Redirect stdin to pipe
|
||||||
|
}
|
||||||
|
|
||||||
|
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
|
||||||
|
execl("/bin/sh", "/bin/sh", "-c", command, NULL);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( index(type, 'r') != NULL )
|
||||||
|
{
|
||||||
|
close(fd[WRITE]); //Close the WRITE end of the pipe since parent's fd is read-only
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
close(fd[READ]); //Close the READ end of the pipe since parent's fd is write-only
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(pid != NULL)
|
||||||
|
*pid = child_pid;
|
||||||
|
|
||||||
|
if ( index(type, 'r') != NULL )
|
||||||
|
{
|
||||||
|
return fdopen(fd[READ], "r");
|
||||||
|
}
|
||||||
|
|
||||||
|
return fdopen(fd[WRITE], "w");
|
||||||
|
}
|
||||||
|
|
||||||
|
int ztd::pclose2(FILE* fp, pid_t pid)
|
||||||
|
{
|
||||||
|
int stat;
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
while (waitpid(pid, &stat, 0) == -1)
|
||||||
|
{
|
||||||
|
if (errno != EINTR)
|
||||||
|
{
|
||||||
|
stat = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
281
src/zsocket.cpp
Normal file
281
src/zsocket.cpp
Normal file
|
|
@ -0,0 +1,281 @@
|
||||||
|
#include "zsocket.hpp"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
|
#include <unistd.h> // read/write/close
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
ztd::socket_abstract::socket_abstract()
|
||||||
|
{
|
||||||
|
m_fd=-1;
|
||||||
|
m_operational=false;
|
||||||
|
m_thread=nullptr;
|
||||||
|
m_parallel=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::socket_abstract::~socket_abstract()
|
||||||
|
{
|
||||||
|
killParallel();
|
||||||
|
close_socket();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::socket_abstract::close_socket()
|
||||||
|
{
|
||||||
|
m_operational=false;
|
||||||
|
close(m_fd);
|
||||||
|
m_fd=-1;
|
||||||
|
parallelOff();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ztd::socket_abstract::send_string(std::string const& text)
|
||||||
|
{
|
||||||
|
if(m_fd < 0 || !m_operational)
|
||||||
|
return false;
|
||||||
|
if(send(m_fd, text.c_str(), text.size()+1, 0) < 0 )
|
||||||
|
{
|
||||||
|
close_socket();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ztd::socket_abstract::read_string()
|
||||||
|
{
|
||||||
|
if(m_fd < 0 || !m_operational)
|
||||||
|
return "";
|
||||||
|
char buf[256]={0};
|
||||||
|
if(read(m_fd, buf, 255) <= 0)
|
||||||
|
{
|
||||||
|
close_socket();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
m_cv.notify_all();
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ztd::socket_abstract::send_data(uint8_t *data, uint32_t size)
|
||||||
|
{
|
||||||
|
if(m_fd < 0 || !m_operational)
|
||||||
|
return false;
|
||||||
|
if(send(m_fd, data, size, 0) < 0 )
|
||||||
|
{
|
||||||
|
close_socket();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ztd::socket_abstract::read_data(uint8_t *data, uint32_t *size)
|
||||||
|
{
|
||||||
|
if(m_fd < 0 || !m_operational)
|
||||||
|
return false;
|
||||||
|
uint32_t n = read(m_fd, data, (*size));
|
||||||
|
if(n <= 0)
|
||||||
|
{
|
||||||
|
close_socket();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*size = n;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> ztd::socket_abstract::retrieve()
|
||||||
|
{
|
||||||
|
if(m_dataSet.size() > 0)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> ret = *m_dataSet.begin();
|
||||||
|
m_dataSet.erase(m_dataSet.begin());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return std::vector<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::socket_abstract::parallel_on(uint32_t bufferSize)
|
||||||
|
{
|
||||||
|
if(!m_parallel)
|
||||||
|
{
|
||||||
|
m_parallel=true;
|
||||||
|
m_thread= new std::thread(parallel_reading, this, bufferSize);
|
||||||
|
m_thread->detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::socket_abstract::parallelOff()
|
||||||
|
{
|
||||||
|
m_parallel=false;
|
||||||
|
m_thread=nullptr;
|
||||||
|
m_cv.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::socket_abstract::killParallel()
|
||||||
|
{
|
||||||
|
if(m_thread!=nullptr)
|
||||||
|
{
|
||||||
|
m_parallel=false;
|
||||||
|
delete m_thread;
|
||||||
|
m_thread=nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::socket_abstract::wait_data()
|
||||||
|
{
|
||||||
|
if(!m_parallel || !m_operational)
|
||||||
|
return;
|
||||||
|
std::unique_lock<std::mutex> lck(m_mtx);
|
||||||
|
while(!data_available() && m_parallel && m_operational) m_cv.wait(lck);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::socket_abstract::parallel_reading(ztd::socket_abstract *s, uint32_t bufferSize)
|
||||||
|
{
|
||||||
|
uint8_t *buffer = (uint8_t*) malloc(bufferSize);
|
||||||
|
uint32_t tmp_size;
|
||||||
|
while(s->parallel() && s->operational())
|
||||||
|
{
|
||||||
|
tmp_size=bufferSize;
|
||||||
|
if(s->read_data(buffer, &tmp_size))
|
||||||
|
{
|
||||||
|
s->data().push_back(std::vector<uint8_t>(buffer, buffer+tmp_size));
|
||||||
|
}
|
||||||
|
s->cv().notify_all();
|
||||||
|
}
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::tcpsocket_abstract::tcpsocket_abstract()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::tcpsocket_abstract::~tcpsocket_abstract()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ztd::tcpsocket_abstract::init_ipv4()
|
||||||
|
{
|
||||||
|
m_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
return m_fd >=0;
|
||||||
|
}
|
||||||
|
bool ztd::tcpsocket_abstract::init_ipv6()
|
||||||
|
{
|
||||||
|
m_fd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
|
return m_fd >=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::tcpsocket_server::tcpsocket_server()
|
||||||
|
{
|
||||||
|
m_port=0;
|
||||||
|
bzero(&m_servaddr, sizeof(m_servaddr));
|
||||||
|
m_listening=false;
|
||||||
|
}
|
||||||
|
ztd::tcpsocket_server::~tcpsocket_server()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ztd::tcpsocket_server::listen_ipv4(uint16_t port, int backlog)
|
||||||
|
{
|
||||||
|
m_port=port;
|
||||||
|
if(m_port == 0)
|
||||||
|
return false;
|
||||||
|
m_servaddr.sin_family = AF_INET;
|
||||||
|
m_servaddr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
m_servaddr.sin_port = htons(m_port);
|
||||||
|
if(bind(m_fd, (struct sockaddr *) &m_servaddr, sizeof(m_servaddr)) < 0) //binding
|
||||||
|
return false;
|
||||||
|
listen(m_fd, 5);
|
||||||
|
if(m_fd < 0)
|
||||||
|
return false;
|
||||||
|
m_listening=true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ztd::tcpsocket_server::listen_ipv6(uint16_t port, int backlog)
|
||||||
|
{
|
||||||
|
m_port=port;
|
||||||
|
if(m_port == 0)
|
||||||
|
return false;
|
||||||
|
m_servaddr.sin_family = AF_INET6;
|
||||||
|
m_servaddr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
m_servaddr.sin_port = htons(m_port);
|
||||||
|
if(bind(m_fd, (struct sockaddr *) &m_servaddr, sizeof(m_servaddr)) < 0) //binding
|
||||||
|
return false;
|
||||||
|
listen(m_fd, backlog);
|
||||||
|
if(m_fd < 0)
|
||||||
|
return false;
|
||||||
|
m_listening=true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::tcpsocket_server_instance::tcpsocket_server_instance(ztd::tcpsocket_server *server)
|
||||||
|
{
|
||||||
|
m_server=server;
|
||||||
|
m_clilen=sizeof(m_cliaddr);
|
||||||
|
}
|
||||||
|
ztd::tcpsocket_server_instance::~tcpsocket_server_instance()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ztd::tcpsocket_server_instance::accept_connection()
|
||||||
|
{
|
||||||
|
if(m_server == nullptr)
|
||||||
|
return false;
|
||||||
|
if(!m_server->is_open())
|
||||||
|
return false;
|
||||||
|
m_fd = accept(m_server->fd(), (struct sockaddr *) &m_cliaddr, &m_clilen);
|
||||||
|
if(m_fd < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_operational=true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* ztd::tcpsocket_server_instance::client_address()
|
||||||
|
{
|
||||||
|
return inet_ntoa(m_cliaddr.sin_addr);
|
||||||
|
}
|
||||||
|
uint16_t ztd::tcpsocket_server_instance::client_port()
|
||||||
|
{
|
||||||
|
return ntohs(m_cliaddr.sin_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
ztd::tcpsocket_client::tcpsocket_client()
|
||||||
|
{
|
||||||
|
bzero( (char *) &m_servaddr, sizeof(m_servaddr));
|
||||||
|
m_server=nullptr;
|
||||||
|
}
|
||||||
|
ztd::tcpsocket_client::~tcpsocket_client()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ztd::tcpsocket_client::connect_ipv4(std::string const& addr, uint16_t port)
|
||||||
|
{
|
||||||
|
m_addr=addr;
|
||||||
|
m_port = port;
|
||||||
|
m_server = gethostbyname(m_addr.c_str());
|
||||||
|
m_servaddr.sin_family = AF_INET;
|
||||||
|
bcopy((char *)m_server->h_addr, (char *)&m_servaddr.sin_addr.s_addr, m_server->h_length);
|
||||||
|
m_servaddr.sin_port = htons(m_port);
|
||||||
|
if(connect(m_fd, (struct sockaddr *) &m_servaddr, sizeof(m_servaddr)) < 0)
|
||||||
|
return false;
|
||||||
|
m_operational = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ztd::tcpsocket_client::connect_ipv6(std::string const& addr, uint16_t port)
|
||||||
|
{
|
||||||
|
m_addr=addr;
|
||||||
|
m_port = port;
|
||||||
|
m_server = gethostbyname(m_addr.c_str());
|
||||||
|
m_servaddr.sin_family = AF_INET6;
|
||||||
|
bcopy((char *)m_server->h_addr, (char *)&m_servaddr.sin_addr.s_addr, m_server->h_length);
|
||||||
|
m_servaddr.sin_port = htons(m_port);
|
||||||
|
if(connect(m_fd, (struct sockaddr *) &m_servaddr, sizeof(m_servaddr)) < 0)
|
||||||
|
return false;
|
||||||
|
m_operational = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
36
src/zthread.cpp
Normal file
36
src/zthread.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#include "zthread.hpp"
|
||||||
|
|
||||||
|
ztd::thread_pool::~thread_pool()
|
||||||
|
{
|
||||||
|
for(auto it : m_threads)
|
||||||
|
{
|
||||||
|
delete it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::thread_pool::join()
|
||||||
|
{
|
||||||
|
for(auto it : m_threads)
|
||||||
|
{
|
||||||
|
it->join();
|
||||||
|
delete it;
|
||||||
|
}
|
||||||
|
m_threads.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::thread_pool::detach()
|
||||||
|
{
|
||||||
|
for(auto it : m_threads)
|
||||||
|
{
|
||||||
|
it->detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::thread_pool::clear()
|
||||||
|
{
|
||||||
|
for(auto it : m_threads)
|
||||||
|
{
|
||||||
|
delete it;
|
||||||
|
}
|
||||||
|
m_threads.clear();
|
||||||
|
}
|
||||||
41
src/ztime.cpp
Normal file
41
src/ztime.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
#include "ztime.hpp"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
ztd::timer::timer()
|
||||||
|
{
|
||||||
|
m_sec=0;
|
||||||
|
m_stopped=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ztd::timer::time() const
|
||||||
|
{
|
||||||
|
if(m_stopped)
|
||||||
|
return m_sec;
|
||||||
|
struct timeval t_time;
|
||||||
|
gettimeofday(&t_time, NULL);
|
||||||
|
return t_time.tv_sec - m_start.tv_sec + (t_time.tv_usec - m_start.tv_usec) / 1000000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::timer::start()
|
||||||
|
{
|
||||||
|
m_sec=0;
|
||||||
|
gettimeofday(&m_start, NULL);
|
||||||
|
m_stopped=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ztd::timer::stop()
|
||||||
|
{
|
||||||
|
if(m_stopped)
|
||||||
|
return false;
|
||||||
|
gettimeofday(&m_end, NULL);
|
||||||
|
m_stopped=true;
|
||||||
|
m_sec = m_end.tv_sec - m_start.tv_sec + (m_end.tv_usec - m_start.tv_usec) / 1000000.0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::timer::reset()
|
||||||
|
{
|
||||||
|
m_sec=0;
|
||||||
|
m_stopped=true;
|
||||||
|
}
|
||||||
17
src/zwait.cpp
Normal file
17
src/zwait.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include "zwait.hpp"
|
||||||
|
|
||||||
|
void ztd::wait_pool::wait()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lck(m_mtx);
|
||||||
|
m_cv.wait(lck);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::wait_pool::notify_one()
|
||||||
|
{
|
||||||
|
m_cv.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ztd::wait_pool::notify_all()
|
||||||
|
{
|
||||||
|
m_cv.notify_all();
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue