diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/Alloc.cxx | 84 | ||||
-rw-r--r-- | src/util/Alloc.hxx | 19 | ||||
-rw-r--r-- | src/util/Cast.hxx | 4 | ||||
-rw-r--r-- | src/util/DivideString.cxx | 48 | ||||
-rw-r--r-- | src/util/DivideString.hxx | 75 | ||||
-rw-r--r-- | src/util/Error.cxx | 8 | ||||
-rw-r--r-- | src/util/Manual.hxx | 39 | ||||
-rw-r--r-- | src/util/SplitString.cxx | 42 | ||||
-rw-r--r-- | src/util/SplitString.hxx | 56 | ||||
-rw-r--r-- | src/util/StringUtil.cxx | 20 | ||||
-rw-r--r-- | src/util/StringUtil.hxx | 8 |
11 files changed, 330 insertions, 73 deletions
diff --git a/src/util/Alloc.cxx b/src/util/Alloc.cxx index ec3579470..0533a58f8 100644 --- a/src/util/Alloc.cxx +++ b/src/util/Alloc.cxx @@ -74,3 +74,87 @@ xstrndup(const char *s, size_t n) return p; } + +#if CLANG_OR_GCC_VERSION(4,7) + +template<typename... Args> +static inline size_t +FillLengths(size_t *lengths, const char *a, Args&&... args) +{ + return FillLengths(lengths, a) + FillLengths(lengths + 1, args...); +} + +template<> +inline size_t +FillLengths(size_t *lengths, const char *a) +{ + return *lengths = strlen(a); +} + +template<typename... Args> +static inline void +StringCat(char *p, const size_t *lengths, const char *a, Args&&... args) +{ + StringCat(p, lengths, a); + StringCat(p + *lengths, lengths + 1, args...); +} + +template<> +inline void +StringCat(char *p, const size_t *lengths, const char *a) +{ + memcpy(p, a, *lengths); +} + +#endif + +template<typename... Args> +gcc_malloc gcc_nonnull_all +static inline char * +t_xstrcatdup(Args&&... args) +{ +#if CLANG_OR_GCC_VERSION(4,7) + constexpr size_t n = sizeof...(args); + + size_t lengths[n]; + const size_t total = FillLengths(lengths, args...); + + char *p = (char *)xalloc(total + 1); + StringCat(p, lengths, args...); + p[total] = 0; + return p; +#else + /* fallback implementation for gcc 4.6, because that old + compiler is too buggy to compile the above template + functions */ + const char *const argv[] = { args... }; + + size_t total = 0; + for (auto i : argv) + total += strlen(i); + + char *p = (char *)xalloc(total + 1), *q = p; + for (auto i : argv) + q = stpcpy(q, i); + + return p; +#endif +} + +char * +xstrcatdup(const char *a, const char *b) +{ + return t_xstrcatdup(a, b); +} + +char * +xstrcatdup(const char *a, const char *b, const char *c) +{ + return t_xstrcatdup(a, b, c); +} + +char * +xstrcatdup(const char *a, const char *b, const char *c, const char *d) +{ + return t_xstrcatdup(a, b, c, d); +} diff --git a/src/util/Alloc.hxx b/src/util/Alloc.hxx index 15c123b7a..654b7d0fe 100644 --- a/src/util/Alloc.hxx +++ b/src/util/Alloc.hxx @@ -64,4 +64,23 @@ gcc_malloc gcc_nonnull_all char * xstrndup(const char *s, size_t n); +/** + * Concatenate two strings, returning a new allocation. Use free() to + * free it. + * + * This function never fails; in out-of-memory situations, it aborts + * the process. + */ +gcc_malloc gcc_nonnull_all +char * +xstrcatdup(const char *a, const char *b); + +gcc_malloc gcc_nonnull_all +char * +xstrcatdup(const char *a, const char *b, const char *c); + +gcc_malloc gcc_nonnull_all +char * +xstrcatdup(const char *a, const char *b, const char *c, const char *d); + #endif diff --git a/src/util/Cast.hxx b/src/util/Cast.hxx index 887137da4..647171970 100644 --- a/src/util/Cast.hxx +++ b/src/util/Cast.hxx @@ -84,7 +84,7 @@ ContainerAttributeOffset(const A C::*p) * Cast the given pointer to a struct member to its parent structure. */ template<class C, class A> -#if defined(__clang__) || GCC_CHECK_VERSION(4,7) +#if CLANG_OR_GCC_VERSION(4,7) constexpr #endif static inline C & @@ -97,7 +97,7 @@ ContainerCast(A &a, A C::*member) * Cast the given pointer to a struct member to its parent structure. */ template<class C, class A> -#if defined(__clang__) || GCC_CHECK_VERSION(4,7) +#if CLANG_OR_GCC_VERSION(4,7) constexpr #endif static inline const C & diff --git a/src/util/DivideString.cxx b/src/util/DivideString.cxx new file mode 100644 index 000000000..f781d141f --- /dev/null +++ b/src/util/DivideString.cxx @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "DivideString.hxx" +#include "StringUtil.hxx" + +#include <string.h> + +DivideString::DivideString(const char *s, char separator, bool strip) + :first(nullptr) +{ + const char *x = strchr(s, separator); + if (x == nullptr) + return; + + size_t length = x - s; + second = x + 1; + + if (strip) + second = StripLeft(second); + + if (strip) { + const char *end = s + length; + s = StripLeft(s); + end = StripRight(s, end); + length = end - s; + } + + first = new char[length + 1]; + memcpy(first, s, length); + first[length] = 0; +} diff --git a/src/util/DivideString.hxx b/src/util/DivideString.hxx new file mode 100644 index 000000000..126aa45d1 --- /dev/null +++ b/src/util/DivideString.hxx @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_DIVIDE_STRING_HXX +#define MPD_DIVIDE_STRING_HXX + +#include "Compiler.h" + +#include <assert.h> + +/** + * Split a given constant string at a separator character. Duplicates + * the first part to be able to null-terminate it. + */ +class DivideString { + char *first; + const char *second; + +public: + /** + * @param strip strip the first part and left-strip the second + * part? + */ + DivideString(const char *s, char separator, bool strip=false); + + ~DivideString() { + delete[] first; + } + + /** + * Was the separator found? + */ + bool IsDefined() const { + return first != nullptr; + } + + /** + * Is the first part empty? + */ + bool IsEmpty() const { + assert(IsDefined()); + + return *first == 0; + } + + const char *GetFirst() const { + assert(IsDefined()); + + return first; + } + + const char *GetSecond() const { + assert(IsDefined()); + + return second; + } +}; + +#endif diff --git a/src/util/Error.cxx b/src/util/Error.cxx index 92b2cc5d0..67a1b03fd 100644 --- a/src/util/Error.cxx +++ b/src/util/Error.cxx @@ -32,7 +32,7 @@ #include "Domain.hxx" #ifdef WIN32 -#include <glib.h> +#include <windows.h> #endif #include <errno.h> @@ -135,7 +135,11 @@ Error::FormatErrno(const char *fmt, ...) void Error::SetLastError(DWORD _code, const char *prefix) { - const char *msg = g_win32_error_message(_code); + char msg[256]; + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, _code, 0, msg, sizeof(msg), nullptr); + Format(win32_domain, int(_code), "%s: %s", prefix, msg); } diff --git a/src/util/Manual.hxx b/src/util/Manual.hxx index baab0a555..6ba932bdd 100644 --- a/src/util/Manual.hxx +++ b/src/util/Manual.hxx @@ -35,13 +35,13 @@ #include <new> #include <utility> -#if !defined(__clang__) && __GNUC__ && !GCC_CHECK_VERSION(4,8) +#if GCC_OLDER_THAN(4,8) #include <type_traits> #endif #include <assert.h> -#if defined(__clang__) || GCC_CHECK_VERSION(4,7) +#if CLANG_OR_GCC_VERSION(4,7) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-aliasing" #endif @@ -54,12 +54,7 @@ */ template<class T> class Manual { -#if !defined(__clang__) && __GNUC__ && !GCC_CHECK_VERSION(4,8) - /* no alignas() on gcc < 4.8: apply worst-case fallback */ - __attribute__((aligned(8))) -#else - alignas(T) -#endif + gcc_alignas(T, 8) char data[sizeof(T)]; #ifndef NDEBUG @@ -89,32 +84,46 @@ public: void Destruct() { assert(initialized); - T *t = (T *)data; - t->T::~T(); + T &t = Get(); + t.T::~T(); #ifndef NDEBUG initialized = false; #endif } + T &Get() { + assert(initialized); + + void *p = static_cast<void *>(data); + return *static_cast<T *>(p); + } + + const T &Get() const { + assert(initialized); + + const void *p = static_cast<const void *>(data); + return *static_cast<const T *>(p); + } + operator T &() { - return *(T *)data; + return Get(); } operator const T &() const { - return *(const T *)data; + return Get(); } T *operator->() { - return (T *)data; + return &Get(); } const T *operator->() const { - return (T *)data; + return &Get(); } }; -#if defined(__clang__) || GCC_VERSION >= 40700 +#if CLANG_OR_GCC_VERSION(4,7) #pragma GCC diagnostic pop #endif diff --git a/src/util/SplitString.cxx b/src/util/SplitString.cxx index 75e799279..0bb1e5165 100644 --- a/src/util/SplitString.cxx +++ b/src/util/SplitString.cxx @@ -18,20 +18,42 @@ */ #include "SplitString.hxx" +#include "StringUtil.hxx" #include <string.h> -SplitString::SplitString(const char *s, char separator) - :first(nullptr) +std::forward_list<std::string> +SplitString(const char *s, char separator, bool strip) { - const char *x = strchr(s, separator); - if (x == nullptr) - return; + if (strip) + s = StripLeft(s); - size_t length = x - s; - second = x + 1; + std::forward_list<std::string> list; + if (*s == 0) + return list; - first = new char[length + 1]; - memcpy(first, s, length); - first[length] = 0; + auto i = list.before_begin(); + + while (true) { + const char *next = strchr(s, separator); + if (next == nullptr) + break; + + const char *end = next++; + if (strip) + end = StripRight(s, end); + + i = list.emplace_after(i, s, end); + + s = next; + if (strip) + s = StripLeft(s); + } + + const char *end = s + strlen(s); + if (strip) + end = StripRight(s, end); + + list.emplace_after(i, s, end); + return list; } diff --git a/src/util/SplitString.hxx b/src/util/SplitString.hxx index 96ffb21ec..bc95cff81 100644 --- a/src/util/SplitString.hxx +++ b/src/util/SplitString.hxx @@ -20,52 +20,20 @@ #ifndef MPD_SPLIT_STRING_HXX #define MPD_SPLIT_STRING_HXX -#include "Compiler.h" - -#include <assert.h> +#include <forward_list> +#include <string> /** - * Split a given constant string at a separator character. Duplicates - * the first part to be able to null-terminate it. + * Split a string at a certain separator character into sub strings + * and returns a list of these. + * + * Two consecutive separator characters result in an empty string in + * the list. + * + * An empty input string, as a special case, results in an empty list + * (and not a list with an empty string). */ -class SplitString { - char *first; - const char *second; - -public: - SplitString(const char *s, char separator); - - ~SplitString() { - delete[] first; - } - - /** - * Was the separator found? - */ - bool IsDefined() const { - return first != nullptr; - } - - /** - * Is the first part empty? - */ - bool IsEmpty() const { - assert(IsDefined()); - - return *first == 0; - } - - const char *GetFirst() const { - assert(IsDefined()); - - return first; - } - - const char *GetSecond() const { - assert(IsDefined()); - - return second; - } -}; +std::forward_list<std::string> +SplitString(const char *s, char separator, bool strip=true); #endif diff --git a/src/util/StringUtil.cxx b/src/util/StringUtil.cxx index bcade2b3b..f5b4b7a8b 100644 --- a/src/util/StringUtil.cxx +++ b/src/util/StringUtil.cxx @@ -120,3 +120,23 @@ string_array_contains(const char *const* haystack, const char *needle) return false; } + +void +ToUpperASCII(char *dest, const char *src, size_t size) +{ + assert(dest != nullptr); + assert(src != nullptr); + assert(size > 1); + + char *const end = dest + size - 1; + + do { + char ch = *src++; + if (ch == 0) + break; + + *dest++ = ToUpperASCII(ch); + } while (dest < end); + + *dest = 0; +} diff --git a/src/util/StringUtil.hxx b/src/util/StringUtil.hxx index 9beda5441..77fe1be18 100644 --- a/src/util/StringUtil.hxx +++ b/src/util/StringUtil.hxx @@ -114,4 +114,12 @@ gcc_pure bool string_array_contains(const char *const* haystack, const char *needle); +/** + * Convert the specified ASCII string (0x00..0x7f) to upper case. + * + * @param size the destination buffer size + */ +void +ToUpperASCII(char *dest, const char *src, size_t size); + #endif |