#ifndef CXXSTDIO_HPP #define CXXSTDIO_HPP // cxxstdio.hpp - pass C++ types through scanf/printf // // Copyright © 2011-2012 Ben Longbons // // 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 . #include "utils2.hpp" #include #include #include #include namespace cxxstdio { inline __attribute__((format(printf, 2, 0))) int do_vprint(FILE *out, const char *fmt, va_list ap) { return vfprintf(out, fmt, ap); } inline __attribute__((format(printf, 2, 0))) int do_vprint(std::string& out, const char *fmt, va_list ap) { int len; { va_list ap2; va_copy(ap2, ap); len = vsnprintf(nullptr, 0, fmt, ap2); va_end(ap2); } char buffer[len + 1]; vsnprintf(buffer, len + 1, fmt, ap); out = buffer; return len; } inline __attribute__((format(scanf, 2, 0))) int do_vscan(FILE *in, const char *fmt, va_list ap) { return vfscanf(in, fmt, ap); } inline __attribute__((format(scanf, 2, 0))) int do_vscan(const char *in, const char *fmt, va_list ap) { return vsscanf(in, fmt, ap); } inline __attribute__((format(scanf, 2, 0))) int do_vscan(const std::string& in, const char *fmt, va_list ap) { return do_vscan(in.c_str(), fmt, ap); } template inline __attribute__((format(printf, 2, 3))) int do_print(T&& t, const char *fmt, ...) throw() { int rv; va_list ap; va_start(ap, fmt); rv = do_vprint(std::forward(t), fmt, ap); va_end(ap); return rv; } template inline __attribute__((format(scanf, 2, 3))) int do_scan(T&& t, const char *fmt, ...) throw() { int rv; va_list ap; va_start(ap, fmt); rv = do_vscan(std::forward(t), fmt, ap); va_end(ap); return rv; } template typename remove_enum::type convert_for_printf(T v) { typedef typename remove_enum::type repr_type; return repr_type(v); } template::value>::type> T& convert_for_scanf(T& v) { return v; } template class EnumConverter { E& out; typedef typename underlying_type::type U; U mid; public: EnumConverter(E& e) : out(e), mid(0) {} ~EnumConverter() { if (U(E::min_value) <= mid && mid <= U(E::max_value)) out = E(mid); } U *operator &() { return ∣ } }; template::value>::type> EnumConverter convert_for_scanf(T& v) { return v; } inline const char *convert_for_printf(const std::string& s) { return s.c_str(); } class StringConverter { std::string& out; char *mid; public: StringConverter(std::string& s) : out(s), mid(nullptr) {} ~StringConverter() { if (mid) { out = mid; free(mid); } } char **operator &() { return ∣ } }; inline StringConverter convert_for_scanf(std::string& s) { return StringConverter(s); } template class PrintFormatter { public: template static int print(T&& t, A&&... a) { constexpr static const char *print_format = Format::print_format(); return do_print(std::forward(t), print_format, convert_for_printf(std::forward(a))...); } }; template class ScanFormatter { public: template static int scan(T&& t, A&&... a) { constexpr static const char *scan_format = Format::scan_format(); return do_scan(std::forward(t), scan_format, &convert_for_scanf(*a)...); } }; #define FPRINTF(file, fmt, args...) \ ({ \ struct format_impl \ { \ constexpr static \ const char *print_format() { return fmt; } \ }; \ cxxstdio::PrintFormatter::print(file, args); \ }) #define FSCANF(file, fmt, args...) \ ({ \ struct format_impl \ { \ constexpr static \ const char *scan_format() { return fmt; } \ }; \ cxxstdio::ScanFormatter::scan(file, args); \ }) #define PRINTF(fmt, args...) FPRINTF(stdout, fmt, args) #define STRPRINTF(str, fmt, args...) FPRINTF(str, fmt, args) #define SCANF(fmt, args...) FSCANF(stdin, fmt, args) #define SSCANF(str, fmt, args...) FSCANF(str, fmt, args) } // namespace cxxstdio #endif // CXXSTDIO_HPP