diff options
Diffstat (limited to 'src/io')
-rw-r--r-- | src/io/fwd.hpp | 2 | ||||
-rw-r--r-- | src/io/line.cpp | 107 | ||||
-rw-r--r-- | src/io/line.hpp | 59 | ||||
-rw-r--r-- | src/io/line_test.cpp | 50 | ||||
-rw-r--r-- | src/io/read.cpp | 38 | ||||
-rw-r--r-- | src/io/read.hpp | 14 | ||||
-rw-r--r-- | src/io/read_test.cpp | 61 | ||||
-rw-r--r-- | src/io/span.cpp | 99 | ||||
-rw-r--r-- | src/io/span.hpp | 90 |
9 files changed, 396 insertions, 124 deletions
diff --git a/src/io/fwd.hpp b/src/io/fwd.hpp index 99268f4..5334fbd 100644 --- a/src/io/fwd.hpp +++ b/src/io/fwd.hpp @@ -34,5 +34,7 @@ namespace io class ReadFile; class WriteFile; class AppendFile; + class LineReader; + class LineCharReader; } // namespace io } // namespace tmwa diff --git a/src/io/line.cpp b/src/io/line.cpp index a1cdf42..5d7e792 100644 --- a/src/io/line.cpp +++ b/src/io/line.cpp @@ -19,9 +19,7 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include "../strings/astring.hpp" -#include "../strings/mstring.hpp" #include "../strings/zstring.hpp" -#include "../strings/xstring.hpp" #include "cxxstdio.hpp" @@ -32,71 +30,6 @@ 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"_fmt, - filename, line, column, cat, msg); - else - out += STRPRINTF("%s:%u: %s: %s\n"_fmt, - filename, line, cat, msg); - 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"_fmt, - filename, line, column, cat, msg); - else - FPRINTF(stderr, "%s:%u: %s: %s\n"_fmt, - filename, line, cat, msg); - FPRINTF(stderr, "%s\n"_fmt, text); - FPRINTF(stderr, "%*c\n"_fmt, column, '^'); - } - - AString LineSpan::message_str(ZString cat, ZString msg) const - { - assert (begin.column); - assert (end.column); - assert (begin.line < end.line || begin.column <= end.column); - - MString out; - if (begin.line == end.line) - { - out += STRPRINTF("%s:%u:%u: %s: %s\n"_fmt, - begin.filename, begin.line, begin.column, cat, msg); - 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"_fmt, - begin.filename, begin.line, begin.column, cat, msg); - 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"_s; - out += STRPRINTF("%s\n"_fmt, end.text); - for (unsigned c = 0; c != end.column; ++c) - out += '~'; - out += '\n'; - } - return AString(out); - } - - void LineSpan::message(ZString cat, ZString msg) const - { - FPRINTF(stderr, "%s"_fmt, message_str(cat, msg)); - } - LineReader::LineReader(ZString name) : filename(name), line(0), column(0), rf(name) {} @@ -105,6 +38,14 @@ namespace io : filename(name), line(0), column(0), rf(fd) {} + LineReader::LineReader(read_file_from_string, ZString name, XString content, int startline, FD fd) + : filename(name), line(startline-1), column(0), rf(from_string, content, fd) + {} + + LineReader::LineReader(read_file_from_string, ZString name, LString content, int startline, FD fd) + : filename(name), line(startline-1), column(0), rf(from_string, content, fd) + {} + bool LineReader::read_line(Line& l) { AString text; @@ -145,6 +86,38 @@ namespace io column = 0; } + LineCharReader::LineCharReader(read_file_from_string, ZString name, XString content, int startline, int startcol, FD fd) + : LineReader(from_string, name, content, 1, fd) + { + column = 1; // not 0, not whole line + if (rf.is_open()) + adv(); + if (!line) + column = 0; + else + { + line = startline; + column = startcol; + line_text = STRPRINTF("%*s"_fmt, static_cast<int>(column-1 + line_text.size()), line_text); + } + } + + LineCharReader::LineCharReader(read_file_from_string, ZString name, LString content, int startline, int startcol, FD fd) + : LineReader(from_string, name, content, 1, fd) + { + column = 1; // not 0, not whole line + if (rf.is_open()) + adv(); + if (!line) + column = 0; + else + { + line = startline; + column = startcol; + line_text = STRPRINTF("%*s"_fmt, static_cast<int>(column-1 + line_text.size()), line_text); + } + } + bool LineCharReader::get(LineChar& c) { if (!column) diff --git a/src/io/line.hpp b/src/io/line.hpp index 5572e98..c94eeb9 100644 --- a/src/io/line.hpp +++ b/src/io/line.hpp @@ -21,68 +21,15 @@ #include "fwd.hpp" #include "../strings/rstring.hpp" -#include "../strings/zstring.hpp" -#include "../strings/literal.hpp" #include "read.hpp" +#include "span.hpp" namespace tmwa { namespace io { - // TODO split this out - struct Line - { - RString text; - - RString filename; - // 1-based - uint16_t line, column; - - AString message_str(ZString cat, ZString msg) const; - AString note_str(ZString msg) const { return message_str("note"_s, msg); } - AString warning_str(ZString msg) const { return message_str("warning"_s, msg); } - AString error_str(ZString msg) const { return message_str("error"_s, msg); } - void message(ZString cat, ZString msg) const; - 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 - struct LineChar : Line - { - char ch() - { - size_t c = column - 1; - if (c == text.size()) - return '\n'; - return text[c]; - } - }; - - struct LineSpan - { - LineChar begin, end; - - AString message_str(ZString cat, ZString msg) const; - AString note_str(ZString msg) const { return message_str("note"_s, msg); } - AString warning_str(ZString msg) const { return message_str("warning"_s, msg); } - AString error_str(ZString msg) const { return message_str("error"_s, msg); } - void message(ZString cat, ZString msg) const; - 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); } - }; - - template<class T> - struct Spanned - { - T data; - LineSpan span; - }; - class LineReader { protected: @@ -96,6 +43,8 @@ namespace io LineReader& operator = (LineReader&&) = delete; // needed for unit tests LineReader(ZString name, FD fd); + LineReader(read_file_from_string, ZString name, XString content, int startline=1, FD fd=FD()); + LineReader(read_file_from_string, ZString name, LString content, int startline=1, FD fd=FD()); bool read_line(Line& l); bool is_open(); @@ -110,6 +59,8 @@ namespace io LineCharReader(LineCharReader&&) = delete; LineCharReader& operator = (LineCharReader&&) = delete; LineCharReader(ZString name, FD fd); + LineCharReader(read_file_from_string, ZString name, XString content, int startline=1, int startcol=1, FD fd=FD()); + LineCharReader(read_file_from_string, ZString name, LString content, int startline=1, int startcol=1, FD fd=FD()); bool get(LineChar& c); void adv(); diff --git a/src/io/line_test.cpp b/src/io/line_test.cpp index 46e7b57..582ee81 100644 --- a/src/io/line_test.cpp +++ b/src/io/line_test.cpp @@ -130,6 +130,20 @@ TEST(io, line5) EXPECT_EQ(hi.column, 0); EXPECT_FALSE(lr.read_line(hi)); } +TEST(io, line1text) +{ + io::LineReader lr(io::from_string, "<string1text>"_s, "Hello\nWorld"_s, 2); + io::Line hi; + EXPECT_TRUE(lr.read_line(hi)); + EXPECT_EQ(hi.text, "Hello"_s); + EXPECT_EQ(hi.line, 2); + EXPECT_EQ(hi.column, 0); + EXPECT_TRUE(lr.read_line(hi)); + EXPECT_EQ(hi.text, "World"_s); + EXPECT_EQ(hi.line, 3); + EXPECT_EQ(hi.column, 0); + EXPECT_FALSE(lr.read_line(hi)); +} TEST(io, linechar1) { @@ -382,6 +396,42 @@ TEST(io, linechar5) lr.adv(); EXPECT_FALSE(lr.get(c)); } +TEST(io, linechar1text) +{ + io::LineCharReader lr(io::from_string, "<stringchar1text>"_s, "Hi\nWu\n"_s, 2, 3); + io::LineChar c; + EXPECT_TRUE(lr.get(c)); + EXPECT_EQ(c.ch(), 'H'); + EXPECT_EQ(c.line, 2); + EXPECT_EQ(c.column, 3); + lr.adv(); + EXPECT_TRUE(lr.get(c)); + EXPECT_EQ(c.ch(), 'i'); + EXPECT_EQ(c.line, 2); + EXPECT_EQ(c.column, 4); + lr.adv(); + EXPECT_TRUE(lr.get(c)); + EXPECT_EQ(c.ch(), '\n'); + EXPECT_EQ(c.line, 2); + EXPECT_EQ(c.column, 5); + lr.adv(); + EXPECT_TRUE(lr.get(c)); + EXPECT_EQ(c.ch(), 'W'); + 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.line, 3); + EXPECT_EQ(c.column, 2); + lr.adv(); + EXPECT_TRUE(lr.get(c)); + EXPECT_EQ(c.ch(), '\n'); + EXPECT_EQ(c.line, 3); + EXPECT_EQ(c.column, 3); + lr.adv(); + EXPECT_FALSE(lr.get(c)); +} TEST(io, linespan) { diff --git a/src/io/read.cpp b/src/io/read.cpp index 30620a1..d701c7f 100644 --- a/src/io/read.cpp +++ b/src/io/read.cpp @@ -1,7 +1,7 @@ #include "read.hpp" // io/read.cpp - Input from files // -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// Copyright © 2013-2014 Ben Longbons <b.r.longbons@gmail.com> // // This file is part of The Mana World (Athena server) // @@ -48,6 +48,32 @@ namespace io : fd(dir.open_fd(name, O_RDONLY | O_CLOEXEC)), start(0), end(0) { } + ReadFile::ReadFile(read_file_from_string, XString content, FD f) + : fd(f), start(0), end(), extra() + { + if (content.size() <= 4096) + { + end = content.size(); + auto z = std::copy(content.begin(), content.end(), buf); + // only for debug sanity + std::fill(z, std::end(buf), 0); + return; + } + auto base = content.base(); + if (!base) + { + extra = content; + end = content.size(); + return; + } + start = &*content.begin() - &*base->begin(); + end = &*content.end() - &*base->begin(); + extra = *base; + } + ReadFile::ReadFile(read_file_from_string, LString content, FD f) + : ReadFile(from_string, RString(content), f) + { + } ReadFile::~ReadFile() { fd.close(); @@ -56,6 +82,14 @@ namespace io bool ReadFile::get(char& c) { + if (extra) + { + c = extra[start]; + ++start; + if (start == end) + extra = ""_s; + return true; + } if (start == end) { if (fd == FD()) @@ -125,7 +159,7 @@ namespace io bool ReadFile::is_open() { - return fd != FD(); + return fd != FD() || start != end; } } // namespace io } // namespace tmwa diff --git a/src/io/read.hpp b/src/io/read.hpp index c1c4882..2e3611b 100644 --- a/src/io/read.hpp +++ b/src/io/read.hpp @@ -1,7 +1,7 @@ #pragma once // io/read.hpp - Input from files. // -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// Copyright © 2013-2014 Ben Longbons <b.r.longbons@gmail.com> // // This file is part of The Mana World (Athena server) // @@ -20,6 +20,8 @@ #include "fwd.hpp" +#include "../strings/rstring.hpp" + #include "dir.hpp" #include "fd.hpp" @@ -27,18 +29,28 @@ namespace tmwa { namespace io { + enum read_file_from_string + { + from_string, + }; + + // TODO - for internal warnings, it would be convenient if this class + // didn't exist at all, and instead everything was done with line info. class ReadFile { private: FD fd; unsigned short start, end; char buf[4096]; + RString extra; public: explicit ReadFile(FD fd); explicit ReadFile(ZString name); ReadFile(const DirFd& dir, ZString name); + ReadFile(read_file_from_string, XString content, FD fd=FD()); + ReadFile(read_file_from_string, LString content, FD fd=FD()); ReadFile& operator = (ReadFile&&) = delete; ReadFile(ReadFile&&) = delete; diff --git a/src/io/read_test.cpp b/src/io/read_test.cpp index e655eb1..22c67c8 100644 --- a/src/io/read_test.cpp +++ b/src/io/read_test.cpp @@ -93,4 +93,65 @@ TEST(io, read5) EXPECT_FALSE(hi); EXPECT_FALSE(rf.getline(hi)); } + +#define S15 "0123456789abcde"_s +#define S16 "0123456789abcdef"_s +#define S255 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S15 +#define S256 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 +#define S4095 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S255 +#define S4096 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 + +TEST(io, readstringr) +{ + LString tests[] = + { + S15, + S16, + S255, + S256, + S4095, + S4096, + S4096 S16, + }; + for (RString test : tests) + { + char buf[test.size() + 1]; + + io::ReadFile rf(io::from_string, test); + EXPECT_EQ(rf.get(buf, sizeof(buf)), test.size()); + EXPECT_EQ(test, XString(buf + 0, buf + test.size(), nullptr)); + + io::ReadFile rf2(io::from_string, test, string_pipe("\na"_s)); + EXPECT_EQ(rf2.get(buf, sizeof(buf)), test.size() + 1); + EXPECT_EQ(test, XString(buf + 0, buf + test.size(), nullptr)); + EXPECT_EQ('\n', buf[test.size()]); + } +} + +TEST(io, readstringx) +{ + LString tests[] = + { + S15, + S16, + S255, + S256, + S4095, + S4096, + S4096 S16, + }; + for (XString test : tests) + { + char buf[test.size() + 1]; + + io::ReadFile rf(io::from_string, test); + EXPECT_EQ(rf.get(buf, sizeof(buf)), test.size()); + EXPECT_EQ(test, XString(buf + 0, buf + test.size(), nullptr)); + + io::ReadFile rf2(io::from_string, test, string_pipe("\na"_s)); + EXPECT_EQ(rf2.get(buf, sizeof(buf)), test.size() + 1); + EXPECT_EQ(test, XString(buf + 0, buf + test.size(), nullptr)); + EXPECT_EQ('\n', buf[test.size()]); + } +} } // namespace tmwa diff --git a/src/io/span.cpp b/src/io/span.cpp new file mode 100644 index 0000000..f4752f0 --- /dev/null +++ b/src/io/span.cpp @@ -0,0 +1,99 @@ +#include "span.hpp" +// io/span.cpp - Tracking info about input +// +// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +#include "../strings/astring.hpp" +#include "../strings/mstring.hpp" +#include "../strings/zstring.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"_fmt, + filename, line, column, cat, msg); + else + out += STRPRINTF("%s:%u: %s: %s\n"_fmt, + filename, line, cat, msg); + 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"_fmt, + filename, line, column, cat, msg); + else + FPRINTF(stderr, "%s:%u: %s: %s\n"_fmt, + filename, line, cat, msg); + FPRINTF(stderr, "%s\n"_fmt, text); + FPRINTF(stderr, "%*c\n"_fmt, column, '^'); + } + + AString LineSpan::message_str(ZString cat, ZString msg) const + { + assert (begin.column); + assert (end.column); + assert (begin.line < end.line || begin.column <= end.column); + + MString out; + if (begin.line == end.line) + { + out += STRPRINTF("%s:%u:%u: %s: %s\n"_fmt, + begin.filename, begin.line, begin.column, cat, msg); + 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"_fmt, + begin.filename, begin.line, begin.column, cat, msg); + 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"_s; + out += STRPRINTF("%s\n"_fmt, end.text); + for (unsigned c = 0; c != end.column; ++c) + out += '~'; + out += '\n'; + } + return AString(out); + } + + void LineSpan::message(ZString cat, ZString msg) const + { + FPRINTF(stderr, "%s"_fmt, message_str(cat, msg)); + } +} // namespace io +} // namespace tmwa diff --git a/src/io/span.hpp b/src/io/span.hpp new file mode 100644 index 0000000..e474a7a --- /dev/null +++ b/src/io/span.hpp @@ -0,0 +1,90 @@ +#pragma once +// io/span.hpp - Tracking info about input +// +// 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/rstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/literal.hpp" + + +namespace tmwa +{ +namespace io +{ + // TODO split this out + struct Line + { + RString text; + + RString filename; + // 1-based + uint16_t line, column; + + AString message_str(ZString cat, ZString msg) const; + AString note_str(ZString msg) const { return message_str("note"_s, msg); } + AString warning_str(ZString msg) const { return message_str("warning"_s, msg); } + AString error_str(ZString msg) const { return message_str("error"_s, msg); } + void message(ZString cat, ZString msg) const; + 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 + struct LineChar : Line + { + char ch() + { + size_t c = column - 1; + if (c == text.size()) + return '\n'; + return text[c]; + } + }; + + struct LineSpan + { + LineChar begin, end; + + AString message_str(ZString cat, ZString msg) const; + AString note_str(ZString msg) const { return message_str("note"_s, msg); } + AString warning_str(ZString msg) const { return message_str("warning"_s, msg); } + AString error_str(ZString msg) const { return message_str("error"_s, msg); } + void message(ZString cat, ZString msg) const; + 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); } + }; + + template<class T> + struct Spanned + { + T data; + LineSpan span; + }; + + template<class T> + Spanned<T> respan(LineSpan span, T data) + { + return Spanned<T>{std::move(data), std::move(span)}; + } +} // namespace io +} // namespace tmwa |