kopia lustrzana https://github.com/jamescoxon/dl-fldigi
279 wiersze
8.7 KiB
C++
279 wiersze
8.7 KiB
C++
// ----------------------------------------------------------------------------
|
|
// strutil.h
|
|
//
|
|
// Copyright (C) 2009
|
|
// Stelios Bounanos, M0GLD
|
|
//
|
|
// This file is part of fldigi.
|
|
//
|
|
// Fldigi is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Fldigi is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with fldigi. If not, see <http://www.gnu.org/licenses/>.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#ifndef STRUTIL_H_
|
|
#define STRUTIL_H_
|
|
|
|
#include <ostream>
|
|
#include <iterator>
|
|
#include <sstream>
|
|
#include <algorithm>
|
|
#include <string>
|
|
|
|
namespace join_ {
|
|
template <typename T> struct empty {
|
|
bool operator()(const T& v) const { return false; };
|
|
};
|
|
template <> struct empty<const char*> {
|
|
bool operator()(const char* v) const { return !v || *v == '\0'; };
|
|
};
|
|
template <> struct empty<char*> {
|
|
bool operator()(char* v) const { return !v || *v == '\0'; };
|
|
};
|
|
template <> struct empty<const wchar_t*> {
|
|
bool operator()(const wchar_t* v) const { return !v || *v == L'\0'; };
|
|
};
|
|
template <> struct empty<wchar_t*> {
|
|
bool operator()(wchar_t* v) const { return !v || *v == L'\0'; };
|
|
};
|
|
template <typename C> struct empty<std::basic_string<C> > {
|
|
bool operator()(const std::basic_string<C>& v) const { return v.empty(); };
|
|
};
|
|
|
|
template <typename T, typename CharT = char, typename TraitsT = std::char_traits<CharT> >
|
|
class ostream_iterator
|
|
: public std::iterator<std::output_iterator_tag, void, void, void, void>
|
|
{
|
|
public:
|
|
typedef std::basic_ostream<CharT, TraitsT> 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<T> is_empty;
|
|
};
|
|
};
|
|
|
|
template <typename T, typename CharT, typename TraitsT>
|
|
std::basic_ostream<CharT, TraitsT>&
|
|
join(std::basic_ostream<CharT, TraitsT>& stream,
|
|
const T* begin, const T* end, const char* sep, bool ignore_empty = false)
|
|
{
|
|
std::copy(begin, end, join_::ostream_iterator<T, CharT, TraitsT>(stream, sep, ignore_empty));
|
|
return stream;
|
|
}
|
|
template <typename T, typename CharT, typename TraitsT>
|
|
std::basic_ostream<CharT, TraitsT>&
|
|
join(std::basic_ostream<CharT, TraitsT>& stream,
|
|
const T* ptr, size_t len, const char* sep, bool ignore_empty = false)
|
|
{
|
|
join<T, CharT, TraitsT>(stream, ptr, ptr + len, sep, ignore_empty);
|
|
return stream;
|
|
}
|
|
|
|
template <typename T>
|
|
std::string join(const T* begin, const T* end, const char* sep, bool ignore_empty = false)
|
|
{
|
|
std::ostringstream stream;
|
|
join<T>(stream, begin, end, sep, ignore_empty);
|
|
return stream.str();
|
|
}
|
|
template <typename T>
|
|
std::string join(const T* ptr, size_t len, const char* sep, bool ignore_empty = false)
|
|
{
|
|
return join<T>(ptr, ptr + len, sep, ignore_empty);
|
|
}
|
|
|
|
template <typename CharT>
|
|
std::basic_string<CharT> join(const std::basic_string<CharT>* begin, const std::basic_string<CharT>* end,
|
|
const char* sep, bool ignore_empty = false)
|
|
{
|
|
std::basic_ostringstream<CharT, std::char_traits<CharT> > stream;
|
|
join<std::basic_string<CharT> >(stream, begin, end, sep, ignore_empty);
|
|
return stream.str();
|
|
}
|
|
template <typename CharT>
|
|
std::basic_string<CharT> join(const std::basic_string<CharT>* begin, size_t len,
|
|
const char* sep, bool ignore_empty = false)
|
|
{
|
|
return join<CharT>(begin, begin + len, sep, ignore_empty);
|
|
}
|
|
|
|
#include <vector>
|
|
#include <climits>
|
|
|
|
std::vector<std::string> split(const char* re_str, const char* str, unsigned max_split = UINT_MAX);
|
|
|
|
// Fills a string with snpritnf format string.
|
|
std::string strformat( const char * fmt, ... );
|
|
|
|
// Eliminates spaces and tabs at the beginning and the end.
|
|
void strtrim( std::string & str );
|
|
|
|
// First letter of each word in uppercase, the rest in lowercase.
|
|
void strcapitalize( std::string & str );
|
|
|
|
// Returns the replacement of all occurences of a given string by another.
|
|
std::string strreplace( const std::string & inp, const std::string & from, const std::string & to );
|
|
|
|
/// Edit distance: Returns an integer which is the distance between the two strings.
|
|
size_t levenshtein(const std::string & source, const std::string & target);
|
|
|
|
// Conversion to uppercase.
|
|
std::string uppercase( const std::string & str );
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/// This is a read-only replacement for std::stringstream.
|
|
struct imemstream : public std::streambuf, public std::istream {
|
|
/// Faster than stringstream because no copy.
|
|
imemstream(char* s, std::size_t n) : std::istream( this )
|
|
{
|
|
setg(s, s, s + n);
|
|
}
|
|
/// Faster than stringstream because no copy.
|
|
imemstream(const std::string & r) : std::istream( this )
|
|
{
|
|
char * s = const_cast< char * >( r.c_str() );
|
|
setg(s, s, s + r.size());
|
|
}
|
|
};
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/// Tells if type is a char[]. Used for SFINAE.
|
|
template< class T >
|
|
struct DtTyp {
|
|
/// In the general case, data types are not char arrays.
|
|
struct Any {};
|
|
};
|
|
|
|
/// Matches if the type is a char[].
|
|
template< size_t N >
|
|
struct DtTyp< char[N] > {
|
|
struct Array {};
|
|
static const size_t Size = N ;
|
|
};
|
|
|
|
/// Reads all chars until after the delimiter.
|
|
bool read_until_delim( char delim, std::istream & istrm );
|
|
|
|
/// Reads a char followed by the delimiter.
|
|
bool read_until_delim( char delim, std::istream & istrm, char & ref, const char dflt );
|
|
|
|
/// Reads a double up to the given delimiter.
|
|
inline bool read_until_delim( char delim, std::istream & istrm, double & ref )
|
|
{
|
|
istrm >> ref ;
|
|
if( ! istrm ) return false ;
|
|
|
|
char tmp = istrm.get();
|
|
if( istrm.eof() ) {
|
|
/// Resets to good to mean that it worked fine.
|
|
istrm.clear();
|
|
return true ;
|
|
}
|
|
return tmp == delim ;
|
|
}
|
|
|
|
/// Reads a string up to the given delimiter.
|
|
inline bool read_until_delim( char delim, std::istream & istrm, std::string & ref )
|
|
{
|
|
std::getline( istrm, ref, delim );
|
|
if ( (istrm.rdstate() & std::istream::goodbit) == 0 )
|
|
return true ;
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
/// For reading from a string with tokens separated by a char. Used to load CSV files.
|
|
template< typename Tp >
|
|
bool read_until_delim( char delim, std::istream & istrm, Tp & ref, typename DtTyp< Tp >::Any = typename DtTyp< Tp >::Any() )
|
|
{
|
|
std::string parsed_str ;
|
|
std::getline( istrm, parsed_str, delim );
|
|
if( ! ((istrm.rdstate() & std::istream::goodbit) == 0)) {
|
|
return false ;
|
|
}
|
|
imemstream sstrm( parsed_str );
|
|
sstrm >> ref ;
|
|
return true ;
|
|
}
|
|
|
|
/// Same, with a default value if there is nothing to read.
|
|
template< typename Tp >
|
|
bool read_until_delim( char delim, std::istream & istrm, Tp & ref, const Tp dflt, typename DtTyp< Tp >::Any = typename DtTyp< Tp >::Any() )
|
|
{
|
|
std::string parsed_str ;
|
|
std::getline( istrm, parsed_str, delim ) ;
|
|
if( ! ((istrm.rdstate() & std::istream::goodbit) == 0) ) {
|
|
return false ;
|
|
}
|
|
if( parsed_str.empty() ) {
|
|
ref = dflt ;
|
|
return true;
|
|
}
|
|
imemstream sstrm( parsed_str );
|
|
sstrm >> ref ;
|
|
return true ;
|
|
}
|
|
|
|
/// For reading from a string with tokens separated by a char to a fixed-size array.
|
|
template< typename Tp >
|
|
bool read_until_delim( char delim, std::istream & istrm, Tp & ref, typename DtTyp< Tp >::Array = typename DtTyp< Tp >::Array() )
|
|
{
|
|
istrm.getline( ref, DtTyp< Tp >::Size, delim );
|
|
// Should we return an error if buffer is too small?
|
|
return( (istrm.rdstate() & std::istream::goodbit) == 0 );
|
|
}
|
|
|
|
/// Same, with a default value if there is nothing to read. Fixed-size array.
|
|
template< typename Tp >
|
|
bool read_until_delim( char delim, std::istream & istrm, Tp & ref, const Tp dflt, typename DtTyp< Tp >::Array = typename DtTyp< Tp >::Array() )
|
|
{
|
|
istrm.getline( ref, DtTyp< Tp >::Size, delim );
|
|
// If nothing to read, copy the default value.
|
|
if( ref[0] == '\0' ) {
|
|
strncpy( ref, dflt, DtTyp< Tp >::Size - 1 );
|
|
}
|
|
// Should we return an error if buffer is too small?
|
|
return ((istrm.rdstate() & std::istream::goodbit) == 0 );
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#endif // STRUTIL_H_
|
|
|
|
// Local Variables:
|
|
// mode: c++
|
|
// c-file-style: "linux"
|
|
// End:
|