From 625fb277caa05918288cafa6f3912cfdc59699ea Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Mon, 25 Jul 2016 19:06:31 -0700 Subject: [PATCH] Add root exception + basic utilities. --- include/ircd/exception.h | 127 +++++++++++++++++++++++++++++++++++++++ include/ircd/ircd.h | 12 ++-- include/ircd/util.h | 65 ++++++++++++++++++++ ircd/Makefile.am | 1 + ircd/exception.cc | 48 +++++++++++++++ ircd/fs.cc | 2 + 6 files changed, 251 insertions(+), 4 deletions(-) create mode 100644 include/ircd/exception.h create mode 100644 include/ircd/util.h create mode 100644 ircd/exception.cc diff --git a/include/ircd/exception.h b/include/ircd/exception.h new file mode 100644 index 000000000..6ddfe9ea4 --- /dev/null +++ b/include/ircd/exception.h @@ -0,0 +1,127 @@ +/* + * charybdis: 21st Century IRCd + * exception.h: Exception root + * + * Copyright (C) 2016 Charybdis Development Team + * Copyright (C) 2016 Jason Volk + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + */ + +#pragma once +#define HAVE_IRCD_EXCEPTION_H + +#include "stdinc.h" +#include "util.h" + +#ifdef __cplusplus +namespace ircd { + + +IRCD_OVERLOAD(pass_name) + +/** The root exception type. + * + * All exceptions in the project inherit from this type. + * To catch any exception from a project developer's code: + * catch(const ircd::exception &) {} + * + * Remember: not all exceptions are from project developer's code, + * such as std::out_of_range. In most contexts if you have to deal with this + * someone else was lazy, which is bad. To be sure and catch any exception: + * catch(const std::exception &) {} + * + * Remember: not all exceptions have to inherit from std::exception, but + * those are rogue exceptions. We do not allow this. To be sure nothing + * can possibly get through, add to the bottom: + * catch(...) {} + * + * Note: Prefer 'noexcept' instead of catch(...), noexcept is like an 'assert' + * for exceptions, and the rogue can be found-out in testing. + */ +struct exception +:std::exception +{ + char buf[1024]; + + const char *what() const noexcept override { return buf; } + + exception(const pass_name_t, const char *const &name = "exception", const char *fmt = " ", ...) noexcept AFP(4, 5); +}; + + +// Disambiguates the constructors in the macro below. + +/** Exception generator convenience macro + * + * If you want to create your own exception type, you have found the right + * place! This macro allows creating an exception in the the hierarchy. + * + * To create an exception, invoke this macro in your header. Examples: + * + * IRCD_EXCEPTION(ircd::exception, my_exception) + * IRCD_EXCEPTION(my_exception, my_specific_exception) + * + * Then your catch sequence can look like the following: + * + * catch(const my_specific_exception &e) + * { + * log("something specifically bad happened: %s", e.what()); + * } + * catch(const my_exception &e) + * { + * log("something generically bad happened: %s", e.what()); + * } + * catch(const ircd::exception &e) + * { + * log("unrelated bad happened: %s", e.what()); + * } + * catch(const std::exception &e) + * { + * log("unhandled bad happened: %s", e.what()); + * } + * + * Remember: the order of the catch blocks is important. + */ +#define IRCD_EXCEPTION(parent, name) \ +struct name \ +:parent \ +{ \ + template \ + name(const pass_name_t &, A&&... a): \ + parent { pass_name, std::forward(a)... } {} \ + \ + template \ + name(A&&... a): \ + parent { pass_name, #name, std::forward(a)... } {} \ +}; + + +/** Generic base exceptions. + * List your own exception somewhere else (unless you're overhauling libircd). + * + * These are useful for random places and spare you the effort of having to + * redefine them. You can also inherit from these if appropriate. + */ +IRCD_EXCEPTION(exception, error) // throw ircd::error("something bad") +IRCD_EXCEPTION(error, not_found) // throw ircd::not_found("looks like a 404") +IRCD_EXCEPTION(error, access_denied) // throw ircd::access_denied("you didn't say the magic word") + + +} // namespace ircd +#endif // __cplusplus diff --git a/include/ircd/ircd.h b/include/ircd/ircd.h index cf79287a0..2ba05c01d 100644 --- a/include/ircd/ircd.h +++ b/include/ircd/ircd.h @@ -22,10 +22,14 @@ * USA */ -#ifndef _IRCD_H -#define _IRCD_H +#pragma once +#define HAVE_IRCD_H -#include "defaults.h" +#include "stdinc.h" +#include "util.h" +#include "exception.h" + +#ifdef __cplusplus struct Client; @@ -104,4 +108,4 @@ extern int maxconnections; void ircd_shutdown(const char *reason) __attribute__((noreturn)); -#endif // _IRCD_H +#endif // __cplusplus diff --git a/include/ircd/util.h b/include/ircd/util.h new file mode 100644 index 000000000..d81aa558f --- /dev/null +++ b/include/ircd/util.h @@ -0,0 +1,65 @@ +/* + * charybdis: 21st Century IRC++d + * util.h: Miscellaneous utilities + * + * Copyright (C) 2016 Charybdis Development Team + * Copyright (C) 2016 Jason Volk + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + */ + +#pragma once +#define HAVE_IRCD_UTIL_H + +#ifdef __cplusplus +namespace ircd { +inline namespace util { + + +#define IRCD_EXPCAT(a, b) a ## b +#define IRCD_CONCAT(a, b) IRCD_EXPCAT(a, b) +#define IRCD_UNIQUE(a) IRCD_CONCAT(a, __COUNTER__) + + +#define IRCD_OVERLOAD(NAME) \ + struct NAME##_t {}; \ + static constexpr NAME##_t NAME {}; + + +#define IRCD_STRONG_TYPEDEF(TYPE, NAME) \ +struct NAME \ +{ \ + TYPE val; \ + \ + operator const TYPE &() const { return val; } \ + operator TYPE &() { return val; } \ +}; + + +// ex: using foo_t = IRCD_STRONG_T(int) +#define IRCD_STRONG_T(TYPE) \ + IRCD_STRONG_TYPEDEF(TYPE, IRCD_UNIQUE(strong_t)) + + +template +using custom_ptr = std::unique_ptr>; + + +} // namespace util +} // namespace ircd +#endif // __cplusplus diff --git a/ircd/Makefile.am b/ircd/Makefile.am index 1f075b6c7..2f3390a75 100644 --- a/ircd/Makefile.am +++ b/ircd/Makefile.am @@ -48,6 +48,7 @@ libircd_la_SOURCES = \ class.cc \ client.cc \ dns.cc \ + exception.cc \ extban.cc \ fs.cc \ getopt.cc \ diff --git a/ircd/exception.cc b/ircd/exception.cc new file mode 100644 index 000000000..7a35f1e6b --- /dev/null +++ b/ircd/exception.cc @@ -0,0 +1,48 @@ +/* + * charybdis: 21st Century IRCd + * exception.cc: Exception root + * + * Copyright (C) 2016 Charybdis Development Team + * Copyright (C) 2016 Jason Volk + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 + +using namespace ircd; + + +exception::exception(const pass_name_t, + const char *const &name, + const char *const fmt, + ...) +noexcept +{ + va_list ap; + va_start(ap, fmt); + + size_t size(0); + const bool empty(!fmt || !fmt[0] || fmt[0] == ' '); + size = rb_strlcpy(buf, name, sizeof(buf)); + size = rb_strlcat(buf, empty? "." : ": ", sizeof(buf)); + if(size < sizeof(buf)) + vsnprintf(buf + size, sizeof(buf) - size, fmt, ap); + + va_end(ap); +} diff --git a/ircd/fs.cc b/ircd/fs.cc index 6485be08f..1afecab1e 100644 --- a/ircd/fs.cc +++ b/ircd/fs.cc @@ -24,6 +24,8 @@ */ #include +#include +#include using namespace ircd;