This commit is contained in:
zawz 2019-08-15 14:20:13 +02:00
parent 693e47744a
commit 24afc71c1a
19 changed files with 5366 additions and 0 deletions

2536
Doxyfile Normal file

File diff suppressed because it is too large Load diff

48
Makefile Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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();
}