# HG changeset patch # User David Demelier # Date 1459357313 -7200 # Node ID c5f4ca941f7958c2876329eac7d007c78ab52941 # Parent 7e9a1faeb6f69f641725d1d11f111e5a78311732 Irccd: add new Irccd.File.lines function, #445 While here also remove optional '\r' in Irccd.File.readline. diff -r 7e9a1faeb6f6 -r c5f4ca941f79 doc/html/api/module/Irccd.File/Files.cmake --- a/doc/html/api/module/Irccd.File/Files.cmake Wed Mar 30 14:17:23 2016 +0200 +++ b/doc/html/api/module/Irccd.File/Files.cmake Wed Mar 30 19:01:53 2016 +0200 @@ -28,6 +28,7 @@ ${CMAKE_CURRENT_LIST_DIR}/method/close.md ${CMAKE_CURRENT_LIST_DIR}/method/constructor.md ${CMAKE_CURRENT_LIST_DIR}/method/dirname.md + ${CMAKE_CURRENT_LIST_DIR}/method/lines.md ${CMAKE_CURRENT_LIST_DIR}/method/read.md ${CMAKE_CURRENT_LIST_DIR}/method/readline.md ${CMAKE_CURRENT_LIST_DIR}/method/remove.md diff -r 7e9a1faeb6f6 -r c5f4ca941f79 doc/html/api/module/Irccd.File/index.md --- a/doc/html/api/module/Irccd.File/index.md Wed Mar 30 14:17:23 2016 +0200 +++ b/doc/html/api/module/Irccd.File/index.md Wed Mar 30 19:01:53 2016 +0200 @@ -37,6 +37,7 @@ - [basename](method/basename.html) - [close](method/close.html) - [dirname](method/dirname.html) + - [lines](method/lines.html) - [read](method/read.html) - [readline](method/readline.html) - [remove](method/remove.html) diff -r 7e9a1faeb6f6 -r c5f4ca941f79 doc/html/api/module/Irccd.File/method/lines.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/html/api/module/Irccd.File/method/lines.md Wed Mar 30 19:01:53 2016 +0200 @@ -0,0 +1,7 @@ +--- +method: lines +summary: "Read all lines and return an array." +synopsis: "File.prototype.lines()" +returns: "An array with all lines." +throws: "An [Irccd.SystemError](@baseurl@/api/module/Irccd/index.html#types) on failures." +--- diff -r 7e9a1faeb6f6 -r c5f4ca941f79 doc/html/api/module/Irccd.File/method/readline.md --- a/doc/html/api/module/Irccd.File/method/readline.md Wed Mar 30 14:17:23 2016 +0200 +++ b/doc/html/api/module/Irccd.File/method/readline.md Wed Mar 30 19:01:53 2016 +0200 @@ -5,3 +5,9 @@ returns: "The next line or undefined if eof." throws: "An [Irccd.SystemError](@baseurl@/api/module/Irccd/index.html#types) on failures." --- + +## Remarks + + diff -r 7e9a1faeb6f6 -r c5f4ca941f79 lib/irccd/js-file.cpp --- a/lib/irccd/js-file.cpp Wed Mar 30 14:17:23 2016 +0200 +++ b/lib/irccd/js-file.cpp Wed Mar 30 19:01:53 2016 +0200 @@ -200,6 +200,15 @@ * File methods * -------------------------------------------------------- */ +/* Remove trailing \r for CRLF line style */ +inline std::string clearCr(std::string input) +{ + if (input.length() > 0 && input.back() == '\r') + input.pop_back(); + + return input; +} + /* * Method: File.basename() * -------------------------------------------------------- @@ -246,6 +255,49 @@ } /* + * Method: File.lines() + * -------------------------------------------------------- + * + * Read all lines and return an array. + * + * Returns: + * An array with all lines. + * Throws + * - Any exception on error. + */ +duk::Ret methodLines(duk::ContextPtr ctx) +{ + duk::push(ctx, duk::Array{}); + + std::FILE *fp = duk::self>(ctx)->handle(); + std::string buffer; + + char data[128]; + int total = 0; + + while (std::fgets(data, sizeof (data), fp) != nullptr) { + buffer += data; + + auto pos = buffer.find('\n'); + + if (pos != std::string::npos) { + duk::putProperty(ctx, -1, total++, clearCr(buffer.substr(0, pos))); + buffer.erase(0, pos + 1); + } + } + + /* Maybe an error in the stream */ + if (std::ferror(fp)) + duk::raise(ctx, SystemError()); + + /* Missing '\n' in end of file */ + if (!buffer.empty()) + duk::putProperty(ctx, -1, total++, clearCr(buffer)); + + return 1; +} + +/* * Method: File.read(amount) * -------------------------------------------------------- * @@ -294,7 +346,7 @@ if (file->isClosed() || file->eof()) return 0; - duk::push(ctx, file->readline()); + duk::push(ctx, clearCr(file->readline())); } catch (const std::exception &) { duk::raise(ctx, SystemError()); } @@ -438,6 +490,7 @@ { "basename", { methodBasename, 0 } }, { "close", { methodClose, 0 } }, { "dirname", { methodDirname, 0 } }, + { "lines", { methodLines, 0 } }, { "read", { methodRead, 1 } }, { "readline", { methodReadline, 0 } }, { "remove", { methodRemove, 0 } }, diff -r 7e9a1faeb6f6 -r c5f4ca941f79 lib/irccd/js-file.h --- a/lib/irccd/js-file.h Wed Mar 30 14:17:23 2016 +0200 +++ b/lib/irccd/js-file.h Wed Mar 30 19:01:53 2016 +0200 @@ -85,6 +85,11 @@ return m_path; } + inline std::FILE *handle() noexcept + { + return m_stream; + } + /** * Force close, can be safely called multiple times. */ diff -r 7e9a1faeb6f6 -r c5f4ca941f79 tests/js-file/main.cpp --- a/tests/js-file/main.cpp Wed Mar 30 14:17:23 2016 +0200 +++ b/tests/js-file/main.cpp Wed Mar 30 19:01:53 2016 +0200 @@ -213,6 +213,31 @@ } } +TEST(TestJsFile, methodLines) +{ + duk::Context ctx; + + loadJsIrccd(ctx); + loadJsFile(ctx); + + try { + duk::putGlobal(ctx, "directory", IRCCD_TESTS_DIRECTORY); + + auto ret = duk::pevalString(ctx, + "lines = new Irccd.File(directory + '/lines.txt', 'r').lines();" + ); + + if (ret != 0) + throw duk::error(ctx, -1); + + std::vector expected{"a", "b", "c"}; + + ASSERT_EQ(expected, duk::getGlobal>(ctx, "lines")); + } catch (const std::exception &ex) { + FAIL() << ex.what(); + } +} + TEST(TestJsFile, methodSeek1) { duk::Context ctx;