aboutsummaryrefslogtreecommitdiffstats
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/util/Domain.hxx46
-rw-r--r--src/util/Error.cxx114
-rw-r--r--src/util/Error.hxx162
-rw-r--r--src/util/HugeAllocator.cxx87
-rw-r--r--src/util/HugeAllocator.hxx82
-rw-r--r--src/util/LazyRandomEngine.cxx31
-rw-r--r--src/util/LazyRandomEngine.hxx67
-rw-r--r--src/util/Manual.hxx121
-rw-r--r--src/util/PeakBuffer.cxx143
-rw-r--r--src/util/PeakBuffer.hxx66
-rw-r--r--src/util/RefCount.hxx59
-rw-r--r--src/util/ReusableArray.hxx88
-rw-r--r--src/util/SliceBuffer.hxx161
-rw-r--r--src/util/StringUtil.cxx46
-rw-r--r--src/util/StringUtil.hxx58
-rw-r--r--src/util/Tokenizer.cxx193
-rw-r--r--src/util/Tokenizer.hxx99
-rw-r--r--src/util/UriUtil.cxx113
-rw-r--r--src/util/UriUtil.hxx58
-rw-r--r--src/util/bit_reverse.h5
-rw-r--r--src/util/fifo_buffer.c218
-rw-r--r--src/util/fifo_buffer.h164
-rw-r--r--src/util/growing_fifo.c (renamed from src/growing_fifo.c)0
-rw-r--r--src/util/growing_fifo.h (renamed from src/growing_fifo.h)0
-rw-r--r--src/util/list.h53
-rw-r--r--src/utils.c121
-rw-r--r--src/utils.h38
27 files changed, 2205 insertions, 188 deletions
diff --git a/src/util/Domain.hxx b/src/util/Domain.hxx
new file mode 100644
index 000000000..bbdbf8371
--- /dev/null
+++ b/src/util/Domain.hxx
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2003-2013 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_DOMAIN_HXX
+#define MPD_DOMAIN_HXX
+
+class Domain {
+ const char *const name;
+
+public:
+ constexpr explicit Domain(const char *_name)
+ :name(_name) {}
+
+ Domain(const Domain &) = delete;
+ Domain &operator=(const Domain &) = delete;
+
+ constexpr const char *GetName() const {
+ return name;
+ }
+
+ bool operator==(const Domain &other) const {
+ return this == &other;
+ }
+
+ bool operator!=(const Domain &other) const {
+ return !(*this == other);
+ }
+};
+
+#endif
diff --git a/src/util/Error.cxx b/src/util/Error.cxx
new file mode 100644
index 000000000..1e6bd9cff
--- /dev/null
+++ b/src/util/Error.cxx
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2003-2013 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 "config.h"
+#include "Error.hxx"
+#include "Domain.hxx"
+
+#include <glib.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+const Domain errno_domain("errno");
+
+Error::~Error() {}
+
+void
+Error::Set(const Domain &_domain, int _code, const char *_message)
+{
+ domain = &_domain;
+ code = _code;
+ message.assign(_message);
+}
+
+void
+Error::Format2(const Domain &_domain, int _code, const char *fmt, ...)
+{
+ char buffer[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ Set(_domain, _code, buffer);
+}
+
+void
+Error::FormatPrefix(const char *fmt, ...)
+{
+ char buffer[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ AddPrefix(buffer);
+}
+
+void
+Error::SetErrno(int e)
+{
+ Set(errno_domain, e, g_strerror(e));
+}
+
+void
+Error::SetErrno()
+{
+ SetErrno(errno);
+}
+
+void
+Error::SetErrno(int e, const char *prefix)
+{
+ Format(errno_domain, e, "%s: %s", prefix, g_strerror(e));
+}
+
+void
+Error::SetErrno(const char *prefix)
+{
+ SetErrno(errno, prefix);
+}
+
+void
+Error::FormatErrno(int e, const char *fmt, ...)
+{
+ char buffer[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ SetErrno(e, buffer);
+}
+
+void
+Error::FormatErrno(const char *fmt, ...)
+{
+ const int e = errno;
+
+ char buffer[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ SetErrno(e, buffer);
+}
diff --git a/src/util/Error.hxx b/src/util/Error.hxx
new file mode 100644
index 000000000..1fcf46061
--- /dev/null
+++ b/src/util/Error.hxx
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2003-2013 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_ERROR_HXX
+#define MPD_ERROR_HXX
+
+#include "check.h"
+#include "gcc.h"
+
+#include <string>
+
+#include <assert.h>
+
+class Domain;
+
+extern const Domain errno_domain;
+
+#ifdef WIN32
+/* fuck WIN32! */
+#include <windows.h>
+#define IgnoreError MPDIgnoreError
+#undef GetMessage
+#endif
+
+/**
+ * This class contains information about a runtime error.
+ */
+class Error {
+ const Domain *domain;
+ int code;
+ std::string message;
+
+public:
+ Error():domain(nullptr), code(0) {}
+
+ Error(const Domain &_domain, int _code, const char *_message)
+ :domain(&_domain), code(_code), message(_message) {}
+
+ Error(const Domain &_domain, const char *_message)
+ :domain(&_domain), code(0), message(_message) {}
+
+ Error(Error &&other)
+ :domain(other.domain), code(other.code),
+ message(std::move(other.message)) {}
+
+ ~Error();
+
+ Error(const Error &) = delete;
+ Error &operator=(const Error &) = delete;
+
+ Error &operator=(Error &&other) {
+ domain = other.domain;
+ code = other.code;
+ std::swap(message, other.message);
+ return *this;
+ }
+
+ bool IsDefined() const {
+ return domain != nullptr;
+ }
+
+ void Clear() {
+ domain = nullptr;
+ }
+
+ const Domain &GetDomain() const {
+ assert(IsDefined());
+
+ return *domain;
+ }
+
+ bool IsDomain(const Domain &other) const {
+ return domain == &other;
+ }
+
+ int GetCode() const {
+ assert(IsDefined());
+
+ return code;
+ }
+
+ const char *GetMessage() const {
+ assert(IsDefined());
+
+ return message.c_str();
+ }
+
+ void Set(const Error &other) {
+ assert(!IsDefined());
+ assert(other.IsDefined());
+
+ domain = other.domain;
+ code = other.code;
+ message = other.message;
+ }
+
+ void Set(const Domain &_domain, int _code, const char *_message);
+
+ void Set(const Domain &_domain, const char *_message) {
+ Set(_domain, 0, _message);
+ }
+
+private:
+ void Format2(const Domain &_domain, int _code, const char *fmt, ...);
+
+public:
+ template<typename... Args>
+ void Format(const Domain &_domain, int _code,
+ const char *fmt, Args&&... args) {
+ Format2(_domain, _code, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ void Format(const Domain &_domain, const char *fmt, Args&&... args) {
+ Format2(_domain, 0, fmt, std::forward<Args>(args)...);
+ }
+
+ void AddPrefix(const char *prefix) {
+ message.insert(0, prefix);
+ }
+
+ void FormatPrefix(const char *fmt, ...);
+
+ void SetErrno(int e);
+ void SetErrno();
+ void SetErrno(int e, const char *prefix);
+ void SetErrno(const char *prefix);
+ void FormatErrno(const char *prefix, ...);
+ void FormatErrno(int e, const char *prefix, ...);
+};
+
+/**
+ * Pass a temporary instance of this class to ignore errors.
+ */
+class IgnoreError final {
+ Error error;
+
+public:
+ operator Error &() {
+ assert(!error.IsDefined());
+
+ return error;
+ }
+};
+
+#endif
diff --git a/src/util/HugeAllocator.cxx b/src/util/HugeAllocator.cxx
new file mode 100644
index 000000000..d1c55c965
--- /dev/null
+++ b/src/util/HugeAllocator.cxx
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2003-2013 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 "HugeAllocator.hxx"
+
+#ifdef __linux__
+#include <sys/mman.h>
+#include <unistd.h>
+#else
+#include <stdlib.h>
+#endif
+
+#ifdef __linux__
+
+/**
+ * Round up the parameter, make it page-aligned.
+ */
+gcc_const
+static size_t
+AlignToPageSize(size_t size)
+{
+ static const long page_size = sysconf(_SC_PAGESIZE);
+ if (page_size > 0)
+ return size;
+
+ size_t ps(page_size);
+ return (size + ps - 1) / ps * ps;
+}
+
+void *
+HugeAllocate(size_t size)
+{
+ size = AlignToPageSize(size);
+
+ constexpr int flags = MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE;
+ void *p = mmap(nullptr, size,
+ PROT_READ|PROT_WRITE, flags,
+ -1, 0);
+ if (p == (void *)-1)
+ return nullptr;
+
+#ifdef MADV_HUGEPAGE
+ /* allow the Linux kernel to use "Huge Pages", which reduces page
+ table overhead for this big chunk of data */
+ madvise(p, size, MADV_HUGEPAGE);
+#endif
+
+#ifdef MADV_DONTFORK
+ /* just in case MPD needs to fork, don't copy this allocation
+ to the child process, to reduce overhead */
+ madvise(p, size, MADV_DONTFORK);
+#endif
+
+ return p;
+}
+
+void
+HugeFree(void *p, size_t size)
+{
+ munmap(p, AlignToPageSize(size));
+}
+
+void
+HugeDiscard(void *p, size_t size)
+{
+#ifdef MADV_DONTNEED
+ madvise(p, AlignToPageSize(size), MADV_DONTNEED);
+#endif
+}
+
+#endif
diff --git a/src/util/HugeAllocator.hxx b/src/util/HugeAllocator.hxx
new file mode 100644
index 000000000..01c92cd43
--- /dev/null
+++ b/src/util/HugeAllocator.hxx
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2003-2013 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_HUGE_ALLOCATOR_HXX
+#define MPD_HUGE_ALLOCATOR_HXX
+
+#include "gcc.h"
+
+#include <stddef.h>
+
+#ifdef __linux__
+
+/**
+ * Allocate a huge amount of memory. This will be done in a way that
+ * allows giving the memory back to the kernel as soon as we don't
+ * need it anymore. On the downside, this call is expensive.
+ */
+gcc_malloc
+void *
+HugeAllocate(size_t size);
+
+/**
+ * @param p an allocation returned by HugeAllocate()
+ * @param size the allocation's size as passed to HugeAllocate()
+ */
+void
+HugeFree(void *p, size_t size);
+
+/**
+ * Discard any data stored in the allocation and give the memory back
+ * to the kernel. After returning, the allocation still exists and
+ * can be reused at any time, but its contents are undefined.
+ *
+ * @param p an allocation returned by HugeAllocate()
+ * @param size the allocation's size as passed to HugeAllocate()
+ */
+void
+HugeDiscard(void *p, size_t size);
+
+#else
+
+/* not Linux: fall back to standard C calls */
+
+#include <stdlib.h>
+
+gcc_malloc
+static inline void *
+HugeAllocate(size_t size)
+{
+ return malloc(size);
+}
+
+static inline void
+HugeFree(void *p, size_t)
+{
+ free(p);
+}
+
+static inline void
+HugeDiscard(void *, size_t)
+{
+}
+
+#endif
+
+#endif
diff --git a/src/util/LazyRandomEngine.cxx b/src/util/LazyRandomEngine.cxx
new file mode 100644
index 000000000..0f90ebb2e
--- /dev/null
+++ b/src/util/LazyRandomEngine.cxx
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2003-2013 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 "config.h"
+#include "LazyRandomEngine.hxx"
+
+void
+LazyRandomEngine::AutoCreate()
+{
+ if (engine != nullptr)
+ return;
+
+ std::random_device rd;
+ engine = new std::mt19937(rd());
+}
diff --git a/src/util/LazyRandomEngine.hxx b/src/util/LazyRandomEngine.hxx
new file mode 100644
index 000000000..8afe1d1c0
--- /dev/null
+++ b/src/util/LazyRandomEngine.hxx
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2003-2013 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_LAZY_RANDOM_ENGINE_HXX
+#define MPD_LAZY_RANDOM_ENGINE_HXX
+
+#include "check.h"
+
+#include <random>
+
+#include <assert.h>
+
+/**
+ * A random engine that will be created and seeded on demand.
+ */
+class LazyRandomEngine {
+ std::mt19937 *engine;
+
+public:
+ typedef std::mt19937::result_type result_type;
+
+ LazyRandomEngine():engine(nullptr) {}
+ ~LazyRandomEngine() {
+ delete engine;
+ }
+
+ LazyRandomEngine(const LazyRandomEngine &other) = delete;
+ LazyRandomEngine &operator=(const LazyRandomEngine &other) = delete;
+
+ /**
+ * Create and seed the real engine. Call this before any
+ * other method.
+ */
+ void AutoCreate();
+
+ result_type min() const {
+ return engine->min();
+ }
+
+ result_type max() const {
+ return engine->max();
+ }
+
+ result_type operator()() {
+ assert(engine != nullptr);
+
+ return engine->operator()();
+ }
+};
+
+#endif
diff --git a/src/util/Manual.hxx b/src/util/Manual.hxx
new file mode 100644
index 000000000..802695224
--- /dev/null
+++ b/src/util/Manual.hxx
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2013 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 MPD_MANUAL_HXX
+#define MPD_MANUAL_HXX
+
+#include "gcc.h"
+
+#include <new>
+#include <utility>
+
+#if !defined(__clang__) && __GNUC__ && !GCC_CHECK_VERSION(4,8)
+#include <type_traits>
+#endif
+
+#include <assert.h>
+
+#if defined(__clang__) || GCC_CHECK_VERSION(4,7)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif
+
+/**
+ * Container for an object that gets constructed and destructed
+ * manually. The object is constructed in-place, and therefore
+ * without allocation overhead. It can be constructed and destructed
+ * repeatedly.
+ */
+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
+ char data[sizeof(T)];
+
+#ifndef NDEBUG
+ bool initialized;
+#endif
+
+public:
+#ifndef NDEBUG
+ Manual():initialized(false) {}
+ ~Manual() {
+ assert(!initialized);
+ }
+#endif
+
+ template<typename... Args>
+ void Construct(Args&&... args) {
+ assert(!initialized);
+
+ void *p = data;
+ new(p) T(std::forward<Args>(args)...);
+
+#ifndef NDEBUG
+ initialized = true;
+#endif
+ }
+
+ void Destruct() {
+ assert(initialized);
+
+ T *t = (T *)data;
+ t->T::~T();
+
+#ifndef NDEBUG
+ initialized = false;
+#endif
+ }
+
+ operator T &() {
+ return *(T *)data;
+ }
+
+ operator const T &() const {
+ return *(const T *)data;
+ }
+
+ T *operator->() {
+ return (T *)data;
+ }
+
+ const T *operator->() const {
+ return (T *)data;
+ }
+};
+
+#if defined(__clang__) || GCC_VERSION >= 40700
+#pragma GCC diagnostic pop
+#endif
+
+#endif
diff --git a/src/util/PeakBuffer.cxx b/src/util/PeakBuffer.cxx
new file mode 100644
index 000000000..a3659b8f4
--- /dev/null
+++ b/src/util/PeakBuffer.cxx
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2003-2013 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 "PeakBuffer.hxx"
+#include "HugeAllocator.hxx"
+#include "fifo_buffer.h"
+
+#include <algorithm>
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+PeakBuffer::~PeakBuffer()
+{
+ if (normal_buffer != nullptr)
+ fifo_buffer_free(normal_buffer);
+
+ if (peak_buffer != nullptr)
+ HugeFree(peak_buffer, peak_size);
+}
+
+bool
+PeakBuffer::IsEmpty() const
+{
+ return (normal_buffer == nullptr ||
+ fifo_buffer_is_empty(normal_buffer)) &&
+ (peak_buffer == nullptr ||
+ fifo_buffer_is_empty(peak_buffer));
+}
+
+const void *
+PeakBuffer::Read(size_t *length_r) const
+{
+ if (normal_buffer != nullptr) {
+ const void *p = fifo_buffer_read(normal_buffer, length_r);
+ if (p != nullptr)
+ return p;
+ }
+
+ if (peak_buffer != nullptr) {
+ const void *p = fifo_buffer_read(peak_buffer, length_r);
+ if (p != nullptr)
+ return p;
+ }
+
+ return nullptr;
+}
+
+void
+PeakBuffer::Consume(size_t length)
+{
+ if (normal_buffer != nullptr && !fifo_buffer_is_empty(normal_buffer)) {
+ fifo_buffer_consume(normal_buffer, length);
+ return;
+ }
+
+ if (peak_buffer != nullptr && !fifo_buffer_is_empty(peak_buffer)) {
+ fifo_buffer_consume(peak_buffer, length);
+ if (fifo_buffer_is_empty(peak_buffer)) {
+ HugeFree(peak_buffer, peak_size);
+ peak_buffer = nullptr;
+ }
+
+ return;
+ }
+}
+
+static size_t
+AppendTo(fifo_buffer *buffer, const void *data, size_t length)
+{
+ assert(data != nullptr);
+ assert(length > 0);
+
+ size_t total = 0;
+
+ do {
+ size_t max_length;
+ void *p = fifo_buffer_write(buffer, &max_length);
+ if (p == nullptr)
+ break;
+
+ const size_t nbytes = std::min(length, max_length);
+ memcpy(p, data, nbytes);
+ fifo_buffer_append(buffer, nbytes);
+
+ data = (const uint8_t *)data + nbytes;
+ length -= nbytes;
+ total += nbytes;
+ } while (length > 0);
+
+ return total;
+}
+
+bool
+PeakBuffer::Append(const void *data, size_t length)
+{
+ if (length == 0)
+ return true;
+
+ if (peak_buffer != nullptr && !fifo_buffer_is_empty(peak_buffer)) {
+ size_t nbytes = AppendTo(peak_buffer, data, length);
+ return nbytes == length;
+ }
+
+ if (normal_buffer == nullptr)
+ normal_buffer = fifo_buffer_new(normal_size);
+
+ size_t nbytes = AppendTo(normal_buffer, data, length);
+ if (nbytes > 0) {
+ data = (const uint8_t *)data + nbytes;
+ length -= nbytes;
+ if (length == 0)
+ return true;
+ }
+
+ if (peak_buffer == nullptr && peak_size > 0) {
+ peak_buffer = (fifo_buffer *)HugeAllocate(peak_size);
+ if (peak_buffer == nullptr)
+ return false;
+
+ fifo_buffer_init(peak_buffer, peak_size);
+ }
+
+ nbytes = AppendTo(peak_buffer, data, length);
+ return nbytes == length;
+}
diff --git a/src/util/PeakBuffer.hxx b/src/util/PeakBuffer.hxx
new file mode 100644
index 000000000..0fbba8d77
--- /dev/null
+++ b/src/util/PeakBuffer.hxx
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2003-2013 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_PEAK_BUFFER_HXX
+#define MPD_PEAK_BUFFER_HXX
+
+#include "gcc.h"
+
+#include <stddef.h>
+
+struct fifo_buffer;
+
+/**
+ * A FIFO-like buffer that will allocate more memory on demand to
+ * allow large peaks. This second buffer will be given back to the
+ * kernel when it has been consumed.
+ */
+class PeakBuffer {
+ size_t normal_size, peak_size;
+
+ fifo_buffer *normal_buffer, *peak_buffer;
+
+public:
+ PeakBuffer(size_t _normal_size, size_t _peak_size)
+ :normal_size(_normal_size), peak_size(_peak_size),
+ normal_buffer(nullptr), peak_buffer(nullptr) {}
+
+ PeakBuffer(PeakBuffer &&other)
+ :normal_size(other.normal_size), peak_size(other.peak_size),
+ normal_buffer(other.normal_buffer),
+ peak_buffer(other.peak_buffer) {
+ other.normal_buffer = nullptr;
+ other.peak_buffer = nullptr;
+ }
+
+ ~PeakBuffer();
+
+ PeakBuffer(const PeakBuffer &) = delete;
+ PeakBuffer &operator=(const PeakBuffer &) = delete;
+
+ gcc_pure
+ bool IsEmpty() const;
+
+ const void *Read(size_t *length_r) const;
+ void Consume(size_t length);
+
+ bool Append(const void *data, size_t length);
+};
+
+#endif
diff --git a/src/util/RefCount.hxx b/src/util/RefCount.hxx
new file mode 100644
index 000000000..9a45a585b
--- /dev/null
+++ b/src/util/RefCount.hxx
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.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.
+ */
+
+/** \file
+ *
+ * A very simple reference counting library.
+ */
+
+#ifndef MPD_REFCOUNT_HXX
+#define MPD_REFCOUNT_HXX
+
+#include <atomic>
+
+class RefCount {
+ std::atomic_uint n;
+
+public:
+ constexpr RefCount():n(1) {}
+
+ void Increment() {
+ ++n;
+ }
+
+ /**
+ * @return true if the number of references has been dropped to 0
+ */
+ bool Decrement() {
+ return --n == 0;
+ }
+};
+
+#endif
diff --git a/src/util/ReusableArray.hxx b/src/util/ReusableArray.hxx
new file mode 100644
index 000000000..30b1a9cd9
--- /dev/null
+++ b/src/util/ReusableArray.hxx
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2013 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 REUSABLE_ARRAY_HXX
+#define REUSABLE_ARRAY_HXX
+
+#include <stddef.h>
+
+#include "gcc.h"
+
+/**
+ * Manager for a temporary array which grows as needed. This attempts
+ * to reduce the number of consecutive heap allocations and
+ * deallocations.
+ *
+ * @param T the array element type
+ * @param M always allocate multiples of this number; must be a power of 2
+ */
+template<typename T, size_t M=1>
+class ReusableArray {
+ T *buffer;
+ size_t capacity;
+
+public:
+ ReusableArray():buffer(nullptr), capacity(0) {}
+
+ ReusableArray(const ReusableArray &other) = delete;
+ ReusableArray &operator=(const ReusableArray &other) = delete;
+
+ ~ReusableArray() {
+ delete[] buffer;
+ }
+
+ /**
+ * Free resources allocated by this object. This invalidates
+ * the buffer returned by Get().
+ */
+ void Clear() {
+ delete[] buffer;
+ buffer = nullptr;
+ capacity = 0;
+ }
+
+ /**
+ * Get the buffer, and guarantee a minimum size. This buffer
+ * becomes invalid with the next Get() call.
+ */
+ gcc_malloc
+ T *Get(size_t size) {
+ if (gcc_unlikely(size > capacity)) {
+ /* too small: grow */
+ delete[] buffer;
+
+ capacity = ((size - 1) | (M - 1)) + 1;
+ buffer = new T[capacity];
+ }
+
+ return buffer;
+ }
+};
+
+#endif
diff --git a/src/util/SliceBuffer.hxx b/src/util/SliceBuffer.hxx
new file mode 100644
index 000000000..c61f164f4
--- /dev/null
+++ b/src/util/SliceBuffer.hxx
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2003-2013 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_SLICE_BUFFER_HXX
+#define MPD_SLICE_BUFFER_HXX
+
+#include "HugeAllocator.hxx"
+#include "gcc.h"
+
+#include <utility>
+#include <new>
+
+#include <assert.h>
+#include <stddef.h>
+
+/**
+ * This class pre-allocates a certain number of objects, and allows
+ * callers to allocate and free these objects ("slices").
+ */
+template<typename T>
+class SliceBuffer {
+ union Slice {
+ Slice *next;
+
+ T value;
+ };
+
+ /**
+ * The maximum number of slices in this container.
+ */
+ const unsigned n_max;
+
+ /**
+ * The number of slices that are initialized. This is used to
+ * avoid page faulting on the new allocation, so the kernel
+ * does not need to reserve physical memory pages.
+ */
+ unsigned n_initialized;
+
+ /**
+ * The number of slices currently allocated.
+ */
+ unsigned n_allocated;
+
+ Slice *const data;
+
+ /**
+ * Pointer to the first free element in the chain.
+ */
+ Slice *available;
+
+ size_t CalcAllocationSize() const {
+ return n_max * sizeof(Slice);
+ }
+
+public:
+ SliceBuffer(unsigned _count)
+ :n_max(_count), n_initialized(0), n_allocated(0),
+ data((Slice *)HugeAllocate(CalcAllocationSize())),
+ available(nullptr) {
+ assert(n_max > 0);
+ }
+
+ ~SliceBuffer() {
+ /* all slices must be freed explicitly, and this
+ assertion checks for leaks */
+ assert(n_allocated == 0);
+
+ HugeFree(data, CalcAllocationSize());
+ }
+
+ SliceBuffer(const SliceBuffer &other) = delete;
+ SliceBuffer &operator=(const SliceBuffer &other) = delete;
+
+ /**
+ * @return true if buffer allocation (by the constructor) has failed
+ */
+ bool IsOOM() {
+ return data == nullptr;
+ }
+
+ unsigned GetCapacity() const {
+ return n_max;
+ }
+
+ bool IsEmpty() const {
+ return n_allocated == 0;
+ }
+
+ bool IsFull() const {
+ return n_allocated == n_max;
+ }
+
+ template<typename... Args>
+ T *Allocate(Args&&... args) {
+ assert(n_initialized <= n_max);
+ assert(n_allocated <= n_initialized);
+
+ if (available == nullptr) {
+ if (n_initialized == n_max) {
+ /* out of (internal) memory, buffer is full */
+ assert(n_allocated == n_max);
+ return nullptr;
+ }
+
+ available = &data[n_initialized++];
+ available->next = nullptr;
+ }
+
+ /* allocate a slice */
+ T *value = &available->value;
+ available = available->next;
+ ++n_allocated;
+
+ /* construct the object */
+ return ::new((void *)value) T(std::forward<Args>(args)...);
+ }
+
+ void Free(T *value) {
+ assert(n_initialized <= n_max);
+ assert(n_allocated > 0);
+ assert(n_allocated <= n_initialized);
+
+ Slice *slice = reinterpret_cast<Slice *>(value);
+ assert(slice >= data && slice < data + n_max);
+
+ /* destruct the object */
+ value->~T();
+
+ /* insert the slice in the "available" linked list */
+ slice->next = available;
+ available = slice;
+ --n_allocated;
+
+ /* give memory back to the kernel when the last slice
+ was freed */
+ if (n_allocated == 0) {
+ HugeDiscard(data, CalcAllocationSize());
+ n_initialized = 0;
+ available = nullptr;
+ }
+ }
+};
+
+#endif
diff --git a/src/util/StringUtil.cxx b/src/util/StringUtil.cxx
new file mode 100644
index 000000000..87d032735
--- /dev/null
+++ b/src/util/StringUtil.cxx
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2003-2013 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 "StringUtil.hxx"
+
+#include <glib.h>
+
+#include <assert.h>
+
+const char *
+strchug_fast_c(const char *p)
+{
+ while (*p != 0 && g_ascii_isspace(*p))
+ ++p;
+
+ return p;
+}
+
+bool
+string_array_contains(const char *const* haystack, const char *needle)
+{
+ assert(haystack != nullptr);
+ assert(needle != nullptr);
+
+ for (; *haystack != nullptr; ++haystack)
+ if (g_ascii_strcasecmp(*haystack, needle) == 0)
+ return true;
+
+ return false;
+}
diff --git a/src/util/StringUtil.hxx b/src/util/StringUtil.hxx
new file mode 100644
index 000000000..6eeca893d
--- /dev/null
+++ b/src/util/StringUtil.hxx
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2003-2013 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_STRING_UTIL_HXX
+#define MPD_STRING_UTIL_HXX
+
+#include "gcc.h"
+
+/**
+ * Returns a pointer to the first non-whitespace character in the
+ * string, or to the end of the string.
+ *
+ * This is a faster version of g_strchug(), because it does not move
+ * data.
+ */
+gcc_pure
+const char *
+strchug_fast_c(const char *p);
+
+/**
+ * Same as strchug_fast_c(), but works with a writable pointer.
+ */
+gcc_pure
+static inline char *
+strchug_fast(char *p)
+{
+ return const_cast<char *>(strchug_fast_c(p));
+}
+
+/**
+ * Checks whether a string array contains the specified string.
+ *
+ * @param haystack a NULL terminated list of strings
+ * @param needle the string to search for; the comparison is
+ * case-insensitive for ASCII characters
+ * @return true if found
+ */
+gcc_pure
+bool
+string_array_contains(const char *const* haystack, const char *needle);
+
+#endif
diff --git a/src/util/Tokenizer.cxx b/src/util/Tokenizer.cxx
new file mode 100644
index 000000000..726da0dd6
--- /dev/null
+++ b/src/util/Tokenizer.cxx
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2003-2013 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 "config.h"
+#include "Tokenizer.hxx"
+#include "StringUtil.hxx"
+#include "Error.hxx"
+#include "Domain.hxx"
+
+#include <glib.h>
+
+#include <assert.h>
+#include <string.h>
+
+static constexpr Domain tokenizer_domain("tokenizer");
+
+static inline bool
+valid_word_first_char(char ch)
+{
+ return g_ascii_isalpha(ch);
+}
+
+static inline bool
+valid_word_char(char ch)
+{
+ return g_ascii_isalnum(ch) || ch == '_';
+}
+
+char *
+Tokenizer::NextWord(Error &error)
+{
+ char *const word = input;
+
+ if (*input == 0)
+ return nullptr;
+
+ /* check the first character */
+
+ if (!valid_word_first_char(*input)) {
+ error.Set(tokenizer_domain, "Letter expected");
+ return nullptr;
+ }
+
+ /* now iterate over the other characters until we find a
+ whitespace or end-of-string */
+
+ while (*++input != 0) {
+ if (g_ascii_isspace(*input)) {
+ /* a whitespace: the word ends here */
+ *input = 0;
+ /* skip all following spaces, too */
+ input = strchug_fast(input + 1);
+ break;
+ }
+
+ if (!valid_word_char(*input)) {
+ error.Set(tokenizer_domain, "Invalid word character");
+ return nullptr;
+ }
+ }
+
+ /* end of string: the string is already null-terminated
+ here */
+
+ return word;
+}
+
+static inline bool
+valid_unquoted_char(char ch)
+{
+ return (unsigned char)ch > 0x20 && ch != '"' && ch != '\'';
+}
+
+char *
+Tokenizer::NextUnquoted(Error &error)
+{
+ char *const word = input;
+
+ if (*input == 0)
+ return nullptr;
+
+ /* check the first character */
+
+ if (!valid_unquoted_char(*input)) {
+ error.Set(tokenizer_domain, "Invalid unquoted character");
+ return nullptr;
+ }
+
+ /* now iterate over the other characters until we find a
+ whitespace or end-of-string */
+
+ while (*++input != 0) {
+ if (g_ascii_isspace(*input)) {
+ /* a whitespace: the word ends here */
+ *input = 0;
+ /* skip all following spaces, too */
+ input = strchug_fast(input + 1);
+ break;
+ }
+
+ if (!valid_unquoted_char(*input)) {
+ error.Set(tokenizer_domain,
+ "Invalid unquoted character");
+ return nullptr;
+ }
+ }
+
+ /* end of string: the string is already null-terminated
+ here */
+
+ return word;
+}
+
+char *
+Tokenizer::NextString(Error &error)
+{
+ char *const word = input, *dest = input;
+
+ if (*input == 0)
+ /* end of line */
+ return nullptr;
+
+ /* check for the opening " */
+
+ if (*input != '"') {
+ error.Set(tokenizer_domain, "'\"' expected");
+ return nullptr;
+ }
+
+ ++input;
+
+ /* copy all characters */
+
+ while (*input != '"') {
+ if (*input == '\\')
+ /* the backslash escapes the following
+ character */
+ ++input;
+
+ if (*input == 0) {
+ /* return input-1 so the caller can see the
+ difference between "end of line" and
+ "error" */
+ --input;
+ error.Set(tokenizer_domain, "Missing closing '\"'");
+ return nullptr;
+ }
+
+ /* copy one character */
+ *dest++ = *input++;
+ }
+
+ /* the following character must be a whitespace (or end of
+ line) */
+
+ ++input;
+ if (*input != 0 && !g_ascii_isspace(*input)) {
+ error.Set(tokenizer_domain,
+ "Space expected after closing '\"'");
+ return nullptr;
+ }
+
+ /* finish the string and return it */
+
+ *dest = 0;
+ input = strchug_fast(input);
+ return word;
+}
+
+char *
+Tokenizer::NextParam(Error &error)
+{
+ if (*input == '"')
+ return NextString(error);
+ else
+ return NextUnquoted(error);
+}
diff --git a/src/util/Tokenizer.hxx b/src/util/Tokenizer.hxx
new file mode 100644
index 000000000..a689dc31d
--- /dev/null
+++ b/src/util/Tokenizer.hxx
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2003-2013 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_TOKENIZER_HXX
+#define MPD_TOKENIZER_HXX
+
+class Error;
+
+class Tokenizer {
+ char *input;
+
+public:
+ /**
+ * @param _input the input string; the contents will be
+ * modified by this class
+ */
+ constexpr Tokenizer(char *_input):input(_input) {}
+
+ Tokenizer(const Tokenizer &) = delete;
+ Tokenizer &operator=(const Tokenizer &) = delete;
+
+ char *Rest() {
+ return input;
+ }
+
+ char CurrentChar() const {
+ return *input;
+ }
+
+ bool IsEnd() const {
+ return CurrentChar() == 0;
+ }
+
+ /**
+ * Reads the next word.
+ *
+ * @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
+ */
+ char *NextWord(Error &error);
+
+ /**
+ * Reads the next unquoted word from the input string.
+ *
+ * @param error_r 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
+ */
+ char *NextUnquoted(Error &error);
+
+ /**
+ * Reads the next quoted string from the input string. A backslash
+ * 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
+ * provides an #Error object in this argument
+ * @return a pointer to the null-terminated string, or nullptr on error
+ * or end of line
+ */
+ char *NextString(Error &error);
+
+ /**
+ * Reads the next unquoted word or quoted string from the
+ * input. This is a wrapper for NextUnquoted() and
+ * NextString().
+ *
+ * @param error_r 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
+ */
+ char *NextParam(Error &error);
+};
+
+#endif
diff --git a/src/util/UriUtil.cxx b/src/util/UriUtil.cxx
new file mode 100644
index 000000000..4b0cec11b
--- /dev/null
+++ b/src/util/UriUtil.cxx
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2003-2013 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 "UriUtil.hxx"
+
+#include <glib.h>
+
+#include <assert.h>
+#include <string.h>
+
+bool uri_has_scheme(const char *uri)
+{
+ return strstr(uri, "://") != nullptr;
+}
+
+/* suffixes should be ascii only characters */
+const char *
+uri_get_suffix(const char *uri)
+{
+ const char *suffix = strrchr(uri, '.');
+ if (suffix == nullptr)
+ return nullptr;
+
+ ++suffix;
+
+ if (strpbrk(suffix, "/\\") != nullptr)
+ return nullptr;
+
+ return suffix;
+}
+
+static const char *
+verify_uri_segment(const char *p)
+{
+ const char *q;
+
+ unsigned dots = 0;
+ while (*p == '.') {
+ ++p;
+ ++dots;
+ }
+
+ if (dots <= 2 && (*p == 0 || *p == '/'))
+ return nullptr;
+
+ q = strchr(p + 1, '/');
+ return q != nullptr ? q : "";
+}
+
+bool
+uri_safe_local(const char *uri)
+{
+ while (true) {
+ uri = verify_uri_segment(uri);
+ if (uri == nullptr)
+ return false;
+
+ if (*uri == 0)
+ return true;
+
+ assert(*uri == '/');
+
+ ++uri;
+ }
+}
+
+char *
+uri_remove_auth(const char *uri)
+{
+ const char *auth, *slash, *at;
+ char *p;
+
+ if (strncmp(uri, "http://", 7) == 0)
+ auth = uri + 7;
+ else if (strncmp(uri, "https://", 8) == 0)
+ auth = uri + 8;
+ else
+ /* unrecognized URI */
+ return nullptr;
+
+ slash = strchr(auth, '/');
+ if (slash == nullptr)
+ slash = auth + strlen(auth);
+
+ at = (const char *)memchr(auth, '@', slash - auth);
+ if (at == nullptr)
+ /* no auth info present, do nothing */
+ return nullptr;
+
+ /* duplicate the full URI and then delete the auth
+ information */
+ p = g_strdup(uri);
+ memmove(p + (auth - uri), p + (at + 1 - uri),
+ strlen(at));
+
+ return p;
+}
diff --git a/src/util/UriUtil.hxx b/src/util/UriUtil.hxx
new file mode 100644
index 000000000..1d288ca1d
--- /dev/null
+++ b/src/util/UriUtil.hxx
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2003-2013 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_URI_UTIL_HXX
+#define MPD_URI_UTIL_HXX
+
+#include "gcc.h"
+
+/**
+ * Checks whether the specified URI has a scheme in the form
+ * "scheme://".
+ */
+gcc_pure
+bool uri_has_scheme(const char *uri);
+
+gcc_pure
+const char *
+uri_get_suffix(const char *uri);
+
+/**
+ * Returns true if this is a safe "local" URI:
+ *
+ * - non-empty
+ * - does not begin or end with a slash
+ * - no double slashes
+ * - no path component begins with a dot
+ */
+gcc_pure
+bool
+uri_safe_local(const char *uri);
+
+/**
+ * Removes HTTP username and password from the URI. This may be
+ * useful for displaying an URI without disclosing secrets. Returns
+ * NULL if nothing needs to be removed, or if the URI is not
+ * recognized.
+ */
+gcc_malloc
+char *
+uri_remove_auth(const char *uri);
+
+#endif
diff --git a/src/util/bit_reverse.h b/src/util/bit_reverse.h
index e44693b1d..54cb789bb 100644
--- a/src/util/bit_reverse.h
+++ b/src/util/bit_reverse.h
@@ -20,12 +20,13 @@
#ifndef MPD_BIT_REVERSE_H
#define MPD_BIT_REVERSE_H
-#include <glib.h>
+#include "gcc.h"
+
#include <stdint.h>
extern const uint8_t bit_reverse_table[256];
-G_GNUC_CONST
+gcc_const
static inline uint8_t
bit_reverse(uint8_t x)
{
diff --git a/src/util/fifo_buffer.c b/src/util/fifo_buffer.c
new file mode 100644
index 000000000..162ddf946
--- /dev/null
+++ b/src/util/fifo_buffer.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.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 "config.h"
+#include "fifo_buffer.h"
+
+#include <glib.h>
+
+#include <assert.h>
+#include <string.h>
+
+struct fifo_buffer {
+ size_t size, start, end;
+ unsigned char buffer[sizeof(size_t)];
+};
+
+struct fifo_buffer *
+fifo_buffer_new(size_t size)
+{
+ struct fifo_buffer *buffer;
+
+ assert(size > 0);
+
+ buffer = (struct fifo_buffer *)g_malloc(sizeof(*buffer) -
+ sizeof(buffer->buffer) + size);
+
+ buffer->size = size;
+ buffer->start = 0;
+ buffer->end = 0;
+
+ return buffer;
+}
+
+void
+fifo_buffer_init(struct fifo_buffer *buffer, size_t size)
+{
+ buffer->size = size - (sizeof(*buffer) - sizeof(buffer->buffer));
+ buffer->start = 0;
+ buffer->end = 0;
+}
+
+static void
+fifo_buffer_move(struct fifo_buffer *buffer);
+
+struct fifo_buffer *
+fifo_buffer_realloc(struct fifo_buffer *buffer, size_t new_size)
+{
+ if (buffer == NULL)
+ return new_size > 0
+ ? fifo_buffer_new(new_size)
+ : NULL;
+
+ /* existing data must fit in new size */
+ assert(new_size >= buffer->end - buffer->start);
+
+ if (new_size == 0) {
+ fifo_buffer_free(buffer);
+ return NULL;
+ }
+
+ /* compress the buffer when we're shrinking and the tail of
+ the buffer would exceed the new size */
+ if (buffer->end > new_size)
+ fifo_buffer_move(buffer);
+
+ /* existing data must fit in new size: second check */
+ assert(buffer->end <= new_size);
+
+ buffer = g_realloc(buffer, sizeof(*buffer) - sizeof(buffer->buffer) +
+ new_size);
+ buffer->size = new_size;
+ return buffer;
+}
+
+void
+fifo_buffer_free(struct fifo_buffer *buffer)
+{
+ assert(buffer != NULL);
+
+ g_free(buffer);
+}
+
+size_t
+fifo_buffer_capacity(const struct fifo_buffer *buffer)
+{
+ assert(buffer != NULL);
+
+ return buffer->size;
+}
+
+size_t
+fifo_buffer_available(const struct fifo_buffer *buffer)
+{
+ assert(buffer != NULL);
+
+ return buffer->end - buffer->start;
+}
+
+void
+fifo_buffer_clear(struct fifo_buffer *buffer)
+{
+ assert(buffer != NULL);
+
+ buffer->start = 0;
+ buffer->end = 0;
+}
+
+const void *
+fifo_buffer_read(const struct fifo_buffer *buffer, size_t *length_r)
+{
+ assert(buffer != NULL);
+ assert(buffer->end >= buffer->start);
+ assert(length_r != NULL);
+
+ if (buffer->start == buffer->end)
+ /* the buffer is empty */
+ return NULL;
+
+ *length_r = buffer->end - buffer->start;
+ return buffer->buffer + buffer->start;
+}
+
+void
+fifo_buffer_consume(struct fifo_buffer *buffer, size_t length)
+{
+ assert(buffer != NULL);
+ assert(buffer->end >= buffer->start);
+ assert(buffer->start + length <= buffer->end);
+
+ buffer->start += length;
+}
+
+/**
+ * Move data to the beginning of the buffer, to make room at the end.
+ */
+static void
+fifo_buffer_move(struct fifo_buffer *buffer)
+{
+ if (buffer->start == 0)
+ return;
+
+ if (buffer->end > buffer->start)
+ memmove(buffer->buffer,
+ buffer->buffer + buffer->start,
+ buffer->end - buffer->start);
+
+ buffer->end -= buffer->start;
+ buffer->start = 0;
+}
+
+void *
+fifo_buffer_write(struct fifo_buffer *buffer, size_t *max_length_r)
+{
+ assert(buffer != NULL);
+ assert(buffer->end <= buffer->size);
+ assert(max_length_r != NULL);
+
+ if (buffer->end == buffer->size) {
+ fifo_buffer_move(buffer);
+ if (buffer->end == buffer->size)
+ return NULL;
+ } else if (buffer->start > 0 && buffer->start == buffer->end) {
+ buffer->start = 0;
+ buffer->end = 0;
+ }
+
+ *max_length_r = buffer->size - buffer->end;
+ return buffer->buffer + buffer->end;
+}
+
+void
+fifo_buffer_append(struct fifo_buffer *buffer, size_t length)
+{
+ assert(buffer != NULL);
+ assert(buffer->end >= buffer->start);
+ assert(buffer->end + length <= buffer->size);
+
+ buffer->end += length;
+}
+
+bool
+fifo_buffer_is_empty(struct fifo_buffer *buffer)
+{
+ return buffer->start == buffer->end;
+}
+
+bool
+fifo_buffer_is_full(struct fifo_buffer *buffer)
+{
+ return buffer->start == 0 && buffer->end == buffer->size;
+}
diff --git a/src/util/fifo_buffer.h b/src/util/fifo_buffer.h
new file mode 100644
index 000000000..ccea97d86
--- /dev/null
+++ b/src/util/fifo_buffer.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.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.
+ */
+
+/** \file
+ *
+ * This is a general purpose FIFO buffer library. You may append data
+ * at the end, while another instance reads data from the beginning.
+ * It is optimized for zero-copy usage: you get pointers to the real
+ * buffer, where you may operate on.
+ *
+ * This library is not thread safe.
+ */
+
+#ifndef MPD_FIFO_BUFFER_H
+#define MPD_FIFO_BUFFER_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+struct fifo_buffer;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Creates a new #fifo_buffer object. Free this object with
+ * fifo_buffer_free().
+ *
+ * @param size the size of the buffer in bytes
+ * @return the new #fifo_buffer object
+ */
+struct fifo_buffer *
+fifo_buffer_new(size_t size);
+
+void
+fifo_buffer_init(struct fifo_buffer *buffer, size_t size);
+
+/**
+ * Change the capacity of the #fifo_buffer, while preserving existing
+ * data.
+ *
+ * @param buffer the old buffer, may be NULL
+ * @param new_size the requested new size of the #fifo_buffer; must
+ * not be smaller than the data which is stored in the old buffer
+ * @return the new buffer, may be NULL if the requested new size is 0
+ */
+struct fifo_buffer *
+fifo_buffer_realloc(struct fifo_buffer *buffer, size_t new_size);
+
+/**
+ * Frees the resources consumed by this #fifo_buffer object.
+ */
+void
+fifo_buffer_free(struct fifo_buffer *buffer);
+
+/**
+ * Return the capacity of the buffer, i.e. the size that was passed to
+ * fifo_buffer_new().
+ */
+size_t
+fifo_buffer_capacity(const struct fifo_buffer *buffer);
+
+/**
+ * Return the number of bytes currently stored in the buffer.
+ */
+size_t
+fifo_buffer_available(const struct fifo_buffer *buffer);
+
+/**
+ * Clears all data currently in this #fifo_buffer object. This does
+ * not overwrite the actuall buffer; it just resets the internal
+ * pointers.
+ */
+void
+fifo_buffer_clear(struct fifo_buffer *buffer);
+
+/**
+ * Reads from the beginning of the buffer. To remove consumed data
+ * from the buffer, call fifo_buffer_consume().
+ *
+ * @param buffer the #fifo_buffer object
+ * @param length_r the maximum amount to read is returned here
+ * @return a pointer to the beginning of the buffer, or NULL if the
+ * buffer is empty
+ */
+const void *
+fifo_buffer_read(const struct fifo_buffer *buffer, size_t *length_r);
+
+/**
+ * Marks data at the beginning of the buffer as "consumed".
+ *
+ * @param buffer the #fifo_buffer object
+ * @param length the number of bytes which were consumed
+ */
+void
+fifo_buffer_consume(struct fifo_buffer *buffer, size_t length);
+
+/**
+ * Prepares writing to the buffer. This returns a buffer which you
+ * can write to. To commit the write operation, call
+ * fifo_buffer_append().
+ *
+ * @param buffer the #fifo_buffer object
+ * @param max_length_r the maximum amount to write is returned here
+ * @return a pointer to the end of the buffer, or NULL if the buffer
+ * is already full
+ */
+void *
+fifo_buffer_write(struct fifo_buffer *buffer, size_t *max_length_r);
+
+/**
+ * Commits the write operation initiated by fifo_buffer_write().
+ *
+ * @param buffer the #fifo_buffer object
+ * @param length the number of bytes which were written
+ */
+void
+fifo_buffer_append(struct fifo_buffer *buffer, size_t length);
+
+/**
+ * Checks if the buffer is empty.
+ */
+bool
+fifo_buffer_is_empty(struct fifo_buffer *buffer);
+
+/**
+ * Checks if the buffer is full.
+ */
+bool
+fifo_buffer_is_full(struct fifo_buffer *buffer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/growing_fifo.c b/src/util/growing_fifo.c
index 88431f60e..88431f60e 100644
--- a/src/growing_fifo.c
+++ b/src/util/growing_fifo.c
diff --git a/src/growing_fifo.h b/src/util/growing_fifo.h
index 723c3b3ff..723c3b3ff 100644
--- a/src/growing_fifo.h
+++ b/src/util/growing_fifo.h
diff --git a/src/util/list.h b/src/util/list.h
index fdab47675..73d99befa 100644
--- a/src/util/list.h
+++ b/src/util/list.h
@@ -25,8 +25,6 @@
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
-#include <glib.h>
-
#ifdef __clang__
/* allow typeof() */
#pragma GCC diagnostic ignored "-Wlanguage-extension-token"
@@ -40,15 +38,15 @@
*
*/
#define container_of(ptr, type, member) \
- (&G_STRUCT_MEMBER(type, ptr, -G_STRUCT_OFFSET(type, member)))
+ ((type *)((uint8_t *)ptr - offsetof(type, member)))
/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/
-#define LIST_POISON1 ((void *) 0x00100100)
-#define LIST_POISON2 ((void *) 0x00200200)
+#define LIST_POISON1 ((struct list_head *)(void *) 0x00100100)
+#define LIST_POISON2 ((struct list_head *)(void *) 0x00200200)
/*
* Simple doubly linked list implementation.
@@ -82,46 +80,47 @@ static inline void INIT_LIST_HEAD(struct list_head *list)
* the prev/next entries already!
*/
#ifndef CONFIG_DEBUG_LIST
-static inline void __list_add(struct list_head *new,
+static inline void __list_add(struct list_head *new_item,
struct list_head *prev,
struct list_head *next)
{
- next->prev = new;
- new->next = next;
- new->prev = prev;
- prev->next = new;
+ next->prev = new_item;
+ new_item->next = next;
+ new_item->prev = prev;
+ prev->next = new_item;
}
#else
-extern void __list_add(struct list_head *new,
- struct list_head *prev,
- struct list_head *next);
+extern void __list_add(struct list_head *new_item,
+ struct list_head *prev,
+ struct list_head *next);
#endif
/**
* list_add - add a new entry
- * @new: new entry to be added
+ * @new_item: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
-static inline void list_add(struct list_head *new, struct list_head *head)
+static inline void list_add(struct list_head *new_item, struct list_head *head)
{
- __list_add(new, head, head->next);
+ __list_add(new_item, head, head->next);
}
/**
* list_add_tail - add a new entry
- * @new: new entry to be added
+ * @new_item: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
-static inline void list_add_tail(struct list_head *new, struct list_head *head)
+static inline void
+list_add_tail(struct list_head *new_item, struct list_head *head)
{
- __list_add(new, head->prev, head);
+ __list_add(new_item, head->prev, head);
}
/*
@@ -163,23 +162,23 @@ extern void list_del(struct list_head *entry);
/**
* list_replace - replace old entry by new one
* @old : the element to be replaced
- * @new : the new element to insert
+ * @new_item : the new element to insert
*
* If @old was empty, it will be overwritten.
*/
static inline void list_replace(struct list_head *old,
- struct list_head *new)
+ struct list_head *new_item)
{
- new->next = old->next;
- new->next->prev = new;
- new->prev = old->prev;
- new->prev->next = new;
+ new_item->next = old->next;
+ new_item->next->prev = new_item;
+ new_item->prev = old->prev;
+ new_item->prev->next = new_item;
}
static inline void list_replace_init(struct list_head *old,
- struct list_head *new)
+ struct list_head *new_item)
{
- list_replace(old, new);
+ list_replace(old, new_item);
INIT_LIST_HEAD(old);
}
diff --git a/src/utils.c b/src/utils.c
deleted file mode 100644
index a2de3212e..000000000
--- a/src/utils.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2003-2011 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 "config.h"
-#include "utils.h"
-#include "glib_compat.h"
-#include "conf.h"
-
-#include <glib.h>
-
-#include <assert.h>
-#include <string.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#ifndef WIN32
-#include <pwd.h>
-#endif
-
-#if HAVE_IPV6 && WIN32
-#include <winsock2.h>
-#endif
-
-#if HAVE_IPV6 && ! WIN32
-#include <sys/socket.h>
-#endif
-
-#ifdef WIN32
-#include <windows.h>
-#endif
-
-G_GNUC_CONST
-static inline GQuark
-parse_path_quark(void)
-{
- return g_quark_from_static_string("path");
-}
-
-char *
-parsePath(const char *path, G_GNUC_UNUSED GError **error_r)
-{
- assert(path != NULL);
- assert(error_r == NULL || *error_r == NULL);
-
-#ifndef WIN32
- if (!g_path_is_absolute(path) && path[0] != '~') {
- g_set_error(error_r, parse_path_quark(), 0,
- "not an absolute path: %s", path);
- return NULL;
- } else if (path[0] == '~') {
- const char *home;
-
- if (path[1] == '/' || path[1] == '\0') {
- const char *user = config_get_string(CONF_USER, NULL);
- if (user != NULL) {
- struct passwd *passwd = getpwnam(user);
- if (!passwd) {
- g_set_error(error_r, parse_path_quark(), 0,
- "no such user: %s", user);
- return NULL;
- }
-
- home = passwd->pw_dir;
- } else {
- home = g_get_home_dir();
- if (home == NULL) {
- g_set_error_literal(error_r, parse_path_quark(), 0,
- "problems getting home "
- "for current user");
- return NULL;
- }
- }
-
- ++path;
- } else {
- ++path;
-
- const char *slash = strchr(path, '/');
- char *user = slash != NULL
- ? g_strndup(path, slash - path)
- : g_strdup(path);
-
- struct passwd *passwd = getpwnam(user);
- if (!passwd) {
- g_set_error(error_r, parse_path_quark(), 0,
- "no such user: %s", user);
- g_free(user);
- return NULL;
- }
-
- g_free(user);
-
- home = passwd->pw_dir;
- path = slash;
- }
-
- return g_strconcat(home, path, NULL);
- } else {
-#endif
- return g_strdup(path);
-#ifndef WIN32
- }
-#endif
-}
diff --git a/src/utils.h b/src/utils.h
deleted file mode 100644
index f8d6657f2..000000000
--- a/src/utils.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2003-2011 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_UTILS_H
-#define MPD_UTILS_H
-
-#include <glib.h>
-#include <stdbool.h>
-
-#ifndef assert_static
-/* Compile time assertion developed by Ralf Holly */
-/* http://pera-software.com/articles/compile-time-assertions.pdf */
-#define assert_static(e) \
- do { \
- enum { assert_static__ = 1/(e) }; \
- } while (0)
-#endif /* !assert_static */
-
-char *
-parsePath(const char *path, GError **error_r);
-
-#endif