summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AK/AKString.h1
-rw-r--r--AK/ByteBuffer.h9
-rw-r--r--AK/String.cpp9
-rw-r--r--Applications/TextEditor/main.cpp27
-rw-r--r--LibGUI/GIODevice.cpp33
-rw-r--r--LibGUI/GIODevice.h2
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 };