util/Error: new error passing library

Replaces GLib's GError.
This commit is contained in:
Max Kellermann
2013-08-10 18:02:44 +02:00
parent c9fcc7f148
commit 29030b54c9
256 changed files with 3269 additions and 3371 deletions

46
src/util/Domain.hxx Normal file
View File

@@ -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

114
src/util/Error.cxx Normal file
View File

@@ -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);
}

162
src/util/Error.hxx Normal file
View File

@@ -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

View File

@@ -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);
}

View File

@@ -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