diff --git a/Kernel/TTY/TTY.cpp b/Kernel/TTY/TTY.cpp index f32e50b5edd..8780cec36a8 100644 --- a/Kernel/TTY/TTY.cpp +++ b/Kernel/TTY/TTY.cpp @@ -90,22 +90,17 @@ KResultOr TTY::write(FileDescription&, u64, const UserOrKernelBuffer& bu constexpr size_t num_chars = 256; return buffer.read_buffered(size, [&](u8 const* data, size_t buffer_bytes) { u8 modified_data[num_chars * 2]; - size_t extra_chars = 0; + size_t modified_data_size = 0; for (size_t i = 0; i < buffer_bytes; ++i) { - auto ch = data[i]; - if (m_termios.c_oflag & OPOST) { - if (ch == '\n' && (m_termios.c_oflag & ONLCR)) { - modified_data[i + extra_chars] = '\r'; - extra_chars++; - } - } - modified_data[i + extra_chars] = ch; + process_output(data[i], [this, &modified_data, &modified_data_size](u8 out_ch) { + modified_data[modified_data_size++] = out_ch; + }); } - ssize_t bytes_written = on_tty_write(UserOrKernelBuffer::for_kernel_buffer(modified_data), buffer_bytes + extra_chars); + ssize_t bytes_written = on_tty_write(UserOrKernelBuffer::for_kernel_buffer(modified_data), modified_data_size); VERIFY(bytes_written != 0); if (bytes_written < 0 || !(m_termios.c_oflag & OPOST) || !(m_termios.c_oflag & ONLCR)) return bytes_written; - if ((size_t)bytes_written == buffer_bytes + extra_chars) + if ((size_t)bytes_written == modified_data_size) return (ssize_t)buffer_bytes; // Degenerate case where we converted some newlines and encountered a partial write @@ -127,6 +122,23 @@ KResultOr TTY::write(FileDescription&, u64, const UserOrKernelBuffer& bu }); } +void TTY::echo_with_processing(u8 ch) +{ + process_output(ch, [this](u8 out_ch) { echo(out_ch); }); +} + +template +void TTY::process_output(u8 ch, Functor put_char) +{ + if (m_termios.c_oflag & OPOST) { + if (ch == '\n' && (m_termios.c_oflag & ONLCR)) + put_char('\r'); + put_char(ch); + } else { + put_char(ch); + } +} + bool TTY::can_read(const FileDescription&, size_t) const { if (in_canonical_mode()) { @@ -239,7 +251,8 @@ void TTY::emit(u8 ch, bool do_evaluate_block_conditions) if (ch == '\n') { if (m_termios.c_lflag & ECHO || m_termios.c_lflag & ECHONL) - echo('\n'); + echo_with_processing('\n'); + set_special_bit(); m_input_buffer.enqueue('\n'); m_available_lines++; @@ -254,7 +267,7 @@ void TTY::emit(u8 ch, bool do_evaluate_block_conditions) m_input_buffer.enqueue(ch); if (m_termios.c_lflag & ECHO) - echo(ch); + echo_with_processing(ch); } bool TTY::can_do_backspace() const @@ -271,6 +284,7 @@ void TTY::do_backspace() { if (can_do_backspace()) { m_input_buffer.dequeue_end(); + // We deliberately don't process the output here. echo(8); echo(' '); echo(8); @@ -318,6 +332,7 @@ void TTY::kill_line() void TTY::erase_character() { + // We deliberately don't process the output here. echo(m_termios.c_cc[VERASE]); echo(' '); echo(m_termios.c_cc[VERASE]); diff --git a/Kernel/TTY/TTY.h b/Kernel/TTY/TTY.h index a34961bad38..9e5ee61bfda 100644 --- a/Kernel/TTY/TTY.h +++ b/Kernel/TTY/TTY.h @@ -80,6 +80,10 @@ protected: private: // ^CharacterDevice virtual bool is_tty() const final override { return true; } + inline void echo_with_processing(u8); + + template + void process_output(u8, Functor put_char); CircularDeque m_input_buffer; // FIXME: use something like AK::Bitmap but which takes a size template parameter