diff options
Diffstat (limited to 'src/io')
-rw-r--r-- | src/io/cxxstdio.cpp | 7 | ||||
-rw-r--r-- | src/io/cxxstdio.hpp | 194 | ||||
-rw-r--r-- | src/io/cxxstdio_enums.cpp | 26 | ||||
-rw-r--r-- | src/io/cxxstdio_enums.hpp | 77 | ||||
-rw-r--r-- | src/io/dir.cpp | 54 | ||||
-rw-r--r-- | src/io/dir.hpp | 50 | ||||
-rw-r--r-- | src/io/fd.cpp | 8 | ||||
-rw-r--r-- | src/io/fd.hpp | 44 | ||||
-rw-r--r-- | src/io/fwd.hpp | 10 | ||||
-rw-r--r-- | src/io/line.cpp | 43 | ||||
-rw-r--r-- | src/io/line.hpp | 31 | ||||
-rw-r--r-- | src/io/line_test.cpp | 207 | ||||
-rw-r--r-- | src/io/lock.cpp | 23 | ||||
-rw-r--r-- | src/io/lock.hpp | 14 | ||||
-rw-r--r-- | src/io/read.cpp | 15 | ||||
-rw-r--r-- | src/io/read.hpp | 17 | ||||
-rw-r--r-- | src/io/read_test.cpp | 26 | ||||
-rw-r--r-- | src/io/tty.cpp | 4 | ||||
-rw-r--r-- | src/io/tty.hpp | 30 | ||||
-rw-r--r-- | src/io/write.cpp | 15 | ||||
-rw-r--r-- | src/io/write.hpp | 21 | ||||
-rw-r--r-- | src/io/write_test.cpp | 25 |
22 files changed, 536 insertions, 405 deletions
diff --git a/src/io/cxxstdio.cpp b/src/io/cxxstdio.cpp index fbfdd46..ca4e880 100644 --- a/src/io/cxxstdio.cpp +++ b/src/io/cxxstdio.cpp @@ -1,5 +1,5 @@ #include "cxxstdio.hpp" -// cxxstdio.cpp - pass C++ types through scanf/printf +// cxxstdio.cpp - pass C++ types through printf // // Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> // @@ -19,3 +19,8 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include "../poison.hpp" + + +namespace tmwa +{ +} // namespace tmwa diff --git a/src/io/cxxstdio.hpp b/src/io/cxxstdio.hpp index 66419df..7312382 100644 --- a/src/io/cxxstdio.hpp +++ b/src/io/cxxstdio.hpp @@ -1,6 +1,5 @@ -#ifndef TMWA_IO_CXXSTDIO_HPP -#define TMWA_IO_CXXSTDIO_HPP -// cxxstdio.hpp - pass C++ types through scanf/printf +#pragma once +// cxxstdio.hpp - pass C++ types through printf // // Copyright © 2011-2013 Ben Longbons <b.r.longbons@gmail.com> // @@ -19,44 +18,27 @@ // 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 "fwd.hpp" -# include <cstdarg> -# include <cstdio> +#include <cstdarg> +#include <cstdio> -# include "../compat/cast.hpp" +#include "../compat/cast.hpp" -# include "../generic/enum.hpp" - -# include "fwd.hpp" +#include "../diagnostics.hpp" +namespace tmwa +{ namespace cxxstdio { - // other implementations of do_vprint or do_vscan are injected by ADL. + // other implementations of do_vprint are injected by ADL. 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(scanf, 2, 0))) - int do_vscan(FILE *in, const char *fmt, va_list ap) - { - return vfscanf(in, fmt, ap); - } - -# if 0 - inline __attribute__((format(scanf, 2, 0))) - int do_vscan(const char *in, const char *fmt, va_list ap) - { - return vsscanf(in, fmt, ap); - } -# else - inline - int do_vscan(const char *, const char *, va_list) = delete; -# endif - template<class T> inline __attribute__((format(printf, 2, 3))) int do_print(T&& t, const char *fmt, ...) @@ -69,24 +51,10 @@ namespace cxxstdio return rv; } - template<class T> - inline __attribute__((format(scanf, 2, 3))) - int do_scan(T&& t, const char *fmt, ...) - { - int rv; - va_list ap; - va_start(ap, fmt); - rv = do_vscan(std::forward<T>(t), fmt, ap); - va_end(ap); - return rv; - } - - template<class T, typename=typename std::enable_if<!std::is_class<T>::value>::type> - typename remove_enum<T>::type decay_for_printf(T v) + T decay_for_printf(T v) { - typedef typename remove_enum<T>::type repr_type; - return repr_type(v); + return v; } template<class T, typename=decltype(decay_for_printf(std::declval<T&&>()))> @@ -95,93 +63,8 @@ namespace cxxstdio return std::forward<T>(v); } - template<class T, typename = typename std::enable_if<!std::is_enum<T>::value>::type> - T& convert_for_scanf(T& v) - { - return v; - } - -# if 0 - template<class E> - constexpr - E get_enum_min_value(decltype(E::min_value)) - { - return E::min_value; - } - template<class E> - constexpr - E get_enum_min_value(E def) - { - return def; - } - - template<class E> - constexpr - E get_enum_max_value(decltype(E::max_value)) - { - return E::max_value; - } - template<class E> - constexpr - E get_enum_max_value(E def) - { - return def; - } -# else - template<class E> - constexpr - E get_enum_min_value(E) - { - return E::min_value; - } - template<class E> - constexpr - E get_enum_max_value(E) - { - return E::max_value; - } -# endif - - template<class E> - class EnumConverter - { - E& out; - typedef typename underlying_type<E>::type U; -# if 0 - constexpr static - U min_value = U(get_enum_min_value<E>(E(std::numeric_limits<U>::min()))); - constexpr static - U max_value = U(get_enum_max_value<E>(E(std::numeric_limits<U>::max()))); -# else - constexpr static - U min_value = U(get_enum_min_value(E())); - constexpr static - U max_value = U(get_enum_max_value(E())); -# endif - U mid; - public: - EnumConverter(E& e) - : out(e), mid(0) - {} - ~EnumConverter() - { -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wtype-limits" - if (min_value <= mid && mid <= max_value) -# pragma GCC diagnostic pop - out = E(mid); - } - U *operator &() - { - return ∣ - } - }; - - template<class T, typename = typename std::enable_if<std::is_enum<T>::value>::type> - EnumConverter<T> convert_for_scanf(T& v) - { - return v; - } + inline + const char *convert_for_printf(const char *) = delete; template<class Format> class PrintFormatter @@ -192,63 +75,35 @@ namespace cxxstdio int print(T&& t, A&&... a) { constexpr static - const char *print_format = Format::print_format(); + const char *print_format = Format::print_format().format_string(); return do_print(std::forward<T>(t), print_format, decay_for_printf(convert_for_printf(std::forward<A>(a)))...); } }; - template<class Format> - class ScanFormatter - { - public: - template<class T, class... A> - static - int scan(T&& t, A&&... a) - { - constexpr static - const char *scan_format = Format::scan_format(); - return do_scan(std::forward<T>(t), scan_format, - &convert_for_scanf(*a)...); - } - }; - -# define XPRINTF(out, fmt, ...) \ +#define XPRINTF(out, fmt, ...) \ ({ \ struct format_impl \ { \ constexpr static \ - const char *print_format() { return fmt; } \ + FormatString print_format() { return fmt; } \ }; \ cxxstdio::PrintFormatter<format_impl>::print(out, ## __VA_ARGS__); \ }) -# define XSCANF(out, fmt, ...) \ - ({ \ - struct format_impl \ - { \ - constexpr static \ - const char *scan_format() { return fmt; } \ - }; \ - cxxstdio::ScanFormatter<format_impl>::scan(out, ## __VA_ARGS__); \ - }) +#define FPRINTF(file, fmt, ...) XPRINTF(/*no_cast<FILE *>*/(file), fmt, ## __VA_ARGS__) +#define PRINTF(fmt, ...) FPRINTF(stdout, fmt, ## __VA_ARGS__) +#define SPRINTF(str, fmt, ...) XPRINTF(base_cast<AString&>(str), fmt, ## __VA_ARGS__) +#define SNPRINTF(str, n, fmt, ...) XPRINTF(base_cast<VString<n-1>&>(str), fmt, ## __VA_ARGS__) -# define FPRINTF(file, fmt, ...) XPRINTF(/*no_cast<FILE *>*/(file), fmt, ## __VA_ARGS__) -# define FSCANF(file, fmt, ...) XSCANF(no_cast<FILE *>(file), fmt, ## __VA_ARGS__) -# define PRINTF(fmt, ...) FPRINTF(stdout, fmt, ## __VA_ARGS__) -# define SPRINTF(str, fmt, ...) XPRINTF(base_cast<AString&>(str), fmt, ## __VA_ARGS__) -# define SNPRINTF(str, n, fmt, ...) XPRINTF(base_cast<VString<n-1>&>(str), fmt, ## __VA_ARGS__) -# define SCANF(fmt, ...) FSCANF(stdin, fmt, ## __VA_ARGS__) -# define SSCANF(str, fmt, ...) XSCANF(maybe_cast<ZString>(str), fmt, ## __VA_ARGS__) - -# define STRPRINTF(fmt, ...) \ +#define STRPRINTF(fmt, ...) \ ({ \ AString _out_impl; \ SPRINTF(_out_impl, fmt, ## __VA_ARGS__); \ _out_impl; \ }) -# define STRNPRINTF(n, fmt, ...) \ +#define STRNPRINTF(n, fmt, ...) \ ({ \ VString<n - 1> _out_impl; \ SNPRINTF(_out_impl, n, fmt, ## __VA_ARGS__); \ @@ -256,5 +111,4 @@ namespace cxxstdio }) } // namespace cxxstdio - -#endif // TMWA_IO_CXXSTDIO_HPP +} // namespace tmwa diff --git a/src/io/cxxstdio_enums.cpp b/src/io/cxxstdio_enums.cpp new file mode 100644 index 0000000..216da1d --- /dev/null +++ b/src/io/cxxstdio_enums.cpp @@ -0,0 +1,26 @@ +#include "cxxstdio_enums.hpp" +// cxxstdio_enums.cpp - Opt-in integer formatting support for enums. +// +// 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 "../poison.hpp" + + +namespace tmwa +{ +} // namespace tmwa diff --git a/src/io/cxxstdio_enums.hpp b/src/io/cxxstdio_enums.hpp new file mode 100644 index 0000000..05cdcae --- /dev/null +++ b/src/io/cxxstdio_enums.hpp @@ -0,0 +1,77 @@ +#pragma once +// cxxstdio_enums.hpp - Opt-in integer formatting support for enums. +// +// 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 "fwd.hpp" + +#include <cstdint> + +#include "../generic/enum.hpp" + + +namespace tmwa +{ +namespace e +{ +enum class BF : uint16_t; +enum class EPOS : uint16_t; +enum class MapCell : uint8_t; +enum class Option : uint16_t; + +inline +auto decay_for_printf(BF v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(EPOS v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(MapCell v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(Option v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +} + +namespace magic +{ +enum class SPELLARG : uint8_t; + +inline +auto decay_for_printf(SPELLARG v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +} + +enum class BL : uint8_t; +enum class ByteCode : uint8_t; +enum class ItemLook : uint16_t; +enum class MS : uint8_t; +enum class SP : uint16_t; +enum class SkillID : uint16_t; +enum class StatusChange : uint16_t; + +inline +auto decay_for_printf(BL v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(ByteCode v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(ItemLook v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(MS v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(SP v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(SkillID v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(StatusChange v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +} // namespace tmwa diff --git a/src/io/dir.cpp b/src/io/dir.cpp new file mode 100644 index 0000000..2acb75a --- /dev/null +++ b/src/io/dir.cpp @@ -0,0 +1,54 @@ +#include "dir.hpp" +// io/dir.cpp - rooted file operations +// +// 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 <fcntl.h> + +#include "../strings/zstring.hpp" + +#include "../poison.hpp" + + +namespace tmwa +{ +namespace io +{ + DirFd::DirFd() + : dirfd(FD::cast_dammit(AT_FDCWD)) + {} + + DirFd::DirFd(ZString path) + : dirfd(FD::open(path, O_DIRECTORY | O_RDONLY, 0)) + {} + + DirFd::DirFd(const DirFd& root, ZString path) + : dirfd(FD::openat(root.dirfd, path, O_DIRECTORY | O_RDONLY, 0)) + {} + + DirFd::~DirFd() + { + dirfd.close(); + } + + FD DirFd::open_fd(ZString name, int flags, int mode) const + { + return FD::openat(dirfd, name, flags, mode); + } +} // namespace io +} // namespace tmwa diff --git a/src/io/dir.hpp b/src/io/dir.hpp new file mode 100644 index 0000000..071f309 --- /dev/null +++ b/src/io/dir.hpp @@ -0,0 +1,50 @@ +#pragma once +// io/dir.hpp - rooted file operations +// +// 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 "fwd.hpp" + +#include "../strings/fwd.hpp" + +#include "fd.hpp" + + +namespace tmwa +{ +namespace io +{ + class DirFd + { + private: + FD dirfd; + + public: + DirFd(); + explicit + DirFd(ZString); + DirFd(const DirFd&, ZString); + + DirFd(const DirFd&) = delete; + ~DirFd(); + DirFd& operator = (const DirFd&) = delete; + + FD open_fd(ZString name, int flags, int mode=FD::DEFAULT_MODE) const; + }; +} // namespace io +} // namespace tmwa diff --git a/src/io/fd.cpp b/src/io/fd.cpp index 4fc33e9..c0b44e8 100644 --- a/src/io/fd.cpp +++ b/src/io/fd.cpp @@ -25,12 +25,19 @@ #include "../poison.hpp" + +namespace tmwa +{ namespace io { FD FD::open(ZString path, int flags, int mode) { return FD(::open(path.c_str(), flags, mode)); } + FD FD::openat(FD dirfd, ZString path, int flags, int mode) + { + return FD(::openat(dirfd.fd, path.c_str(), flags, mode)); + } FD FD::socket(int domain, int type, int protocol) { return FD(::socket(domain, type, protocol)); @@ -163,3 +170,4 @@ namespace io timeout, sigmask); } } // namespace io +} // namespace tmwa diff --git a/src/io/fd.hpp b/src/io/fd.hpp index 7afb40f..d04d5bf 100644 --- a/src/io/fd.hpp +++ b/src/io/fd.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_IO_FD_HPP -#define TMWA_IO_FD_HPP +#pragma once // io/fd.hpp - typesafe (but not scopesafe) file descriptors // // Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> @@ -19,16 +18,18 @@ // 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 "fwd.hpp" -# include <sys/select.h> -# include <sys/socket.h> +#include <sys/select.h> +#include <sys/socket.h> -# include <unistd.h> +#include "../strings/fwd.hpp" -# include "../strings/fwd.hpp" +#include "../diagnostics.hpp" +namespace tmwa +{ namespace io { class FD @@ -55,8 +56,13 @@ namespace io FD stdout() { return FD(1); } static FD stderr() { return FD(2); } + + static const int DEFAULT_MODE = 0666; + static - FD open(ZString path, int flags, int mode=0666); + FD open(ZString path, int flags, int mode=DEFAULT_MODE); + static + FD openat(FD dirfd, ZString path, int flags, int mode=DEFAULT_MODE); static FD socket(int domain, int type, int protocol); FD accept(struct sockaddr *addr, socklen_t *addrlen); @@ -64,6 +70,7 @@ namespace io int pipe(FD& r, FD& w); static int pipe2(FD& r, FD& w, int flags); + static FD sysconf_SC_OPEN_MAX(); @@ -138,24 +145,24 @@ namespace io } void clr(FD fd) { -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wold-style-cast" + DIAG_PUSH(); + DIAG_I(old_style_cast); FD_CLR(fd.uncast_dammit(), &fds); -# pragma GCC diagnostic pop + DIAG_POP(); } bool isset(FD fd) { -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wold-style-cast" + DIAG_PUSH(); + DIAG_I(old_style_cast); return FD_ISSET(fd.uncast_dammit(), &fds); -# pragma GCC diagnostic pop + DIAG_POP(); } void set(FD fd) { -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wold-style-cast" + DIAG_PUSH(); + DIAG_I(old_style_cast); FD_SET(fd.uncast_dammit(), &fds); -# pragma GCC diagnostic pop + DIAG_POP(); } static @@ -164,5 +171,4 @@ namespace io int pselect(int nfds, FD_Set *readfds, FD_Set *writefds, FD_Set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask); }; } // namespace io - -#endif // TMWA_IO_FD_HPP +} // namespace tmwa diff --git a/src/io/fwd.hpp b/src/io/fwd.hpp index 1e5fa82..deeb08c 100644 --- a/src/io/fwd.hpp +++ b/src/io/fwd.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_IO_FWD_HPP -#define TMWA_IO_FWD_HPP +#pragma once // io/fwd.hpp - Forward declarations of I/O classes // // Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> @@ -19,14 +18,15 @@ // 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 "../sanity.hpp" +namespace tmwa +{ namespace io { class ReadFile; class WriteFile; class AppendFile; } // namespace io - -#endif // TMWA_IO_FWD_HPP +} // namespace tmwa diff --git a/src/io/line.cpp b/src/io/line.cpp index f7470a6..a1cdf42 100644 --- a/src/io/line.cpp +++ b/src/io/line.cpp @@ -1,5 +1,5 @@ #include "line.hpp" -// io/line.hpp - Input from files, line-by-line +// io/line.cpp - Input from files, line-by-line // // Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> // @@ -18,44 +18,44 @@ // 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 <fcntl.h> -#include <unistd.h> - #include "../strings/astring.hpp" #include "../strings/mstring.hpp" #include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" #include "cxxstdio.hpp" #include "../poison.hpp" +namespace tmwa +{ namespace io { AString Line::message_str(ZString cat, ZString msg) const { MString out; if (column) - out += STRPRINTF("%s:%u:%u: %s: %s\n", + out += STRPRINTF("%s:%u:%u: %s: %s\n"_fmt, filename, line, column, cat, msg); else - out += STRPRINTF("%s:%u: %s: %s\n", + out += STRPRINTF("%s:%u: %s: %s\n"_fmt, filename, line, cat, msg); - out += STRPRINTF("%s\n", text); - out += STRPRINTF("%*c\n", column, '^'); + out += STRPRINTF("%s\n"_fmt, text); + out += STRPRINTF("%*c\n"_fmt, column, '^'); return AString(out); } void Line::message(ZString cat, ZString msg) const { if (column) - FPRINTF(stderr, "%s:%u:%u: %s: %s\n", + FPRINTF(stderr, "%s:%u:%u: %s: %s\n"_fmt, filename, line, column, cat, msg); else - FPRINTF(stderr, "%s:%u: %s: %s\n", + FPRINTF(stderr, "%s:%u: %s: %s\n"_fmt, filename, line, cat, msg); - FPRINTF(stderr, "%s\n", text); - FPRINTF(stderr, "%*c\n", column, '^'); + FPRINTF(stderr, "%s\n"_fmt, text); + FPRINTF(stderr, "%*c\n"_fmt, column, '^'); } AString LineSpan::message_str(ZString cat, ZString msg) const @@ -67,24 +67,24 @@ namespace io MString out; if (begin.line == end.line) { - out += STRPRINTF("%s:%u:%u: %s: %s\n", + out += STRPRINTF("%s:%u:%u: %s: %s\n"_fmt, begin.filename, begin.line, begin.column, cat, msg); - out += STRPRINTF("%s\n", begin.text); - out += STRPRINTF("%*c", begin.column, '^'); + out += STRPRINTF("%s\n"_fmt, begin.text); + out += STRPRINTF("%*c"_fmt, begin.column, '^'); for (unsigned c = begin.column; c != end.column; ++c) out += '~'; out += '\n'; } else { - out += STRPRINTF("%s:%u:%u: %s: %s\n", + out += STRPRINTF("%s:%u:%u: %s: %s\n"_fmt, begin.filename, begin.line, begin.column, cat, msg); - out += STRPRINTF("%s\n", begin.text); - out += STRPRINTF("%*c", begin.column, '^'); + out += STRPRINTF("%s\n"_fmt, begin.text); + out += STRPRINTF("%*c"_fmt, begin.column, '^'); for (unsigned c = begin.column; c != begin.text.size(); ++c) out += '~'; - out += " ...\n"; - out += STRPRINTF("%s\n", end.text); + out += " ...\n"_s; + out += STRPRINTF("%s\n"_fmt, end.text); for (unsigned c = 0; c != end.column; ++c) out += '~'; out += '\n'; @@ -94,7 +94,7 @@ namespace io void LineSpan::message(ZString cat, ZString msg) const { - FPRINTF(stderr, "%s", message_str(cat, msg)); + FPRINTF(stderr, "%s"_fmt, message_str(cat, msg)); } LineReader::LineReader(ZString name) @@ -180,3 +180,4 @@ namespace io return line != 0; } } // namespace io +} // namespace tmwa diff --git a/src/io/line.hpp b/src/io/line.hpp index a9e8944..8244c5e 100644 --- a/src/io/line.hpp +++ b/src/io/line.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_IO_LINE_HPP -#define TMWA_IO_LINE_HPP +#pragma once // io/line.hpp - Input from files, line-by-line // // Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> @@ -19,16 +18,17 @@ // 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 "fwd.hpp" -# include "../strings/rstring.hpp" -# include "../strings/astring.hpp" -# include "../strings/zstring.hpp" +#include "../strings/rstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/literal.hpp" -# include "fd.hpp" -# include "read.hpp" +#include "read.hpp" +namespace tmwa +{ namespace io { // TODO split this out @@ -42,9 +42,9 @@ namespace io AString message_str(ZString cat, ZString msg) const; void message(ZString cat, ZString msg) const; - void note(ZString msg) const { message("note", msg); } - void warning(ZString msg) const { message("warning", msg); } - void error(ZString msg) const { message("error", msg); } + void note(ZString msg) const { message("note"_s, msg); } + void warning(ZString msg) const { message("warning"_s, msg); } + void error(ZString msg) const { message("error"_s, msg); } }; // psst, don't tell anyone @@ -65,9 +65,9 @@ namespace io AString message_str(ZString cat, ZString msg) const; void message(ZString cat, ZString msg) const; - void note(ZString msg) const { message("note", msg); } - void warning(ZString msg) const { message("warning", msg); } - void error(ZString msg) const { message("error", msg); } + void note(ZString msg) const { message("note"_s, msg); } + void warning(ZString msg) const { message("warning"_s, msg); } + void error(ZString msg) const { message("error"_s, msg); } }; class LineReader @@ -104,5 +104,4 @@ namespace io bool is_open(); }; } // namespace io - -#endif // TMWA_IO_LINE_HPP +} // namespace tmwa diff --git a/src/io/line_test.cpp b/src/io/line_test.cpp index feee1fb..edf60bd 100644 --- a/src/io/line_test.cpp +++ b/src/io/line_test.cpp @@ -20,10 +20,14 @@ #include <gtest/gtest.h> +#include "../strings/astring.hpp" #include "../strings/zstring.hpp" #include "../poison.hpp" + +namespace tmwa +{ static io::FD string_pipe(ZString sz) { @@ -42,80 +46,80 @@ io::FD string_pipe(ZString sz) TEST(io, line1) { - io::LineReader lr("<string1>", string_pipe("Hello World\n")); + io::LineReader lr("<string1>"_s, string_pipe("Hello World\n"_s)); io::Line hi; EXPECT_TRUE(lr.read_line(hi)); - EXPECT_EQ(hi.text, "Hello World"); - EXPECT_EQ(hi.filename, "<string1>"); + EXPECT_EQ(hi.text, "Hello World"_s); + EXPECT_EQ(hi.filename, "<string1>"_s); EXPECT_EQ(hi.line, 1); EXPECT_EQ(hi.column, 0); EXPECT_FALSE(lr.read_line(hi)); } TEST(io, line2) { - io::LineReader lr("<string2>", string_pipe("Hello\nWorld")); + io::LineReader lr("<string2>"_s, string_pipe("Hello\nWorld"_s)); io::Line hi; EXPECT_TRUE(lr.read_line(hi)); - EXPECT_EQ(hi.text, "Hello"); - EXPECT_EQ(hi.filename, "<string2>"); + EXPECT_EQ(hi.text, "Hello"_s); + EXPECT_EQ(hi.filename, "<string2>"_s); EXPECT_EQ(hi.line, 1); EXPECT_EQ(hi.column, 0); EXPECT_TRUE(lr.read_line(hi)); - EXPECT_EQ(hi.text, "World"); - EXPECT_EQ(hi.filename, "<string2>"); + EXPECT_EQ(hi.text, "World"_s); + EXPECT_EQ(hi.filename, "<string2>"_s); EXPECT_EQ(hi.line, 2); EXPECT_EQ(hi.column, 0); EXPECT_FALSE(lr.read_line(hi)); } TEST(io, line3) { - io::LineReader lr("<string3>", string_pipe("Hello\rWorld")); + io::LineReader lr("<string3>"_s, string_pipe("Hello\rWorld"_s)); io::Line hi; EXPECT_TRUE(lr.read_line(hi)); - EXPECT_EQ(hi.text, "Hello"); - EXPECT_EQ(hi.filename, "<string3>"); + EXPECT_EQ(hi.text, "Hello"_s); + EXPECT_EQ(hi.filename, "<string3>"_s); EXPECT_EQ(hi.line, 1); EXPECT_EQ(hi.column, 0); EXPECT_TRUE(lr.read_line(hi)); - EXPECT_EQ(hi.text, "World"); - EXPECT_EQ(hi.filename, "<string3>"); + EXPECT_EQ(hi.text, "World"_s); + EXPECT_EQ(hi.filename, "<string3>"_s); EXPECT_EQ(hi.line, 2); EXPECT_EQ(hi.column, 0); EXPECT_FALSE(lr.read_line(hi)); } TEST(io, line4) { - io::LineReader lr("<string4>", string_pipe("Hello\r\nWorld")); + io::LineReader lr("<string4>"_s, string_pipe("Hello\r\nWorld"_s)); io::Line hi; EXPECT_TRUE(lr.read_line(hi)); - EXPECT_EQ(hi.text, "Hello"); - EXPECT_EQ(hi.filename, "<string4>"); + EXPECT_EQ(hi.text, "Hello"_s); + EXPECT_EQ(hi.filename, "<string4>"_s); EXPECT_EQ(hi.line, 1); EXPECT_EQ(hi.column, 0); EXPECT_TRUE(lr.read_line(hi)); - EXPECT_EQ(hi.text, "World"); - EXPECT_EQ(hi.filename, "<string4>"); + EXPECT_EQ(hi.text, "World"_s); + EXPECT_EQ(hi.filename, "<string4>"_s); EXPECT_EQ(hi.line, 2); EXPECT_EQ(hi.column, 0); EXPECT_FALSE(lr.read_line(hi)); } TEST(io, line5) { - io::LineReader lr("<string5>", string_pipe("Hello\n\rWorld")); + io::LineReader lr("<string5>"_s, string_pipe("Hello\n\rWorld"_s)); io::Line hi; EXPECT_TRUE(lr.read_line(hi)); - EXPECT_EQ(hi.text, "Hello"); - EXPECT_EQ(hi.filename, "<string5>"); + EXPECT_EQ(hi.text, "Hello"_s); + EXPECT_EQ(hi.filename, "<string5>"_s); EXPECT_EQ(hi.line, 1); EXPECT_EQ(hi.column, 0); EXPECT_TRUE(lr.read_line(hi)); - EXPECT_EQ(hi.text, ""); - EXPECT_EQ(hi.filename, "<string5>"); + EXPECT_EQ(hi.text, ""_s); + EXPECT_EQ(hi.filename, "<string5>"_s); EXPECT_EQ(hi.line, 2); EXPECT_EQ(hi.column, 0); EXPECT_TRUE(lr.read_line(hi)); - EXPECT_EQ(hi.text, "World"); - EXPECT_EQ(hi.filename, "<string5>"); + EXPECT_EQ(hi.text, "World"_s); + EXPECT_EQ(hi.filename, "<string5>"_s); EXPECT_EQ(hi.line, 3); EXPECT_EQ(hi.column, 0); EXPECT_FALSE(lr.read_line(hi)); @@ -123,47 +127,47 @@ TEST(io, line5) TEST(io, linechar1) { - io::LineCharReader lr("<stringchar1>", string_pipe("Hi Wu\n")); + io::LineCharReader lr("<stringchar1>"_s, string_pipe("Hi Wu\n"_s)); io::LineChar c; EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'H'); - EXPECT_EQ(c.text, "Hi Wu"); - EXPECT_EQ(c.filename, "<stringchar1>"); + EXPECT_EQ(c.text, "Hi Wu"_s); + EXPECT_EQ(c.filename, "<stringchar1>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 1); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'i'); - EXPECT_EQ(c.text, "Hi Wu"); - EXPECT_EQ(c.filename, "<stringchar1>"); + EXPECT_EQ(c.text, "Hi Wu"_s); + EXPECT_EQ(c.filename, "<stringchar1>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 2); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), ' '); - EXPECT_EQ(c.text, "Hi Wu"); - EXPECT_EQ(c.filename, "<stringchar1>"); + EXPECT_EQ(c.text, "Hi Wu"_s); + EXPECT_EQ(c.filename, "<stringchar1>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 3); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'W'); - EXPECT_EQ(c.text, "Hi Wu"); - EXPECT_EQ(c.filename, "<stringchar1>"); + EXPECT_EQ(c.text, "Hi Wu"_s); + EXPECT_EQ(c.filename, "<stringchar1>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 4); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'u'); - EXPECT_EQ(c.text, "Hi Wu"); - EXPECT_EQ(c.filename, "<stringchar1>"); + EXPECT_EQ(c.text, "Hi Wu"_s); + EXPECT_EQ(c.filename, "<stringchar1>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 5); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), '\n'); - EXPECT_EQ(c.text, "Hi Wu"); - EXPECT_EQ(c.filename, "<stringchar1>"); + EXPECT_EQ(c.text, "Hi Wu"_s); + EXPECT_EQ(c.filename, "<stringchar1>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 6); lr.adv(); @@ -171,47 +175,47 @@ TEST(io, linechar1) } TEST(io, linechar2) { - io::LineCharReader lr("<stringchar2>", string_pipe("Hi\nWu")); + io::LineCharReader lr("<stringchar2>"_s, string_pipe("Hi\nWu"_s)); io::LineChar c; EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'H'); - EXPECT_EQ(c.text, "Hi"); - EXPECT_EQ(c.filename, "<stringchar2>"); + EXPECT_EQ(c.text, "Hi"_s); + EXPECT_EQ(c.filename, "<stringchar2>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 1); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'i'); - EXPECT_EQ(c.text, "Hi"); - EXPECT_EQ(c.filename, "<stringchar2>"); + EXPECT_EQ(c.text, "Hi"_s); + EXPECT_EQ(c.filename, "<stringchar2>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 2); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), '\n'); - EXPECT_EQ(c.text, "Hi"); - EXPECT_EQ(c.filename, "<stringchar2>"); + EXPECT_EQ(c.text, "Hi"_s); + EXPECT_EQ(c.filename, "<stringchar2>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 3); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'W'); - EXPECT_EQ(c.text, "Wu"); - EXPECT_EQ(c.filename, "<stringchar2>"); + EXPECT_EQ(c.text, "Wu"_s); + EXPECT_EQ(c.filename, "<stringchar2>"_s); EXPECT_EQ(c.line, 2); EXPECT_EQ(c.column, 1); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'u'); - EXPECT_EQ(c.text, "Wu"); - EXPECT_EQ(c.filename, "<stringchar2>"); + EXPECT_EQ(c.text, "Wu"_s); + EXPECT_EQ(c.filename, "<stringchar2>"_s); EXPECT_EQ(c.line, 2); EXPECT_EQ(c.column, 2); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), '\n'); - EXPECT_EQ(c.text, "Wu"); - EXPECT_EQ(c.filename, "<stringchar2>"); + EXPECT_EQ(c.text, "Wu"_s); + EXPECT_EQ(c.filename, "<stringchar2>"_s); EXPECT_EQ(c.line, 2); EXPECT_EQ(c.column, 3); lr.adv(); @@ -219,47 +223,47 @@ TEST(io, linechar2) } TEST(io, linechar3) { - io::LineCharReader lr("<stringchar3>", string_pipe("Hi\rWu")); + io::LineCharReader lr("<stringchar3>"_s, string_pipe("Hi\rWu"_s)); io::LineChar c; EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'H'); - EXPECT_EQ(c.text, "Hi"); - EXPECT_EQ(c.filename, "<stringchar3>"); + EXPECT_EQ(c.text, "Hi"_s); + EXPECT_EQ(c.filename, "<stringchar3>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 1); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'i'); - EXPECT_EQ(c.text, "Hi"); - EXPECT_EQ(c.filename, "<stringchar3>"); + EXPECT_EQ(c.text, "Hi"_s); + EXPECT_EQ(c.filename, "<stringchar3>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 2); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), '\n'); - EXPECT_EQ(c.text, "Hi"); - EXPECT_EQ(c.filename, "<stringchar3>"); + EXPECT_EQ(c.text, "Hi"_s); + EXPECT_EQ(c.filename, "<stringchar3>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 3); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'W'); - EXPECT_EQ(c.text, "Wu"); - EXPECT_EQ(c.filename, "<stringchar3>"); + EXPECT_EQ(c.text, "Wu"_s); + EXPECT_EQ(c.filename, "<stringchar3>"_s); EXPECT_EQ(c.line, 2); EXPECT_EQ(c.column, 1); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'u'); - EXPECT_EQ(c.text, "Wu"); - EXPECT_EQ(c.filename, "<stringchar3>"); + EXPECT_EQ(c.text, "Wu"_s); + EXPECT_EQ(c.filename, "<stringchar3>"_s); EXPECT_EQ(c.line, 2); EXPECT_EQ(c.column, 2); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), '\n'); - EXPECT_EQ(c.text, "Wu"); - EXPECT_EQ(c.filename, "<stringchar3>"); + EXPECT_EQ(c.text, "Wu"_s); + EXPECT_EQ(c.filename, "<stringchar3>"_s); EXPECT_EQ(c.line, 2); EXPECT_EQ(c.column, 3); lr.adv(); @@ -267,47 +271,47 @@ TEST(io, linechar3) } TEST(io, linechar4) { - io::LineCharReader lr("<stringchar4>", string_pipe("Hi\r\nWu")); + io::LineCharReader lr("<stringchar4>"_s, string_pipe("Hi\r\nWu"_s)); io::LineChar c; EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'H'); - EXPECT_EQ(c.text, "Hi"); - EXPECT_EQ(c.filename, "<stringchar4>"); + EXPECT_EQ(c.text, "Hi"_s); + EXPECT_EQ(c.filename, "<stringchar4>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 1); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'i'); - EXPECT_EQ(c.text, "Hi"); - EXPECT_EQ(c.filename, "<stringchar4>"); + EXPECT_EQ(c.text, "Hi"_s); + EXPECT_EQ(c.filename, "<stringchar4>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 2); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), '\n'); - EXPECT_EQ(c.text, "Hi"); - EXPECT_EQ(c.filename, "<stringchar4>"); + EXPECT_EQ(c.text, "Hi"_s); + EXPECT_EQ(c.filename, "<stringchar4>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 3); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'W'); - EXPECT_EQ(c.text, "Wu"); - EXPECT_EQ(c.filename, "<stringchar4>"); + EXPECT_EQ(c.text, "Wu"_s); + EXPECT_EQ(c.filename, "<stringchar4>"_s); EXPECT_EQ(c.line, 2); EXPECT_EQ(c.column, 1); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'u'); - EXPECT_EQ(c.text, "Wu"); - EXPECT_EQ(c.filename, "<stringchar4>"); + EXPECT_EQ(c.text, "Wu"_s); + EXPECT_EQ(c.filename, "<stringchar4>"_s); EXPECT_EQ(c.line, 2); EXPECT_EQ(c.column, 2); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), '\n'); - EXPECT_EQ(c.text, "Wu"); - EXPECT_EQ(c.filename, "<stringchar4>"); + EXPECT_EQ(c.text, "Wu"_s); + EXPECT_EQ(c.filename, "<stringchar4>"_s); EXPECT_EQ(c.line, 2); EXPECT_EQ(c.column, 3); lr.adv(); @@ -315,54 +319,54 @@ TEST(io, linechar4) } TEST(io, linechar5) { - io::LineCharReader lr("<stringchar5>", string_pipe("Hi\n\rWu")); + io::LineCharReader lr("<stringchar5>"_s, string_pipe("Hi\n\rWu"_s)); io::LineChar c; EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'H'); - EXPECT_EQ(c.text, "Hi"); - EXPECT_EQ(c.filename, "<stringchar5>"); + EXPECT_EQ(c.text, "Hi"_s); + EXPECT_EQ(c.filename, "<stringchar5>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 1); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'i'); - EXPECT_EQ(c.text, "Hi"); - EXPECT_EQ(c.filename, "<stringchar5>"); + EXPECT_EQ(c.text, "Hi"_s); + EXPECT_EQ(c.filename, "<stringchar5>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 2); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), '\n'); - EXPECT_EQ(c.text, "Hi"); - EXPECT_EQ(c.filename, "<stringchar5>"); + EXPECT_EQ(c.text, "Hi"_s); + EXPECT_EQ(c.filename, "<stringchar5>"_s); EXPECT_EQ(c.line, 1); EXPECT_EQ(c.column, 3); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), '\n'); - EXPECT_EQ(c.text, ""); - EXPECT_EQ(c.filename, "<stringchar5>"); + EXPECT_EQ(c.text, ""_s); + EXPECT_EQ(c.filename, "<stringchar5>"_s); EXPECT_EQ(c.line, 2); EXPECT_EQ(c.column, 1); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'W'); - EXPECT_EQ(c.text, "Wu"); - EXPECT_EQ(c.filename, "<stringchar5>"); + EXPECT_EQ(c.text, "Wu"_s); + EXPECT_EQ(c.filename, "<stringchar5>"_s); EXPECT_EQ(c.line, 3); EXPECT_EQ(c.column, 1); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), 'u'); - EXPECT_EQ(c.text, "Wu"); - EXPECT_EQ(c.filename, "<stringchar5>"); + EXPECT_EQ(c.text, "Wu"_s); + EXPECT_EQ(c.filename, "<stringchar5>"_s); EXPECT_EQ(c.line, 3); EXPECT_EQ(c.column, 2); lr.adv(); EXPECT_TRUE(lr.get(c)); EXPECT_EQ(c.ch(), '\n'); - EXPECT_EQ(c.text, "Wu"); - EXPECT_EQ(c.filename, "<stringchar5>"); + EXPECT_EQ(c.text, "Wu"_s); + EXPECT_EQ(c.filename, "<stringchar5>"_s); EXPECT_EQ(c.line, 3); EXPECT_EQ(c.column, 3); lr.adv(); @@ -371,7 +375,7 @@ TEST(io, linechar5) TEST(io, linespan) { - io::LineCharReader lr("<span>", string_pipe("Hello,\nWorld!\n")); + io::LineCharReader lr("<span>"_s, string_pipe("Hello,\nWorld!\n"_s)); io::LineSpan span; do { @@ -385,10 +389,10 @@ TEST(io, linespan) lr.adv(); } while (span.end.ch() != 'o'); - EXPECT_EQ(span.message_str("info", "meh"), + EXPECT_EQ(span.message_str("info"_s, "meh"_s), "<span>:1:2: info: meh\n" "Hello,\n" - " ^~~~\n" + " ^~~~\n"_s ); span.begin = span.end; do @@ -398,21 +402,22 @@ TEST(io, linespan) } while (span.end.ch() != 'r'); - EXPECT_EQ(span.begin.message_str("note", "foo"), + EXPECT_EQ(span.begin.message_str("note"_s, "foo"_s), "<span>:1:5: note: foo\n" "Hello,\n" - " ^\n" + " ^\n"_s ); - EXPECT_EQ(span.end.message_str("warning", "bar"), + EXPECT_EQ(span.end.message_str("warning"_s, "bar"_s), "<span>:2:3: warning: bar\n" "World!\n" - " ^\n" + " ^\n"_s ); - EXPECT_EQ(span.message_str("error", "qux"), + EXPECT_EQ(span.message_str("error"_s, "qux"_s), "<span>:1:5: error: qux\n" "Hello,\n" " ^~ ...\n" "World!\n" - "~~~\n" + "~~~\n"_s ); } +} // namespace tmwa diff --git a/src/io/lock.cpp b/src/io/lock.cpp index 96c3649..911b5db 100644 --- a/src/io/lock.cpp +++ b/src/io/lock.cpp @@ -1,5 +1,5 @@ #include "lock.hpp" -// io/lock.hpp - Output to files with atomic replacement and backups. +// io/lock.cpp - Output to files with atomic replacement and backups. // // Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> // @@ -21,7 +21,13 @@ #include <fcntl.h> #include <unistd.h> +#include <cerrno> +#include <cstdio> +#include <cstdlib> + +#include "../strings/astring.hpp" #include "../strings/zstring.hpp" +#include "../strings/literal.hpp" #include "cxxstdio.hpp" #include "fd.hpp" @@ -29,9 +35,11 @@ #include "../poison.hpp" +namespace tmwa +{ /// number of backups to keep static -const int backup_count = 10; +const int backup_count = 9; /// Protected file writing /// (Until the file is closed, it keeps the old file) @@ -49,7 +57,7 @@ namespace io AString newfile; do { - newfile = STRPRINTF("%s_%d.tmp", filename, no++); + newfile = STRPRINTF("%s_%d.tmp"_fmt, filename, no++); fd = FD::open(newfile, O_WRONLY | O_CREAT | O_EXCL, 0666); } while (fd == FD() && errno == EEXIST); @@ -67,21 +75,22 @@ namespace io if (!WriteFile::close()) { // leave partial file - FPRINTF(stderr, "Warning: failed to write replacement for %s\n", filename); + FPRINTF(stderr, "Warning: failed to write replacement for %s\n"_fmt, filename); abort(); } int n = backup_count; - AString old_filename = STRPRINTF("%s.%d", filename, n); + AString old_filename = STRPRINTF("%s.%d"_fmt, filename, n); while (--n) { - AString newer_filename = STRPRINTF("%s.%d", filename, n); + AString newer_filename = STRPRINTF("%s.%d"_fmt, filename, n); rename(newer_filename.c_str(), old_filename.c_str()); old_filename = std::move(newer_filename); } rename(filename.c_str(), old_filename.c_str()); - AString tmpfile = STRPRINTF("%s_%d.tmp", filename, tmp_suffix); + AString tmpfile = STRPRINTF("%s_%d.tmp"_fmt, filename, tmp_suffix); rename(tmpfile.c_str(), filename.c_str()); } } // namespace io +} // namespace tmwa diff --git a/src/io/lock.hpp b/src/io/lock.hpp index b879da5..005b371 100644 --- a/src/io/lock.hpp +++ b/src/io/lock.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_IO_LOCK_HPP -#define TMWA_IO_LOCK_HPP +#pragma once // io/lock.hpp - Output to files with atomic replacement and backups. // // Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> @@ -19,13 +18,15 @@ // 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 "fwd.hpp" -# include "write.hpp" +#include "write.hpp" -# include "../strings/rstring.hpp" +#include "../strings/rstring.hpp" +namespace tmwa +{ namespace io { class WriteLock : public WriteFile @@ -38,5 +39,4 @@ namespace io bool close() = delete; }; } // namespace io - -#endif // TMWA_IO_LOCK_HPP +} // namespace tmwa diff --git a/src/io/read.cpp b/src/io/read.cpp index 2ef35cc..3ae5246 100644 --- a/src/io/read.cpp +++ b/src/io/read.cpp @@ -19,17 +19,19 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include <fcntl.h> -#include <unistd.h> #include "../strings/astring.hpp" #include "../strings/mstring.hpp" #include "../strings/zstring.hpp" +#include "../strings/literal.hpp" #include "../io/cxxstdio.hpp" #include "../poison.hpp" +namespace tmwa +{ namespace io { ReadFile::ReadFile(FD f) @@ -40,6 +42,10 @@ namespace io : fd(FD::open(name, O_RDONLY | O_CLOEXEC)), start(0), end(0) { } + ReadFile::ReadFile(const DirFd& dir, ZString name) + : fd(dir.open_fd(name, O_RDONLY | O_CLOEXEC)), start(0), end(0) + { + } ReadFile::~ReadFile() { fd.close(); @@ -105,12 +111,12 @@ namespace io if (unhappy) { if (happy) - PRINTF("warning: file contains CR\n"); + FPRINTF(stderr, "warning: file contains CR\n"_fmt); else - PRINTF("warning: file contains bare CR\n"); + FPRINTF(stderr, "warning: file contains bare CR\n"_fmt); } else if (!happy && anything) - PRINTF("warning: file does not contain a trailing newline\n"); + FPRINTF(stderr, "warning: file does not contain a trailing newline\n"_fmt); line = AString(tmp); return anything; } @@ -120,3 +126,4 @@ namespace io return fd != FD(); } } // namespace io +} // namespace tmwa diff --git a/src/io/read.hpp b/src/io/read.hpp index f99fb56..1ec26ca 100644 --- a/src/io/read.hpp +++ b/src/io/read.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_IO_READ_HPP -#define TMWA_IO_READ_HPP +#pragma once // io/read.hpp - Input from files. // // Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> @@ -19,12 +18,15 @@ // 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 "fwd.hpp" -# include "../strings/fwd.hpp" +#include "../strings/fwd.hpp" -# include "fd.hpp" +#include "dir.hpp" +#include "fd.hpp" +namespace tmwa +{ namespace io { class ReadFile @@ -38,6 +40,8 @@ namespace io ReadFile(FD fd); explicit ReadFile(ZString name); + ReadFile(const DirFd& dir, ZString name); + ReadFile& operator = (ReadFile&&) = delete; ReadFile(ReadFile&&) = delete; ~ReadFile(); @@ -49,5 +53,4 @@ namespace io bool is_open(); }; } // namespace io - -#endif // TMWA_IO_READ_HPP +} // namespace tmwa diff --git a/src/io/read_test.cpp b/src/io/read_test.cpp index 87f95ba..8fe84b7 100644 --- a/src/io/read_test.cpp +++ b/src/io/read_test.cpp @@ -20,10 +20,15 @@ #include <gtest/gtest.h> +#include "../strings/astring.hpp" #include "../strings/zstring.hpp" +#include "../strings/literal.hpp" #include "../poison.hpp" + +namespace tmwa +{ static io::FD string_pipe(ZString sz) { @@ -42,43 +47,44 @@ io::FD string_pipe(ZString sz) TEST(io, read1) { - io::ReadFile rf(string_pipe("Hello")); + io::ReadFile rf(string_pipe("Hello"_s)); AString hi; EXPECT_TRUE(rf.getline(hi)); - EXPECT_EQ(hi, "Hello"); + EXPECT_EQ(hi, "Hello"_s); EXPECT_FALSE(rf.getline(hi)); } TEST(io, read2) { - io::ReadFile rf(string_pipe("Hello\n")); + io::ReadFile rf(string_pipe("Hello\n"_s)); AString hi; EXPECT_TRUE(rf.getline(hi)); - EXPECT_EQ(hi, "Hello"); + EXPECT_EQ(hi, "Hello"_s); EXPECT_FALSE(rf.getline(hi)); } TEST(io, read3) { - io::ReadFile rf(string_pipe("Hello\r")); + io::ReadFile rf(string_pipe("Hello\r"_s)); AString hi; EXPECT_TRUE(rf.getline(hi)); - EXPECT_EQ(hi, "Hello"); + EXPECT_EQ(hi, "Hello"_s); EXPECT_FALSE(rf.getline(hi)); } TEST(io, read4) { - io::ReadFile rf(string_pipe("Hello\r\n")); + io::ReadFile rf(string_pipe("Hello\r\n"_s)); AString hi; EXPECT_TRUE(rf.getline(hi)); - EXPECT_EQ(hi, "Hello"); + EXPECT_EQ(hi, "Hello"_s); EXPECT_FALSE(rf.getline(hi)); } TEST(io, read5) { - io::ReadFile rf(string_pipe("Hello\n\r")); + io::ReadFile rf(string_pipe("Hello\n\r"_s)); AString hi; EXPECT_TRUE(rf.getline(hi)); - EXPECT_EQ(hi, "Hello"); + EXPECT_EQ(hi, "Hello"_s); EXPECT_TRUE(rf.getline(hi)); EXPECT_FALSE(hi); EXPECT_FALSE(rf.getline(hi)); } +} // namespace tmwa diff --git a/src/io/tty.cpp b/src/io/tty.cpp index e71ee44..c498740 100644 --- a/src/io/tty.cpp +++ b/src/io/tty.cpp @@ -20,4 +20,8 @@ #include "../poison.hpp" + +namespace tmwa +{ /* Nothing to see here, move along */ +} // namespace tmwa diff --git a/src/io/tty.hpp b/src/io/tty.hpp index 97487b8..f754b91 100644 --- a/src/io/tty.hpp +++ b/src/io/tty.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_IO_TTY_HPP -#define TMWA_IO_TTY_HPP +#pragma once // io/tty.hpp - terminal escape sequences // // Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> @@ -19,20 +18,21 @@ // 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 "fwd.hpp" -# define SGR_BLACK "\e[30m" -# define SGR_RED "\e[31m" -# define SGR_GREEN "\e[32m" -# define SGR_YELLOW "\e[33m" -# define SGR_BLUE "\e[34m" -# define SGR_MAGENTA "\e[35m" -# define SGR_CYAN "\e[36m" -# define SGR_WHITE "\e[37m" +namespace tmwa +{ +#define SGR_BLACK "\e[30m" +#define SGR_RED "\e[31m" +#define SGR_GREEN "\e[32m" +#define SGR_YELLOW "\e[33m" +#define SGR_BLUE "\e[34m" +#define SGR_MAGENTA "\e[35m" +#define SGR_CYAN "\e[36m" +#define SGR_WHITE "\e[37m" -# define SGR_BOLD "\e[1m" +#define SGR_BOLD "\e[1m" -# define SGR_RESET "\e[0m" - -#endif // TMWA_IO_TTY_HPP +#define SGR_RESET "\e[0m" +} // namespace tmwa diff --git a/src/io/write.cpp b/src/io/write.cpp index a216b03..5359c7a 100644 --- a/src/io/write.cpp +++ b/src/io/write.cpp @@ -18,16 +18,21 @@ // 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 <sys/uio.h> - #include <fcntl.h> -#include <unistd.h> +#include <cstdio> +#include <cstdlib> + +#include <algorithm> + +#include "../strings/zstring.hpp" #include "../strings/xstring.hpp" #include "../poison.hpp" +namespace tmwa +{ namespace io { WriteFile::WriteFile(FD f, bool linebuffered) @@ -36,6 +41,9 @@ namespace io WriteFile::WriteFile(ZString name, bool linebuffered) : fd(FD::open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)), lb(linebuffered), buflen(0) {} + WriteFile::WriteFile(const DirFd& dir, ZString name, bool linebuffered) + : fd(dir.open_fd(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)), lb(linebuffered), buflen(0) + {} WriteFile::~WriteFile() { if (fd != FD()) @@ -175,3 +183,4 @@ namespace io return len; } } // namespace io +} // namespace tmwa diff --git a/src/io/write.hpp b/src/io/write.hpp index 870ebb5..1ab05f3 100644 --- a/src/io/write.hpp +++ b/src/io/write.hpp @@ -1,5 +1,4 @@ -#ifndef TMWA_IO_WRITE_HPP -#define TMWA_IO_WRITE_HPP +#pragma once // io/write.hpp - Output to files. // // Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> @@ -19,14 +18,18 @@ // 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 "fwd.hpp" -# include <cstdarg> +#include <cstdarg> -# include "../strings/fwd.hpp" +#include "../strings/fwd.hpp" -# include "fd.hpp" +#include "dir.hpp" +#include "fd.hpp" + +namespace tmwa +{ namespace io { class WriteFile @@ -34,7 +37,6 @@ namespace io private: FD fd; bool lb; - struct {} _unused; unsigned short buflen; char buf[4096]; public: @@ -42,6 +44,8 @@ namespace io WriteFile(FD fd, bool linebuffered=false); explicit WriteFile(ZString name, bool linebuffered=false); + WriteFile(const DirFd& dir, ZString name, bool linebuffered=false); + WriteFile(WriteFile&&) = delete; WriteFile& operator = (WriteFile&&) = delete; ~WriteFile(); @@ -65,5 +69,4 @@ namespace io __attribute__((format(printf, 2, 0))) int do_vprint(WriteFile& out, const char *fmt, va_list ap); } // namespace io - -#endif // TMWA_IO_WRITE_HPP +} // namespace tmwa diff --git a/src/io/write_test.cpp b/src/io/write_test.cpp index 8c08833..405d28a 100644 --- a/src/io/write_test.cpp +++ b/src/io/write_test.cpp @@ -26,9 +26,13 @@ #include "../strings/astring.hpp" #include "../strings/mstring.hpp" #include "../strings/xstring.hpp" +#include "../strings/literal.hpp" //#include "../poison.hpp" + +namespace tmwa +{ static io::FD pipew(io::FD& rfd) { @@ -65,7 +69,7 @@ public: if (rv == -1) { if (errno != EAGAIN) - return {"Error, read failed :("}; + return "Error, read failed :("_s; rv = 0; } if (rv == 0) @@ -81,11 +85,11 @@ TEST(io, write1) PipeWriter pw(false); io::WriteFile& wf = pw.wf; wf.really_put("Hello, ", 7); - EXPECT_EQ("", pw.slurp()); - wf.put_line("World!\n"); - EXPECT_EQ("", pw.slurp()); + EXPECT_EQ(""_s, pw.slurp()); + wf.put_line("World!\n"_s); + EXPECT_EQ(""_s, pw.slurp()); EXPECT_TRUE(wf.close()); - EXPECT_EQ("Hello, World!\n", pw.slurp()); + EXPECT_EQ("Hello, World!\n"_s, pw.slurp()); } TEST(io, write2) @@ -93,12 +97,12 @@ TEST(io, write2) PipeWriter pw(true); io::WriteFile& wf = pw.wf; wf.really_put("Hello, ", 7); - EXPECT_EQ("", pw.slurp()); - wf.put_line("World!"); + EXPECT_EQ(""_s, pw.slurp()); + wf.put_line("World!"_s); wf.really_put("XXX", 3); - EXPECT_EQ("Hello, World!\n", pw.slurp()); + EXPECT_EQ("Hello, World!\n"_s, pw.slurp()); EXPECT_TRUE(wf.close()); - EXPECT_EQ("XXX", pw.slurp()); + EXPECT_EQ("XXX"_s, pw.slurp()); } TEST(io, write3) @@ -112,7 +116,7 @@ TEST(io, write3) memset(buf, 'a', sizeof(buf)); wf.really_put(buf, 1); - EXPECT_EQ("", pw.slurp()); + EXPECT_EQ(""_s, pw.slurp()); memset(buf, 'b', sizeof(buf)); wf.really_put(buf, sizeof(buf)); @@ -133,3 +137,4 @@ TEST(io, write3) EXPECT_TRUE(wf.close()); EXPECT_EQ(pw.slurp(), XString(buf, buf + remaining, nullptr)); } +} // namespace tmwa |