diff options
-rw-r--r-- | AK/AKString.h | 1 | ||||
-rw-r--r-- | AK/ByteBuffer.h | 9 | ||||
-rw-r--r-- | AK/String.cpp | 9 | ||||
-rw-r--r-- | Applications/TextEditor/main.cpp | 27 | ||||
-rw-r--r-- | LibGUI/GIODevice.cpp | 33 | ||||
-rw-r--r-- | LibGUI/GIODevice.h | 2 |
6 files changed, 57 insertions, 24 deletions
diff --git a/AK/AKString.h b/AK/AKString.h index 31b2b4d383..a9ad132c57 100644 --- a/AK/AKString.h +++ b/AK/AKString.h @@ -100,6 +100,7 @@ public: } ByteBuffer to_byte_buffer() const; + static String from_byte_buffer(const ByteBuffer&); static String format(const char*, ...); diff --git a/AK/ByteBuffer.h b/AK/ByteBuffer.h index b1e3607ac6..55d09b37df 100644 --- a/AK/ByteBuffer.h +++ b/AK/ByteBuffer.h @@ -38,6 +38,7 @@ public: byte* offset_pointer(int offset) { return m_data + offset; } const byte* offset_pointer(int offset) const { return m_data + offset; } + void* end_pointer() { return m_data + m_size; } const void* end_pointer() const { return m_data + m_size; } // NOTE: trim() does not reallocate. @@ -109,6 +110,7 @@ public: byte* offset_pointer(ssize_t offset) { return m_impl ? m_impl->offset_pointer(offset) : nullptr; } const byte* offset_pointer(ssize_t offset) const { return m_impl ? m_impl->offset_pointer(offset) : nullptr; } + void* end_pointer() { return m_impl ? m_impl->end_pointer() : nullptr; } const void* end_pointer() const { return m_impl ? m_impl->end_pointer() : nullptr; } // NOTE: trim() does not reallocate. @@ -137,6 +139,13 @@ public: m_impl->grow(size); } + void append(const void* data, int data_size) + { + int old_size = size(); + grow(size() + data_size); + memcpy(pointer() + old_size, data, data_size); + } + private: explicit ByteBuffer(RetainPtr<ByteBufferImpl>&& impl) : m_impl(move(impl)) diff --git a/AK/String.cpp b/AK/String.cpp index e6195700d8..7aa31c5581 100644 --- a/AK/String.cpp +++ b/AK/String.cpp @@ -92,6 +92,15 @@ ByteBuffer String::to_byte_buffer() const return ByteBuffer::copy(reinterpret_cast<const byte*>(characters()), length()); } +String String::from_byte_buffer(const ByteBuffer& buffer) +{ + if (buffer.is_null()) + return nullptr; + if (buffer.is_empty()) + return empty(); + return String((const char*)buffer.pointer(), buffer.size()); +} + unsigned String::to_uint(bool& ok) const { unsigned value = 0; diff --git a/Applications/TextEditor/main.cpp b/Applications/TextEditor/main.cpp index 1c3e791f48..4df7073241 100644 --- a/Applications/TextEditor/main.cpp +++ b/Applications/TextEditor/main.cpp @@ -8,6 +8,7 @@ #include <LibGUI/GTextEditor.h> #include <LibGUI/GAction.h> #include <LibGUI/GFontDatabase.h> +#include <LibGUI/GFile.h> #include <AK/StringBuilder.h> #include <unistd.h> #include <stdio.h> @@ -34,31 +35,13 @@ int main(int argc, char** argv) String path = "/tmp/TextEditor.save.txt"; if (argc >= 2) { path = argv[1]; - StringBuilder builder; - int fd = open(path.characters(), O_RDONLY); - if (fd < 0) { - perror("open"); - return 1; - } - for (;;) { - char buffer[BUFSIZ]; - ssize_t nread = read(fd, buffer, sizeof(buffer)); - if (nread < 0) { - perror("read"); - return 1; - } - if (nread == 0) - break; - builder.append(buffer, nread); - } + GFile file(path); - int rc = close(fd); - if (rc < 0) { - perror("close"); + if (!file.open(GIODevice::ReadOnly)) { + fprintf(stderr, "Opening %s: %s\n", path.characters(), file.error_string()); return 1; } - - text_editor->set_text(builder.to_string()); + text_editor->set_text(String::from_byte_buffer(file.read_all())); } auto new_action = GAction::create("New document", { Mod_Ctrl, Key_N }, GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/new.rgb", { 16, 16 }), [] (const GAction&) { diff --git a/LibGUI/GIODevice.cpp b/LibGUI/GIODevice.cpp index 0b0f8de1d1..7be5bcd09f 100644 --- a/LibGUI/GIODevice.cpp +++ b/LibGUI/GIODevice.cpp @@ -46,7 +46,7 @@ ByteBuffer GIODevice::read(int max_size) return buffer; } -bool GIODevice::can_read() const +bool GIODevice::can_read_from_fd() const { // FIXME: Can we somehow remove this once GSocket is implemented using non-blocking sockets? fd_set rfds; @@ -68,12 +68,41 @@ bool GIODevice::can_read_line() return true; if (m_buffered_data.contains_slow('\n')) return true; - if (!can_read()) + if (!can_read_from_fd()) return false; populate_read_buffer(); return m_buffered_data.contains_slow('\n'); } +bool GIODevice::can_read() const +{ + return !m_buffered_data.is_empty() || can_read_from_fd(); +} + +ByteBuffer GIODevice::read_all() +{ + ByteBuffer buffer; + if (!m_buffered_data.is_empty()) { + buffer = ByteBuffer::copy(m_buffered_data.data(), m_buffered_data.size()); + m_buffered_data.clear(); + } + + while (can_read_from_fd()) { + char read_buffer[4096]; + int nread = ::read(m_fd, read_buffer, sizeof(read_buffer)); + if (nread < 0) { + set_error(nread); + return buffer; + } + if (nread == 0) { + set_eof(true); + break; + } + buffer.append(read_buffer, nread); + } + return buffer; +} + ByteBuffer GIODevice::read_line(int max_size) { if (m_fd < 0) diff --git a/LibGUI/GIODevice.h b/LibGUI/GIODevice.h index d7d7cd094c..d2aca72b06 100644 --- a/LibGUI/GIODevice.h +++ b/LibGUI/GIODevice.h @@ -28,6 +28,7 @@ public: ByteBuffer read(int max_size); ByteBuffer read_line(int max_size); + ByteBuffer read_all(); // FIXME: I would like this to be const but currently it needs to call populate_read_buffer(). bool can_read_line(); @@ -49,6 +50,7 @@ protected: private: bool populate_read_buffer(); + bool can_read_from_fd() const; int m_fd { -1 }; int m_error { 0 }; |