aboutsummaryrefslogtreecommitdiffstats
path: root/src/util
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2013-08-10 18:02:44 +0200
committerMax Kellermann <max@duempel.org>2013-09-04 18:14:22 +0200
commit29030b54c98b0aee65fbc10ebf7ba36bed98c02c (patch)
tree79766830b55ebca38ddbce84d8d548227eedb69e /src/util
parentc9fcc7f14860777458153eb2d13c773ccfa1daa2 (diff)
downloadmpd-29030b54c98b0aee65fbc10ebf7ba36bed98c02c.tar.gz
mpd-29030b54c98b0aee65fbc10ebf7ba36bed98c02c.tar.xz
mpd-29030b54c98b0aee65fbc10ebf7ba36bed98c02c.zip
util/Error: new error passing library
Replaces GLib's GError.
Diffstat (limited to 'src/util')
-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/Tokenizer.cxx44
-rw-r--r--src/util/Tokenizer.hxx20
5 files changed, 350 insertions, 36 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/Tokenizer.cxx b/src/util/Tokenizer.cxx
index 0bb6edd71..726da0dd6 100644
--- a/src/util/Tokenizer.cxx
+++ b/src/util/Tokenizer.cxx
@@ -20,18 +20,15 @@
#include "config.h"
#include "Tokenizer.hxx"
#include "StringUtil.hxx"
+#include "Error.hxx"
+#include "Domain.hxx"
#include <glib.h>
#include <assert.h>
#include <string.h>
-gcc_const
-static GQuark
-tokenizer_quark(void)
-{
- return g_quark_from_static_string("tokenizer");
-}
+static constexpr Domain tokenizer_domain("tokenizer");
static inline bool
valid_word_first_char(char ch)
@@ -46,7 +43,7 @@ valid_word_char(char ch)
}
char *
-Tokenizer::NextWord(GError **error_r)
+Tokenizer::NextWord(Error &error)
{
char *const word = input;
@@ -56,8 +53,7 @@ Tokenizer::NextWord(GError **error_r)
/* check the first character */
if (!valid_word_first_char(*input)) {
- g_set_error(error_r, tokenizer_quark(), 0,
- "Letter expected");
+ error.Set(tokenizer_domain, "Letter expected");
return nullptr;
}
@@ -74,8 +70,7 @@ Tokenizer::NextWord(GError **error_r)
}
if (!valid_word_char(*input)) {
- g_set_error(error_r, tokenizer_quark(), 0,
- "Invalid word character");
+ error.Set(tokenizer_domain, "Invalid word character");
return nullptr;
}
}
@@ -93,7 +88,7 @@ valid_unquoted_char(char ch)
}
char *
-Tokenizer::NextUnquoted(GError **error_r)
+Tokenizer::NextUnquoted(Error &error)
{
char *const word = input;
@@ -103,8 +98,7 @@ Tokenizer::NextUnquoted(GError **error_r)
/* check the first character */
if (!valid_unquoted_char(*input)) {
- g_set_error(error_r, tokenizer_quark(), 0,
- "Invalid unquoted character");
+ error.Set(tokenizer_domain, "Invalid unquoted character");
return nullptr;
}
@@ -121,8 +115,8 @@ Tokenizer::NextUnquoted(GError **error_r)
}
if (!valid_unquoted_char(*input)) {
- g_set_error(error_r, tokenizer_quark(), 0,
- "Invalid unquoted character");
+ error.Set(tokenizer_domain,
+ "Invalid unquoted character");
return nullptr;
}
}
@@ -134,7 +128,7 @@ Tokenizer::NextUnquoted(GError **error_r)
}
char *
-Tokenizer::NextString(GError **error_r)
+Tokenizer::NextString(Error &error)
{
char *const word = input, *dest = input;
@@ -145,8 +139,7 @@ Tokenizer::NextString(GError **error_r)
/* check for the opening " */
if (*input != '"') {
- g_set_error(error_r, tokenizer_quark(), 0,
- "'\"' expected");
+ error.Set(tokenizer_domain, "'\"' expected");
return nullptr;
}
@@ -165,8 +158,7 @@ Tokenizer::NextString(GError **error_r)
difference between "end of line" and
"error" */
--input;
- g_set_error(error_r, tokenizer_quark(), 0,
- "Missing closing '\"'");
+ error.Set(tokenizer_domain, "Missing closing '\"'");
return nullptr;
}
@@ -179,8 +171,8 @@ Tokenizer::NextString(GError **error_r)
++input;
if (*input != 0 && !g_ascii_isspace(*input)) {
- g_set_error(error_r, tokenizer_quark(), 0,
- "Space expected after closing '\"'");
+ error.Set(tokenizer_domain,
+ "Space expected after closing '\"'");
return nullptr;
}
@@ -192,10 +184,10 @@ Tokenizer::NextString(GError **error_r)
}
char *
-Tokenizer::NextParam(GError **error_r)
+Tokenizer::NextParam(Error &error)
{
if (*input == '"')
- return NextString(error_r);
+ return NextString(error);
else
- return NextUnquoted(error_r);
+ return NextUnquoted(error);
}
diff --git a/src/util/Tokenizer.hxx b/src/util/Tokenizer.hxx
index da45348d4..a689dc31d 100644
--- a/src/util/Tokenizer.hxx
+++ b/src/util/Tokenizer.hxx
@@ -20,7 +20,7 @@
#ifndef MPD_TOKENIZER_HXX
#define MPD_TOKENIZER_HXX
-#include "gerror.h"
+class Error;
class Tokenizer {
char *input;
@@ -50,23 +50,23 @@ public:
/**
* Reads the next word.
*
- * @param error_r if this function returns nullptr and
- * **input_p!=0, it optionally provides a GError object in
+ * @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(GError **error_r);
+ 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
- * optionally provides a GError object in this argument
+ * 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(GError **error_r);
+ char *NextUnquoted(Error &error);
/**
* Reads the next quoted string from the input string. A backslash
@@ -76,11 +76,11 @@ public:
* @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
- * optionally provides a GError object in this argument
+ * 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(GError **error_r);
+ char *NextString(Error &error);
/**
* Reads the next unquoted word or quoted string from the
@@ -88,12 +88,12 @@ public:
* NextString().
*
* @param error_r if this function returns nullptr and
- * **input_p!=0, it optionally provides a GError object in
+ * **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(GError **error_r);
+ char *NextParam(Error &error);
};
#endif