Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Utilities: Support reading arbitrarily long lines #24311

Merged
merged 5 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 18 additions & 21 deletions Userland/Utilities/comm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,27 +113,27 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
int col3_count { 0 };
ByteString file1_line;
ByteString file2_line;
Array<u8, PAGE_SIZE> buffer;
auto buffer = TRY(ByteBuffer::create_uninitialized(PAGE_SIZE));

auto should_continue_comparing_files = [&]() {
if (read_file1) {
auto can_read_file1_line = file1->can_read_line();
if (can_read_file1_line.is_error() || !can_read_file1_line.value())
return false;
}
if (read_file2) {
auto can_read_file2_line = file2->can_read_line();
if (can_read_file2_line.is_error() || !can_read_file2_line.value())
return false;
}
if (read_file1 && file1->is_eof())
return false;
if (read_file2 && file2->is_eof())
return false;
return true;
};

while (should_continue_comparing_files()) {
if (read_file1)
file1_line = TRY(file1->read_line(buffer));
if (read_file2)
file2_line = TRY(file2->read_line(buffer));
if (read_file1) {
file1_line = TRY(file1->read_line_with_resize(buffer));
if (file1_line.is_empty() && file1->is_eof())
break;
}
if (read_file2) {
file2_line = TRY(file2->read_line_with_resize(buffer));
if (file2_line.is_empty() && file2->is_eof())
break;
}

int cmp_result = cmp(file1_line, file2_line);

Expand Down Expand Up @@ -168,13 +168,10 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
}

auto process_remaining = [&](ByteString const& fmt, auto& file, int& count, bool print) {
while (true) {
auto can_read_result = file->can_read_line();
if (can_read_result.is_error() || !can_read_result.value())
break;
while (!file->is_eof()) {
++count;
auto line = file->read_line(buffer);
if (line.is_error())
auto line = file->read_line_with_resize(buffer);
if (line.is_error() || (line.value().is_empty() && file->is_eof()))
break;
if (print)
outln(fmt, line.value());
Expand Down
12 changes: 6 additions & 6 deletions Userland/Utilities/cut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ static bool expand_list(ByteString& list, Vector<Range>& ranges)
static void process_line_bytes(StringView line, Vector<Range> const& ranges)
{
for (auto& i : ranges) {
if (i.m_from >= line.length())
if (i.m_from > line.length())
continue;

auto to = min(i.m_to, line.length());
Expand All @@ -143,7 +143,7 @@ static void process_line_bytes(StringView line, Vector<Range> const& ranges)
static void process_line_characters(StringView line, Vector<Range> const& ranges)
{
for (auto const& range : ranges) {
if (range.m_from >= line.length())
if (range.m_from > line.length())
continue;

auto s = String::from_utf8(line).release_value_but_fixme_should_propagate_errors();
Expand Down Expand Up @@ -271,10 +271,10 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
}
auto file = TRY(Core::InputBufferedFile::create(maybe_file.release_value()));

Array<u8, PAGE_SIZE> buffer;
while (TRY(file->can_read_line())) {
auto line = TRY(file->read_line(buffer));
if (line == "\n" && TRY(file->can_read_line()))
auto buffer = TRY(ByteBuffer::create_uninitialized(PAGE_SIZE));
while (!file->is_eof()) {
auto line = TRY(file->read_line_with_resize(buffer));
if (line.is_empty() && file->is_eof())
break;

if (selected_bytes) {
Expand Down
12 changes: 7 additions & 5 deletions Userland/Utilities/grep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,9 @@ ErrorOr<int> serenity_main(Main::Arguments args)
if (!pattern_file.is_empty()) {
auto file = TRY(Core::File::open(pattern_file, Core::File::OpenMode::Read));
auto buffered_file = TRY(Core::InputBufferedFile::create(move(file)));
Array<u8, PAGE_SIZE> buffer;
auto buffer = TRY(ByteBuffer::create_uninitialized(PAGE_SIZE));
while (!buffered_file->is_eof()) {
auto next_pattern = TRY(buffered_file->read_line(buffer));
auto next_pattern = TRY(buffered_file->read_line_with_resize(buffer));
// Empty lines represent a valid pattern, but the trailing newline
// should be ignored.
if (next_pattern.is_empty() && buffered_file->is_eof())
Expand Down Expand Up @@ -300,9 +300,11 @@ ErrorOr<int> serenity_main(Main::Arguments args)
auto file = TRY(Core::File::open_file_or_standard_stream(filename, Core::File::OpenMode::Read));
auto buffered_file = TRY(Core::InputBufferedFile::create(move(file)));

for (size_t line_number = 1; TRY(buffered_file->can_read_line()); ++line_number) {
Array<u8, PAGE_SIZE> buffer;
auto line = TRY(buffered_file->read_line(buffer));
auto buffer = TRY(ByteBuffer::create_uninitialized(PAGE_SIZE));
for (size_t line_number = 1; !buffered_file->is_eof(); ++line_number) {
auto line = TRY(buffered_file->read_line_with_resize(buffer));
if (line.is_empty() && buffered_file->is_eof())
break;

auto is_binary = line.contains('\0');

Expand Down
20 changes: 11 additions & 9 deletions Userland/Utilities/sed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,15 +659,15 @@ class File {
};
}

ErrorOr<bool> has_next() const
bool has_next() const
{
return m_file->can_read_line();
return !m_file->is_eof();
}

ErrorOr<StringView> next()
{
VERIFY(TRY(has_next()));
m_current_line = TRY(m_file->read_line(m_buffer));
VERIFY(has_next());
m_current_line = TRY(m_file->read_line_with_resize(m_buffer));
++m_line_number;
return m_current_line;
}
Expand Down Expand Up @@ -700,6 +700,7 @@ class File {
, m_file(move(file))
, m_output(move(output))
, m_output_temp_file(move(temp_file))
, m_buffer(MUST(ByteBuffer::create_uninitialized(PAGE_SIZE)))
{
}

Expand All @@ -711,8 +712,7 @@ class File {
OwnPtr<FileSystem::TempFile> m_output_temp_file;
size_t m_line_number { 0 };
ByteString m_current_line;
constexpr static size_t MAX_SUPPORTED_LINE_SIZE = 4096;
Array<u8, MAX_SUPPORTED_LINE_SIZE> m_buffer;
ByteBuffer m_buffer;
};

static ErrorOr<void> write_pattern_space(File& output, StringBuilder& pattern_space)
Expand Down Expand Up @@ -796,7 +796,7 @@ static ErrorOr<CycleDecision> apply(Command const& command, StringBuilder& patte
if (!suppress_default_output)
TRY(write_pattern_space(stdout, pattern_space));
TRY(write_pattern_space(input, pattern_space));
if (TRY(input.has_next())) {
if (input.has_next()) {
pattern_space.clear();
pattern_space.append(TRY(input.next()));
}
Expand Down Expand Up @@ -853,11 +853,13 @@ static ErrorOr<void> run(Vector<File>& inputs, Script& script, bool suppress_def
auto stdout = TRY(File::create_from_stdout());

// main loop
while (TRY(input.has_next())) {
while (input.has_next()) {

// Avoid potential last, empty line
auto line = TRY(input.next());
auto is_last_line = !TRY(input.has_next());
auto is_last_line = !input.has_next();
if (is_last_line && line.is_empty())
break;

// TODO: "Reading from input shall be skipped if a <newline> was in the pattern space prior to a D command ending the previous cycle"
pattern_space.append(line);
Expand Down
Loading