mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 19:22:45 +00:00 
			
		
		
		
	GIODevice: Add a read_all() that returns a ByteBuffer with all we can read.
Use this to implement file opening in TextEditor.
This commit is contained in:
		
							parent
							
								
									8e3d0a23d5
								
							
						
					
					
						commit
						9ad076178a
					
				
					 6 changed files with 58 additions and 25 deletions
				
			
		|  | @ -100,6 +100,7 @@ public: | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ByteBuffer to_byte_buffer() const; |     ByteBuffer to_byte_buffer() const; | ||||||
|  |     static String from_byte_buffer(const ByteBuffer&); | ||||||
| 
 | 
 | ||||||
|     static String format(const char*, ...); |     static String format(const char*, ...); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -38,6 +38,7 @@ public: | ||||||
|     byte* offset_pointer(int offset) { return m_data + offset; } |     byte* offset_pointer(int offset) { return m_data + offset; } | ||||||
|     const byte* offset_pointer(int offset) const { 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; } |     const void* end_pointer() const { return m_data + m_size; } | ||||||
| 
 | 
 | ||||||
|     // NOTE: trim() does not reallocate.
 |     // 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; } |     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; } |     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; } |     const void* end_pointer() const { return m_impl ? m_impl->end_pointer() : nullptr; } | ||||||
| 
 | 
 | ||||||
|     // NOTE: trim() does not reallocate.
 |     // NOTE: trim() does not reallocate.
 | ||||||
|  | @ -137,6 +139,13 @@ public: | ||||||
|             m_impl->grow(size); |             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: | private: | ||||||
|     explicit ByteBuffer(RetainPtr<ByteBufferImpl>&& impl) |     explicit ByteBuffer(RetainPtr<ByteBufferImpl>&& impl) | ||||||
|         : m_impl(move(impl)) |         : m_impl(move(impl)) | ||||||
|  |  | ||||||
|  | @ -92,6 +92,15 @@ ByteBuffer String::to_byte_buffer() const | ||||||
|     return ByteBuffer::copy(reinterpret_cast<const byte*>(characters()), length()); |     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 String::to_uint(bool& ok) const | ||||||
| { | { | ||||||
|     unsigned value = 0; |     unsigned value = 0; | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ | ||||||
| #include <LibGUI/GTextEditor.h> | #include <LibGUI/GTextEditor.h> | ||||||
| #include <LibGUI/GAction.h> | #include <LibGUI/GAction.h> | ||||||
| #include <LibGUI/GFontDatabase.h> | #include <LibGUI/GFontDatabase.h> | ||||||
|  | #include <LibGUI/GFile.h> | ||||||
| #include <AK/StringBuilder.h> | #include <AK/StringBuilder.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
|  | @ -34,31 +35,13 @@ int main(int argc, char** argv) | ||||||
|     String path = "/tmp/TextEditor.save.txt"; |     String path = "/tmp/TextEditor.save.txt"; | ||||||
|     if (argc >= 2) { |     if (argc >= 2) { | ||||||
|         path = argv[1]; |         path = argv[1]; | ||||||
|         StringBuilder builder; |         GFile file(path); | ||||||
|         int fd = open(path.characters(), O_RDONLY); | 
 | ||||||
|         if (fd < 0) { |         if (!file.open(GIODevice::ReadOnly)) { | ||||||
|             perror("open"); |             fprintf(stderr, "Opening %s: %s\n", path.characters(), file.error_string()); | ||||||
|             return 1; |             return 1; | ||||||
|         } |         } | ||||||
|         for (;;) { |         text_editor->set_text(String::from_byte_buffer(file.read_all())); | ||||||
|             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); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         int rc = close(fd); |  | ||||||
|         if (rc < 0) { |  | ||||||
|             perror("close"); |  | ||||||
|             return 1; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         text_editor->set_text(builder.to_string()); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     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&) { |     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&) { | ||||||
|  |  | ||||||
|  | @ -46,7 +46,7 @@ ByteBuffer GIODevice::read(int max_size) | ||||||
|     return buffer; |     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?
 |     // FIXME: Can we somehow remove this once GSocket is implemented using non-blocking sockets?
 | ||||||
|     fd_set rfds; |     fd_set rfds; | ||||||
|  | @ -68,12 +68,41 @@ bool GIODevice::can_read_line() | ||||||
|         return true; |         return true; | ||||||
|     if (m_buffered_data.contains_slow('\n')) |     if (m_buffered_data.contains_slow('\n')) | ||||||
|         return true; |         return true; | ||||||
|     if (!can_read()) |     if (!can_read_from_fd()) | ||||||
|         return false; |         return false; | ||||||
|     populate_read_buffer(); |     populate_read_buffer(); | ||||||
|     return m_buffered_data.contains_slow('\n'); |     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) | ByteBuffer GIODevice::read_line(int max_size) | ||||||
| { | { | ||||||
|     if (m_fd < 0) |     if (m_fd < 0) | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     ByteBuffer read(int max_size); |     ByteBuffer read(int max_size); | ||||||
|     ByteBuffer read_line(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().
 |     // FIXME: I would like this to be const but currently it needs to call populate_read_buffer().
 | ||||||
|     bool can_read_line(); |     bool can_read_line(); | ||||||
|  | @ -49,6 +50,7 @@ protected: | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     bool populate_read_buffer(); |     bool populate_read_buffer(); | ||||||
|  |     bool can_read_from_fd() const; | ||||||
| 
 | 
 | ||||||
|     int m_fd { -1 }; |     int m_fd { -1 }; | ||||||
|     int m_error { 0 }; |     int m_error { 0 }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling