diff options
Diffstat (limited to 'src/util')
46 files changed, 1643 insertions, 157 deletions
diff --git a/src/util/ASCII.hxx b/src/util/ASCII.hxx index 9f7147338..d9a2198e1 100644 --- a/src/util/ASCII.hxx +++ b/src/util/ASCII.hxx @@ -27,8 +27,8 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MPD_ASCII_HXX -#define MPD_ASCII_HXX +#ifndef ASCII_HXX +#define ASCII_HXX #include "Compiler.h" diff --git a/src/util/Alloc.cxx b/src/util/Alloc.cxx index 006e09701..c2676ca3d 100644 --- a/src/util/Alloc.cxx +++ b/src/util/Alloc.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -75,3 +75,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..9e1007e69 100644 --- a/src/util/Alloc.hxx +++ b/src/util/Alloc.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -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/AllocatedString.cxx b/src/util/AllocatedString.cxx new file mode 100644 index 000000000..486462fa4 --- /dev/null +++ b/src/util/AllocatedString.cxx @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 Max Kellermann <max@duempel.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "AllocatedString.hxx" +#include "StringAPI.hxx" + +template<> +AllocatedString<char> +AllocatedString<char>::Duplicate(const_pointer src) +{ + return Duplicate(src, StringLength(src)); +} diff --git a/src/util/AllocatedString.hxx b/src/util/AllocatedString.hxx new file mode 100644 index 000000000..01eefac8a --- /dev/null +++ b/src/util/AllocatedString.hxx @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2015 Max Kellermann <max@duempel.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ALLOCATED_STRING_HXX +#define ALLOCATED_STRING_HXX + +#include "StringPointer.hxx" + +#include <utility> +#include <algorithm> + +/** + * A string pointer whose memory is managed by this class. + * + * Unlike std::string, this object can hold a "nullptr" special value. + */ +template<typename T=char> +class AllocatedString { +public: + typedef typename StringPointer<T>::value_type value_type; + typedef typename StringPointer<T>::pointer pointer; + typedef typename StringPointer<T>::const_pointer const_pointer; + + static constexpr value_type SENTINEL = '\0'; + +private: + pointer value; + + explicit AllocatedString(pointer _value) + :value(_value) {} + +public: + AllocatedString(std::nullptr_t n):value(n) {} + + AllocatedString(AllocatedString &&src) + :value(src.Steal()) {} + + ~AllocatedString() { + delete[] value; + } + + static AllocatedString Donate(pointer value) { + return AllocatedString(value); + } + + static AllocatedString Null() { + return nullptr; + } + + static AllocatedString Empty() { + auto p = new value_type[1]; + p[0] = SENTINEL; + return Donate(p); + } + + static AllocatedString Duplicate(const_pointer src); + + static AllocatedString Duplicate(const_pointer begin, + const_pointer end) { + auto p = new value_type[end - begin + 1]; + *std::copy(begin, end, p) = SENTINEL; + return Donate(p); + } + + static AllocatedString Duplicate(const_pointer begin, + size_t length) { + auto p = new value_type[length + 1]; + *std::copy_n(begin, length, p) = SENTINEL; + return Donate(p); + } + + AllocatedString &operator=(AllocatedString &&src) { + std::swap(value, src.value); + return *this; + } + + constexpr bool IsNull() const { + return value == nullptr; + } + + constexpr const_pointer c_str() const { + return value; + } + + bool empty() const { + return *value == SENTINEL; + } + + pointer Steal() { + pointer result = value; + value = nullptr; + return result; + } + + AllocatedString Clone() const { + return Duplicate(c_str()); + } +}; + +#endif diff --git a/src/util/ByteReverse.cxx b/src/util/ByteReverse.cxx index 5cc8692a7..c0c2946ca 100644 --- a/src/util/ByteReverse.cxx +++ b/src/util/ByteReverse.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/ByteReverse.hxx b/src/util/ByteReverse.hxx index 0c060c0cb..55d6a64db 100644 --- a/src/util/ByteReverse.hxx +++ b/src/util/ByteReverse.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify 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/CharUtil.hxx b/src/util/CharUtil.hxx index 84a88a94e..efd40896a 100644 --- a/src/util/CharUtil.hxx +++ b/src/util/CharUtil.hxx @@ -128,7 +128,7 @@ ToUpperASCII(char ch) /** * Convert the specified ASCII character (0x00..0x7f) to lower case. - * Unlike toupper(), it ignores the system locale. + * Unlike tolower(), it ignores the system locale. */ constexpr static inline char diff --git a/src/util/ConstBuffer.hxx b/src/util/ConstBuffer.hxx index 4d0a49e98..b98a8b543 100644 --- a/src/util/ConstBuffer.hxx +++ b/src/util/ConstBuffer.hxx @@ -246,6 +246,20 @@ struct ConstBuffer { data += n; size -= n; } + + /** + * Move the front pointer to the given address, and adjust the + * size attribute to retain the old end address. + */ + void MoveFront(pointer_type new_data) { +#ifndef NDEBUG + assert(IsNull() == (new_data == nullptr)); + assert(new_data <= end()); +#endif + + size = end() - new_data; + data = new_data; + } }; #endif diff --git a/src/util/DeleteDisposer.hxx b/src/util/DeleteDisposer.hxx new file mode 100644 index 000000000..dd91e1299 --- /dev/null +++ b/src/util/DeleteDisposer.hxx @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015 Max Kellermann <max@duempel.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DELETE_DISPOSER_HXX +#define DELETE_DISPOSER_HXX + +/** + * A disposer for boost::intrusive that invokes the "delete" operator + * on the given pointer. + */ +struct DeleteDisposer { + template<typename T> + void operator()(T *t) { + delete t; + } +}; + +#endif diff --git a/src/util/DivideString.cxx b/src/util/DivideString.cxx new file mode 100644 index 000000000..8e3d5a1b8 --- /dev/null +++ b/src/util/DivideString.cxx @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2003-2015 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..d98b512a6 --- /dev/null +++ b/src/util/DivideString.hxx @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2003-2015 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/DynamicFifoBuffer.hxx b/src/util/DynamicFifoBuffer.hxx index c1e5d1b94..5a9056edb 100644 --- a/src/util/DynamicFifoBuffer.hxx +++ b/src/util/DynamicFifoBuffer.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 Max Kellermann <max@duempel.org> + * Copyright (C) 2003-2015 Max Kellermann <max@duempel.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,8 +27,8 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FIFO_BUFFER_HPP -#define FIFO_BUFFER_HPP +#ifndef DYNAMIC_FIFO_BUFFER_HXX +#define DYNAMIC_FIFO_BUFFER_HXX #include "ForeignFifoBuffer.hxx" 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/FormatString.cxx b/src/util/FormatString.cxx index d222a505c..5ada067cb 100644 --- a/src/util/FormatString.cxx +++ b/src/util/FormatString.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/FormatString.hxx b/src/util/FormatString.hxx index dc1ac3c67..b0f8dd7f9 100644 --- a/src/util/FormatString.hxx +++ b/src/util/FormatString.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/LazyRandomEngine.cxx b/src/util/LazyRandomEngine.cxx index b0aac913c..abd83da8c 100644 --- a/src/util/LazyRandomEngine.cxx +++ b/src/util/LazyRandomEngine.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/LazyRandomEngine.hxx b/src/util/LazyRandomEngine.hxx index 4156b3bb1..7b9b1c655 100644 --- a/src/util/LazyRandomEngine.hxx +++ b/src/util/LazyRandomEngine.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/Manual.hxx b/src/util/Manual.hxx index 75cffac06..6ba932bdd 100644 --- a/src/util/Manual.hxx +++ b/src/util/Manual.hxx @@ -41,7 +41,7 @@ #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 GCC_OLDER_THAN(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/OptionDef.hxx b/src/util/OptionDef.hxx index dd82154c4..29b7e268b 100644 --- a/src/util/OptionDef.hxx +++ b/src/util/OptionDef.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/OptionParser.cxx b/src/util/OptionParser.cxx index b10008527..45be084c9 100644 --- a/src/util/OptionParser.cxx +++ b/src/util/OptionParser.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/OptionParser.hxx b/src/util/OptionParser.hxx index b9d34adbb..c6c794a7d 100644 --- a/src/util/OptionParser.hxx +++ b/src/util/OptionParser.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/PeakBuffer.cxx b/src/util/PeakBuffer.cxx index e4624bbec..da3b275d8 100644 --- a/src/util/PeakBuffer.cxx +++ b/src/util/PeakBuffer.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/PeakBuffer.hxx b/src/util/PeakBuffer.hxx index 702a3dee0..784b3cdbd 100644 --- a/src/util/PeakBuffer.hxx +++ b/src/util/PeakBuffer.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/RefCount.hxx b/src/util/RefCount.hxx index 02ef8818c..c6cf2e41f 100644 --- a/src/util/RefCount.hxx +++ b/src/util/RefCount.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * Redistribution and use in source and binary forms, with or without diff --git a/src/util/SliceBuffer.hxx b/src/util/SliceBuffer.hxx index 63ca087ae..16c1cf744 100644 --- a/src/util/SliceBuffer.hxx +++ b/src/util/SliceBuffer.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/SplitString.cxx b/src/util/SplitString.cxx index 75e799279..9588312f8 100644 --- a/src/util/SplitString.cxx +++ b/src/util/SplitString.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -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..545470c7a 100644 --- a/src/util/SplitString.hxx +++ b/src/util/SplitString.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -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/StringAPI.hxx b/src/util/StringAPI.hxx new file mode 100644 index 000000000..08087f5f8 --- /dev/null +++ b/src/util/StringAPI.hxx @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2010-2015 Max Kellermann <max@duempel.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STRING_API_HXX +#define STRING_API_HXX + +#include "Compiler.h" + +#include <string.h> + +#ifdef _UNICODE +#include "WStringAPI.hxx" +#endif + +gcc_pure gcc_nonnull_all +static inline size_t +StringLength(const char *p) +{ + return strlen(p); +} + +gcc_pure gcc_nonnull_all +static inline const char * +StringFind(const char *haystack, const char *needle) +{ + return strstr(haystack, needle); +} + +gcc_pure gcc_nonnull_all +static inline char * +StringFind(char *haystack, char needle, size_t size) +{ + return (char *)memchr(haystack, needle, size); +} + +gcc_pure gcc_nonnull_all +static inline const char * +StringFind(const char *haystack, char needle, size_t size) +{ + return (const char *)memchr(haystack, needle, size); +} + +gcc_pure gcc_nonnull_all +static inline const char * +StringFind(const char *haystack, char needle) +{ + return strchr(haystack, needle); +} + +gcc_pure gcc_nonnull_all +static inline char * +StringFind(char *haystack, char needle) +{ + return strchr(haystack, needle); +} + +gcc_pure gcc_nonnull_all +static inline const char * +StringFindLast(const char *haystack, char needle) +{ + return strrchr(haystack, needle); +} + +gcc_pure gcc_nonnull_all +static inline char * +StringFindLast(char *haystack, char needle) +{ + return strrchr(haystack, needle); +} + +gcc_nonnull_all +static inline void +UnsafeCopyString(char *dest, const char *src) +{ + strcpy(dest, src); +} + +gcc_nonnull_all +static inline char * +UnsafeCopyStringP(char *dest, const char *src) +{ +#if defined(WIN32) || defined(__BIONIC__) + /* emulate stpcpy() */ + UnsafeCopyString(dest, src); + return dest + StringLength(dest); +#else + return stpcpy(dest, src); +#endif +} + +/** + * Checks whether #a and #b are equal. + */ +gcc_pure gcc_nonnull_all +static inline bool +StringIsEqual(const char *a, const char *b) +{ + return strcmp(a, b) == 0; +} + +/** + * Checks whether #a and #b are equal. + */ +gcc_pure gcc_nonnull_all +static inline bool +StringIsEqual(const char *a, const char *b, size_t length) +{ + return strncmp(a, b, length) == 0; +} + +/** + * Copy the string to a new allocation. The return value must be + * freed with free(). + */ +gcc_malloc gcc_nonnull_all +static inline char * +DuplicateString(const char *p) +{ + return strdup(p); +} + +#endif diff --git a/src/util/StringPointer.hxx b/src/util/StringPointer.hxx new file mode 100644 index 000000000..4859d8265 --- /dev/null +++ b/src/util/StringPointer.hxx @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2015 Max Kellermann <max@duempel.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STRING_POINTER_HXX +#define STRING_POINTER_HXX + +/** + * Simple OO wrapper for a const string pointer. + */ +template<typename T=char> +class StringPointer { +public: + typedef T value_type; + typedef T *pointer; + typedef const T *const_pointer; + +private: + const_pointer value; + +public: + StringPointer() = default; + constexpr StringPointer(const_pointer _value) + :value(_value) {} + + /** + * Check if this is a "nulled" instance. A "nulled" instance + * must not be used. + */ + constexpr bool IsNull() const { + return value == nullptr; + } + + constexpr const_pointer c_str() const { + return value; + } +}; + +#endif diff --git a/src/util/StringUtil.cxx b/src/util/StringUtil.cxx index bcade2b3b..b9c99eb4a 100644 --- a/src/util/StringUtil.cxx +++ b/src/util/StringUtil.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -18,6 +18,7 @@ */ #include "StringUtil.hxx" +#include "StringAPI.hxx" #include "CharUtil.hxx" #include "ASCII.hxx" @@ -26,6 +27,66 @@ #include <assert.h> #include <string.h> +bool +StringStartsWith(const char *haystack, const char *needle) +{ + const size_t length = strlen(needle); + return memcmp(haystack, needle, length) == 0; +} + +bool +StringEndsWith(const char *haystack, const char *needle) +{ + const size_t haystack_length = strlen(haystack); + const size_t needle_length = strlen(needle); + + return haystack_length >= needle_length && + memcmp(haystack + haystack_length - needle_length, + needle, needle_length) == 0; +} + +const char * +StringAfterPrefix(const char *string, const char *prefix) +{ +#if !CLANG_CHECK_VERSION(3,6) + /* disabled on clang due to -Wtautological-pointer-compare */ + assert(string != nullptr); + assert(prefix != nullptr); +#endif + + size_t prefix_length = strlen(prefix); + return StringIsEqual(string, prefix, prefix_length) + ? string + prefix_length + : nullptr; +} + +const char * +FindStringSuffix(const char *p, const char *suffix) +{ + const size_t p_length = strlen(p); + const size_t suffix_length = strlen(suffix); + + if (p_length < suffix_length) + return nullptr; + + const char *q = p + p_length - suffix_length; + return memcmp(q, suffix, suffix_length) == 0 + ? q + : nullptr; +} + +char * +CopyString(char *gcc_restrict dest, const char *gcc_restrict src, size_t size) +{ + size_t length = strlen(src); + if (length >= size) + length = size - 1; + + char *p = std::copy_n(src, length, dest); + *p = '\0'; + return p; +} + const char * StripLeft(const char *p) { @@ -79,36 +140,6 @@ Strip(char *p) } bool -StringStartsWith(const char *haystack, const char *needle) -{ - const size_t length = strlen(needle); - return memcmp(haystack, needle, length) == 0; -} - -bool -StringEndsWith(const char *haystack, const char *needle) -{ - const size_t haystack_length = strlen(haystack); - const size_t needle_length = strlen(needle); - - return haystack_length >= needle_length && - memcmp(haystack + haystack_length - needle_length, - needle, needle_length) == 0; -} - -char * -CopyString(char *gcc_restrict dest, const char *gcc_restrict src, size_t size) -{ - size_t length = strlen(src); - if (length >= size) - length = size - 1; - - char *p = std::copy(src, src + length, dest); - *p = '\0'; - return p; -} - -bool string_array_contains(const char *const* haystack, const char *needle) { assert(haystack != nullptr); @@ -120,3 +151,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..7e6dc4d61 100644 --- a/src/util/StringUtil.hxx +++ b/src/util/StringUtil.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -24,6 +24,47 @@ #include <stddef.h> +#ifdef _UNICODE +#include "WStringUtil.hxx" +#endif + +gcc_pure +bool +StringStartsWith(const char *haystack, const char *needle); + +gcc_pure +bool +StringEndsWith(const char *haystack, const char *needle); + +/** + * Returns the portion of the string after a prefix. If the string + * does not begin with the specified prefix, this function returns + * nullptr. + */ +gcc_pure gcc_nonnull_all +const char * +StringAfterPrefix(const char *string, const char *prefix); + +/** + * Check if the given string ends with the specified suffix. If yes, + * returns the position of the suffix, and nullptr otherwise. + */ +gcc_pure +const char * +FindStringSuffix(const char *p, const char *suffix); + +/** + * Copy a string. If the buffer is too small, then the string is + * truncated. This is a safer version of strncpy(). + * + * @param size the size of the destination buffer (including the null + * terminator) + * @return a pointer to the null terminator + */ +gcc_nonnull_all +char * +CopyString(char *dest, const char *src, size_t size); + /** * Returns a pointer to the first non-whitespace character in the * string, or to the end of the string. @@ -82,26 +123,6 @@ StripRight(char *p); char * Strip(char *p); -gcc_pure -bool -StringStartsWith(const char *haystack, const char *needle); - -gcc_pure -bool -StringEndsWith(const char *haystack, const char *needle); - -/** - * Copy a string. If the buffer is too small, then the string is - * truncated. This is a safer version of strncpy(). - * - * @param size the size of the destination buffer (including the null - * terminator) - * @return a pointer to the null terminator - */ -gcc_nonnull_all -char * -CopyString(char *dest, const char *src, size_t size); - /** * Checks whether a string array contains the specified string. * @@ -114,4 +135,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 diff --git a/src/util/StringView.cxx b/src/util/StringView.cxx new file mode 100644 index 000000000..904f92f65 --- /dev/null +++ b/src/util/StringView.cxx @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2013-2015 Max Kellermann <max@duempel.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "StringView.hxx" +#include "CharUtil.hxx" + +void +StringView::StripLeft() +{ + while (!IsEmpty() && IsWhitespaceOrNull(front())) + pop_front(); +} + +void +StringView::StripRight() +{ + while (!IsEmpty() && IsWhitespaceOrNull(back())) + pop_back(); +} diff --git a/src/util/StringView.hxx b/src/util/StringView.hxx new file mode 100644 index 000000000..dd6c4dc77 --- /dev/null +++ b/src/util/StringView.hxx @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2013-2015 Max Kellermann <max@duempel.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STRING_VIEW_HXX +#define STRING_VIEW_HXX + +#include "ConstBuffer.hxx" + +#include <string.h> + +struct StringView : ConstBuffer<char> { + StringView() = default; + + constexpr StringView(pointer_type _data, size_type _size) + :ConstBuffer<char>(_data, _size) {} + + constexpr StringView(pointer_type _begin, pointer_type _end) + :ConstBuffer<char>(_begin, _end - _begin) {} + + StringView(pointer_type _data) + :ConstBuffer<char>(_data, + _data != nullptr ? strlen(_data) : 0) {} + + StringView(std::nullptr_t n) + :ConstBuffer<char>(n) {} + + static constexpr StringView Empty() { + return StringView("", size_t(0)); + } + + void SetEmpty() { + data = ""; + size = 0; + } + + gcc_pure + pointer_type Find(char ch) const { + return (pointer_type)memchr(data, ch, size); + } + + StringView &operator=(std::nullptr_t) { + data = nullptr; + size = 0; + return *this; + } + + StringView &operator=(pointer_type _data) { + data = _data; + size = _data != nullptr ? strlen(_data) : 0; + return *this; + } + + gcc_pure + bool StartsWith(StringView needle) const { + return size >= needle.size && + memcmp(data, needle.data, needle.size) == 0; + } + + gcc_pure + bool Equals(StringView other) const { + return size == other.size && + memcmp(data, other.data, size) == 0; + } + + template<size_t n> + bool EqualsLiteral(const char (&other)[n]) const { + return Equals({other, n - 1}); + } + + gcc_pure + bool EqualsIgnoreCase(StringView other) const { + return size == other.size && + strncasecmp(data, other.data, size) == 0; + } + + template<size_t n> + bool EqualsLiteralIgnoreCase(const char (&other)[n]) const { + return EqualsIgnoreCase({other, n - 1}); + } + + /** + * Skip all whitespace at the beginning. + */ + void StripLeft(); + + /** + * Skip all whitespace at the end. + */ + void StripRight(); +}; + +#endif diff --git a/src/util/Tokenizer.hxx b/src/util/Tokenizer.hxx index dc2646589..3f3448d52 100644 --- a/src/util/Tokenizer.hxx +++ b/src/util/Tokenizer.hxx @@ -71,7 +71,7 @@ public: /** * Reads the next unquoted word from the input string. * - * @param error_r if this function returns nullptr and **input_p!=0, it + * @param error if this function returns nullptr and **input_p!=0, it * provides an #Error object in this argument * @return a pointer to the null-terminated word, or nullptr * on error or end of line @@ -83,9 +83,7 @@ public: * escapes the following character. This function modifies the input * string. * - * @param input_p the input string; this function returns a pointer to - * the first non-whitespace character of the following token - * @param error_r if this function returns nullptr and **input_p!=0, it + * @param error if this function returns nullptr and **input_p!=0, it * provides an #Error object in this argument * @return a pointer to the null-terminated string, or nullptr on error * or end of line @@ -97,7 +95,7 @@ public: * input. This is a wrapper for NextUnquoted() and * NextString(). * - * @param error_r if this function returns nullptr and + * @param error if this function returns nullptr and * **input_p!=0, it provides an #Error object in * this argument * @return a pointer to the null-terminated string, or nullptr diff --git a/src/util/UriUtil.cxx b/src/util/UriUtil.cxx index 54d0ded77..0782304e3 100644 --- a/src/util/UriUtil.cxx +++ b/src/util/UriUtil.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/UriUtil.hxx b/src/util/UriUtil.hxx index d478d5b92..e8edfb5a0 100644 --- a/src/util/UriUtil.hxx +++ b/src/util/UriUtil.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/VarSize.hxx b/src/util/VarSize.hxx index 04f1bf580..4da115fba 100644 --- a/src/util/VarSize.hxx +++ b/src/util/VarSize.hxx @@ -42,7 +42,7 @@ * example when you want to store a variable-length string as the last * attribute without the overhead of a second allocation. * - * @param T a struct/class with a variable-size last attribute + * @tparam T a struct/class with a variable-size last attribute * @param declared_tail_size the declared size of the last element in * #T * @param real_tail_size the real required size of the last element in diff --git a/src/util/WStringAPI.hxx b/src/util/WStringAPI.hxx new file mode 100644 index 000000000..e020ecd7f --- /dev/null +++ b/src/util/WStringAPI.hxx @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2010-2015 Max Kellermann <max@duempel.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WSTRING_API_HXX +#define WSTRING_API_HXX + +#include "Compiler.h" + +#include <wchar.h> + +gcc_pure gcc_nonnull_all +static inline size_t +StringLength(const wchar_t *p) +{ + return wcslen(p); +} + +gcc_pure gcc_nonnull_all +static inline const wchar_t * +StringFind(const wchar_t *haystack, const wchar_t *needle) +{ + return wcsstr(haystack, needle); +} + +gcc_pure gcc_nonnull_all +static inline const wchar_t * +StringFind(const wchar_t *haystack, wchar_t needle, size_t size) +{ + return wmemchr(haystack, needle, size); +} + +gcc_pure gcc_nonnull_all +static inline wchar_t * +StringFind(wchar_t *haystack, wchar_t needle, size_t size) +{ + return wmemchr(haystack, needle, size); +} + +gcc_pure gcc_nonnull_all +static inline const wchar_t * +StringFind(const wchar_t *haystack, wchar_t needle) +{ + return wcschr(haystack, needle); +} + +gcc_pure gcc_nonnull_all +static inline wchar_t * +StringFind(wchar_t *haystack, wchar_t needle) +{ + return wcschr(haystack, needle); +} + +gcc_pure gcc_nonnull_all +static inline const wchar_t * +StringFindLast(const wchar_t *haystack, wchar_t needle) +{ + return wcsrchr(haystack, needle); +} + +gcc_pure gcc_nonnull_all +static inline wchar_t * +StringFindLast(wchar_t *haystack, wchar_t needle) +{ + return wcsrchr(haystack, needle); +} + +gcc_nonnull_all +static inline void +UnsafeCopyString(wchar_t *dest, const wchar_t *src) +{ + wcscpy(dest, src); +} + +gcc_nonnull_all +static inline wchar_t * +UnsafeCopyStringP(wchar_t *dest, const wchar_t *src) +{ +#if defined(WIN32) || defined(__BIONIC__) + /* emulate wcpcpy() */ + UnsafeCopyString(dest, src); + return dest + StringLength(dest); +#else + return wcpcpy(dest, src); +#endif +} + +/** + * Checks whether str1 and str2 are equal. + * @param str1 String 1 + * @param str2 String 2 + * @return True if equal, False otherwise + */ +gcc_pure gcc_nonnull_all +static inline bool +StringIsEqual(const wchar_t *str1, const wchar_t *str2) +{ + return wcscmp(str1, str2) == 0; +} + +/** + * Checks whether #a and #b are equal. + */ +gcc_pure gcc_nonnull_all +static inline bool +StringIsEqual(const wchar_t *a, const wchar_t *b, size_t length) +{ + return wcsncmp(a, b, length) == 0; +} + +#ifndef __BIONIC__ + +gcc_malloc gcc_nonnull_all +static inline wchar_t * +DuplicateString(const wchar_t *p) +{ + return wcsdup(p); +} + +#endif + +#endif diff --git a/src/util/WStringUtil.cxx b/src/util/WStringUtil.cxx new file mode 100644 index 000000000..19e4fc68d --- /dev/null +++ b/src/util/WStringUtil.cxx @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2003-2015 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 "WStringUtil.hxx" +#include "WStringAPI.hxx" +#include "ASCII.hxx" + +#include <algorithm> + +#include <assert.h> +#include <string.h> + +bool +StringStartsWith(const wchar_t *haystack, const wchar_t *needle) +{ + return memcmp(haystack, needle, StringLength(needle) * sizeof(needle[0])) == 0; +} + +bool +StringEndsWith(const wchar_t *haystack, const wchar_t *needle) +{ + const size_t haystack_length = StringLength(haystack); + const size_t needle_length = StringLength(needle); + + return haystack_length >= needle_length && + StringIsEqual(haystack + haystack_length - needle_length, needle); +} + +const wchar_t * +StringAfterPrefix(const wchar_t *string, const wchar_t *prefix) +{ +#if !CLANG_CHECK_VERSION(3,6) + /* disabled on clang due to -Wtautological-pointer-compare */ + assert(string != nullptr); + assert(prefix != nullptr); +#endif + + size_t prefix_length = StringLength(prefix); + return StringIsEqual(string, prefix, prefix_length) + ? string + prefix_length + : nullptr; +} + +const wchar_t * +FindStringSuffix(const wchar_t *p, const wchar_t *suffix) +{ + const size_t p_length = StringLength(p); + const size_t suffix_length = StringLength(suffix); + + if (p_length < suffix_length) + return nullptr; + + const auto *q = p + p_length - suffix_length; + return memcmp(q, suffix, suffix_length * sizeof(*suffix)) == 0 + ? q + : nullptr; +} diff --git a/src/util/WStringUtil.hxx b/src/util/WStringUtil.hxx new file mode 100644 index 000000000..3dde0162e --- /dev/null +++ b/src/util/WStringUtil.hxx @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2003-2015 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 WSTRING_UTIL_HXX +#define WSTRING_UTIL_HXX + +#include "Compiler.h" + +#include <wchar.h> + +gcc_pure +bool +StringStartsWith(const wchar_t *haystack, const wchar_t *needle); + +gcc_pure +bool +StringEndsWith(const wchar_t *haystack, const wchar_t *needle); + +/** + * Returns the portion of the string after a prefix. If the string + * does not begin with the specified prefix, this function returns + * nullptr. + */ +gcc_nonnull_all +const wchar_t * +StringAfterPrefix(const wchar_t *string, const wchar_t *prefix); + +/** + * Check if the given string ends with the specified suffix. If yes, + * returns the position of the suffix, and nullptr otherwise. + */ +gcc_pure +const wchar_t * +FindStringSuffix(const wchar_t *p, const wchar_t *suffix); + +#endif diff --git a/src/util/bit_reverse.c b/src/util/bit_reverse.c index 9226c4261..271eee166 100644 --- a/src/util/bit_reverse.c +++ b/src/util/bit_reverse.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/bit_reverse.h b/src/util/bit_reverse.h index b39b02e92..f4d378e61 100644 --- a/src/util/bit_reverse.h +++ b/src/util/bit_reverse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/util/format.c b/src/util/format.c new file mode 100644 index 000000000..66243c8ec --- /dev/null +++ b/src/util/format.c @@ -0,0 +1,259 @@ +/* + * music player command (mpc) + * Copyright (C) 2003-2015 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 "format.h" + +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +/** + * Reallocate the given string and append the source string. + */ +gcc_malloc +static char * +string_append(char *dest, const char *src, size_t len) +{ + size_t destlen = dest != NULL + ? strlen(dest) + : 0; + + dest = realloc(dest, destlen + len + 1); + memcpy(dest + destlen, src, len); + dest[destlen + len] = '\0'; + + return dest; +} + +/** + * Skip the format string until the current group is closed by either + * '&', '|' or ']' (supports nesting). + */ +gcc_pure +static const char * +skip_format(const char *p) +{ + unsigned stack = 0; + + while (*p != '\0') { + if (*p == '[') + stack++; + else if (*p == '#' && p[1] != '\0') + /* skip escaped stuff */ + ++p; + else if (stack > 0) { + if (*p == ']') + --stack; + } else if (*p == '&' || *p == '|' || *p == ']') + break; + + ++p; + } + + return p; +} + +static bool +is_name_char(char ch) +{ + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || ch == '_'; +} + +static char * +format_object2(const char *format, const char **last, const void *object, + const char *(*getter)(const void *object, const char *name)) +{ + char *ret = NULL; + const char *p; + bool found = false; + + for (p = format; *p != '\0';) { + switch (p[0]) { + case '|': + ++p; + if (!found) { + /* nothing found yet: try the next + section */ + free(ret); + ret = NULL; + } else + /* already found a value: skip the + next section */ + p = skip_format(p); + break; + + case '&': + ++p; + if (!found) + /* nothing found yet, so skip this + section */ + p = skip_format(p); + else + /* we found something yet, but it will + only be used if the next section + also found something, so reset the + flag */ + found = false; + break; + + case '[': { + char *t = format_object2(p + 1, &p, object, getter); + if (t != NULL) { + ret = string_append(ret, t, strlen(t)); + free(t); + found = true; + } + } + break; + + case ']': + if (last != NULL) + *last = p + 1; + if (!found) { + free(ret); + ret = NULL; + } + return ret; + + case '\\': { + /* take care of escape sequences */ + char ltemp; + switch (p[1]) { + case 'a': + ltemp = '\a'; + break; + + case 'b': + ltemp = '\b'; + break; + + case 't': + ltemp = '\t'; + break; + + case 'n': + ltemp = '\n'; + break; + + case 'v': + ltemp = '\v'; + break; + + case 'f': + ltemp = '\f'; + break; + + case 'r': + ltemp = '\r'; + break; + + case '[': + case ']': + ltemp = p[1]; + break; + + default: + /* unknown escape: copy the + backslash */ + ltemp = p[0]; + --p; + break; + } + + ret = string_append(ret, <emp, 1); + p += 2; + } + break; + + case '%': { + /* find the extent of this format specifier + (stop at \0, ' ', or esc) */ + const char *end = p + 1; + while (is_name_char(*end)) + ++end; + + const size_t length = end - p + 1; + + if (*end != '%') { + ret = string_append(ret, p, length - 1); + p = end; + continue; + } + + char name[32]; + if (length > (int)sizeof(name)) { + ret = string_append(ret, p, length); + p = end + 1; + continue; + } + + memcpy(name, p + 1, length - 2); + name[length - 2] = 0; + + const char *value = getter(object, name); + size_t value_length; + if (value != NULL) { + if (*value != 0) + found = true; + value_length = strlen(value); + } else { + /* unknown variable: copy verbatim + from format string */ + value = p; + value_length = length; + } + + ret = string_append(ret, value, value_length); + + /* advance past the specifier */ + p = end + 1; + } + break; + + case '#': + /* let the escape character escape itself */ + if (p[1] != '\0') { + ret = string_append(ret, p + 1, 1); + p += 2; + break; + } + + /* fall through */ + + default: + /* pass-through non-escaped portions of the format string */ + ret = string_append(ret, p, 1); + ++p; + } + } + + if (last != NULL) + *last = p; + return ret; +} + +char * +format_object(const char *format, const void *object, + const char *(*getter)(const void *object, const char *name)) +{ + return format_object2(format, NULL, object, getter); +} diff --git a/src/util/format.h b/src/util/format.h new file mode 100644 index 000000000..fa3624b51 --- /dev/null +++ b/src/util/format.h @@ -0,0 +1,51 @@ +/* + * music player command (mpc) + * Copyright (C) 2003-2015 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 MPC_FORMAT_H +#define MPC_FORMAT_H + +#include "Compiler.h" + +struct mpd_song; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Pretty-print an object into a string using the given format + * specification. + * + * @param format the format string + * @param object the object + * @param getter a getter function that extracts a value from the object + * @return the resulting string to be freed by free(); NULL if + * no format string group produced any output + */ +gcc_malloc +char * +format_object(const char *format, const void *object, + const char *(*getter)(const void *object, const char *name)); + +#ifdef __cplusplus +} +#endif + +#endif |