diff options
-rw-r--r-- | Applications/ProcessManager/ProcessTableModel.cpp | 17 | ||||
-rw-r--r-- | LibGUI/GFile.cpp | 56 | ||||
-rw-r--r-- | LibGUI/GFile.h | 22 | ||||
-rw-r--r-- | LibGUI/GIODevice.cpp | 89 | ||||
-rw-r--r-- | LibGUI/GIODevice.h | 53 | ||||
-rw-r--r-- | LibGUI/Makefile | 2 |
6 files changed, 230 insertions, 9 deletions
diff --git a/Applications/ProcessManager/ProcessTableModel.cpp b/Applications/ProcessManager/ProcessTableModel.cpp index df9320b7b3..58277b5dd0 100644 --- a/Applications/ProcessManager/ProcessTableModel.cpp +++ b/Applications/ProcessManager/ProcessTableModel.cpp @@ -1,4 +1,5 @@ #include "ProcessTableModel.h" +#include <LibGUI/GFile.h> #include <fcntl.h> #include <stdio.h> #include <pwd.h> @@ -121,10 +122,11 @@ GVariant ProcessTableModel::data(const GModelIndex& index, Role role) const void ProcessTableModel::update() { - FILE* fp = fopen("/proc/all", "r"); - if (!fp) { - perror("failed to open /proc/all"); + GFile file("/proc/all"); + if (!file.open(GIODevice::ReadOnly)) { + fprintf(stderr, "ProcessManager: Failed to open /proc/all: %s\n", file.error_string()); exit(1); + return; } unsigned last_sum_nsched = 0; @@ -134,11 +136,10 @@ void ProcessTableModel::update() HashTable<pid_t> live_pids; unsigned sum_nsched = 0; for (;;) { - char buf[BUFSIZ]; - char* ptr = fgets(buf, sizeof(buf), fp); - if (!ptr) + auto line = file.read_line(1024); + if (line.is_empty()) break; - auto parts = String(buf, Chomp).split(','); + auto parts = String((const char*)line.pointer(), line.size() - 1, Chomp).split(','); if (parts.size() < 17) break; bool ok; @@ -178,8 +179,6 @@ void ProcessTableModel::update() live_pids.set(pid); } - int rc = fclose(fp); - ASSERT(rc == 0); m_pids.clear(); Vector<pid_t> pids_to_remove; diff --git a/LibGUI/GFile.cpp b/LibGUI/GFile.cpp new file mode 100644 index 0000000000..45b083191c --- /dev/null +++ b/LibGUI/GFile.cpp @@ -0,0 +1,56 @@ +#include <LibGUI/GFile.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> + +GFile::GFile(const String& filename) + : m_filename(filename) +{ +} + +GFile::~GFile() +{ + if (mode() != NotOpen) + close(); +} + +bool GFile::open(GIODevice::OpenMode mode) +{ + int flags = 0; + if ((mode & GIODevice::ReadWrite) == GIODevice::ReadWrite) { + flags |= O_RDWR | O_CREAT; + } else if (mode & GIODevice::ReadOnly) { + flags |= O_RDONLY; + } else if (mode & GIODevice::WriteOnly) { + flags |= O_WRONLY | O_CREAT; + } + if (mode & GIODevice::Append) + flags |= O_APPEND; + if (mode & GIODevice::Truncate) + flags |= O_TRUNC; + if (mode & GIODevice::MustBeNew) + flags |= O_EXCL; + int fd = ::open(m_filename.characters(), flags, 0666); + if (fd < 0) { + set_error(errno); + return false; + } + + set_fd(fd); + set_mode(mode); + return true; +} + +bool GFile::close() +{ + if (fd() < 0 || mode() == NotOpen) + return false; + int rc = ::close(fd()); + if (rc < 0) { + set_error(rc); + return false; + } + set_fd(-1); + set_mode(GIODevice::NotOpen); + return true; +} diff --git a/LibGUI/GFile.h b/LibGUI/GFile.h new file mode 100644 index 0000000000..de7325fb93 --- /dev/null +++ b/LibGUI/GFile.h @@ -0,0 +1,22 @@ +#pragma once + +#include <LibGUI/GIODevice.h> +#include <AK/AKString.h> + +class GFile final : public GIODevice { +public: + GFile() { } + explicit GFile(const String&); + virtual ~GFile() override; + + String filename() const { return m_filename; } + void set_filename(const String& filename) { m_filename = filename; } + + virtual bool open(GIODevice::OpenMode) override; + virtual bool close() override; + + virtual const char* class_name() const override { return "GFile"; } + +private: + String m_filename; +}; diff --git a/LibGUI/GIODevice.cpp b/LibGUI/GIODevice.cpp new file mode 100644 index 0000000000..d62d36622f --- /dev/null +++ b/LibGUI/GIODevice.cpp @@ -0,0 +1,89 @@ +#include <LibGUI/GIODevice.h> +#include <unistd.h> + +GIODevice::GIODevice(GObject* parent) + : GObject(parent) +{ +} + +GIODevice::~GIODevice() +{ +} + +const char* GIODevice::error_string() const +{ + return strerror(m_error); +} + +ByteBuffer GIODevice::read(int max_size) +{ + if (m_fd < 0) + return { }; + if (!max_size) + return { }; + auto buffer = ByteBuffer::create_uninitialized(max_size); + auto* buffer_ptr = (char*)buffer.pointer(); + int remaining_buffer_space = buffer.size(); + if (!m_buffered_data.is_empty()) { + int taken_from_buffered = min(remaining_buffer_space, m_buffered_data.size()); + memcpy(buffer_ptr, m_buffered_data.data(), taken_from_buffered); + Vector<byte> new_buffered_data; + new_buffered_data.append(m_buffered_data.data() + taken_from_buffered, m_buffered_data.size() - taken_from_buffered); + m_buffered_data = move(new_buffered_data); + remaining_buffer_space -= taken_from_buffered; + buffer_ptr += taken_from_buffered; + } + if (!remaining_buffer_space) + return buffer; + int nread = ::read(m_fd, buffer_ptr, remaining_buffer_space); + if (nread < 0) { + set_error(errno); + return { }; + } + buffer.trim(nread); + return buffer; +} + +ByteBuffer GIODevice::read_line(int max_size) +{ + if (m_fd < 0) + return { }; + if (!max_size) + return { }; + auto line = ByteBuffer::create_uninitialized(max_size); + int line_index = 0; + while (line_index < line.size()) { + if (line_index >= m_buffered_data.size()) { + if (!populate_read_buffer()) + return { }; + } + byte ch = m_buffered_data[line_index]; + line[line_index++] = ch; + if (ch == '\n') { + Vector<byte> new_buffered_data; + new_buffered_data.append(m_buffered_data.data() + line_index, m_buffered_data.size() - line_index); + m_buffered_data = move(new_buffered_data); + line.trim(line_index); + return line; + } + } + return { }; +} + +bool GIODevice::populate_read_buffer() +{ + if (m_fd < 0) + return false; + auto buffer = ByteBuffer::create_uninitialized(1024); + int nread = ::read(m_fd, buffer.pointer(), buffer.size()); + if (nread < 0) { + set_error(errno); + return false; + } + if (nread == 0) { + set_eof(true); + return false; + } + m_buffered_data.append(buffer.pointer(), buffer.size()); + return true; +} diff --git a/LibGUI/GIODevice.h b/LibGUI/GIODevice.h new file mode 100644 index 0000000000..744e1997d0 --- /dev/null +++ b/LibGUI/GIODevice.h @@ -0,0 +1,53 @@ +#pragma once + +#include <LibGUI/GObject.h> +#include <AK/ByteBuffer.h> + +class GIODevice : public GObject { +public: + enum OpenMode { + NotOpen = 0, + ReadOnly = 1, + WriteOnly = 2, + ReadWrite = 3, + Append = 4, + Truncate = 8, + MustBeNew = 16, + }; + + virtual ~GIODevice() override; + + int fd() const { return m_fd; } + unsigned mode() const { return m_mode; } + bool eof() const { return m_eof; } + + int error() const { return m_error; } + const char* error_string() const; + + bool has_error() const { return m_error != 0; } + + ByteBuffer read(int max_size); + ByteBuffer read_line(int max_size); + + virtual bool open(GIODevice::OpenMode) = 0; + virtual bool close() = 0; + + virtual const char* class_name() const override { return "GIODevice"; } + +protected: + explicit GIODevice(GObject* parent = nullptr); + + void set_fd(int fd) { m_fd = fd; } + void set_mode(OpenMode mode) { m_mode = mode; } + void set_error(int error) { m_error = error; } + void set_eof(bool eof) { m_eof = eof; } + +private: + bool populate_read_buffer(); + + int m_fd { -1 }; + int m_error { 0 }; + bool m_eof { false }; + OpenMode m_mode { NotOpen }; + Vector<byte> m_buffered_data; +}; diff --git a/LibGUI/Makefile b/LibGUI/Makefile index 9e1d100c1a..c39478d130 100644 --- a/LibGUI/Makefile +++ b/LibGUI/Makefile @@ -7,6 +7,8 @@ SHAREDGRAPHICS_OBJS = \ ../SharedGraphics/Color.o LIBGUI_OBJS = \ + GIODevice.o \ + GFile.o \ GButton.o \ GCheckBox.o \ GEventLoop.o \ |