summaryrefslogtreecommitdiff
path: root/src/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/io')
-rw-r--r--src/io/cxxstdio.cpp7
-rw-r--r--src/io/cxxstdio.hpp133
-rw-r--r--src/io/dir.cpp54
-rw-r--r--src/io/dir.hpp50
-rw-r--r--src/io/fd.cpp8
-rw-r--r--src/io/fd.hpp44
-rw-r--r--src/io/fwd.hpp10
-rw-r--r--src/io/line.cpp43
-rw-r--r--src/io/line.hpp31
-rw-r--r--src/io/line_test.cpp207
-rw-r--r--src/io/lock.cpp23
-rw-r--r--src/io/lock.hpp14
-rw-r--r--src/io/read.cpp15
-rw-r--r--src/io/read.hpp17
-rw-r--r--src/io/read_test.cpp26
-rw-r--r--src/io/tty.cpp4
-rw-r--r--src/io/tty.hpp30
-rw-r--r--src/io/write.cpp15
-rw-r--r--src/io/write.hpp21
-rw-r--r--src/io/write_test.cpp23
20 files changed, 442 insertions, 333 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..20d3a33 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,29 @@
// 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 "../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,19 +53,6 @@ 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)
{
@@ -95,13 +66,10 @@ 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;
- }
+ inline
+ const char *convert_for_printf(const char *) = delete;
-# if 0
+#if 0
template<class E>
constexpr
E get_enum_min_value(decltype(E::min_value))
@@ -127,7 +95,7 @@ namespace cxxstdio
{
return def;
}
-# else
+#else
template<class E>
constexpr
E get_enum_min_value(E)
@@ -140,24 +108,24 @@ namespace cxxstdio
{
return E::max_value;
}
-# endif
+#endif
template<class E>
class EnumConverter
{
E& out;
typedef typename underlying_type<E>::type U;
-# if 0
+#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
+#else
constexpr static
U min_value = U(get_enum_min_value(E()));
constexpr static
U max_value = U(get_enum_max_value(E()));
-# endif
+#endif
U mid;
public:
EnumConverter(E& e)
@@ -165,11 +133,13 @@ namespace cxxstdio
{}
~EnumConverter()
{
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wtype-limits"
+ DIAG_PUSH();
+ DIAG_I(type_limits);
if (min_value <= mid && mid <= max_value)
-# pragma GCC diagnostic pop
+ {
+ DIAG_POP();
out = E(mid);
+ }
}
U *operator &()
{
@@ -177,12 +147,6 @@ namespace cxxstdio
}
};
- template<class T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
- EnumConverter<T> convert_for_scanf(T& v)
- {
- return v;
- }
-
template<class Format>
class PrintFormatter
{
@@ -192,63 +156,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 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 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 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 +192,4 @@ namespace cxxstdio
})
} // namespace cxxstdio
-
-#endif // TMWA_IO_CXXSTDIO_HPP
+} // 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 5993a69..833b173 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())
@@ -174,3 +182,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 ae8eccd..2347e7e 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,10 +97,11 @@ 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());
}
+} // namespace tmwa