util/Error: new error passing library
Replaces GLib's GError.
This commit is contained in:
46
src/util/Domain.hxx
Normal file
46
src/util/Domain.hxx
Normal 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
114
src/util/Error.cxx
Normal 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
162
src/util/Error.hxx
Normal 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
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user