diff --git a/src/Makefile.am b/src/Makefile.am index a91659cc..82785c81 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -358,6 +358,7 @@ fldigi_SOURCES += \ include/spot.h \ include/stacktrace.h \ include/status.h \ + include/strutil.h \ include/testmodem.h \ include/threads.h \ include/throb.h \ @@ -424,6 +425,7 @@ fldigi_SOURCES += \ misc/socket.cxx \ misc/stacktrace.cxx \ misc/status.cxx \ + misc/strutil.cxx \ misc/threads.cxx \ misc/timeops.cxx \ misc/util.cxx \ diff --git a/src/include/strutil.h b/src/include/strutil.h new file mode 100644 index 00000000..70cc328f --- /dev/null +++ b/src/include/strutil.h @@ -0,0 +1,119 @@ +#ifndef STRUTIL_H_ +#define STRUTIL_H_ + +#include +#include +#include +#include +#include + +namespace join_ { + template struct empty { + bool operator()(const T& v) const { return false; }; + }; + template <> struct empty { + bool operator()(const char* v) const { return !v || *v == '\0'; }; + }; + template <> struct empty { + bool operator()(char* v) const { return !v || *v == '\0'; }; + }; + template <> struct empty { + bool operator()(const wchar_t* v) const { return !v || *v == L'\0'; }; + }; + template <> struct empty { + bool operator()(wchar_t* v) const { return !v || *v == L'\0'; }; + }; + template struct empty > { + bool operator()(const std::basic_string& v) const { return v.empty(); }; + }; + + template > + class ostream_iterator + : public std::iterator + { + public: + typedef std::basic_ostream ostream_type; + + ostream_iterator(ostream_type& s, const CharT* sep = 0, bool ie = false) + : stream(&s), join_string(sep), print_sep(false), ignore_empty(ie) { } + + ostream_iterator& operator=(const T& value) + { + if (!ignore_empty || !is_empty(value)) { + if (print_sep) + *stream << join_string; + *stream << value; + print_sep = true; + } + + return *this; + } + + ostream_iterator& operator*(void) { return *this; } + ostream_iterator& operator++(void) { return *this; } + ostream_iterator& operator++(int) { return *this; } + + private: + ostream_type* stream; + const CharT* join_string; + bool print_sep, ignore_empty; + empty is_empty; + }; +}; + +template +std::basic_ostream& +join(std::basic_ostream& stream, + const T* begin, const T* end, const char* sep, bool ignore_empty = false) +{ + std::copy(begin, end, join_::ostream_iterator(stream, sep, ignore_empty)); + return stream; +} +template +std::basic_ostream& +join(std::basic_ostream& stream, + const T* ptr, size_t len, const char* sep, bool ignore_empty = false) +{ + join(stream, ptr, ptr + len, sep, ignore_empty); + return stream; +} + +template +std::string join(const T* begin, const T* end, const char* sep, bool ignore_empty = false) +{ + std::ostringstream stream; + join(stream, begin, end, sep, ignore_empty); + return stream.str(); +} +template +std::string join(const T* ptr, size_t len, const char* sep, bool ignore_empty = false) +{ + return join(ptr, ptr + len, sep, ignore_empty); +} + +template +std::basic_string join(const std::basic_string* begin, const std::basic_string* end, + const char* sep, bool ignore_empty = false) +{ + std::basic_ostringstream > stream; + join >(stream, begin, end, sep, ignore_empty); + return stream.str(); +} +template +std::basic_string join(const std::basic_string* begin, size_t len, + const char* sep, bool ignore_empty = false) +{ + return join(begin, begin + len, sep, ignore_empty); +} + +#include +#include + +std::vector split(const char* re_str, const char* str, unsigned max_split = UINT_MAX); + +#endif // STRUTIL_H_ + +// Local Variables: +// mode: c++ +// c-file-style: "linux" +// End: diff --git a/src/misc/strutil.cxx b/src/misc/strutil.cxx new file mode 100644 index 00000000..dd37a541 --- /dev/null +++ b/src/misc/strutil.cxx @@ -0,0 +1,41 @@ +#include + +#include +#include +#include +#include + +#include "re.h" +#include "strutil.h" + +using namespace std; + +vector split(const char* re_str, const char* str, unsigned max_split) +{ + vector v; + size_t n = strlen(re_str); + string s; s.reserve(n + 2); s.append(1, '(').append(re_str, n).append(1, ')'); + fre_t re(s.c_str(), REG_EXTENDED); + + bool ignore_trailing_empty = false; + if (max_split == 0) { + max_split = UINT_MAX; + ignore_trailing_empty = true; + } + + s = str; + const vector& sub = re.suboff(); + while (re.match(s.c_str())) { + if (unlikely(sub.empty() || ((max_split != UINT_MAX) && --max_split == 0))) + break; + else { + s[sub[0].rm_so] = '\0'; + v.push_back(s.c_str()); + s.erase(0, sub[0].rm_eo); + } + } + + if (!(ignore_trailing_empty && s.empty())) + v.push_back(s); + return v; +}