diff options
author | Ben Longbons <b.r.longbons@gmail.com> | 2014-03-15 19:34:59 -0700 |
---|---|---|
committer | Ben Longbons <b.r.longbons@gmail.com> | 2014-03-16 18:58:48 -0700 |
commit | c812c92d1a1835f0bda783e709481188c8d92225 (patch) | |
tree | b401ede48a088ad1aaed88fe3b997cd26ff7ae08 /src/common | |
parent | de9ee1b9754af9d954487121947352f32d7ebb7e (diff) | |
download | tmwa-c812c92d1a1835f0bda783e709481188c8d92225.tar.gz tmwa-c812c92d1a1835f0bda783e709481188c8d92225.tar.bz2 tmwa-c812c92d1a1835f0bda783e709481188c8d92225.tar.xz tmwa-c812c92d1a1835f0bda783e709481188c8d92225.zip |
Clean up header organization
Diffstat (limited to 'src/common')
44 files changed, 0 insertions, 5515 deletions
diff --git a/src/common/GNUmakefile b/src/common/GNUmakefile deleted file mode 100644 index 917ce0e..0000000 --- a/src/common/GNUmakefile +++ /dev/null @@ -1,7 +0,0 @@ -.SUFFIXES: -common: - ${MAKE} -C ../.. common -clean: - rm -r ../../obj/common/ -%:: - ${MAKE} -C ../.. obj/common/$@ diff --git a/src/common/config_parse.cpp b/src/common/config_parse.cpp deleted file mode 100644 index d677d8e..0000000 --- a/src/common/config_parse.cpp +++ /dev/null @@ -1,154 +0,0 @@ -#include "config_parse.hpp" -// config_parse.hpp - Framework for per-server config parsers. -// -// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -#include "../strings/xstring.hpp" -#include "../strings/zstring.hpp" - -#include "../io/cxxstdio.hpp" -#include "../io/line.hpp" - -#include "version.hpp" - -#include "../poison.hpp" - -bool is_comment(XString line) -{ - return not line or line.startswith("//"); -} - -template<class ZS> -inline -bool config_split_impl(ZS line, XString *key, ZS *value) -{ - // unconditionally fail if line contains control characters - if (std::find_if(line.begin(), line.end(), - [](unsigned char c) { return c < ' '; } - ) != line.end()) - return false; - // try to find a colon, fail if not found - typename ZS::iterator colon = std::find(line.begin(), line.end(), ':'); - if (colon == line.end()) - return false; - - *key = line.xislice_h(colon).strip(); - // move past the colon and any spaces - ++colon; - *value = line.xislice_t(colon).lstrip(); - return true; -} - -// eventually this should go away -bool config_split(ZString line, XString *key, ZString *value) -{ - return config_split_impl(line, key, value); -} -// and use this instead -bool config_split(XString line, XString *key, XString *value) -{ - return config_split_impl(line, key, value); -} - -/// Master config parser. This handles 'import' and 'version-ge' etc. -/// Then it defers to the inferior parser for a line it does not understand. -bool load_config_file(ZString filename, ConfigItemParser slave) -{ - io::LineReader in(filename); - if (!in.is_open()) - { - PRINTF("Unable to open file: %s\n", filename); - return false; - } - io::Line line; - bool rv = true; - while (in.read_line(line)) - { - if (is_comment(line.text)) - continue; - XString key; - ZString value; - if (!config_split(line.text, &key, &value)) - { - line.error("Bad config line"); - rv = false; - continue; - } - if (key == "import") - { - rv &= load_config_file(value, slave); - continue; - } - else if (key == "version-lt") - { - Version vers; - if (!extract(value, &vers)) - { - rv = false; - continue; - } - if (CURRENT_VERSION < vers) - continue; - break; - } - else if (key == "version-le") - { - Version vers; - if (!extract(value, &vers)) - { - rv = false; - continue; - } - if (CURRENT_VERSION <= vers) - continue; - break; - } - else if (key == "version-gt") - { - Version vers; - if (!extract(value, &vers)) - { - rv = false; - continue; - } - if (CURRENT_VERSION > vers) - continue; - break; - } - else if (key == "version-ge") - { - Version vers; - if (!extract(value, &vers)) - { - rv = false; - continue; - } - if (CURRENT_VERSION >= vers) - continue; - break; - } - else if (!slave(key, value)) - { - line.error("Bad config key or value"); - rv = false; - continue; - } - // nothing to see here, move along - } - return rv; -} diff --git a/src/common/config_parse.hpp b/src/common/config_parse.hpp deleted file mode 100644 index 6a55174..0000000 --- a/src/common/config_parse.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef TMWA_COMMON_CONFIG_PARSE_HPP -#define TMWA_COMMON_CONFIG_PARSE_HPP -// config_parse.hpp - Framework for per-server config parsers. -// -// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -# include "../sanity.hpp" - -# include "../strings/fwd.hpp" - -typedef bool (*ConfigItemParser)(XString key, ZString value); - -bool is_comment(XString line); -bool config_split(ZString line, XString *key, ZString *value); -bool config_split(XString line, XString *key, XString *value); - -/// Master config parser. This handles 'import' and 'version-ge' etc. -/// Then it defers to the inferior parser for a line it does not understand. -bool load_config_file(ZString filename, ConfigItemParser slave); - -#endif // TMWA_COMMON_CONFIG_PARSE_HPP diff --git a/src/common/const_array.hpp b/src/common/const_array.hpp deleted file mode 100644 index fe15728..0000000 --- a/src/common/const_array.hpp +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef CONST_ARRAY_HPP -#define CONST_ARRAY_HPP -// const_array.hpp - just a pointer-to-const and a length -// -// Copyright © 2011-2012 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -# include "../sanity.hpp" - -# include <cstring> - -# include <iterator> -# include <ostream> -# include <vector> - -# ifdef WORKAROUND_GCC46_COMPILER -// constexpr is buggy with templates in this version -// Is this still needed now that const_string is removed? -# define constexpr /* nothing */ -# endif - -// TODO see if I ever actually use this, and not the subclass -template<class T> -class const_array -{ - const T *d; - size_t n; -public: - typedef const T *iterator; - typedef std::reverse_iterator<iterator> reverse_iterator; - - constexpr - const_array(std::nullptr_t) - : d(nullptr), n(0) - {} - - constexpr - const_array(const T *p, size_t z) - : d(p), n(z) - {} - - constexpr - const_array(const T *b, const T *e) - : d(b), n(e - b) - {} - - const_array(std::initializer_list<T> list) - : d(list.begin()), n(list.size()) - {} - - // Implicit conversion from std::vector - const_array(const std::vector<T>& v) - : d(v.data()), n(v.size()) - {} - - // but disallow conversion from a temporary - const_array(std::vector<T>&&) = delete; - - // Oops. see src/warnings.hpp - constexpr - const T *data() const { return d; } - constexpr - size_t size() const { return n; } - constexpr - bool empty() const { return not n; } - constexpr explicit - operator bool() const { return n; } - - constexpr - std::pair<const_array, const_array> cut(size_t o) const - { - return {const_array(d, o), const_array(d + o, n - o)}; - } - - constexpr - const_array first(size_t o) const - { - return cut(o).first; - } - - constexpr - const_array last(size_t l) const - { - return cut(size() - l).second; - } - - constexpr - const_array after(size_t o) const - { - return cut(o).second; - } - - constexpr - iterator begin() const { return d; } - constexpr - iterator end() const { return d + n; } - constexpr - reverse_iterator rbegin() const { return reverse_iterator(end()); } - constexpr - reverse_iterator rend() const { return reverse_iterator(begin()); } - - constexpr - const T& front() const { return *begin(); } - constexpr - const T& back() const { return *rbegin(); } - - // This probably shouldn't be used, but I'm adding it for porting. - T& operator[](size_t i) - { - return const_cast<T&>(d[i]); - } -}; - -# ifdef WORKAROUND_GCC46_COMPILER -# undef constexpr -# endif - -#endif // CONST_ARRAY_HPP diff --git a/src/common/core.cpp b/src/common/core.cpp deleted file mode 100644 index d57e970..0000000 --- a/src/common/core.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "core.hpp" - -#include <sys/wait.h> - -#include <unistd.h> - -#include <csignal> -#include <cstdlib> -#include <ctime> - -#include "../strings/zstring.hpp" - -#include "../io/cxxstdio.hpp" - -#include "random.hpp" -#include "socket.hpp" -#include "timer.hpp" - -#include "../poison.hpp" - -// Added by Gabuzomeu -// -// This is an implementation of signal() using sigaction() for portability. -// (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced -// Programming in the UNIX Environment_. -// -typedef void(*sigfunc)(int); -static -sigfunc compat_signal(int signo, sigfunc func) -{ - struct sigaction sact, oact; - - sact.sa_handler = func; - sigfillset(&sact.sa_mask); - sigdelset(&sact.sa_mask, SIGSEGV); - sigdelset(&sact.sa_mask, SIGBUS); - sigdelset(&sact.sa_mask, SIGTRAP); - sigdelset(&sact.sa_mask, SIGILL); - sigdelset(&sact.sa_mask, SIGFPE); - sact.sa_flags = 0; - - if (sigaction(signo, &sact, &oact) < 0) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - return SIG_ERR; -#pragma GCC diagnostic pop - - return oact.sa_handler; -} - -volatile -bool runflag = true; - -static -void chld_proc(int) -{ - wait(NULL); -} -static -void sig_proc(int) -{ - for (int i = 1; i < 31; ++i) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - compat_signal(i, SIG_IGN); -#pragma GCC diagnostic pop - runflag = false; -} - -/* - Note about fatal signals: - - Under certain circumstances, - the following signals MUST not be ignored: - SIGFPE, SIGSEGV, SIGILL - Unless you use SA_SIGINFO and *carefully* check the origin, - that means they must be SIG_DFL. - */ -int main(int argc, char **argv) -{ - // ZString args[argc]; is (deliberately!) not supported by clang yet - ZString *args = static_cast<ZString *>(alloca(argc * sizeof(ZString))); - for (int i = 0; i < argc; ++i) - args[i] = ZString(strings::really_construct_from_a_pointer, argv[i], nullptr); - do_init(argc, args); - - if (!runflag) - { - PRINTF("Fatal error during startup; exiting\n"); - return 1; - } - // set up exit handlers *after* the initialization has happened. - // This is because term_func is likely to depend on successful init. - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - compat_signal(SIGPIPE, SIG_IGN); -#pragma GCC diagnostic pop - compat_signal(SIGTERM, sig_proc); - compat_signal(SIGINT, sig_proc); - compat_signal(SIGCHLD, chld_proc); - - // Signal to create coredumps by system when necessary (crash) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - compat_signal(SIGSEGV, SIG_DFL); - compat_signal(SIGBUS, SIG_DFL); - compat_signal(SIGTRAP, SIG_DFL); - compat_signal(SIGILL, SIG_DFL); - compat_signal(SIGFPE, SIG_DFL); -#pragma GCC diagnostic pop - - atexit(term_func); - - while (runflag) - { - // TODO - if timers take a long time to run, this - // may wait too long in sendrecv - tick_t now = milli_clock::now(); - interval_t next = do_timer(now); - do_sendrecv(next); - do_parsepacket(); - } -} diff --git a/src/common/core.hpp b/src/common/core.hpp deleted file mode 100644 index 8141e9c..0000000 --- a/src/common/core.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CORE_HPP -#define CORE_HPP - -# include "../sanity.hpp" - -# include "../strings/fwd.hpp" - -/// core.c contains a server-independent main() function -/// and then runs a do_sendrecv loop - -/// When this is cleared, the server exits gracefully. -extern volatile bool runflag; - -/// This is an external function defined by each server -/// This function must register stuff for the parse loop -extern int do_init(int, ZString *); - -/// Cleanup function called whenever a signal kills us -/// or when if we manage to exit() gracefully. -extern void term_func(void); - -#endif // CORE_HPP diff --git a/src/common/db.cpp b/src/common/db.cpp deleted file mode 100644 index cc58ad8..0000000 --- a/src/common/db.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "db.hpp" - -#include "../poison.hpp" diff --git a/src/common/db.hpp b/src/common/db.hpp deleted file mode 100644 index 0384f1c..0000000 --- a/src/common/db.hpp +++ /dev/null @@ -1,180 +0,0 @@ -#ifndef DB_HPP -#define DB_HPP -// db.hpp - convenience wrappers over std::map<K, V> -// -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -# include "../sanity.hpp" - -# include <map> -# include <memory> - -template<class K, class V> -class Map -{ - typedef std::map<K, V> Impl; - - Impl impl; -public: - Map() = default; - Map(std::initializer_list<std::pair<const K, V>> il) - : impl(il) - {} - typedef typename Impl::iterator iterator; - typedef typename Impl::const_iterator const_iterator; - - iterator begin() { return impl.begin(); } - iterator end() { return impl.end(); } - const_iterator begin() const { return impl.begin(); } - const_iterator end() const { return impl.end(); } - - V *search(const K& k) - { - iterator it = impl.find(k); - if (it == impl.end()) - return nullptr; - return &it->second; - } - const V *search(const K& k) const - { - const_iterator it = impl.find(k); - if (it == impl.end()) - return nullptr; - return &it->second; - } - void insert(const K& k, V v) - { - // As far as I can tell, this is the simplest way to - // implement move-only insert-with-replacement. - iterator it = impl.lower_bound(k); - // invariant: if it is valid, it->first >= k - if (it != impl.end() && it->first == k) - it->second = std::move(v); - else - it = impl.insert(std::pair<K, V>(std::move(k), std::move(v))).first; - return (void)&it->second; - - } - V *init(const K& k) - { - return &impl[k]; - } - void erase(const K& k) - { - impl.erase(k); - } - void clear() - { - impl.clear(); - } - bool empty() const - { - return impl.empty(); - } - size_t size() const - { - return impl.size(); - } -}; - -template<class K, class V> -class DMap -{ - typedef Map<K, V> Impl; - - Impl impl; -public: - typedef typename Impl::iterator iterator; - typedef typename Impl::const_iterator const_iterator; - - iterator begin() { return impl.begin(); } - iterator end() { return impl.end(); } - const_iterator begin() const { return impl.begin(); } - const_iterator end() const { return impl.end(); } - - // const V& ? with a static default V? - V get(const K& k) - { - V *vp = impl.search(k); - return vp ? *vp : V(); - } - void put(const K& k, V v) - { - if (v == V()) - impl.erase(k); - else - impl.insert(k, std::move(v)); - } - void clear() - { - impl.clear(); - } - bool empty() const - { - return impl.empty(); - } - size_t size() const - { - return impl.size(); - } -}; - -template<class K, class V> -class UPMap -{ - typedef std::unique_ptr<V> U; - typedef Map<K, U> Impl; - - Impl impl; -public: - typedef typename Impl::iterator iterator; - typedef typename Impl::const_iterator const_iterator; - - iterator begin() { return impl.begin(); } - iterator end() { return impl.end(); } - const_iterator begin() const { return impl.begin(); } - const_iterator end() const { return impl.end(); } - - // const V& ? with a static default V? - V *get(const K& k) - { - U *up = impl.search(k); - return up ? up->get() : nullptr; - } - void put(const K& k, U v) - { - if (!v) - impl.erase(k); - else - impl.insert(k, std::move(v)); - } - void clear() - { - impl.clear(); - } - bool empty() const - { - return impl.empty(); - } - size_t size() const - { - return impl.size(); - } -}; - -#endif // DB_HPP diff --git a/src/common/dumb_ptr.hpp b/src/common/dumb_ptr.hpp deleted file mode 100644 index bf97f22..0000000 --- a/src/common/dumb_ptr.hpp +++ /dev/null @@ -1,276 +0,0 @@ -#ifndef TMWA_COMMON_DUMB_PTR_HPP -#define TMWA_COMMON_DUMB_PTR_HPP -// ptr.hpp - temporary new/delete wrappers -// -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -# include "../sanity.hpp" - -# include <cstring> - -# include <algorithm> - -# include "../strings/astring.hpp" -# include "../strings/zstring.hpp" -# include "../strings/xstring.hpp" - -# include "const_array.hpp" - -// unmanaged new/delete-able pointer -// should be replaced by std::unique_ptr<T> -template<class T> -class dumb_ptr -{ - template<class U> - friend class dumb_ptr; - T *impl; -public: - explicit - dumb_ptr(T *p=nullptr) - : impl(p) - {} - template<class U> - dumb_ptr(dumb_ptr<U> p) - : impl(p.impl) - {} - dumb_ptr(std::nullptr_t) - : impl(nullptr) - {} - - void delete_() - { - delete impl; - *this = nullptr; - } - template<class... A> - void new_(A&&... a) - { - impl = new T(std::forward<A>(a)...); - } - template<class... A> - static - dumb_ptr<T> make(A&&... a) - { - return dumb_ptr<T>(new T(std::forward<A>(a)...)); - } - dumb_ptr& operator = (std::nullptr_t) - { - impl = nullptr; - return *this; - } - - T& operator *() const - { - return *impl; - } - T *operator->() const - { - return impl; - } - - explicit - operator bool() const - { - return impl; - } - bool operator !() const - { - return !impl; - } - - friend bool operator == (dumb_ptr l, dumb_ptr r) - { - return l.impl == r.impl; - } - friend bool operator != (dumb_ptr l, dumb_ptr r) - { - return !(l == r); - } -}; - -// unmanaged new/delete-able pointer -// should be replaced by std::unique_ptr<T[]> or std::vector<T> -template<class T> -class dumb_ptr<T[]> -{ - T *impl; - size_t sz; -public: - dumb_ptr() : impl(), sz() {} - dumb_ptr(std::nullptr_t) - : impl(nullptr), sz(0) {} - dumb_ptr(T *p, size_t z) - : impl(p) - , sz(z) - {} - - void delete_() - { - delete[] impl; - *this = nullptr; - } - void new_(size_t z) - { - impl = new T[z](); - sz = z; - } - static - dumb_ptr<T[]> make(size_t z) - { - return dumb_ptr<T[]>(new T[z](), z); - } - dumb_ptr& operator = (std::nullptr_t) - { - impl = nullptr; - sz = 0; - return *this; - } - - size_t size() const - { - return sz; - } - void resize(size_t z) - { - if (z == sz) - return; - T *np = new T[z](); - // not exception-safe, but we don't have a dtor anyway - size_t i = std::min(z, sz); - while (i-->0) - np[i] = std::move(impl[i]); - delete[] impl; - impl = np; - sz = z; - } - - T& operator[](size_t i) const - { - return impl[i]; - } - - explicit - operator bool() const - { - return impl; - } - bool operator !() const - { - return !impl; - } - - friend bool operator == (dumb_ptr l, dumb_ptr r) - { - return l.impl == r.impl; - } - friend bool operator != (dumb_ptr l, dumb_ptr r) - { - return !(l == r); - } -}; - -struct dumb_string -{ - dumb_ptr<char[]> impl; - - dumb_string() - : impl() - {} - dumb_string(char *) = delete; - // copy ctor, copy assign, and dtor are all default - - static dumb_string copy(const char *b, const char *e) - { - dumb_string rv; - rv.impl.new_((e - b) + 1); - std::copy(b, e, &rv.impl[0]); - return rv; - } - static dumb_string copy(const char *sz) - { - return dumb_string::copy(sz, sz + strlen(sz)); - } - static dumb_string copys(XString s) - { - return dumb_string::copy(&*s.begin(), &*s.end()); - } - static -# ifndef __clang__ - __attribute__((warning("shouldn't use this - slice instead"))) -# endif - dumb_string copyn(const char *sn, size_t n) - { - return dumb_string::copy(sn, sn + strnlen(sn, n)); - } - - static - dumb_string fake(ZString p) - { - dumb_string rv; - size_t len = p.size(); - rv.impl = dumb_ptr<char[]>(const_cast<char *>(p.c_str()), len); - return rv; - } - - dumb_string dup() const - { - return dumb_string::copy(&impl[0]); - } - void delete_() - { - impl.delete_(); - } - - const char *c_str() const - { - return &impl[0]; - } - - operator ZString() const - { - return ZString(strings::really_construct_from_a_pointer, c_str(), nullptr); - } - - AString str() const - { - return ZString(*this); - } - - char& operator[](size_t i) const - { - return impl[i]; - } - - explicit - operator bool() const - { - return bool(impl); - } - bool operator !() const - { - return !impl; - } -}; - -inline -const char *convert_for_printf(dumb_string ds) -{ - return ds.c_str(); -} - -#endif // TMWA_COMMON_DUMB_PTR_HPP diff --git a/src/common/extract.cpp b/src/common/extract.cpp deleted file mode 100644 index 378986d..0000000 --- a/src/common/extract.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "extract.hpp" -// extract.cpp - a simple, hierarchical, tokenizer -// -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -#include "../strings/astring.hpp" -#include "../strings/xstring.hpp" -#include "../strings/vstring.hpp" - -#include "../poison.hpp" - -bool extract(XString str, XString *rv) -{ - *rv = str; - return true; -} - -bool extract(XString str, AString *rv) -{ - *rv = str; - return true; -} - -bool extract(XString str, struct global_reg *var) -{ - return extract(str, - record<','>(&var->str, &var->value)); -} - -bool extract(XString str, struct item *it) -{ - XString ignored; - return extract(str, - record<',', 11>( - &it->id, - &it->nameid, - &it->amount, - &it->equip, - &ignored, - &ignored, - &ignored, - &ignored, - &ignored, - &ignored, - &ignored, - &ignored)); -} diff --git a/src/common/extract.hpp b/src/common/extract.hpp deleted file mode 100644 index 31cf111..0000000 --- a/src/common/extract.hpp +++ /dev/null @@ -1,223 +0,0 @@ -#ifndef EXTRACT_HPP -#define EXTRACT_HPP -// extract.hpp - a simple, hierarchical, tokenizer -// -// Copyright © 2012-2013 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -# include "../sanity.hpp" - -# include <algorithm> - -# include "../strings/xstring.hpp" - -# include "const_array.hpp" -# include "mmo.hpp" -# include "utils.hpp" - -template<class T, typename=typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, char>::value && !std::is_same<T, bool>::value>::type> -bool extract(XString str, T *iv) -{ - if (!str || str.size() > 20) - return false; - if (!((str.front() == '-' && std::is_signed<T>::value) - || ('0' <= str.front() && str.front() <= '9'))) - return false; - // needs a NUL, but can't always be given one. TODO VString? - char buf[20 + 1]; - std::copy(str.begin(), str.end(), buf); - buf[str.size()] = '\0'; - - char *end; - errno = 0; - if (std::is_signed<T>::value) - { - long long v = strtoll(buf, &end, 10); - if (errno || *end) - return false; - *iv = v; - return *iv == v; - } - else - { - unsigned long long v = strtoull(buf, &end, 10); - if (errno || *end) - return false; - *iv = v; - return *iv == v; - } -} - -inline -bool extract(XString str, TimeT *tv) -{ - return extract(str, &tv->value); -} - -// extra typename=void to workaround some duplicate overload rule -template<class T, typename=typename std::enable_if<std::is_enum<T>::value>::type, typename=void> -bool extract(XString str, T *iv) -{ - typedef typename underlying_type<T>::type U; - U v; - // defer to integer version - if (!extract(str, &v)) - return false; - // TODO check bounds using enum min/max as in SSCANF - *iv = static_cast<T>(v); - return true; -} - -bool extract(XString str, XString *rv); - -bool extract(XString str, AString *rv); - -template<uint8_t N> -bool extract(XString str, VString<N> *out) -{ - if (str.size() > N) - return false; - *out = str; - return true; -} - -template<class T> -class LStripper -{ -public: - T impl; -}; - -template<class T> -LStripper<T> lstripping(T v) -{ - return {v}; -} - -template<class T> -bool extract(XString str, LStripper<T> out) -{ - return extract(str.lstrip(), out.impl); -} - -// basically just a std::tuple -// but it provides its data members publically -template<char split, int n, class... T> -class Record; -template<char split, int n> -class Record<split, n> -{ -}; -template<char split, int n, class F, class... R> -class Record<split, n, F, R...> -{ -public: - F frist; - Record<split, n - 1, R...> rest; -public: - Record(F f, R... r) - : frist(f), rest(r...) - {} -}; -template<char split, class... T> -Record<split, sizeof...(T), T...> record(T... t) -{ - return Record<split, sizeof...(T), T...>(t...); -} -template<char split, int n, class... T> -Record<split, n, T...> record(T... t) -{ - static_assert(0 < n && n < sizeof...(T), "don't be silly"); - return Record<split, n, T...>(t...); -} - -template<char split, int n> -bool extract(XString str, Record<split, n>) -{ - return !str; -} - -template<char split, int n, class F, class... R> -bool extract(XString str, Record<split, n, F, R...> rec) -{ - XString::iterator s = std::find(str.begin(), str.end(), split); - XString::iterator s2 = s; - if (s2 != str.end()) - ++s2; - XString head = str.xislice_h(s); - XString tail = str.xislice_t(s2); - if (s == str.end()) - return (extract(head, rec.frist) && n <= 1) - || (!head && n <= 0); - - return (extract(head, rec.frist) || n <= 0) - && extract(tail, rec.rest); -} - -template<char split, class T> -struct VRecord -{ - std::vector<T> *arr; -}; - -template<char split, class T> -VRecord<split, T> vrec(std::vector<T> *arr) -{ - return {arr}; -} - -template<char split, class T> -bool extract(XString str, VRecord<split, T> rec) -{ - if (!str) - return true; - XString::iterator s = std::find(str.begin(), str.end(), split); - rec.arr->emplace_back(); - if (s == str.end()) - return extract(str, &rec.arr->back()); - return extract(str.xislice_h(s), &rec.arr->back()) - && extract(str.xislice_t(s + 1), rec); -} - -bool extract(XString str, struct global_reg *var); - -bool extract(XString str, struct item *it); - -inline -bool extract(XString str, MapName *m) -{ - XString::iterator it = std::find(str.begin(), str.end(), '.'); - str = str.xislice_h(it); - VString<15> tmp; - bool rv = extract(str, &tmp); - *m = tmp; - return rv; -} - -inline -bool extract(XString str, CharName *out) -{ - VString<23> tmp; - if (extract(str, &tmp)) - { - *out = CharName(tmp); - return true; - } - return false; -} - -#endif // EXTRACT_HPP diff --git a/src/common/extract_test.cpp b/src/common/extract_test.cpp deleted file mode 100644 index 3d0610e..0000000 --- a/src/common/extract_test.cpp +++ /dev/null @@ -1,334 +0,0 @@ -#include "extract.hpp" - -#include <gtest/gtest.h> - -#include "../strings/xstring.hpp" - -TEST(extract, record_int) -{ - int x, y, z; - x = y = z = 0; - EXPECT_FALSE(extract("1 2 3 4 ", record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_FALSE(extract("1 2 3 4", record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 3 ", record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 3", record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_FALSE(extract("1 2 ", record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract("1 2", record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract("1 ", record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract("1", record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract(" ", record<' '>(&x, &y, &z))); - EXPECT_EQ(0, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract("", record<' '>(&x, &y, &z))); - EXPECT_EQ(0, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - - EXPECT_FALSE(extract("1 2 3 4 ", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_FALSE(extract("1 2 3 4", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 3 ", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 3", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 ", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract("1 ", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract("1", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract(" ", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(0, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract("", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(0, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - - EXPECT_FALSE(extract("1 2 3 4 ", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_FALSE(extract("1 2 3 4", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 3 ", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 3", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 ", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 ", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_TRUE(extract("1", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract(" ", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(0, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract("", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(0, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; -} - -TEST(extract, record_str) -{ - XString x, y, z; - x = y = z = ""; - EXPECT_FALSE(extract("1 2 3 4 ", record<' '>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("3", z); - x = y = z = ""; - EXPECT_FALSE(extract("1 2 3 4", record<' '>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("3", z); - x = y = z = ""; - EXPECT_TRUE(extract("1 2 3 ", record<' '>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("3", z); - x = y = z = ""; - EXPECT_TRUE(extract("1 2 3", record<' '>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("3", z); - x = y = z = ""; - EXPECT_TRUE(extract("1 2 ", record<' '>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_FALSE(extract("1 2", record<' '>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_FALSE(extract("1 ", record<' '>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_FALSE(extract("1", record<' '>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_FALSE(extract(" ", record<' '>(&x, &y, &z))); - EXPECT_EQ("", x); - EXPECT_EQ("", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_FALSE(extract("", record<' '>(&x, &y, &z))); - EXPECT_EQ("", x); - EXPECT_EQ("", y); - EXPECT_EQ("", z); - x = y = z = ""; - - EXPECT_FALSE(extract("1 2 3 4 ", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("3", z); - x = y = z = ""; - EXPECT_FALSE(extract("1 2 3 4", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("3", z); - x = y = z = ""; - EXPECT_TRUE(extract("1 2 3 ", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("3", z); - x = y = z = ""; - EXPECT_TRUE(extract("1 2 3", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("3", z); - x = y = z = ""; - EXPECT_TRUE(extract("1 2 ", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_TRUE(extract("1 2", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_TRUE(extract("1 ", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_FALSE(extract("1", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_TRUE(extract(" ", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("", x); - EXPECT_EQ("", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_FALSE(extract("", record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("", x); - EXPECT_EQ("", y); - EXPECT_EQ("", z); - x = y = z = ""; - - EXPECT_FALSE(extract("1 2 3 4 ", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("3", z); - x = y = z = ""; - EXPECT_FALSE(extract("1 2 3 4", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("3", z); - x = y = z = ""; - EXPECT_TRUE(extract("1 2 3 ", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("3", z); - x = y = z = ""; - EXPECT_TRUE(extract("1 2 3", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("3", z); - x = y = z = ""; - EXPECT_TRUE(extract("1 2 ", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_TRUE(extract("1 2", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("2", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_TRUE(extract("1 ", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_TRUE(extract("1", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1", x); - EXPECT_EQ("", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_TRUE(extract(" ", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("", x); - EXPECT_EQ("", y); - EXPECT_EQ("", z); - x = y = z = ""; - EXPECT_TRUE(extract("", record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("", x); - EXPECT_EQ("", y); - EXPECT_EQ("", z); - x = y = z = ""; -} - -TEST(extract, mapname) -{ - MapName map; - EXPECT_TRUE(extract("abc", &map)); - EXPECT_EQ(map, "abc"); - EXPECT_TRUE(extract("abc.gat", &map)); - EXPECT_EQ(map, "abc"); - EXPECT_TRUE(extract("abcdefghijklmno", &map)); - EXPECT_EQ(map, "abcdefghijklmno"); - EXPECT_TRUE(extract("abcdefghijklmno.gat", &map)); - EXPECT_EQ(map, "abcdefghijklmno"); -} diff --git a/src/common/human_time_diff.hpp b/src/common/human_time_diff.hpp deleted file mode 100644 index b8040b8..0000000 --- a/src/common/human_time_diff.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef TMWA_COMMON_HUMAN_TIME_DIFF_HPP -#define TMWA_COMMON_HUMAN_TIME_DIFF_HPP -// human_time_diff.hpp - broken deltas -// -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -# include "../sanity.hpp" - -# include "../strings/xstring.hpp" - -# include "extract.hpp" - -struct HumanTimeDiff -{ - short year, month, day, hour, minute, second; - - explicit - operator bool() - { - return year || month || day || hour || minute || second; - } - - bool operator !() - { - return !bool(*this); - } -}; - -inline -bool extract(XString str, HumanTimeDiff *iv) -{ - // str is a sequence of [-+]?[0-9]+([ay]|m|[jd]|h|mn|s) - // there are NO spaces here - // parse by counting the number starts - auto is_num = [](char c) - { return c == '-' || c == '+' || ('0' <= c && c <= '9'); }; - if (!str || !is_num(str.front())) - return false; - *iv = HumanTimeDiff{}; - while (str) - { - auto it = std::find_if_not(str.begin(), str.end(), is_num); - auto it2 = std::find_if(it, str.end(), is_num); - XString number = str.xislice_h(it); - XString suffix = str.xislice(it, it2); - str = str.xislice_t(it2); - - short *ptr = nullptr; - if (suffix == "y" || suffix == "a") - ptr = &iv->year; - else if (suffix == "m") - ptr = &iv->month; - else if (suffix == "j" || suffix == "d") - ptr = &iv->day; - else if (suffix == "h") - ptr = &iv->hour; - else if (suffix == "mn") - ptr = &iv->minute; - else if (suffix == "s") - ptr = &iv->second; - else - return false; - if (number.startswith('+') && !number.startswith("+-")) - number = number.xslice_t(1); - if (*ptr || !extract(number, ptr)) - return false; - } - return true; -} - -#endif // TMWA_COMMON_HUMAN_TIME_DIFF_HPP diff --git a/src/common/human_time_diff_test.cpp b/src/common/human_time_diff_test.cpp deleted file mode 100644 index d3ddad1..0000000 --- a/src/common/human_time_diff_test.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "human_time_diff.hpp" - -#include <gtest/gtest.h> - -// a sequence of [-+]?[0-9]+([ay]|m|[jd]|h|mn|s) - -TEST(humantimediff, single) -{ - HumanTimeDiff diff; - - EXPECT_TRUE(extract("42y", &diff)); - EXPECT_EQ(42, diff.year); - EXPECT_EQ(0, diff.month); - EXPECT_EQ(0, diff.day); - EXPECT_EQ(0, diff.hour); - EXPECT_EQ(0, diff.minute); - EXPECT_EQ(0, diff.second); - - EXPECT_TRUE(extract("42m", &diff)); - EXPECT_EQ(0, diff.year); - EXPECT_EQ(42, diff.month); - EXPECT_EQ(0, diff.day); - EXPECT_EQ(0, diff.hour); - EXPECT_EQ(0, diff.minute); - EXPECT_EQ(0, diff.second); - - EXPECT_TRUE(extract("42d", &diff)); - EXPECT_EQ(0, diff.year); - EXPECT_EQ(0, diff.month); - EXPECT_EQ(42, diff.day); - EXPECT_EQ(0, diff.hour); - EXPECT_EQ(0, diff.minute); - EXPECT_EQ(0, diff.second); - - EXPECT_TRUE(extract("42h", &diff)); - EXPECT_EQ(0, diff.year); - EXPECT_EQ(0, diff.month); - EXPECT_EQ(0, diff.day); - EXPECT_EQ(42, diff.hour); - EXPECT_EQ(0, diff.minute); - EXPECT_EQ(0, diff.second); - - EXPECT_TRUE(extract("42mn", &diff)); - EXPECT_EQ(0, diff.year); - EXPECT_EQ(0, diff.month); - EXPECT_EQ(0, diff.day); - EXPECT_EQ(0, diff.hour); - EXPECT_EQ(42, diff.minute); - EXPECT_EQ(0, diff.second); - - EXPECT_TRUE(extract("42s", &diff)); - EXPECT_EQ(0, diff.year); - EXPECT_EQ(0, diff.month); - EXPECT_EQ(0, diff.day); - EXPECT_EQ(0, diff.hour); - EXPECT_EQ(0, diff.minute); - EXPECT_EQ(42, diff.second); - - EXPECT_TRUE(extract("+42y", &diff)); - EXPECT_EQ(42, diff.year); - EXPECT_TRUE(extract("-42y", &diff)); - EXPECT_EQ(-42, diff.year); - EXPECT_FALSE(extract("++42y", &diff)); - EXPECT_FALSE(extract("+-42y", &diff)); - EXPECT_FALSE(extract("-+42y", &diff)); - EXPECT_FALSE(extract("--42y", &diff)); - EXPECT_FALSE(extract("4+2y", &diff)); - EXPECT_FALSE(extract("42z", &diff)); -} - -TEST(humantimediff, multiple) -{ - HumanTimeDiff diff; - - EXPECT_TRUE(extract("42y23m-2d", &diff)); - EXPECT_EQ(42, diff.year); - EXPECT_EQ(23, diff.month); - EXPECT_EQ(-2, diff.day); - EXPECT_EQ(0, diff.hour); - EXPECT_EQ(0, diff.minute); - EXPECT_EQ(0, diff.second); - EXPECT_FALSE(extract("1y2y", &diff)); -} diff --git a/src/common/intern-pool.hpp b/src/common/intern-pool.hpp deleted file mode 100644 index e75a359..0000000 --- a/src/common/intern-pool.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef INTERN_POOL_HPP -#define INTERN_POOL_HPP - -# include <cassert> - -# include <map> -# include <vector> - -# include "../strings/rstring.hpp" -# include "../strings/zstring.hpp" -# include "../strings/xstring.hpp" - -class InternPool -{ - std::map<RString, size_t> known; - std::vector<RString> names; -public: - size_t intern(XString name_) - { - // TODO just look up the XString, the memory should not move by now - RString name = name_; - // hm, I could change this to do aliases - auto pair = known.insert({name, known.size()}); - if (pair.second) - names.push_back(name); - assert (known.size() == names.size()); - return pair.first->second; - } - - ZString outtern(size_t sz) const - { - return names[sz]; - } - - size_t size() const - { - return known.size(); - } -}; - -#endif //INTERN_POOL_HPP diff --git a/src/common/intern-pool_test.cpp b/src/common/intern-pool_test.cpp deleted file mode 100644 index bf17b67..0000000 --- a/src/common/intern-pool_test.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "intern-pool.hpp" - -#include <gtest/gtest.h> - -#include "../strings/base.hpp" - -TEST(InternPool, whydoesthisalwaysneedasecondname) -{ - InternPool p; - EXPECT_EQ(0, p.size()); - EXPECT_EQ(0, p.intern("hello")); - EXPECT_EQ(0, p.intern("hello")); - EXPECT_EQ(1, p.size()); - EXPECT_EQ(1, p.intern("world")); - EXPECT_EQ(0, p.intern("hello")); - EXPECT_EQ(1, p.intern("world")); - EXPECT_EQ(2, p.size()); - EXPECT_EQ("hello", p.outtern(0)); - EXPECT_EQ("world", p.outtern(1)); -} diff --git a/src/common/ip.cpp b/src/common/ip.cpp deleted file mode 100644 index 146734a..0000000 --- a/src/common/ip.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "ip.hpp" -// ip.cpp - Implementation of IP address functions. -// -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -#include "../strings/xstring.hpp" -#include "../strings/vstring.hpp" - -#include "../io/cxxstdio.hpp" - -#include "../poison.hpp" - -bool extract(XString str, IP4Address *rv) -{ - if (str.endswith('.')) - return false; - uint8_t buf[4]; - if (extract(str, record<'.'>(&buf[0], &buf[1], &buf[2], &buf[3]))) - { - *rv = IP4Address(buf); - return true; - } - return false; -} - -bool extract(XString str, IP4Mask *rv) -{ - IP4Address a, m; - unsigned b; - XString l, r; - if (str.endswith('/')) - return false; - if (extract(str, record<'/'>(&l, &r))) - { - // a.b.c.d/e.f.g.h or a.b.c.d/n - if (!extract(l, &a)) - return false; - if (extract(r, &m)) - { - *rv = IP4Mask(a, m); - return true; - } - if (!extract(r, &b) || b > 32) - return false; - } - else - { - // a.b.c.d or a.b.c.d. or a.b.c. or a.b. or a. - if (extract(str, &a)) - { - *rv = IP4Mask(a, IP4_BROADCAST); - return true; - } - if (!str.endswith('.')) - return false; - uint8_t d[4] {}; - if (extract(str, record<'.'>(&d[0], &d[1], &d[2], &d[3]))) - b = 32; - else if (extract(str, record<'.'>(&d[0], &d[1], &d[2]))) - b = 24; - else if (extract(str, record<'.'>(&d[0], &d[1]))) - b = 16; - else if (extract(str, record<'.'>(&d[0]))) - b = 8; - else - return false; - a = IP4Address(d); - } - // a is set; need to construct m from b - if (b == 0) - m = IP4Address(); - else if (b == 32) - m = IP4_BROADCAST; - else - { - uint32_t s = -1; - s <<= (32 - b); - m = IP4Address({ - static_cast<uint8_t>(s >> 24), - static_cast<uint8_t>(s >> 16), - static_cast<uint8_t>(s >> 8), - static_cast<uint8_t>(s >> 0), - }); - } - *rv = IP4Mask(a, m); - return true; -} - -VString<15> convert_for_printf(IP4Address a_) -{ - const uint8_t *a = a_.bytes(); - return STRNPRINTF(16, "%hhu.%hhu.%hhu.%hhu", a[0], a[1], a[2], a[3]); -} - -VString<31> convert_for_printf(IP4Mask a) -{ - return STRNPRINTF(32, "%s/%s", - a.addr(), a.mask()); -} diff --git a/src/common/ip.hpp b/src/common/ip.hpp deleted file mode 100644 index d6e6f04..0000000 --- a/src/common/ip.hpp +++ /dev/null @@ -1,164 +0,0 @@ -#ifndef TMWA_COMMON_IP_HPP -#define TMWA_COMMON_IP_HPP -// ip.hpp - classes to deal with IP addresses. -// -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -# include "../sanity.hpp" - -# include <netinet/in.h> - -# include "../strings/fwd.hpp" - -# include "extract.hpp" - -// TODO - in the long run ports belong here also -// and of course, IPv6 stuff. -// But what about unix socket addresses? - -/// Helper function -template<class T, size_t n> -constexpr -bool _ce_a_lt(T (&a)[n], T (&b)[n], size_t i=0) -{ - return (i != n - && (a[i] < b[i] - || (a[i] == b[i] - && _ce_a_lt(a, b, i + 1)))); -} - -/// A 32-bit Ipv4 address. Does not include a port. -/// Guaranteed to be laid out like the network wants. -class IP4Address -{ - uint8_t _addr[4]; -public: - constexpr - IP4Address() - : _addr{} - {} - constexpr explicit - IP4Address(const uint8_t (&a)[4]) - : _addr{a[0], a[1], a[2], a[3]} - {} - explicit - IP4Address(struct in_addr addr) - { - static_assert(sizeof(addr) == sizeof(_addr), "4 bytes"); - *this = IP4Address(reinterpret_cast<const uint8_t (&)[4]>(addr)); - } - explicit - operator struct in_addr() const - { - return reinterpret_cast<const struct in_addr&>(_addr); - } - - constexpr friend - IP4Address operator & (IP4Address l, IP4Address r) - { - return IP4Address({ - static_cast<uint8_t>(l._addr[0] & r._addr[0]), - static_cast<uint8_t>(l._addr[1] & r._addr[1]), - static_cast<uint8_t>(l._addr[2] & r._addr[2]), - static_cast<uint8_t>(l._addr[3] & r._addr[3]), - }); - } - - IP4Address& operator &= (IP4Address m) - { return *this = *this & m; } - - const uint8_t *bytes() const - { return _addr; } - - constexpr friend - bool operator < (IP4Address l, IP4Address r) - { - return _ce_a_lt(l._addr, r._addr); - } - - constexpr friend - bool operator > (IP4Address l, IP4Address r) - { - return _ce_a_lt(r._addr, l._addr); - } - - constexpr friend - bool operator >= (IP4Address l, IP4Address r) - { - return !_ce_a_lt(l._addr, r._addr); - } - - constexpr friend - bool operator <= (IP4Address l, IP4Address r) - { - return !_ce_a_lt(r._addr, l._addr); - } - - constexpr friend - bool operator == (IP4Address l, IP4Address r) - { - return !(l < r || r < l); - } - - constexpr friend - bool operator != (IP4Address l, IP4Address r) - { - return (l < r || r < l); - } -}; - -class IP4Mask -{ - IP4Address _addr, _mask; -public: - constexpr - IP4Mask() : _addr(), _mask() - {} - constexpr - IP4Mask(IP4Address a, IP4Address m) : _addr(a & m), _mask(m) - {} - - constexpr - IP4Address addr() const - { return _addr; } - constexpr - IP4Address mask() const - { return _mask; } - - constexpr - bool covers(IP4Address a) const - { - return (a & _mask) == _addr; - } -}; - - -constexpr -IP4Address IP4_LOCALHOST({127, 0, 0, 1}); -constexpr -IP4Address IP4_BROADCAST({255, 255, 255, 255}); - - -VString<15> convert_for_printf(IP4Address a); -VString<31> convert_for_printf(IP4Mask m); - -bool extract(XString str, IP4Address *iv); - -bool extract(XString str, IP4Mask *iv); - -#endif // TMWA_COMMON_IP_HPP diff --git a/src/common/ip.py b/src/common/ip.py deleted file mode 100644 index e6a8183..0000000 --- a/src/common/ip.py +++ /dev/null @@ -1,14 +0,0 @@ -class IP4Address(object): - ''' print an IP4Address - ''' - __slots__ = ('_value') - name = 'IP4Address' - enabled = True - - def __init__(self, value): - self._value = value - - def to_string(self): - addr = self._value['_addr'] - addr = tuple(int(addr[i]) for i in range(4)) - return '%d.%d.%d.%d' % addr diff --git a/src/common/ip_test.cpp b/src/common/ip_test.cpp deleted file mode 100644 index 7ef1047..0000000 --- a/src/common/ip_test.cpp +++ /dev/null @@ -1,332 +0,0 @@ -#include "ip.hpp" - -#include <gtest/gtest.h> - -#include "../io/cxxstdio.hpp" - -#define CB(X) (std::integral_constant<bool, (X)>::value) -TEST(ip4addr, cmp) -{ - constexpr static - IP4Address a = IP4_LOCALHOST; - constexpr static - IP4Address b = IP4_BROADCAST; - - EXPECT_FALSE(CB(a < a)); - EXPECT_TRUE (CB(a < b)); - EXPECT_FALSE(CB(b < a)); - EXPECT_FALSE(CB(b < b)); - - EXPECT_FALSE(CB(a > a)); - EXPECT_FALSE(CB(a > b)); - EXPECT_TRUE (CB(b > a)); - EXPECT_FALSE(CB(b > b)); - - EXPECT_TRUE (CB(a <= a)); - EXPECT_TRUE (CB(a <= b)); - EXPECT_FALSE(CB(b <= a)); - EXPECT_TRUE (CB(b <= b)); - - EXPECT_TRUE (CB(a >= a)); - EXPECT_FALSE(CB(a >= b)); - EXPECT_TRUE (CB(b >= a)); - EXPECT_TRUE (CB(b >= b)); - - EXPECT_TRUE (CB(a == a)); - EXPECT_FALSE(CB(a == b)); - EXPECT_FALSE(CB(b == a)); - EXPECT_TRUE (CB(b == b)); - - EXPECT_FALSE(CB(a != a)); - EXPECT_TRUE (CB(a != b)); - EXPECT_TRUE (CB(b != a)); - EXPECT_FALSE(CB(b != b)); -} - -TEST(ip4addr, str) -{ - IP4Address a; - EXPECT_EQ("0.0.0.0", STRNPRINTF(17, "%s", a)); - EXPECT_EQ("127.0.0.1", STRNPRINTF(17, "%s", IP4_LOCALHOST)); - EXPECT_EQ("255.255.255.255", STRNPRINTF(17, "%s", IP4_BROADCAST)); -} - -TEST(ip4addr, extract) -{ - IP4Address a; - EXPECT_TRUE(extract("0.0.0.0", &a)); - EXPECT_EQ("0.0.0.0", STRNPRINTF(16, "%s", a)); - EXPECT_TRUE(extract("127.0.0.1", &a)); - EXPECT_EQ("127.0.0.1", STRNPRINTF(16, "%s", a)); - EXPECT_TRUE(extract("255.255.255.255", &a)); - EXPECT_EQ("255.255.255.255", STRNPRINTF(16, "%s", a)); - EXPECT_TRUE(extract("1.2.3.4", &a)); - EXPECT_EQ("1.2.3.4", STRNPRINTF(16, "%s", a)); - - EXPECT_FALSE(extract("1.2.3.4.5", &a)); - EXPECT_FALSE(extract("1.2.3.4.", &a)); - EXPECT_FALSE(extract("1.2.3.", &a)); - EXPECT_FALSE(extract("1.2.3", &a)); - EXPECT_FALSE(extract("1.2.", &a)); - EXPECT_FALSE(extract("1.2", &a)); - EXPECT_FALSE(extract("1.", &a)); - EXPECT_FALSE(extract("1", &a)); - EXPECT_FALSE(extract("", &a)); -} - - -TEST(ip4mask, body) -{ - IP4Mask m; - EXPECT_EQ(IP4Address(), m.addr()); - EXPECT_EQ(IP4Address(), m.mask()); - m = IP4Mask(IP4_LOCALHOST, IP4_BROADCAST); - EXPECT_EQ(IP4_LOCALHOST, m.addr()); - EXPECT_EQ(IP4_BROADCAST, m.mask()); -} - -TEST(ip4mask, str) -{ - IP4Mask m; - EXPECT_EQ("0.0.0.0/0.0.0.0", STRNPRINTF(33, "%s", m)); - m = IP4Mask(IP4_LOCALHOST, IP4_BROADCAST); - EXPECT_EQ("127.0.0.1/255.255.255.255", STRNPRINTF(33, "%s", m)); -} - -TEST(ip4mask, extract) -{ - IP4Mask m; - EXPECT_FALSE(extract("9.8.7.6/33", &m)); - EXPECT_FALSE(extract("9.8.7.6.5", &m)); - EXPECT_FALSE(extract("9.8.7.6/", &m)); - EXPECT_FALSE(extract("9.8.7", &m)); - EXPECT_FALSE(extract("9.8", &m)); - EXPECT_FALSE(extract("9", &m)); - - EXPECT_TRUE(extract("127.0.0.1", &m)); - EXPECT_EQ("127.0.0.1/255.255.255.255", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("127.0.0.1.", &m)); - EXPECT_EQ("127.0.0.1/255.255.255.255", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("127.0.0.", &m)); - EXPECT_EQ("127.0.0.0/255.255.255.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("127.0.", &m)); - EXPECT_EQ("127.0.0.0/255.255.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("127.", &m)); - EXPECT_EQ("127.0.0.0/255.0.0.0", STRNPRINTF(32, "%s", m)); - - EXPECT_TRUE(extract("1.2.3.4/255.255.255.255", &m)); - EXPECT_EQ("1.2.3.4/255.255.255.255", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("1.2.3.0/255.255.255.0", &m)); - EXPECT_EQ("1.2.3.0/255.255.255.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("1.2.0.4/255.255.0.255", &m)); - EXPECT_EQ("1.2.0.4/255.255.0.255", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("1.2.0.0/255.255.0.0", &m)); - EXPECT_EQ("1.2.0.0/255.255.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("1.0.3.4/255.0.255.255", &m)); - EXPECT_EQ("1.0.3.4/255.0.255.255", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("1.0.3.0/255.0.255.0", &m)); - EXPECT_EQ("1.0.3.0/255.0.255.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("1.0.0.4/255.0.0.255", &m)); - EXPECT_EQ("1.0.0.4/255.0.0.255", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("1.0.0.0/255.0.0.0", &m)); - EXPECT_EQ("1.0.0.0/255.0.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.2.3.4/0.255.255.255", &m)); - EXPECT_EQ("0.2.3.4/0.255.255.255", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.2.3.0/0.255.255.0", &m)); - EXPECT_EQ("0.2.3.0/0.255.255.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.2.0.4/0.255.0.255", &m)); - EXPECT_EQ("0.2.0.4/0.255.0.255", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.2.0.0/0.255.0.0", &m)); - EXPECT_EQ("0.2.0.0/0.255.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.3.4/0.0.255.255", &m)); - EXPECT_EQ("0.0.3.4/0.0.255.255", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.3.0/0.0.255.0", &m)); - EXPECT_EQ("0.0.3.0/0.0.255.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.4/0.0.0.255", &m)); - EXPECT_EQ("0.0.0.4/0.0.0.255", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/0.0.0.0", &m)); - EXPECT_EQ("0.0.0.0/0.0.0.0", STRNPRINTF(32, "%s", m)); - - // please don't do this - EXPECT_TRUE(extract("120.248.200.217/89.57.126.5", &m)); - EXPECT_EQ("88.56.72.1/89.57.126.5", STRNPRINTF(32, "%s", m)); - - EXPECT_TRUE(extract("0.0.0.0/32", &m)); - EXPECT_EQ("0.0.0.0/255.255.255.255", STRNPRINTF(32, "%s", m)); - - EXPECT_TRUE(extract("0.0.0.0/31", &m)); - EXPECT_EQ("0.0.0.0/255.255.255.254", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/30", &m)); - EXPECT_EQ("0.0.0.0/255.255.255.252", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/29", &m)); - EXPECT_EQ("0.0.0.0/255.255.255.248", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/28", &m)); - EXPECT_EQ("0.0.0.0/255.255.255.240", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/27", &m)); - EXPECT_EQ("0.0.0.0/255.255.255.224", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/26", &m)); - EXPECT_EQ("0.0.0.0/255.255.255.192", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/25", &m)); - EXPECT_EQ("0.0.0.0/255.255.255.128", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/24", &m)); - EXPECT_EQ("0.0.0.0/255.255.255.0", STRNPRINTF(32, "%s", m)); - - EXPECT_TRUE(extract("0.0.0.0/23", &m)); - EXPECT_EQ("0.0.0.0/255.255.254.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/22", &m)); - EXPECT_EQ("0.0.0.0/255.255.252.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/21", &m)); - EXPECT_EQ("0.0.0.0/255.255.248.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/20", &m)); - EXPECT_EQ("0.0.0.0/255.255.240.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/19", &m)); - EXPECT_EQ("0.0.0.0/255.255.224.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/18", &m)); - EXPECT_EQ("0.0.0.0/255.255.192.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/17", &m)); - EXPECT_EQ("0.0.0.0/255.255.128.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/16", &m)); - EXPECT_EQ("0.0.0.0/255.255.0.0", STRNPRINTF(32, "%s", m)); - - EXPECT_TRUE(extract("0.0.0.0/15", &m)); - EXPECT_EQ("0.0.0.0/255.254.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/14", &m)); - EXPECT_EQ("0.0.0.0/255.252.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/13", &m)); - EXPECT_EQ("0.0.0.0/255.248.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/12", &m)); - EXPECT_EQ("0.0.0.0/255.240.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/11", &m)); - EXPECT_EQ("0.0.0.0/255.224.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/10", &m)); - EXPECT_EQ("0.0.0.0/255.192.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/9", &m)); - EXPECT_EQ("0.0.0.0/255.128.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/8", &m)); - EXPECT_EQ("0.0.0.0/255.0.0.0", STRNPRINTF(32, "%s", m)); - - EXPECT_TRUE(extract("0.0.0.0/7", &m)); - EXPECT_EQ("0.0.0.0/254.0.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/6", &m)); - EXPECT_EQ("0.0.0.0/252.0.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/5", &m)); - EXPECT_EQ("0.0.0.0/248.0.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/4", &m)); - EXPECT_EQ("0.0.0.0/240.0.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/3", &m)); - EXPECT_EQ("0.0.0.0/224.0.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/2", &m)); - EXPECT_EQ("0.0.0.0/192.0.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/1", &m)); - EXPECT_EQ("0.0.0.0/128.0.0.0", STRNPRINTF(32, "%s", m)); - EXPECT_TRUE(extract("0.0.0.0/0", &m)); - EXPECT_EQ("0.0.0.0/0.0.0.0", STRNPRINTF(32, "%s", m)); -} - -TEST(ip4mask, cover) -{ - IP4Address a; - IP4Address b = IP4_BROADCAST; - IP4Address l = IP4_LOCALHOST; - IP4Address h({127, 255, 255, 255}); - IP4Address p24l({10, 0, 0, 0}); - IP4Address p24h({10, 255, 255, 255}); - IP4Address p20l({172, 16, 0, 0}); - IP4Address p20h({172, 31, 255, 255}); - IP4Address p16l({192, 168, 0, 0}); - IP4Address p16h({192, 168, 255, 255}); - IP4Mask m; - EXPECT_TRUE(m.covers(a)); - EXPECT_TRUE(m.covers(b)); - EXPECT_TRUE(m.covers(l)); - EXPECT_TRUE(m.covers(h)); - EXPECT_TRUE(m.covers(p24l)); - EXPECT_TRUE(m.covers(p24h)); - EXPECT_TRUE(m.covers(p20l)); - EXPECT_TRUE(m.covers(p20h)); - EXPECT_TRUE(m.covers(p16l)); - EXPECT_TRUE(m.covers(p16h)); - m = IP4Mask(l, a); - EXPECT_TRUE(m.covers(a)); - EXPECT_TRUE(m.covers(b)); - EXPECT_TRUE(m.covers(l)); - EXPECT_TRUE(m.covers(h)); - EXPECT_TRUE(m.covers(p24l)); - EXPECT_TRUE(m.covers(p24h)); - EXPECT_TRUE(m.covers(p20l)); - EXPECT_TRUE(m.covers(p20h)); - EXPECT_TRUE(m.covers(p16l)); - EXPECT_TRUE(m.covers(p16h)); - m = IP4Mask(l, b); - EXPECT_FALSE(m.covers(a)); - EXPECT_FALSE(m.covers(b)); - EXPECT_TRUE(m.covers(l)); - EXPECT_FALSE(m.covers(h)); - EXPECT_FALSE(m.covers(p24l)); - EXPECT_FALSE(m.covers(p24h)); - EXPECT_FALSE(m.covers(p20l)); - EXPECT_FALSE(m.covers(p20h)); - EXPECT_FALSE(m.covers(p16l)); - EXPECT_FALSE(m.covers(p16h)); - - // but the really useful ones are with partial masks - m = IP4Mask(IP4Address({10, 0, 0, 0}), IP4Address({255, 0, 0, 0})); - EXPECT_FALSE(m.covers(a)); - EXPECT_FALSE(m.covers(b)); - EXPECT_FALSE(m.covers(l)); - EXPECT_FALSE(m.covers(h)); - EXPECT_TRUE(m.covers(p24l)); - EXPECT_TRUE(m.covers(p24h)); - EXPECT_FALSE(m.covers(p20l)); - EXPECT_FALSE(m.covers(p20h)); - EXPECT_FALSE(m.covers(p16l)); - EXPECT_FALSE(m.covers(p16h)); - EXPECT_FALSE(m.covers(IP4Address({9, 255, 255, 255}))); - EXPECT_FALSE(m.covers(IP4Address({11, 0, 0, 0}))); - m = IP4Mask(IP4Address({127, 0, 0, 0}), IP4Address({255, 0, 0, 0})); - EXPECT_FALSE(m.covers(a)); - EXPECT_FALSE(m.covers(b)); - EXPECT_TRUE(m.covers(l)); - EXPECT_TRUE(m.covers(h)); - EXPECT_FALSE(m.covers(p24l)); - EXPECT_FALSE(m.covers(p24h)); - EXPECT_FALSE(m.covers(p20l)); - EXPECT_FALSE(m.covers(p20h)); - EXPECT_FALSE(m.covers(p16l)); - EXPECT_FALSE(m.covers(p16h)); - EXPECT_FALSE(m.covers(IP4Address({126, 255, 255, 255}))); - EXPECT_FALSE(m.covers(IP4Address({128, 0, 0, 0}))); - m = IP4Mask(IP4Address({172, 16, 0, 0}), IP4Address({255, 240, 0, 0})); - EXPECT_FALSE(m.covers(a)); - EXPECT_FALSE(m.covers(b)); - EXPECT_FALSE(m.covers(l)); - EXPECT_FALSE(m.covers(h)); - EXPECT_FALSE(m.covers(p24l)); - EXPECT_FALSE(m.covers(p24h)); - EXPECT_TRUE(m.covers(p20l)); - EXPECT_TRUE(m.covers(p20h)); - EXPECT_FALSE(m.covers(p16l)); - EXPECT_FALSE(m.covers(p16h)); - EXPECT_FALSE(m.covers(IP4Address({172, 15, 255, 255}))); - EXPECT_FALSE(m.covers(IP4Address({172, 32, 0, 0}))); - m = IP4Mask(IP4Address({192, 168, 0, 0}), IP4Address({255, 255, 0, 0})); - EXPECT_FALSE(m.covers(a)); - EXPECT_FALSE(m.covers(b)); - EXPECT_FALSE(m.covers(l)); - EXPECT_FALSE(m.covers(h)); - EXPECT_FALSE(m.covers(p24l)); - EXPECT_FALSE(m.covers(p24h)); - EXPECT_FALSE(m.covers(p20l)); - EXPECT_FALSE(m.covers(p20h)); - EXPECT_TRUE(m.covers(p16l)); - EXPECT_TRUE(m.covers(p16h)); - EXPECT_FALSE(m.covers(IP4Address({192, 167, 255, 255}))); - EXPECT_FALSE(m.covers(IP4Address({192, 169, 0, 0}))); - - // OTOH this is crazy - EXPECT_TRUE(extract("120.248.200.217/89.57.126.5", &m)); - EXPECT_TRUE(m.covers(IP4Address({120, 248, 200, 217}))); - EXPECT_TRUE(m.covers(IP4Address({88, 56, 72, 1}))); - EXPECT_FALSE(m.covers(IP4Address({88, 56, 72, 0}))); - EXPECT_FALSE(m.covers(IP4Address({88, 56, 72, 255}))); -} diff --git a/src/common/iter.hpp b/src/common/iter.hpp deleted file mode 100644 index 5b39588..0000000 --- a/src/common/iter.hpp +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef TMWA_COMMON_ITER_HPP -#define TMWA_COMMON_ITER_HPP -// iter.hpp - tools for dealing with iterators -// -// Copyright © 2012-2014 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -# include "../sanity.hpp" - -# include <iterator> - - -/// Simple class to use a pair of iterators with foreach -template<class It> -class IteratorPair -{ - It _b, _e; -public: - IteratorPair(It b, It e) - : _b(b), _e(e) - {} - - It begin() { return _b; } - It end() { return _e; } -}; - -template<class It> -IteratorPair<It> iterator_pair(It b, It e) -{ - return {b, e}; -} - -template<class T> -class PassthroughMath -{ -public: - static - T inced(T v) { return ++v; } -}; - -// An iterator that just directly contains an integer-like value -// TODO port this once the new integer API happens -template<class T, class Math=PassthroughMath<T>> -class ValueIterator -{ - T value; -public: - typedef std::forward_iterator_tag iterator_category; - typedef void difference_type; - typedef T value_type; - typedef void reference; - typedef void pointer; -public: - ValueIterator(T v) - : value(v) - {} - - T operator *() - { - return value; - } - ValueIterator& operator++ () - { - value = Math::inced(value); - return *this; - } - friend bool operator == (ValueIterator l, ValueIterator r) - { - return l.value == r.value; - } - friend bool operator != (ValueIterator l, ValueIterator r) - { - return !(l == r); - } -}; - -template<class T> -IteratorPair<ValueIterator<T>> value_range(T b, T e) -{ - return {b, e}; -} - -#endif // TMWA_COMMON_ITER_HPP diff --git a/src/common/iter_test.cpp b/src/common/iter_test.cpp deleted file mode 100644 index 647ebf9..0000000 --- a/src/common/iter_test.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "iter.hpp" - -#include <gtest/gtest.h> - -#include "../strings/xstring.hpp" - -TEST(iterpair, string) -{ - IteratorPair<ValueIterator<char>> pair = value_range('0', ':'); - const char *str = "0123456789"; - EXPECT_TRUE(std::equal(pair.begin(), pair.end(), str)); -} - -TEST(iterpair, signed8) -{ - IteratorPair<ValueIterator<int8_t>> pair = value_range(int8_t(-128), int8_t(127)); - int8_t arr[255] = - { - -128, -127, -126, -125, -124, -123, -122, -121, -120, - -119, -118, -117, -116, -115, -114, -113, -112, -111, -110, - -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, - -99, -98, -97, -96, -95, -94, -93, -92, -91, -90, - -89, -88, -87, -86, -85, -84, -83, -82, -81, -80, - -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, - -69, -68, -67, -66, -65, -64, -63, -62, -61, -60, - -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, - -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, - -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, - -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, - -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, - -9, -8, -7, -6, -5, -4, -3, -2, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, - }; - EXPECT_TRUE(std::equal(pair.begin(), pair.end(), arr + 0)); -} - -TEST(iterpair, unsigned8) -{ - IteratorPair<ValueIterator<uint8_t>> pair = value_range(uint8_t(0), uint8_t(255)); - uint8_t arr[255] = - { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, - 250, 251, 252, 253, 254, - }; - EXPECT_TRUE(std::equal(pair.begin(), pair.end(), arr)); -} diff --git a/src/common/matrix.hpp b/src/common/matrix.hpp deleted file mode 100644 index 8595191..0000000 --- a/src/common/matrix.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef TMWA_COMMON_MATRIX_HPP -#define TMWA_COMMON_MATRIX_HPP - -template<class T> -class Matrix -{ - std::unique_ptr<T[]> _data; - size_t _xs, _ys; -public: - Matrix() - : _data() - , _xs() - , _ys() - {} - Matrix(size_t x, size_t y) - : _data(new T[x * y]()) - , _xs(x) - , _ys(y) - {} - // no copy-ctor or copy-assign - - void reset(size_t x, size_t y) - { - *this = Matrix(x, y); - } - void clear() - { - *this = Matrix(); - } - - T& ref(size_t x, size_t y) - { - return _data[x + y * _xs]; - } - const T& ref(size_t x, size_t y) const - { - return _data[x + y * _xs]; - } - - size_t xs() const - { - return _xs; - } - size_t ys() const - { - return _ys; - } -}; - -#endif // TMWA_COMMON_MATRIX_HPP diff --git a/src/common/md5calc.cpp b/src/common/md5calc.cpp deleted file mode 100644 index d23f8e3..0000000 --- a/src/common/md5calc.cpp +++ /dev/null @@ -1,352 +0,0 @@ -#include "md5calc.hpp" - -#include <cstring> - -#include "../strings/xstring.hpp" -#include "../strings/vstring.hpp" - -#include "../io/cxxstdio.hpp" -#include "../io/read.hpp" - -#include "random.hpp" -#include "utils.hpp" - -#include "../poison.hpp" - -// auxilary data -/* -sin() constant table -#Reformatted output of: -echo 'scale=40; obase=16; for (i=1;i<=64;i++) print 2^32 * sin(i), "\n"' | -bc | sed 's/^-//;s/^/0x/;s/\..*$/,/' -*/ -static -const uint32_t T[64] = -{ - // used by round 1 - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, //0 - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, //4 - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, //8 - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, //12 - // used by round 2 - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, //16 - 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, //20 - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, //24 - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, //28 - // used by round 3 - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, //32 - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, //36 - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, //40 - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, //44 - // used by round 4 - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, //48 - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, //52 - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, //56 - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, //60 -}; - -// auxilary functions -// note - the RFC defines these by non-CS conventions: or=v, and=(empty) -static -uint32_t rotate_left(uint32_t val, unsigned shift) -{ - return val << shift | val >> (32 - shift); -} - -static -uint32_t F(uint32_t X, uint32_t Y, uint32_t Z) -{ - return (X & Y) | (~X & Z); -} -static -uint32_t G(uint32_t X, uint32_t Y, uint32_t Z) -{ - return (X & Z) | (Y & ~Z); -} -static -uint32_t H(uint32_t X, uint32_t Y, uint32_t Z) -{ - return X ^ Y ^ Z; -} -static -uint32_t I(uint32_t X, uint32_t Y, uint32_t Z) -{ - return Y ^ (X | ~Z); -} - -static -const struct -{ - uint8_t k : 4; - uint8_t : 0; - uint8_t s : 5; -// uint8_t i : 6; just increments constantly, from 1 .. 64 over all rounds -} -MD5_round1[16] = -{ - { 0, 7}, { 1, 12}, { 2, 17}, { 3, 22}, - { 4, 7}, { 5, 12}, { 6, 17}, { 7, 22}, - { 8, 7}, { 9, 12}, {10, 17}, {11, 22}, - {12, 7}, {13, 12}, {14, 17}, {15, 22}, -}, -MD5_round2[16] = -{ - { 1, 5}, { 6, 9}, {11, 14}, { 0, 20}, - { 5, 5}, {10, 9}, {15, 14}, { 4, 20}, - { 9, 5}, {14, 9}, { 3, 14}, { 8, 20}, - {13, 5}, { 2, 9}, { 7, 14}, {12, 20}, -}, -MD5_round3[16] = -{ - { 5, 4}, { 8, 11}, {11, 16}, {14, 23}, - { 1, 4}, { 4, 11}, { 7, 16}, {10, 23}, - {13, 4}, { 0, 11}, { 3, 16}, { 6, 23}, - { 9, 4}, {12, 11}, {15, 16}, { 2, 23}, -}, -MD5_round4[16] = -{ - { 0, 6}, { 7, 10}, {14, 15}, { 5, 21}, - {12, 6}, { 3, 10}, {10, 15}, { 1, 21}, - { 8, 6}, {15, 10}, { 6, 15}, {13, 21}, - { 4, 6}, {11, 10}, { 2, 15}, { 9, 21}, -}; - - -void MD5_init(MD5_state* state) -{ - // in the RFC, these are specified as bytes, interpreted as little-endian - state->val[0] = 0x67452301; - state->val[1] = 0xEFCDAB89; - state->val[2] = 0x98BADCFE; - state->val[3] = 0x10325476; -} - -void MD5_do_block(MD5_state* state, MD5_block block) -{ -#define X block.data -#define a state->val[(16 - i) % 4] -#define b state->val[(17 - i) % 4] -#define c state->val[(18 - i) % 4] -#define d state->val[(19 - i) % 4] - // save the values - const MD5_state saved = *state; - // round 1 - for (int i = 0; i < 16; i++) - { -#define k MD5_round1[i].k -#define s MD5_round1[i].s - a = b + rotate_left(a + F(b, c, d) + X[k] + T[i + 0x0], s); -#undef k -#undef s - } - // round 2 - for (int i = 0; i < 16; i++) - { -#define k MD5_round2[i].k -#define s MD5_round2[i].s - a = b + rotate_left(a + G(b, c, d) + X[k] + T[i + 0x10], s); -#undef k -#undef s - } - // round 3 - for (int i = 0; i < 16; i++) - { -#define k MD5_round3[i].k -#define s MD5_round3[i].s - a = b + rotate_left(a + H(b, c, d) + X[k] + T[i + 0x20], s); -#undef k -#undef s - } - // round 4 - for (int i = 0; i < 16; i++) - { -#define k MD5_round4[i].k -#define s MD5_round4[i].s - a = b + rotate_left(a + I(b, c, d) + X[k] + T[i + 0x30], s); -#undef k -#undef s - } - // adjust state based on original - state->val[0] += saved.val[0]; - state->val[1] += saved.val[1]; - state->val[2] += saved.val[2]; - state->val[3] += saved.val[3]; -#undef a -#undef b -#undef c -#undef d -} - -void MD5_to_bin(MD5_state state, md5_binary& out) -{ - for (int i = 0; i < 0x10; i++) - out[i] = state.val[i / 4] >> 8 * (i % 4); -} - -static -const char hex[] = "0123456789abcdef"; - -void MD5_to_str(MD5_state state, md5_string& out_) -{ - md5_binary bin; - MD5_to_bin(state, bin); - char out[0x20]; - for (int i = 0; i < 0x10; i++) - out[2 * i] = hex[bin[i] >> 4], - out[2 * i + 1] = hex[bin[i] & 0xf]; - out_ = stringish<md5_string>(XString(out, out + 0x20, nullptr)); -} - -MD5_state MD5_from_string(XString msg) -{ - MD5_state state; - MD5_init(&state); - MD5_block block; - const uint64_t msg_full_len = msg.size(); - while (msg.size() >= 64) - { - for (int i = 0; i < 0x10; i++) - X[i] = msg[4 * i + 0] | msg[4 * i + 1] << 8 | msg[4 * i + 2] << 16 | msg[4 * i + 3] << 24; - MD5_do_block(&state, block); - msg = msg.xslice_t(64); - } - // now pad 1-512 bits + the 64-bit length - may be two blocks - uint8_t buf[0x40] = {}; - really_memcpy(buf, reinterpret_cast<const uint8_t *>(msg.data()), msg.size()); - buf[msg.size()] = 0x80; // a single one bit - if (64 - msg.size() > 8) - { - for (int i = 0; i < 8; i++) - buf[0x38 + i] = (msg_full_len * 8) >> (i * 8); - } - for (int i = 0; i < 0x10; i++) - X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; - MD5_do_block(&state, block); - if (64 - msg.size() <= 8) - { - really_memset0(buf, 0x38); - for (int i = 0; i < 8; i++) - buf[0x38 + i] = (msg_full_len * 8) >> (i * 8); - for (int i = 0; i < 0x10; i++) - X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; - MD5_do_block(&state, block); - } - return state; -} - -// TODO - refactor MD5 into a stream, and merge the implementations -// I once implemented an ostream that does it ... -MD5_state MD5_from_FILE(io::ReadFile& in) -{ - uint64_t total_len = 0; - - uint8_t buf[0x40]; - uint8_t block_len = 0; - - MD5_state state; - MD5_init(&state); - - MD5_block block; - - while (true) - { - size_t rv = in.get(sign_cast<char *>(buf + block_len), 0x40 - block_len); - if (!rv) - break; - total_len += 8 * rv; // in bits - block_len += rv; - if (block_len != 0x40) - continue; - for (int i = 0; i < 0x10; i++) - X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; - MD5_do_block(&state, block); - block_len = 0; - } - // no more input, just pad and append the length - buf[block_len] = 0x80; - really_memset0(buf + block_len + 1, 0x40 - block_len - 1); - if (block_len < 0x38) - { - for (int i = 0; i < 8; i++) - buf[0x38 + i] = total_len >> i * 8; - } - for (int i = 0; i < 0x10; i++) - X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; - MD5_do_block(&state, block); - if (0x38 <= block_len) - { - really_memset0(buf, 0x38); - for (int i = 0; i < 8; i++) - buf[0x38 + i] = total_len >> i * 8; - for (int i = 0; i < 0x10; i++) - X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; - MD5_do_block(&state, block); - } - return state; -} - - -// Hash a password with a salt. -// Whoever wrote this FAILS programming -AccountCrypt MD5_saltcrypt(AccountPass key, SaltString salt) -{ - char cbuf[64] {}; - - // hash the key then the salt - // buf ends up as a 64-char NUL-terminated string - md5_string tbuf, tbuf2; - MD5_to_str(MD5_from_string(key), tbuf); - MD5_to_str(MD5_from_string(salt), tbuf2); - const auto it = std::copy(tbuf.begin(), tbuf.end(), std::begin(cbuf)); - auto it2 = std::copy(tbuf2.begin(), tbuf2.end(), it); - assert(it2 == std::end(cbuf)); - - md5_string tbuf3; - MD5_to_str(MD5_from_string(XString(std::begin(cbuf), it2, nullptr)), tbuf3); - - VString<31> obuf; - - // This truncates the string, but we have to keep it like that for compatibility - SNPRINTF(obuf, 32, "!%s$%s", salt, tbuf3); - return stringish<AccountCrypt>(obuf); -} - -SaltString make_salt(void) -{ - char salt[5]; - for (int i = 0; i < 5; i++) - // 126 would probably actually be okay - salt[i] = random_::in(48, 125); - return stringish<SaltString>(XString(salt + 0, salt + 5, nullptr)); -} - -bool pass_ok(AccountPass password, AccountCrypt crypted) -{ - // crypted is like !salt$hash - auto begin = crypted.begin() + 1; - auto end = std::find(begin, crypted.end(), '$'); - SaltString salt = stringish<SaltString>(crypted.xislice(begin, end)); - - return crypted == MD5_saltcrypt(password, salt); -} - -// [M|h]ashes up an IP address and a secret key -// to return a hopefully unique masked IP. -IP4Address MD5_ip(IP4Address ip) -{ - static SaltString secret = make_salt(); - - // MD5sum a secret + the IP address - VString<31> ipbuf; - SNPRINTF(ipbuf, 32, "%s %s", ip, secret); - md5_binary obuf; - MD5_to_bin(MD5_from_string(ipbuf), obuf); - - // Fold the md5sum to 32 bits, pack the bytes to an in_addr - return IP4Address({ - static_cast<uint8_t>(obuf[0] ^ obuf[1] ^ obuf[8] ^ obuf[9]), - static_cast<uint8_t>(obuf[2] ^ obuf[3] ^ obuf[10] ^ obuf[11]), - static_cast<uint8_t>(obuf[4] ^ obuf[5] ^ obuf[12] ^ obuf[13]), - static_cast<uint8_t>(obuf[6] ^ obuf[7] ^ obuf[14] ^ obuf[15]), - }); -} diff --git a/src/common/md5calc.hpp b/src/common/md5calc.hpp deleted file mode 100644 index 45bec84..0000000 --- a/src/common/md5calc.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef MD5CALC_HPP -#define MD5CALC_HPP - -# include "../sanity.hpp" - -# include <netinet/in.h> - -# include <cstdint> -# include <cstddef> -# include <cstdio> - -# include <array> - -# include "../strings/fwd.hpp" -# include "../strings/vstring.hpp" - -# include "../io/fwd.hpp" - -# include "ip.hpp" -# include "mmo.hpp" - -/// The digest state - becomes the output -struct MD5_state -{ - // classically named {A,B,C,D} - // but use an so we can index - uint32_t val[4]; -}; -struct MD5_block -{ - uint32_t data[16]; -}; - -struct md5_binary : std::array<uint8_t, 0x10> {}; -struct md5_string : VString<0x20> {}; -struct SaltString : VString<5> {}; - -// Implementation -void MD5_init(MD5_state *state); -void MD5_do_block(MD5_state *state, MD5_block block); - -// Output formatting -void MD5_to_bin(MD5_state state, md5_binary& out); -void MD5_to_str(MD5_state state, md5_string& out); - -// Convenience -MD5_state MD5_from_string(XString msg); -MD5_state MD5_from_FILE(io::ReadFile& in); - - -// whoever wrote this fails basic understanding of -AccountCrypt MD5_saltcrypt(AccountPass key, SaltString salt); - -/// return some random characters (statically allocated) -// Currently, returns a 5-char string -SaltString make_salt(void); - -/// check plaintext password against saved saltcrypt -bool pass_ok(AccountPass password, AccountCrypt crypted); - -/// This returns an IP4Address because it is configurable whether it gets called at all -IP4Address MD5_ip(IP4Address ip); - -#endif // MD5CALC_HPP diff --git a/src/common/md5calc_test.cpp b/src/common/md5calc_test.cpp deleted file mode 100644 index ab5f242..0000000 --- a/src/common/md5calc_test.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "md5calc.hpp" - -#include <gtest/gtest.h> - -#include "../strings/xstring.hpp" -#include "../strings/vstring.hpp" - -#include "utils.hpp" - -// This should be made part of the main API, -// but is not yet to keep the diff small. -// Edit: hack to fix the new strict comparison. -static -VString<32> MD5(XString in) -{ - md5_string out; - MD5_to_str(MD5_from_string(in), out); - return out; -} - -TEST(md5calc, rfc1321) -{ - EXPECT_EQ("d41d8cd98f00b204e9800998ecf8427e", MD5("")); - EXPECT_EQ("0cc175b9c0f1b6a831c399e269772661", MD5("a")); - EXPECT_EQ("900150983cd24fb0d6963f7d28e17f72", MD5("abc")); - EXPECT_EQ("f96b697d7cb7938d525a2f31aaf161d0", MD5("message digest")); - EXPECT_EQ("c3fcd3d76192e4007dfb496cca67e13b", MD5("abcdefghijklmnopqrstuvwxyz")); - EXPECT_EQ("d174ab98d277d9f5a5611c2c9f419d9f", MD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")); - EXPECT_EQ("57edf4a22be3c955ac49da2e2107b67a", MD5("12345678901234567890123456789012345678901234567890123456789012345678901234567890")); -} diff --git a/src/common/mmo.hpp b/src/common/mmo.hpp deleted file mode 100644 index bb30682..0000000 --- a/src/common/mmo.hpp +++ /dev/null @@ -1,380 +0,0 @@ -/// Global structures and defines -#ifndef MMO_HPP -#define MMO_HPP - -# include "../sanity.hpp" - -# include "../strings/vstring.hpp" - -# include "timer.t.hpp" -# include "utils2.hpp" - -// affects CharName -# define NAME_IGNORING_CASE 1 - -constexpr int FIFOSIZE_SERVERLINK = 256 * 1024; - -constexpr int MAX_MAP_PER_SERVER = 512; -constexpr int MAX_INVENTORY = 100; -constexpr int MAX_AMOUNT = 30000; -constexpr int MAX_ZENY = 1000000000; // 1G zeny - -enum class SkillID : uint16_t; -constexpr SkillID MAX_SKILL = SkillID(474); // not 450 -constexpr SkillID get_enum_min_value(SkillID) { return SkillID(); } -constexpr SkillID get_enum_max_value(SkillID) { return MAX_SKILL; } - -constexpr int GLOBAL_REG_NUM = 96; -constexpr int ACCOUNT_REG_NUM = 16; -constexpr int ACCOUNT_REG2_NUM = 16; -constexpr interval_t DEFAULT_WALK_SPEED = std::chrono::milliseconds(150); -constexpr interval_t MIN_WALK_SPEED = interval_t::zero(); -constexpr interval_t MAX_WALK_SPEED = std::chrono::seconds(1); -constexpr int MAX_STORAGE = 300; -constexpr int MAX_PARTY = 12; - -# define MIN_HAIR_STYLE battle_config.min_hair_style -# define MAX_HAIR_STYLE battle_config.max_hair_style -# define MIN_HAIR_COLOR battle_config.min_hair_color -# define MAX_HAIR_COLOR battle_config.max_hair_color -# define MIN_CLOTH_COLOR battle_config.min_cloth_color -# define MAX_CLOTH_COLOR battle_config.max_cloth_color - -struct AccountName : VString<23> {}; -struct AccountPass : VString<23> {}; -struct AccountCrypt : VString<39> {}; -struct AccountEmail : VString<39> {}; -struct ServerName : VString<19> {}; -struct PartyName : VString<23> {}; -struct VarName : VString<31> {}; -template<class T> -T stringish(VString<sizeof(T) - 1> iv) -{ - T rv; - static_cast<VString<sizeof(T) - 1>&>(rv) = iv; - return rv; -} -# define DEFAULT_EMAIL stringish<AccountEmail>("a@a.com") - -// It is decreed: a mapname shall not contain an extension -class MapName : public strings::_crtp_string<MapName, MapName, strings::ZPair> -{ - VString<15> _impl; -public: - MapName() = default; - MapName(VString<15> v) : _impl(v.xislice_h(std::find(v.begin(), v.end(), '.'))) {} - - iterator begin() const { return &*_impl.begin(); } - iterator end() const { return &*_impl.end(); } - const char *c_str() const { return _impl.c_str(); } - - operator RString() const { return _impl; } - operator AString() const { return _impl; } - operator TString() const { return _impl; } - operator SString() const { return _impl; } - operator ZString() const { return _impl; } - operator XString() const { return _impl; } -}; -template<> -inline -MapName stringish<MapName>(VString<15> iv) -{ - return iv; -} -inline -const char *decay_for_printf(const MapName& vs) { return vs.c_str(); } - -// It is decreed: a charname is sometimes case sensitive -struct CharName -{ -private: - VString<23> _impl; -public: - CharName() = default; - explicit CharName(VString<23> name) - : _impl(name) - {} - - VString<23> to__actual() const - { - return _impl; - } - VString<23> to__lower() const - { - return _impl.to_lower(); - } - VString<23> to__upper() const - { - return _impl.to_upper(); - } - VString<23> to__canonical() const - { -# if NAME_IGNORING_CASE == 0 - return to__actual(); -# endif -# if NAME_IGNORING_CASE == 1 - return to__lower(); -# endif - } - - friend bool operator == (const CharName& l, const CharName& r) - { return l.to__canonical() == r.to__canonical(); } - friend bool operator != (const CharName& l, const CharName& r) - { return l.to__canonical() != r.to__canonical(); } - friend bool operator < (const CharName& l, const CharName& r) - { return l.to__canonical() < r.to__canonical(); } - friend bool operator <= (const CharName& l, const CharName& r) - { return l.to__canonical() <= r.to__canonical(); } - friend bool operator > (const CharName& l, const CharName& r) - { return l.to__canonical() > r.to__canonical(); } - friend bool operator >= (const CharName& l, const CharName& r) - { return l.to__canonical() >= r.to__canonical(); } - - friend - VString<23> convert_for_printf(const CharName& vs) { return vs.to__actual(); } -}; -template<> -inline -CharName stringish<CharName>(VString<23> iv) -{ - return CharName(iv); -} - -namespace e -{ -enum class EPOS : uint16_t -{ - ZERO = 0x0000, - - LEGS = 0x0001, - WEAPON = 0x0002, - GLOVES = 0x0004, - CAPE = 0x0008, - MISC1 = 0x0010, - SHIELD = 0x0020, - SHOES = 0x0040, - MISC2 = 0x0080, - HAT = 0x0100, - TORSO = 0x0200, - - ARROW = 0x8000, -}; -ENUM_BITWISE_OPERATORS(EPOS) - -constexpr EPOS get_enum_min_value(EPOS) { return EPOS(0x0000); } -constexpr EPOS get_enum_max_value(EPOS) { return EPOS(0xffff); } -} -using e::EPOS; - -struct item -{ - int id; - short nameid; - short amount; - EPOS equip; -}; - -struct point -{ - MapName map_; - short x, y; -}; - -namespace e -{ -enum class SkillFlags : uint16_t; -} -using e::SkillFlags; - -struct skill_value -{ - unsigned short lv; - SkillFlags flags; - - friend bool operator == (const skill_value& l, const skill_value& r) - { - return l.lv == r.lv && l.flags == r.flags; - } - friend bool operator != (const skill_value& l, const skill_value& r) - { - return !(l == r); - } -}; - -struct global_reg -{ - VarName str; - int value; -}; - -// Option and Opt1..3 in map.hpp -namespace e -{ -enum class Option : uint16_t; -constexpr Option get_enum_min_value(Option) { return Option(0x0000); } -constexpr Option get_enum_max_value(Option) { return Option(0xffff); } -} -using e::Option; - -enum class ATTR -{ - STR = 0, - AGI = 1, - VIT = 2, - INT = 3, - DEX = 4, - LUK = 5, - - COUNT = 6, -}; - -constexpr ATTR ATTRs[6] = -{ - ATTR::STR, - ATTR::AGI, - ATTR::VIT, - ATTR::INT, - ATTR::DEX, - ATTR::LUK, -}; - -enum class ItemLook : uint16_t -{ - NONE = 0, - BLADE = 1, // or some other common weapons - _2, - SETZER_AND_SCYTHE = 3, - _6, - STAFF = 10, - BOW = 11, - _13 = 13, - _14 = 14, - _16 = 16, - SINGLE_HANDED_COUNT = 17, - - DUAL_BLADE = 0x11, - DUAL_2 = 0x12, - DUAL_6 = 0x13, - DUAL_12 = 0x14, - DUAL_16 = 0x15, - DUAL_26 = 0x16, -}; - -enum class SEX : uint8_t -{ - FEMALE = 0, - MALE = 1, - // For items. This is also used as error, sometime. - NEUTRAL = 2, -}; -inline -char sex_to_char(SEX sex) -{ - switch (sex) - { - case SEX::FEMALE: return 'F'; - case SEX::MALE: return 'M'; - default: return '\0'; - } -} -inline -SEX sex_from_char(char c) -{ - switch (c) - { - case 'F': return SEX::FEMALE; - case 'M': return SEX::MALE; - default: return SEX::NEUTRAL; - } -} - -struct CharKey -{ - CharName name; - int account_id; - int char_id; - unsigned char char_num; -}; - -struct CharData -{ - int partner_id; - - int base_exp, job_exp, zeny; - - short species; - short status_point, skill_point; - int hp, max_hp, sp, max_sp; - Option option; - short karma, manner; - short hair, hair_color, clothes_color; - int party_id; - - ItemLook weapon; - short shield; - short head_top, head_mid, head_bottom; - - unsigned char base_level, job_level; - earray<short, ATTR, ATTR::COUNT> attrs; - SEX sex; - - unsigned long mapip; - unsigned int mapport; - - struct point last_point, save_point; - struct item inventory[MAX_INVENTORY]; - earray<skill_value, SkillID, MAX_SKILL> skill; - int global_reg_num; - struct global_reg global_reg[GLOBAL_REG_NUM]; - int account_reg_num; - struct global_reg account_reg[ACCOUNT_REG_NUM]; - int account_reg2_num; - struct global_reg account_reg2[ACCOUNT_REG2_NUM]; -}; - -struct CharPair -{ - CharKey key; - std::unique_ptr<CharData> data; - - CharPair() - : key{}, data(make_unique<CharData>()) - {} -}; - -struct storage -{ - int dirty; - int account_id; - short storage_status; - short storage_amount; - struct item storage_[MAX_STORAGE]; -}; - -struct map_session_data; - -struct GM_Account -{ - int account_id; - uint8_t level; -}; - -struct party_member -{ - int account_id; - CharName name; - MapName map; - int leader, online, lv; - struct map_session_data *sd; -}; - -struct party -{ - int party_id; - PartyName name; - int exp; - int item; - struct party_member member[MAX_PARTY]; -}; - -#endif // MMO_HPP diff --git a/src/common/nullpo.cpp b/src/common/nullpo.cpp deleted file mode 100644 index 423ed8c..0000000 --- a/src/common/nullpo.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "nullpo.hpp" - -#include <cstdio> - -#include "../poison.hpp" - -/// Actual output function -static -void nullpo_info(const char *file, int line, const char *func) -{ - if (!file) - file = "??"; - if (!func || !*func) - func = "unknown"; - - fprintf(stderr, "%s:%d: in func `%s': NULL pointer\n", - file, line, func); -} - -bool nullpo_chk(const char *file, int line, const char *func, - const void *target) -{ - if (target) - return 0; - - nullpo_info(file, line, func); - return 1; -} diff --git a/src/common/nullpo.hpp b/src/common/nullpo.hpp deleted file mode 100644 index 0eaa1b2..0000000 --- a/src/common/nullpo.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/// return wrappers for unexpected NULL pointers -#ifndef NULLPO_HPP -#define NULLPO_HPP -/// Uncomment this to live dangerously -/// (really exist to detect mostly-unused variables) -//# define BUG_FREE - -/// All functions print to standard error (was: standard output) -/// nullpo_ret(cond) - return 0 if given pointer is NULL -/// nullpo_retv(cond) - just return (function returns void) -/// nullpo_retr(rv, cond) - return given value instead - -# ifndef BUG_FREE -# define nullpo_retr(ret, t) \ - if (nullpo_chk(__FILE__, __LINE__, __PRETTY_FUNCTION__, t)) \ - return ret; -# else // BUG_FREE -# define nullpo_retr(ret, t) /*t*/ -# endif // BUG_FREE - -# define nullpo_ret(t) nullpo_retr(0, t) -# define nullpo_retv(t) nullpo_retr(, t) - -# include "../sanity.hpp" - -/// Used by macros in this header -bool nullpo_chk(const char *file, int line, const char *func, - const void *target); - -template<class T> -bool nullpo_chk(const char *file, int line, const char *func, T target) -{ - return nullpo_chk(file, line, func, target.operator->()); -} -template<class T> -bool nullpo_chk(const char *file, int line, const char *func, T *target) -{ - return nullpo_chk(file, line, func, static_cast<const void *>(target)); -} - -#endif // NULLPO_HPP diff --git a/src/common/operators.hpp b/src/common/operators.hpp deleted file mode 100644 index 3d44b81..0000000 --- a/src/common/operators.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef OPERATORS_HPP -#define OPERATORS_HPP - -namespace _operators -{ - class Comparable {}; - - template<class T> - bool operator == (T l, T r) - { - return l.value == r.value; - } - - template<class T> - bool operator != (T l, T r) - { - return l.value != r.value; - } - - template<class T> - bool operator < (T l, T r) - { - return l.value < r.value; - } - - template<class T> - bool operator <= (T l, T r) - { - return l.value <= r.value; - } - - template<class T> - bool operator > (T l, T r) - { - return l.value > r.value; - } - - template<class T> - bool operator >= (T l, T r) - { - return l.value >= r.value; - } -} - -using _operators::Comparable; - -#endif // OPERATORS_HPP diff --git a/src/common/random.cpp b/src/common/random.cpp deleted file mode 100644 index 273dcec..0000000 --- a/src/common/random.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "random2.hpp" - -#include "../poison.hpp" - -namespace random_ -{ - std::mt19937 generate{std::random_device()()}; -} // namespace random_ diff --git a/src/common/random.hpp b/src/common/random.hpp deleted file mode 100644 index a694cce..0000000 --- a/src/common/random.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef RANDOM_HPP -#define RANDOM_HPP - -# include "random.t.hpp" - -# include "../sanity.hpp" - -# include <random> - -// This is not namespace random since that collides with a C function, -// but this can be revisited when everything goes into namespace tmwa. -namespace random_ -{ - /// Get a random number from 0 .. 2**32 - 1 - extern std::mt19937 generate; - - /// Get a random number from 0 .. bound - 1 - inline - int to(int bound) - { - std::uniform_int_distribution<int> dist(0, bound - 1); - return dist(generate); - } - - /// Get a random number from low .. high (inclusive!) - inline - int in(int low, int high) - { - std::uniform_int_distribution<int> dist(low, high); - return dist(generate); - } - - inline - bool coin() - { - // sigh, can't specify <bool> directly ... - std::uniform_int_distribution<int> dist(false, true); - return dist(generate); - } - - inline - bool chance(Fraction f) - { - if (f.num <= 0) - return false; - if (f.num >= f.den) - return true; - return random_::to(f.den) < f.num; - } - - // C is usually one of: - // std::vector<T> - // std::initializer_list<T> - // std::array<T, n> - template<class C> - auto choice(C&& c) -> decltype(*c.begin()) - { - return *(c.begin() + random_::to(c.size())); - } - - // allow bare braces - template<class T> - T choice(std::initializer_list<T>&& il) - { - return random_::choice(il); - } -} // namespace random_ - -#endif // RANDOM_HPP diff --git a/src/common/random.t.hpp b/src/common/random.t.hpp deleted file mode 100644 index 98a6c59..0000000 --- a/src/common/random.t.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef RANDOM_T_HPP -#define RANDOM_T_HPP - -namespace random_ -{ - struct Fraction - { - int num, den; - }; - - template<class T, T den> - struct Fixed - { - T num; - - operator Fraction() - { - return {num, den}; - } - }; -} // namespace random_ - -#endif // RANDOM_T_HPP diff --git a/src/common/random2.hpp b/src/common/random2.hpp deleted file mode 100644 index 86deddf..0000000 --- a/src/common/random2.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef RANDOM2_HPP -#define RANDOM2_HPP - -# include "random.hpp" -# include "utils2.hpp" - -# include <algorithm> - -namespace random_ -{ - namespace detail - { - struct RandomIterator - { - int bound; - int current; - bool frist; - - void operator ++() - { - frist = false; - // TODO: reimplement in terms of LFSRs, so that certain - // blockage patterns don't favor adjacent cells. - current = current + 1; - if (current == bound) - current = 0; - } - int operator *() - { - return current; - } - }; - - inline - bool operator == (RandomIterator l, RandomIterator r) - { - return l.current == r.current && l.frist == r.frist; - } - - inline - bool operator != (RandomIterator l, RandomIterator r) - { - return !(l == r); - } - } - - /// Yield every cell from 0 .. bound - 1 in some order. - /// The starting position is random, but not the order itself. - /// - /// Expected usage: - /// for (int i : random_::iterator(vec.size())) - /// if (vec[i].okay()) - /// return frob(vec[i]); - inline - IteratorPair<detail::RandomIterator> iterator(int bound) - { - int current = random_::to(bound); - return - { - detail::RandomIterator{bound, current, true}, - detail::RandomIterator{bound, current, false} - }; - } - - /// similar to std::random_shuffle(c.begin(), c.end()), but guaranteed - /// to use a good source of randomness. - template<class C> - void shuffle(C&& c) - { - std::random_shuffle(c.begin(), c.end(), random_::to); - } -} // namespace random_ - -#endif // RANDOM2_HPP diff --git a/src/common/socket.cpp b/src/common/socket.cpp deleted file mode 100644 index 73e32a4..0000000 --- a/src/common/socket.cpp +++ /dev/null @@ -1,474 +0,0 @@ -#include "socket.hpp" - -#include <arpa/inet.h> -#include <netinet/tcp.h> -#include <sys/socket.h> -//#include <sys/types.h> - -#include <fcntl.h> -#include <unistd.h> - -#include <cstdlib> -#include <cstring> -#include <ctime> - -#include "../io/cxxstdio.hpp" -#include "core.hpp" -#include "timer.hpp" -#include "utils.hpp" - -#include "../poison.hpp" - -static -io::FD_Set readfds; -static -int fd_max; - -static -const uint32_t RFIFO_SIZE = 65536; -static -const uint32_t WFIFO_SIZE = 65536; - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" -static -std::array<std::unique_ptr<Session>, FD_SETSIZE> session; -#pragma GCC diagnostic pop - -void set_session(io::FD fd, std::unique_ptr<Session> sess) -{ - int f = fd.uncast_dammit(); - assert (0 <= f && f < FD_SETSIZE); - session[f] = std::move(sess); -} -Session *get_session(io::FD fd) -{ - int f = fd.uncast_dammit(); - if (0 <= f && f < FD_SETSIZE) - return session[f].get(); - return nullptr; -} -void reset_session(io::FD fd) -{ - int f = fd.uncast_dammit(); - assert (0 <= f && f < FD_SETSIZE); - session[f] = nullptr; -} -int get_fd_max() { return fd_max; } -IteratorPair<ValueIterator<io::FD, IncrFD>> iter_fds() -{ - return {io::FD::cast_dammit(0), io::FD::cast_dammit(fd_max)}; -} - -/// clean up by discarding handled bytes -inline -void RFIFOFLUSH(Session *s) -{ - really_memmove(&s->rdata[0], &s->rdata[s->rdata_pos], RFIFOREST(s)); - s->rdata_size = RFIFOREST(s); - s->rdata_pos = 0; -} - -/// how much room there is to read more data -inline -size_t RFIFOSPACE(Session *s) -{ - return s->max_rdata - s->rdata_size; -} - - -/// Discard all input -static -void null_parse(Session *s); -/// Default parser for new connections -static -void (*default_func_parse)(Session *) = null_parse; - -void set_defaultparse(void (*defaultparse)(Session *)) -{ - default_func_parse = defaultparse; -} - -/// Read from socket to the queue -static -void recv_to_fifo(Session *s) -{ - if (s->eof) - return; - - ssize_t len = s->fd.read(&s->rdata[s->rdata_size], - RFIFOSPACE(s)); - - if (len > 0) - { - s->rdata_size += len; - s->connected = 1; - } - else - { - s->eof = 1; - } -} - -static -void send_from_fifo(Session *s) -{ - if (s->eof) - return; - - ssize_t len = s->fd.write(&s->wdata[0], s->wdata_size); - - if (len > 0) - { - s->wdata_size -= len; - if (s->wdata_size) - { - really_memmove(&s->wdata[0], &s->wdata[len], - s->wdata_size); - } - s->connected = 1; - } - else - { - s->eof = 1; - } -} - -static -void null_parse(Session *s) -{ - PRINTF("null_parse : %d\n", s); - RFIFOSKIP(s, RFIFOREST(s)); -} - - -static -void connect_client(Session *ls) -{ - struct sockaddr_in client_address; - socklen_t len = sizeof(client_address); - - io::FD fd = ls->fd.accept(reinterpret_cast<struct sockaddr *>(&client_address), &len); - if (fd == io::FD()) - { - perror("accept"); - return; - } - if (fd.uncast_dammit() >= SOFT_LIMIT) - { - FPRINTF(stderr, "softlimit reached, disconnecting : %d\n", fd.uncast_dammit()); - fd.shutdown(SHUT_RDWR); - fd.close(); - return; - } - if (fd_max <= fd.uncast_dammit()) - { - fd_max = fd.uncast_dammit() + 1; - } - - const int yes = 1; - /// Allow to bind() again after the server restarts. - // Since the socket is still in the TIME_WAIT, there's a possibility - // that formerly lost packets might be delivered and confuse the server. - fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - /// Send packets as soon as possible - /// even if the kernel thinks there is too little for it to be worth it! - /// Testing shows this is indeed a good idea. - fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); - - // Linux-ism: Set socket options to optimize for thin streams - // See http://lwn.net/Articles/308919/ and - // Documentation/networking/tcp-thin.txt .. Kernel 3.2+ -#ifdef TCP_THIN_LINEAR_TIMEOUTS - fd.setsockopt(IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof yes); -#endif -#ifdef TCP_THIN_DUPACK - fd.setsockopt(IPPROTO_TCP, TCP_THIN_DUPACK, &yes, sizeof yes); -#endif - - readfds.set(fd); - - fd.fcntl(F_SETFL, O_NONBLOCK); - - set_session(fd, make_unique<Session>()); - Session *s = get_session(fd); - s->fd = fd; - s->rdata.new_(RFIFO_SIZE); - s->wdata.new_(WFIFO_SIZE); - - s->max_rdata = RFIFO_SIZE; - s->max_wdata = WFIFO_SIZE; - s->func_recv = recv_to_fifo; - s->func_send = send_from_fifo; - s->func_parse = default_func_parse; - s->client_ip = IP4Address(client_address.sin_addr); - s->created = TimeT::now(); - s->connected = 0; -} - -Session *make_listen_port(uint16_t port) -{ - struct sockaddr_in server_address; - io::FD fd = io::FD::socket(AF_INET, SOCK_STREAM, 0); - if (fd == io::FD()) - { - perror("socket"); - return nullptr; - } - if (fd_max <= fd.uncast_dammit()) - fd_max = fd.uncast_dammit() + 1; - - fd.fcntl(F_SETFL, O_NONBLOCK); - - const int yes = 1; - /// Allow to bind() again after the server restarts. - // Since the socket is still in the TIME_WAIT, there's a possibility - // that formerly lost packets might be delivered and confuse the server. - fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - /// Send packets as soon as possible - /// even if the kernel thinks there is too little for it to be worth it! - // I'm not convinced this is a good idea; although in minimizes the - // latency for an individual write, it increases traffic in general. - fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); - - server_address.sin_family = AF_INET; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" -#if __GNUC__ > 4 || __GNUC_MINOR__ >= 8 -# pragma GCC diagnostic ignored "-Wuseless-cast" -#endif - server_address.sin_addr.s_addr = htonl(INADDR_ANY); - server_address.sin_port = htons(port); -#pragma GCC diagnostic pop - - if (fd.bind(reinterpret_cast<struct sockaddr *>(&server_address), - sizeof(server_address)) == -1) - { - perror("bind"); - exit(1); - } - if (fd.listen(5) == -1) - { /* error */ - perror("listen"); - exit(1); - } - - readfds.set(fd); - - set_session(fd, make_unique<Session>()); - Session *s = get_session(fd); - s->fd = fd; - - s->func_recv = connect_client; - s->created = TimeT::now(); - s->connected = 1; - - return s; -} - -Session *make_connection(IP4Address ip, uint16_t port) -{ - struct sockaddr_in server_address; - io::FD fd = io::FD::socket(AF_INET, SOCK_STREAM, 0); - if (fd == io::FD()) - { - perror("socket"); - return nullptr; - } - if (fd_max <= fd.uncast_dammit()) - fd_max = fd.uncast_dammit() + 1; - - const int yes = 1; - /// Allow to bind() again after the server restarts. - // Since the socket is still in the TIME_WAIT, there's a possibility - // that formerly lost packets might be delivered and confuse the server. - fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - /// Send packets as soon as possible - /// even if the kernel thinks there is too little for it to be worth it! - // I'm not convinced this is a good idea; although in minimizes the - // latency for an individual write, it increases traffic in general. - fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); - - server_address.sin_family = AF_INET; - server_address.sin_addr = in_addr(ip); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" -#if __GNUC__ > 4 || __GNUC_MINOR__ >= 8 -# pragma GCC diagnostic ignored "-Wuseless-cast" -#endif - server_address.sin_port = htons(port); -#pragma GCC diagnostic pop - - fd.fcntl(F_SETFL, O_NONBLOCK); - - /// Errors not caught - we must not block - /// Let the main select() loop detect when we know the state - fd.connect(reinterpret_cast<struct sockaddr *>(&server_address), - sizeof(struct sockaddr_in)); - - readfds.set(fd); - - set_session(fd, make_unique<Session>()); - Session *s = get_session(fd); - s->fd = fd; - s->rdata.new_(RFIFO_SIZE); - s->wdata.new_(WFIFO_SIZE); - - s->max_rdata = RFIFO_SIZE; - s->max_wdata = WFIFO_SIZE; - s->func_recv = recv_to_fifo; - s->func_send = send_from_fifo; - s->func_parse = default_func_parse; - s->created = TimeT::now(); - s->connected = 1; - - return s; -} - -void delete_session(Session *s) -{ - if (!s) - return; - - io::FD fd = s->fd; - // If this was the highest fd, decrease it - // We could add a loop to decrement fd_max further for every null session, - // but this is cheap and good enough for the typical case - if (fd.uncast_dammit() == fd_max - 1) - fd_max--; - readfds.clr(fd); - { - s->rdata.delete_(); - s->wdata.delete_(); - s->session_data.reset(); - reset_session(fd); - } - - // just close() would try to keep sending buffers - fd.shutdown(SHUT_RDWR); - fd.close(); -} - -void realloc_fifo(Session *s, size_t rfifo_size, size_t wfifo_size) -{ - if (s->max_rdata != rfifo_size && s->rdata_size < rfifo_size) - { - s->rdata.resize(rfifo_size); - s->max_rdata = rfifo_size; - } - if (s->max_wdata != wfifo_size && s->wdata_size < wfifo_size) - { - s->wdata.resize(wfifo_size); - s->max_wdata = wfifo_size; - } -} - -void WFIFOSET(Session *s, size_t len) -{ - if (s->wdata_size + len + 16384 > s->max_wdata) - { - realloc_fifo(s, s->max_rdata, s->max_wdata << 1); - PRINTF("socket: %d wdata expanded to %zu bytes.\n", s, s->max_wdata); - } - if (s->wdata_size + len + 2048 < s->max_wdata) - s->wdata_size += len; - else - FPRINTF(stderr, "socket: %d wdata lost !!\n", s), abort(); -} - -void do_sendrecv(interval_t next_ms) -{ - bool any = false; - io::FD_Set rfd = readfds, wfd; - for (io::FD i : iter_fds()) - { - Session *s = get_session(i); - if (s) - { - any = true; - if (s->wdata_size) - wfd.set(i); - } - } - if (!any) - { - if (!has_timers()) - { - PRINTF("Shutting down - nothing to do\n"); - runflag = false; - } - return; - } - struct timeval timeout; - { - std::chrono::seconds next_s = std::chrono::duration_cast<std::chrono::seconds>(next_ms); - std::chrono::microseconds next_us = next_ms - next_s; - timeout.tv_sec = next_s.count(); - timeout.tv_usec = next_us.count(); - } - if (io::FD_Set::select(fd_max, &rfd, &wfd, NULL, &timeout) <= 0) - return; - for (io::FD i : iter_fds()) - { - Session *s = get_session(i); - if (!s) - continue; - if (wfd.isset(i)) - { - if (s->func_send) - //send_from_fifo(i); - s->func_send(s); - } - if (rfd.isset(i)) - { - if (s->func_recv) - //recv_to_fifo(i); - //or connect_client(i); - s->func_recv(s); - } - } -} - -void do_parsepacket(void) -{ - for (io::FD i : iter_fds()) - { - Session *s = get_session(i); - if (!s) - continue; - if (!s->connected - && static_cast<time_t>(TimeT::now()) - static_cast<time_t>(s->created) > CONNECT_TIMEOUT) - { - PRINTF("Session #%d timed out\n", s); - s->eof = 1; - } - if (!s->rdata_size && !s->eof) - continue; - if (s->func_parse) - { - s->func_parse(s); - /// some func_parse may call delete_session - s = get_session(i); - if (s && s->eof) - { - delete_session(s); - s = nullptr; - } - if (!s) - continue; - } - /// Reclaim buffer space for what was read - RFIFOFLUSH(s); - } -} - -void RFIFOSKIP(Session *s, size_t len) -{ - s->rdata_pos += len; - - if (s->rdata_size < s->rdata_pos) - { - FPRINTF(stderr, "too many skip\n"); - abort(); - } -} diff --git a/src/common/socket.hpp b/src/common/socket.hpp deleted file mode 100644 index e0847ac..0000000 --- a/src/common/socket.hpp +++ /dev/null @@ -1,371 +0,0 @@ -#ifndef SOCKET_HPP -#define SOCKET_HPP - -# include "../sanity.hpp" - -# include <netinet/in.h> - -# include <cstdio> - -# include <array> - -# include "../strings/astring.hpp" -# include "../strings/vstring.hpp" -# include "../strings/xstring.hpp" - -# include "../io/fd.hpp" - -# include "dumb_ptr.hpp" -# include "ip.hpp" -# include "utils.hpp" -# include "timer.t.hpp" - -struct SessionData -{ -}; -struct SessionDeleter -{ - // defined per-server - void operator()(SessionData *sd); -}; - -// Struct declaration - -struct Session -{ - /// Checks whether a newly-connected socket actually does anything - TimeT created; - bool connected; - - /// Flag needed since structure must be freed in a server-dependent manner - bool eof; - - /// Since this is a single-threaded application, it can't block - /// These are the read/write queues - dumb_ptr<uint8_t[]> rdata, wdata; - size_t max_rdata, max_wdata; - /// How much is actually in the queue - size_t rdata_size, wdata_size; - /// How much has already been read from the queue - /// Note that there is no need for a wdata_pos - size_t rdata_pos; - - IP4Address client_ip; - - /// Send or recieve - /// Only called when select() indicates the socket is ready - /// If, after that, nothing is read, it sets eof - // These could probably be hard-coded with a little work - void (*func_recv)(Session *); - void (*func_send)(Session *); - /// This is the important one - /// Set to different functions depending on whether the connection - /// is a player or a server/ladmin - /// Can be set explicitly or via set_defaultparse - void (*func_parse)(Session *); - /// Server-specific data type - std::unique_ptr<SessionData, SessionDeleter> session_data; - - io::FD fd; -}; - -inline -int convert_for_printf(Session *s) -{ - return s->fd.uncast_dammit(); -} - -// save file descriptors for important stuff -constexpr int SOFT_LIMIT = FD_SETSIZE - 50; - -// socket timeout to establish a full connection in seconds -constexpr int CONNECT_TIMEOUT = 15; - - -void set_session(io::FD fd, std::unique_ptr<Session> sess); -Session *get_session(io::FD fd); -void reset_session(io::FD fd); -int get_fd_max(); - -class IncrFD -{ -public: - static - io::FD inced(io::FD v) - { - return io::FD::cast_dammit(v.uncast_dammit() + 1); - } -}; -IteratorPair<ValueIterator<io::FD, IncrFD>> iter_fds(); - - -/// open a socket, bind, and listen. Return an fd, or -1 if socket() fails, -/// but exit if bind() or listen() fails -Session *make_listen_port(uint16_t port); -/// Connect to an address, return a connected socket or -1 -// FIXME - this is IPv4 only! -Session *make_connection(IP4Address ip, uint16_t port); -/// free() the structure and close() the fd -void delete_session(Session *); -/// Make a the internal queues bigger -void realloc_fifo(Session *s, size_t rfifo_size, size_t wfifo_size); -/// Update all sockets that can be read/written from the queues -void do_sendrecv(interval_t next); -/// Call the parser function for every socket that has read data -void do_parsepacket(void); - -/// Change the default parser for newly connected clients -// typically called once per server, but individual clients may identify -// themselves as servers -void set_defaultparse(void(*defaultparse)(Session *)); - -template<class T> -uint8_t *pod_addressof_m(T& structure) -{ - static_assert(is_trivially_copyable<T>::value, "Can only byte-copy POD-ish structs"); - return &reinterpret_cast<uint8_t&>(structure); -} - -template<class T> -const uint8_t *pod_addressof_c(const T& structure) -{ - static_assert(is_trivially_copyable<T>::value, "Can only byte-copy POD-ish structs"); - return &reinterpret_cast<const uint8_t&>(structure); -} - - -/// Check how much can be read -inline -size_t RFIFOREST(Session *s) -{ - return s->rdata_size - s->rdata_pos; -} -/// Read from the queue -inline -const void *RFIFOP(Session *s, size_t pos) -{ - return &s->rdata[s->rdata_pos + pos]; -} -inline -uint8_t RFIFOB(Session *s, size_t pos) -{ - return *static_cast<const uint8_t *>(RFIFOP(s, pos)); -} -inline -uint16_t RFIFOW(Session *s, size_t pos) -{ - return *static_cast<const uint16_t *>(RFIFOP(s, pos)); -} -inline -uint32_t RFIFOL(Session *s, size_t pos) -{ - return *static_cast<const uint32_t *>(RFIFOP(s, pos)); -} -template<class T> -void RFIFO_STRUCT(Session *s, size_t pos, T& structure) -{ - really_memcpy(pod_addressof_m(structure), static_cast<const uint8_t *>(RFIFOP(s, pos)), sizeof(T)); -} -inline -IP4Address RFIFOIP(Session *s, size_t pos) -{ - IP4Address o; - RFIFO_STRUCT(s, pos, o); - return o; -} -template<uint8_t len> -inline -VString<len-1> RFIFO_STRING(Session *s, size_t pos) -{ - const char *const begin = static_cast<const char *>(RFIFOP(s, pos)); - const char *const end = begin + len-1; - const char *const mid = std::find(begin, end, '\0'); - return XString(begin, mid, nullptr); -} -inline -AString RFIFO_STRING(Session *s, size_t pos, size_t len) -{ - const char *const begin = static_cast<const char *>(RFIFOP(s, pos)); - const char *const end = begin + len; - const char *const mid = std::find(begin, end, '\0'); - return XString(begin, mid, nullptr); -} -inline -void RFIFO_BUF_CLONE(Session *s, uint8_t *buf, size_t len) -{ - really_memcpy(buf, static_cast<const uint8_t *>(RFIFOP(s, 0)), len); -} - -/// Done reading -void RFIFOSKIP(Session *s, size_t len); - -/// Read from an arbitrary buffer -inline -const void *RBUFP(const uint8_t *p, size_t pos) -{ - return p + pos; -} -inline -uint8_t RBUFB(const uint8_t *p, size_t pos) -{ - return *static_cast<const uint8_t *>(RBUFP(p, pos)); -} -inline -uint16_t RBUFW(const uint8_t *p, size_t pos) -{ - return *static_cast<const uint16_t *>(RBUFP(p, pos)); -} -inline -uint32_t RBUFL(const uint8_t *p, size_t pos) -{ - return *static_cast<const uint32_t *>(RBUFP(p, pos)); -} -template<class T> -void RBUF_STRUCT(const uint8_t *p, size_t pos, T& structure) -{ - really_memcpy(pod_addressof_m(structure), p + pos, sizeof(T)); -} -inline -IP4Address RBUFIP(const uint8_t *p, size_t pos) -{ - IP4Address o; - RBUF_STRUCT(p, pos, o); - return o; -} -template<uint8_t len> -inline -VString<len-1> RBUF_STRING(const uint8_t *p, size_t pos) -{ - const char *const begin = static_cast<const char *>(RBUFP(p, pos)); - const char *const end = begin + len-1; - const char *const mid = std::find(begin, end, '\0'); - return XString(begin, mid, nullptr); -} -inline -AString RBUF_STRING(const uint8_t *p, size_t pos, size_t len) -{ - const char *const begin = static_cast<const char *>(RBUFP(p, pos)); - const char *const end = begin + len; - const char *const mid = std::find(begin, end, '\0'); - return XString(begin, mid, nullptr); -} - - -/// Unused - check how much data can be written -// the existence of this seems scary -inline -size_t WFIFOSPACE(Session *s) -{ - return s->max_wdata - s->wdata_size; -} -/// Write to the queue -inline -void *WFIFOP(Session *s, size_t pos) -{ - return &s->wdata[s->wdata_size + pos]; -} -inline -uint8_t& WFIFOB(Session *s, size_t pos) -{ - return *static_cast<uint8_t *>(WFIFOP(s, pos)); -} -inline -uint16_t& WFIFOW(Session *s, size_t pos) -{ - return *static_cast<uint16_t *>(WFIFOP(s, pos)); -} -inline -uint32_t& WFIFOL(Session *s, size_t pos) -{ - return *static_cast<uint32_t *>(WFIFOP(s, pos)); -} -template<class T> -void WFIFO_STRUCT(Session *s, size_t pos, T& structure) -{ - really_memcpy(static_cast<uint8_t *>(WFIFOP(s, pos)), pod_addressof_c(structure), sizeof(T)); -} -inline -IP4Address& WFIFOIP(Session *s, size_t pos) -{ - static_assert(is_trivially_copyable<IP4Address>::value, "That was the whole point"); - return *static_cast<IP4Address *>(WFIFOP(s, pos)); -} -inline -void WFIFO_STRING(Session *s, size_t pos, XString str, size_t len) -{ - char *const begin = static_cast<char *>(WFIFOP(s, pos)); - char *const end = begin + len; - char *const mid = std::copy(str.begin(), str.end(), begin); - std::fill(mid, end, '\0'); -} -inline -void WFIFO_ZERO(Session *s, size_t pos, size_t len) -{ - uint8_t *b = static_cast<uint8_t *>(WFIFOP(s, pos)); - uint8_t *e = b + len; - std::fill(b, e, '\0'); -} -inline -void WFIFO_BUF_CLONE(Session *s, const uint8_t *buf, size_t len) -{ - really_memcpy(static_cast<uint8_t *>(WFIFOP(s, 0)), buf, len); -} - -/// Finish writing -void WFIFOSET(Session *s, size_t len); - -/// Write to an arbitrary buffer -inline -void *WBUFP(uint8_t *p, size_t pos) -{ - return p + pos; -} -inline -uint8_t& WBUFB(uint8_t *p, size_t pos) -{ - return *static_cast<uint8_t *>(WBUFP(p, pos)); -} -inline -uint16_t& WBUFW(uint8_t *p, size_t pos) -{ - return *static_cast<uint16_t *>(WBUFP(p, pos)); -} -inline -uint32_t& WBUFL(uint8_t *p, size_t pos) -{ - return *static_cast<uint32_t *>(WBUFP(p, pos)); -} -template<class T> -void WBUF_STRUCT(uint8_t *p, size_t pos, T& structure) -{ - really_memcpy(p + pos, pod_addressof_c(structure), sizeof(T)); -} -inline -IP4Address& WBUFIP(uint8_t *p, size_t pos) -{ - return *static_cast<IP4Address *>(WBUFP(p, pos)); -} -inline -void WBUF_STRING(uint8_t *p, size_t pos, XString s, size_t len) -{ - char *const begin = static_cast<char *>(WBUFP(p, pos)); - char *const end = begin + len; - char *const mid = std::copy(s.begin(), s.end(), begin); - std::fill(mid, end, '\0'); -} -inline -void WBUF_ZERO(uint8_t *p, size_t pos, size_t len) -{ - uint8_t *b = static_cast<uint8_t *>(WBUFP(p, pos)); - uint8_t *e = b + len; - std::fill(b, e, '\0'); -} - -inline -void RFIFO_WFIFO_CLONE(Session *rs, Session *ws, size_t len) -{ - really_memcpy(static_cast<uint8_t *>(WFIFOP(ws, 0)), - static_cast<const uint8_t *>(RFIFOP(rs, 0)), len); -} - -#endif // SOCKET_HPP diff --git a/src/common/timer.cpp b/src/common/timer.cpp deleted file mode 100644 index b5a2a5e..0000000 --- a/src/common/timer.cpp +++ /dev/null @@ -1,201 +0,0 @@ -#include "timer.hpp" - -#include <sys/stat.h> -#include <sys/time.h> - -#include <cassert> -#include <cstring> - -#include <queue> - -#include "../strings/zstring.hpp" - -#include "../io/cxxstdio.hpp" - -#include "utils.hpp" - -#include "../poison.hpp" - -struct TimerData -{ - /// This will be reset on call, to avoid problems. - Timer *owner; - - /// When it will be triggered - tick_t tick; - /// What will be done - timer_func func; - /// Repeat rate - 0 for oneshot - interval_t interval; - - TimerData(Timer *o, tick_t t, timer_func f, interval_t i) - : owner(o) - , tick(t) - , func(std::move(f)) - , interval(i) - {} -}; - -struct TimerCompare -{ - /// implement "less than" - bool operator() (dumb_ptr<TimerData> l, dumb_ptr<TimerData> r) - { - // C++ provides a max-heap, but we want - // the smallest tick to be the head (a min-heap). - return l->tick > r->tick; - } -}; - -static -std::priority_queue<dumb_ptr<TimerData>, std::vector<dumb_ptr<TimerData>>, TimerCompare> timer_heap; - - -tick_t gettick_cache; - -tick_t milli_clock::now(void) noexcept -{ - struct timeval tval; - // BUG: This will cause strange behavior if the system clock is changed! - // it should be reimplemented in terms of clock_gettime(CLOCK_MONOTONIC, ) - gettimeofday(&tval, NULL); - return gettick_cache = tick_t(std::chrono::seconds(tval.tv_sec) - + std::chrono::duration_cast<std::chrono::milliseconds>( - std::chrono::microseconds(tval.tv_usec))); -} - -static -void do_nothing(TimerData *, tick_t) -{ -} - -void Timer::cancel() -{ - if (!td) - return; - - assert (this == td->owner); - td->owner = nullptr; - td->func = do_nothing; - td->interval = interval_t::zero(); - td = nullptr; -} - -void Timer::detach() -{ - assert (this == td->owner); - td->owner = nullptr; - td = nullptr; -} - -static -void push_timer_heap(dumb_ptr<TimerData> td) -{ - timer_heap.push(td); -} - -static -dumb_ptr<TimerData> top_timer_heap(void) -{ - if (timer_heap.empty()) - return dumb_ptr<TimerData>(); - return timer_heap.top(); -} - -static -void pop_timer_heap(void) -{ - timer_heap.pop(); -} - -Timer::Timer(tick_t tick, timer_func func, interval_t interval) -: td(dumb_ptr<TimerData>::make(this, tick, std::move(func), interval)) -{ - assert (interval >= interval_t::zero()); - - push_timer_heap(td); -} - -Timer::Timer(Timer&& t) -: td(t.td) -{ - t.td = nullptr; - if (td) - { - assert (td->owner == &t); - td->owner = this; - } -} - -Timer& Timer::operator = (Timer&& t) -{ - std::swap(td, t.td); - if (td) - { - assert (td->owner == &t); - td->owner = this; - } - if (t.td) - { - assert (t.td->owner == this); - t.td->owner = &t; - } - return *this; -} - -interval_t do_timer(tick_t tick) -{ - /// Number of milliseconds until it calls this again - // this says to wait 1 sec if all timers get popped - interval_t nextmin = std::chrono::seconds(1); - - while (dumb_ptr<TimerData> td = top_timer_heap()) - { - // while the heap is not empty and - if (td->tick > tick) - { - /// Return the time until the next timer needs to goes off - nextmin = td->tick - tick; - break; - } - pop_timer_heap(); - - // Prevent destroying the object we're in. - // Note: this would be surprising in an interval timer, - // but all interval timers do an immediate explicit detach(). - if (td->owner) - td->owner->detach(); - // If we are too far past the requested tick, call with - // the current tick instead to fix reregistration problems - if (td->tick + std::chrono::seconds(1) < tick) - td->func(td.operator->(), tick); - else - td->func(td.operator->(), td->tick); - - if (td->interval == interval_t::zero()) - { - td.delete_(); - continue; - } - if (td->tick + std::chrono::seconds(1) < tick) - td->tick = tick + td->interval; - else - td->tick += td->interval; - push_timer_heap(td); - } - - return std::max(nextmin, std::chrono::milliseconds(10)); -} - -tick_t file_modified(ZString name) -{ - struct stat buf; - if (stat(name.c_str(), &buf)) - return tick_t(); - return tick_t(std::chrono::seconds(buf.st_mtime)); -} - -bool has_timers() -{ - return !timer_heap.empty(); -} diff --git a/src/common/timer.hpp b/src/common/timer.hpp deleted file mode 100644 index 7e187a3..0000000 --- a/src/common/timer.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef TIMER_HPP -#define TIMER_HPP - -# include "timer.t.hpp" - -# include "../sanity.hpp" - -# include "../strings/fwd.hpp" - -// updated automatically when using milli_clock::now() -// which is done only by core.cpp -extern tick_t gettick_cache; - -inline -tick_t gettick(void) -{ - return gettick_cache; -} - -/// Do all timers scheduled before tick, and return the number of -/// milliseconds until the next timer happens -interval_t do_timer(tick_t tick); - -/// Stat a file, and return its modification time, truncated to seconds. -tick_t file_modified(ZString name); - -/// Check if there are any events at all scheduled. -bool has_timers(); - -#endif // TIMER_HPP diff --git a/src/common/timer.t.hpp b/src/common/timer.t.hpp deleted file mode 100644 index 1e3a87a..0000000 --- a/src/common/timer.t.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef TIMER_T_HPP -#define TIMER_T_HPP - -# include <chrono> -# include <functional> - -# include "dumb_ptr.hpp" - -struct TimerData; - -/// An implementation of the C++ "clock" concept, exposing -/// durations in milliseconds. -class milli_clock -{ -public: - typedef std::chrono::milliseconds duration; - typedef duration::rep rep; - typedef duration::period period; - typedef std::chrono::time_point<milli_clock, duration> time_point; - static const bool is_steady = true; // assumed - not necessarily true - - static time_point now() noexcept; -}; - -/// A point in time. -typedef milli_clock::time_point tick_t; -/// The difference between two points in time. -typedef milli_clock::duration interval_t; -/// (to get additional arguments, use std::bind or a lambda). -typedef std::function<void (TimerData *, tick_t)> timer_func; - -class Timer -{ - friend struct TimerData; - dumb_ptr<TimerData> td; - - Timer(const Timer&) = delete; - Timer& operator = (const Timer&) = delete; -public: - /// Don't own anything yet. - Timer() = default; - /// Schedule a timer for the given tick. - /// If you do not wish to keep track of it, call disconnect(). - /// Otherwise, you may cancel() or replace (operator =) it later. - /// - /// If the interval argument is given, the timer will reschedule - /// itself again forever. Otherwise, it will disconnect() itself - /// just BEFORE it is called. - Timer(tick_t tick, timer_func func, interval_t interval=interval_t::zero()); - - Timer(Timer&& t); - Timer& operator = (Timer&& t); - ~Timer() { cancel(); } - - /// Cancel the delivery of this timer's function, and make it falsy. - /// Implementation note: this doesn't actually remove it, just sets - /// the functor to do_nothing, and waits for the tick before removing. - void cancel(); - /// Make it falsy without cancelling the timer, - void detach(); - - /// Check if there is a timer connected. - explicit operator bool() { return bool(td); } - /// Check if there is no connected timer. - bool operator !() { return !td; } -}; - -#endif // TIMER_T_HPP diff --git a/src/common/utils.cpp b/src/common/utils.cpp deleted file mode 100644 index 0dbf145..0000000 --- a/src/common/utils.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "utils.hpp" - -#include <netinet/in.h> -#include <sys/time.h> - -#include <algorithm> - -#include "../strings/astring.hpp" -#include "../strings/zstring.hpp" -#include "../strings/xstring.hpp" - -#include "../io/cxxstdio.hpp" -#include "../io/write.hpp" - -#include "extract.hpp" - -#include "../poison.hpp" - -//--------------------------------------------------- -// E-mail check: return 0 (not correct) or 1 (valid). -//--------------------------------------------------- -bool e_mail_check(XString email) -{ - // athena limits - if (email.size() < 3 || email.size() > 39) - return 0; - - // part of RFC limits (official reference of e-mail description) - XString::iterator at = std::find(email.begin(), email.end(), '@'); - if (at == email.end()) - return 0; - XString username = email.xislice_h(at); - XString hostname = email.xislice_t(at + 1); - if (!username || !hostname) - return 0; - if (hostname.contains('@')) - return 0; - if (hostname.front() == '.' || hostname.back() == '.') - return 0; - if (hostname.contains_seq("..")) - return 0; - if (email.contains_any(" ;")) - return 0; - return email.is_print(); -} - -//------------------------------------------------- -// Return numerical value of a switch configuration -// on/off, english, français, deutsch, español -//------------------------------------------------- -int config_switch(ZString str) -{ - if (str == "true" || str == "on" || str == "yes" - || str == "oui" || str == "ja" - || str == "si") - return 1; - if (str == "false" || str == "off" || str == "no" - || str == "non" || str == "nein") - return 0; - - int rv; - if (extract(str, &rv)) - return rv; - FPRINTF(stderr, "Fatal: bad option value %s", str); - abort(); -} - -static_assert(sizeof(timestamp_seconds_buffer) == 20, "seconds buffer"); -static_assert(sizeof(timestamp_milliseconds_buffer) == 24, "millis buffer"); - -void stamp_time(timestamp_seconds_buffer& out, const TimeT *t) -{ - struct tm when = t ? *t : TimeT::now(); - char buf[20]; - strftime(buf, 20, "%Y-%m-%d %H:%M:%S", &when); - out = stringish<timestamp_seconds_buffer>(const_(buf)); -} -void stamp_time(timestamp_milliseconds_buffer& out) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - struct tm when = TimeT(tv.tv_sec); - char buf[24]; - strftime(buf, 20, "%Y-%m-%d %H:%M:%S", &when); - sprintf(buf + 19, ".%03d", static_cast<int>(tv.tv_usec / 1000)); - out = stringish<timestamp_milliseconds_buffer>(const_(buf)); -} - -void log_with_timestamp(io::WriteFile& out, XString line) -{ - if (!line) - { - out.put('\n'); - return; - } - timestamp_milliseconds_buffer tmpstr; - stamp_time(tmpstr); - out.really_put(tmpstr.data(), tmpstr.size()); - out.really_put(": ", 2); - out.put_line(line); -} diff --git a/src/common/utils.hpp b/src/common/utils.hpp deleted file mode 100644 index 161cbd4..0000000 --- a/src/common/utils.hpp +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef UTILS_HPP -#define UTILS_HPP - -# include "../sanity.hpp" - -# include <cstdio> -# include <cstring> - -# include <type_traits> - -# include "../strings/fwd.hpp" -# include "../strings/vstring.hpp" - -# include "../io/fwd.hpp" - -# include "const_array.hpp" -# include "operators.hpp" -# include "utils2.hpp" - -template<class T> -struct is_trivially_copyable -: std::integral_constant<bool, - // come back when GCC actually implements the public traits properly - __has_trivial_copy(T) - && __has_trivial_assign(T) - && __has_trivial_destructor(T)> -{}; - -bool e_mail_check(XString email); -int config_switch (ZString str); - -inline -void really_memcpy(uint8_t *dest, const uint8_t *src, size_t n) -{ - memcpy(dest, src, n); -} - -inline -void really_memmove(uint8_t *dest, const uint8_t *src, size_t n) -{ - memmove(dest, src, n); -} -inline -bool really_memequal(const uint8_t *a, const uint8_t *b, size_t n) -{ - return memcmp(a, b, n) == 0; -} - -inline -void really_memset0(uint8_t *dest, size_t n) -{ - memset(dest, '\0', n); -} -template<class T> -void really_memzero_this(T *v) -{ - static_assert(is_trivially_copyable<T>::value, "only for mostly-pod types"); - static_assert(std::is_class<T>::value || std::is_union<T>::value, "Only for user-defined structures (for now)"); - memset(v, '\0', sizeof(*v)); -} -template<class T, size_t n> -void really_memzero_this(T (&)[n]) = delete; - -// Exists in place of time_t, to give it a predictable printf-format. -// (on x86 and amd64, time_t == long, but not on x32) -static_assert(sizeof(long long) >= sizeof(time_t), "long long >= time_t"); -struct TimeT : Comparable -{ - long long value; - - // conversion - TimeT(time_t t=0) : value(t) {} - TimeT(struct tm t) : value(timegm(&t)) {} - operator time_t() const { return value; } - operator struct tm() const { time_t v = value; return *gmtime(&v); } - - explicit operator bool() const { return value; } - bool operator !() const { return !value; } - - // prevent surprises - template<class T> - TimeT(T) = delete; - template<class T> - operator T() const = delete; - - static - TimeT now() - { - // poisoned, but this is still in header-land - return time(NULL); - } - - bool error() const - { - return value == -1; - } - bool okay() const - { - return !error(); - } -}; - -inline -long long convert_for_printf(TimeT t) -{ - return t.value; -} - -inline -long long& convert_for_scanf(TimeT& t) -{ - return t.value; -} - -struct timestamp_seconds_buffer : VString<19> {}; -struct timestamp_milliseconds_buffer : VString<23> {}; -void stamp_time(timestamp_seconds_buffer&, const TimeT *t=nullptr); -void stamp_time(timestamp_milliseconds_buffer&); - -void log_with_timestamp(io::WriteFile& out, XString line); - -// TODO VString? -# define TIMESTAMP_DUMMY "YYYY-MM-DD HH:MM:SS" -static_assert(sizeof(TIMESTAMP_DUMMY) == sizeof(timestamp_seconds_buffer), - "timestamp size"); -# define WITH_TIMESTAMP(str) str TIMESTAMP_DUMMY -// str: prefix: YYYY-MM-DD HH:MM:SS -// sizeof: 01234567890123456789012345678 -// str + sizeof: ^ -// -1: ^ -// there's probably a better way to do this now -# define REPLACE_TIMESTAMP(str, t) \ - stamp_time( \ - reinterpret_cast<timestamp_seconds_buffer *>( \ - str + sizeof(str) \ - )[-1], \ - &t \ - ) - -#endif //UTILS_HPP diff --git a/src/common/utils2.hpp b/src/common/utils2.hpp deleted file mode 100644 index 9af39e5..0000000 --- a/src/common/utils2.hpp +++ /dev/null @@ -1,256 +0,0 @@ -#ifndef UTILS2_HPP -#define UTILS2_HPP - -# include "../sanity.hpp" - -# include <algorithm> -# include <functional> -# include <iterator> -# include <memory> -# include <type_traits> - -# include "iter.hpp" - -# ifdef __clang__ -# define FALLTHROUGH [[clang::fallthrough]] -# else -# define FALLTHROUGH /* fallthrough */ -# endif - -template<class T, class E, E max> -struct earray -{ - // no ctor/dtor and one public member variable for easy initialization - T _data[size_t(max)]; - - T& operator[](E v) - { - return _data[size_t(v)]; - } - - const T& operator[](E v) const - { - return _data[size_t(v)]; - } - - T *begin() - { - return _data; - } - - T *end() - { - return _data + size_t(max); - } - - const T *begin() const - { - return _data; - } - - const T *end() const - { - return _data + size_t(max); - } - - friend bool operator == (const earray& l, const earray& r) - { - return std::equal(l.begin(), l.end(), r.begin()); - } - - friend bool operator != (const earray& l, const earray& r) - { - return !(l == r); - } -}; - -template<class T, class E> -class eptr -{ - T *_data; -public: - eptr(decltype(nullptr)=nullptr) - : _data(nullptr) - {} - - template<E max> - eptr(earray<T, E, max>& arr) - : _data(arr._data) - {} - - T& operator [](E v) - { - return _data[size_t(v)]; - } - - explicit operator bool() - { - return _data; - } - - bool operator not() - { - return not _data; - } -}; - -// std::underlying_type isn't supported until gcc 4.7 -// this is a poor man's emulation -template<class E> -struct underlying_type -{ - static_assert(std::is_enum<E>::value, "Only enums have underlying type!"); - typedef typename std::conditional< - std::is_signed<E>::value, - typename std::make_signed<E>::type, - typename std::make_unsigned<E>::type - >::type type; -}; - -template<class E, bool=std::is_enum<E>::value> -struct remove_enum -{ - typedef E type; -}; -template<class E> -struct remove_enum<E, true> -{ - typedef typename underlying_type<E>::type type; -}; - - -# define ENUM_BITWISE_OPERATORS(E) \ -inline \ -E operator & (E l, E r) \ -{ \ - typedef underlying_type<E>::type U; \ - return E(U(l) & U(r)); \ -} \ -inline \ -E operator | (E l, E r) \ -{ \ - typedef underlying_type<E>::type U; \ - return E(U(l) | U(r)); \ -} \ -inline \ -E operator ^ (E l, E r) \ -{ \ - typedef underlying_type<E>::type U; \ - return E(U(l) ^ U(r)); \ -} \ -inline \ -E& operator &= (E& l, E r) \ -{ \ - return l = l & r; \ -} \ -inline \ -E& operator |= (E& l, E r) \ -{ \ - return l = l | r; \ -} \ -inline \ -E& operator ^= (E& l, E r) \ -{ \ - return l = l ^ r; \ -} \ -inline \ -E operator ~ (E r) \ -{ \ - return E(-1) ^ r; \ -} - -template<class E> -class EnumMath -{ - typedef typename underlying_type<E>::type U; -public: - static - E inced(E v) - { - return E(U(v) + 1); - } -}; - -template<class E> -IteratorPair<ValueIterator<E, EnumMath<E>>> erange(E b, E e) -{ - return {b, e}; -} - -namespace ph = std::placeholders; - -template<class A, class B> -typename std::common_type<A, B>::type min(A a, B b) -{ - return a < b ? a : b; -} - -template<class A, class B> -typename std::common_type<A, B>::type max(A a, B b) -{ - return b < a ? a : b; -} - -template<class T> -struct is_array_of_unknown_bound -: std::is_same<T, typename std::remove_extent<T>::type[]> -{}; - -template<class T, class D=std::default_delete<T>, class... A> -typename std::enable_if<!is_array_of_unknown_bound<T>::value, std::unique_ptr<T, D>>::type make_unique(A&&... a) -{ - return std::unique_ptr<T, D>(new T(std::forward<A>(a)...)); -} - -template<class T, class D=std::default_delete<T>> -typename std::enable_if<is_array_of_unknown_bound<T>::value, std::unique_ptr<T, D>>::type make_unique(size_t sz) -{ - typedef typename std::remove_extent<T>::type E; - return std::unique_ptr<E[], D>(new E[sz]()); -} - -template<class T> -const T& const_(T& t) -{ - return t; -} - -template<class T, class U> -T no_cast(U&& u) -{ - typedef typename std::remove_reference<T>::type Ti; - typedef typename std::remove_reference<U>::type Ui; - typedef typename std::remove_cv<Ti>::type Tb; - typedef typename std::remove_cv<Ui>::type Ub; - static_assert(std::is_same<Tb, Ub>::value, "not no cast"); - return std::forward<U>(u); -} - -template<class T, class U> -T base_cast(U&& u) -{ - static_assert(std::is_reference<T>::value, "must base cast with references"); - typedef typename std::remove_reference<T>::type Ti; - typedef typename std::remove_reference<U>::type Ui; - typedef typename std::remove_cv<Ti>::type Tb; - typedef typename std::remove_cv<Ui>::type Ub; - static_assert(std::is_base_of<Tb, Ub>::value, "not base cast"); - return std::forward<U>(u); -} - -// use this when e.g. U is an int of unknown size -template<class T, class U> -T maybe_cast(U u) -{ - return u; -} - -template<class T, class U> -typename std::remove_pointer<T>::type *sign_cast(U *u) -{ - typedef typename std::remove_pointer<T>::type T_; - static_assert(sizeof(T_) == sizeof(U), "sign cast must be same size"); - return reinterpret_cast<T_ *>(u); -} - -#endif // UTILS2_HPP diff --git a/src/common/version.cpp b/src/common/version.cpp deleted file mode 100644 index 811ffdf..0000000 --- a/src/common/version.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "version.hpp" - -#include "../conf/version.hpp" - -#include "../strings/xstring.hpp" - -#include "extract.hpp" - -Version CURRENT_VERSION = -{ - VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, - VERSION_DEVEL, - - 0, 0, - VENDOR_VERSION, -}; -Version CURRENT_LOGIN_SERVER_VERSION = -{ - VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, - VERSION_DEVEL, - - 0, TMWA_SERVER_LOGIN, - VENDOR_VERSION, -}; -Version CURRENT_CHAR_SERVER_VERSION = -{ - VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, - VERSION_DEVEL, - - 0, TMWA_SERVER_CHAR | TMWA_SERVER_INTER, - VENDOR_VERSION, -}; -Version CURRENT_MAP_SERVER_VERSION = -{ - VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, - VERSION_DEVEL, - - 0, TMWA_SERVER_MAP, - VENDOR_VERSION, -}; - -#define S2(a) #a -#define S(a) S2(a) - -const char CURRENT_VERSION_STRING[] = "TMWA " - S(VERSION_MAJOR) "." S(VERSION_MINOR) "." S(VERSION_PATCH) - " dev" S(VERSION_DEVEL) " (" VENDOR " " S(VENDOR_VERSION) ")"; - -bool extract(XString str, Version *vers) -{ - *vers = {}; - return extract(str, record<'.'>(&vers->major, &vers->minor, &vers->patch)); -} diff --git a/src/common/version.hpp b/src/common/version.hpp deleted file mode 100644 index a2c4e05..0000000 --- a/src/common/version.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef TMWA_COMMON_VERSION_HPP -#define TMWA_COMMON_VERSION_HPP - -# include <cstdint> - -# include "../strings/fwd.hpp" - -// TODO make these bitwise enums -# define TMWA_FLAG_REGISTRATION 0x01 - -# define TMWA_SERVER_LOGIN 0x01 -# define TMWA_SERVER_CHAR 0x02 -# define TMWA_SERVER_INTER 0x04 -# define TMWA_SERVER_MAP 0x08 - -struct Version -{ - uint8_t major; - uint8_t minor; // flavor1 - uint8_t patch; // flavor2 - uint8_t devel; // flavor3 - - uint8_t flags; - uint8_t which; - uint16_t vend; - // can't add vendor name yet -}; -static_assert(sizeof(Version) == 8, "this is sent over the network, can't change"); - -extern Version CURRENT_VERSION; - -extern Version CURRENT_LOGIN_SERVER_VERSION; -extern Version CURRENT_CHAR_SERVER_VERSION; -extern Version CURRENT_MAP_SERVER_VERSION; - -extern const char CURRENT_VERSION_STRING[]; - -bool extract(XString str, Version *vers); - -constexpr -bool operator < (Version l, Version r) -{ - return (l.major < r.major - || (l.major == r.major - && (l.minor < r.minor - || (l.minor == r.minor - && (l.patch < r.patch - || (l.patch == r.patch - && (l.devel < r.devel - || (l.devel == r.devel - && l.vend < r.vend)))))))); -} -constexpr -bool operator > (Version l, Version r) -{ - return r < l; -} -constexpr -bool operator <= (Version l, Version r) -{ - return !(r < l); -} -constexpr -bool operator >= (Version l, Version r) -{ - return !(l < r); -} - -#endif // TMWA_COMMON_VERSION_HPP |