From dddd0e7b0317f02e1aad5d60d87844da8f6785e4 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 3 Feb 2019 16:11:28 +0100 Subject: Get nyancat nyanning in Serenity. I found a cute program that renders an animated nyancat in the terminal. This patch adds enough hackery to get it working correctly. :^) --- AK/StringImpl.cpp | 3 + Kernel/Process.cpp | 14 +++ Kernel/Process.h | 1 + Kernel/Syscall.cpp | 2 + Kernel/Syscall.h | 1 + Kernel/types.h | 1 + LibC/string.cpp | 10 ++ LibC/string.h | 2 + LibC/sys/types.h | 1 + LibC/time.h | 2 + LibC/unistd.cpp | 5 + LibC/unistd.h | 1 + Terminal/Terminal.cpp | 96 +++++++----------- Terminal/Terminal.h | 8 +- Terminal/XtermColors.h | 260 +++++++++++++++++++++++++++++++++++++++++++++++++ 15 files changed, 342 insertions(+), 65 deletions(-) create mode 100644 Terminal/XtermColors.h diff --git a/AK/StringImpl.cpp b/AK/StringImpl.cpp index 3bf43dd1cd..396d556851 100644 --- a/AK/StringImpl.cpp +++ b/AK/StringImpl.cpp @@ -81,6 +81,9 @@ RetainPtr StringImpl::create(const char* cstring, size_t length, Sho if (!*cstring) return the_empty_stringimpl(); + if (!length) + return the_empty_stringimpl(); + char* buffer; auto new_stringimpl = create_uninitialized(length, buffer); if (!new_stringimpl) diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 317614cbd9..edc5bb08ca 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -1425,6 +1425,20 @@ int Process::sys$kill(pid_t pid, int signal) return 0; } +int Process::sys$usleep(useconds_t usec) +{ + if (!usec) + return 0; + + sleep(usec / 1000); + if (m_wakeup_time > system.uptime) { + ASSERT(m_was_interrupted_while_blocked); + dword ticks_left_until_original_wakeup_time = m_wakeup_time - system.uptime; + return ticks_left_until_original_wakeup_time / TICKS_PER_SECOND; + } + return 0; +} + int Process::sys$sleep(unsigned seconds) { if (!seconds) diff --git a/Kernel/Process.h b/Kernel/Process.h index f4eb329c78..2e524e3618 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -166,6 +166,7 @@ public: int sys$getcwd(char*, size_t); int sys$chdir(const char*); int sys$sleep(unsigned seconds); + int sys$usleep(useconds_t usec); int sys$gettimeofday(timeval*); int sys$gethostname(char* name, size_t length); int sys$get_arguments(int* argc, char*** argv); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 848465a50a..4b2b8d4d2e 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -62,6 +62,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2, break; case Syscall::SC_sleep: return current->sys$sleep((unsigned)arg1); + case Syscall::SC_usleep: + return current->sys$usleep((unsigned)arg1); case Syscall::SC_gettimeofday: return current->sys$gettimeofday((timeval*)arg1); case Syscall::SC_get_dir_entries: diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index dd552a3abb..964426454d 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -84,6 +84,7 @@ __ENUMERATE_SYSCALL(gui_set_global_cursor_tracking_enabled) \ __ENUMERATE_SYSCALL(rmdir) \ __ENUMERATE_SYSCALL(chmod) \ + __ENUMERATE_SYSCALL(usleep) \ #ifdef SERENITY diff --git a/Kernel/types.h b/Kernel/types.h index b355315b46..45cd0bb45d 100644 --- a/Kernel/types.h +++ b/Kernel/types.h @@ -16,6 +16,7 @@ typedef dword uid_t; typedef dword gid_t; typedef signed_word pid_t; typedef dword time_t; +typedef dword useconds_t; typedef dword suseconds_t; struct timeval { diff --git a/LibC/string.cpp b/LibC/string.cpp index 02d8d934ea..47ddf45e3f 100644 --- a/LibC/string.cpp +++ b/LibC/string.cpp @@ -5,6 +5,7 @@ #include #include #include +#include extern "C" { @@ -60,6 +61,15 @@ char* strdup(const char* str) return new_str; } +char* strndup(const char* str, size_t maxlen) +{ + size_t len = min(strlen(str), maxlen); + char* new_str = (char*)malloc(len + 1); + memcpy(new_str, str, len); + new_str[len] = 0; + return new_str; +} + int strcmp(const char* s1, const char* s2) { while (*s1 == *s2++) diff --git a/LibC/string.h b/LibC/string.h index c2d501a8a7..7783731d91 100644 --- a/LibC/string.h +++ b/LibC/string.h @@ -15,6 +15,8 @@ void* memchr(const void*, int c, size_t); void bzero(void*, size_t); void bcopy(const void*, void*, size_t); void* memset(void*, int, size_t); +char* strdup(const char*); +char* strndup(const char*, size_t); char* strcpy(char* dest, const char* src); char* strncpy(char* dest, const char* src, size_t); char* strchr(const char*, int c); diff --git a/LibC/sys/types.h b/LibC/sys/types.h index 18a3fcb1aa..8a80a4c340 100644 --- a/LibC/sys/types.h +++ b/LibC/sys/types.h @@ -29,6 +29,7 @@ typedef uint32_t nlink_t; typedef uint32_t blksize_t; typedef uint32_t blkcnt_t; typedef uint32_t time_t; +typedef uint32_t useconds_t; typedef uint32_t suseconds_t; typedef uint32_t clock_t; typedef uint32_t socklen_t; diff --git a/LibC/time.h b/LibC/time.h index fcb723a8f3..45f17cd4f5 100644 --- a/LibC/time.h +++ b/LibC/time.h @@ -30,5 +30,7 @@ time_t time(time_t*); char* ctime(const time_t*); void tzset(); +#define difftime(t1,t0) (double)(t1 - t0) + __END_DECLS diff --git a/LibC/unistd.cpp b/LibC/unistd.cpp index 3064e438c9..6c7282e809 100644 --- a/LibC/unistd.cpp +++ b/LibC/unistd.cpp @@ -201,6 +201,11 @@ int sleep(unsigned seconds) return syscall(SC_sleep, seconds); } +int usleep(useconds_t usec) +{ + return syscall(SC_usleep, usec); +} + int gethostname(char* buffer, size_t size) { int rc = syscall(SC_gethostname, buffer, size); diff --git a/LibC/unistd.h b/LibC/unistd.h index a88a11b7c6..a3355cbc99 100644 --- a/LibC/unistd.h +++ b/LibC/unistd.h @@ -42,6 +42,7 @@ int fstat(int fd, struct stat* statbuf); int lstat(const char* path, struct stat* statbuf); int stat(const char* path, struct stat* statbuf); int sleep(unsigned seconds); +int usleep(useconds_t); int gethostname(char*, size_t); ssize_t readlink(const char* path, char* buffer, size_t); char* ttyname(int fd); diff --git a/Terminal/Terminal.cpp b/Terminal/Terminal.cpp index bb016016c1..4d0c8aae6e 100644 --- a/Terminal/Terminal.cpp +++ b/Terminal/Terminal.cpp @@ -1,4 +1,5 @@ #include "Terminal.h" +#include "XtermColors.h" #include #include #include @@ -72,12 +73,12 @@ Terminal::Line::~Line() delete [] attributes; } -void Terminal::Line::clear() +void Terminal::Line::clear(Attribute attribute) { dirty = true; memset(characters, ' ', length); for (word i = 0 ; i < length; ++i) - attributes[i].reset(); + attributes[i] = attribute; } Terminal::~Terminal() @@ -91,7 +92,7 @@ Terminal::~Terminal() void Terminal::clear() { for (size_t i = 0; i < rows(); ++i) - line(i).clear(); + line(i).clear(m_current_attribute); set_cursor(0, 0); } @@ -125,50 +126,22 @@ unsigned parse_uint(const String& str, bool& ok) return value; } -enum ANSIColor : byte { - Black = 0, - Red, - Green, - Brown, - Blue, - Magenta, - Cyan, - LightGray, - DarkGray, - BrightRed, - BrightGreen, - Yellow, - BrightBlue, - BrightMagenta, - BrightCyan, - White, -}; - -static inline Color ansi_color(unsigned color) -{ - static const RGBA32 s_ansi_color[16] = { - make_rgb(0, 0, 0), // Black - make_rgb(225, 56, 43), // Red - make_rgb(57, 181, 74), // Green - make_rgb(255, 199, 6), // Brown - make_rgb(0, 111, 184), // Blue - make_rgb(118, 38, 113), // Magenta - make_rgb(44, 181, 233), // Cyan - make_rgb(204, 204, 204), // LightGray - make_rgb(128, 128, 128), // DarkGray - make_rgb(255, 0, 0), // BrightRed - make_rgb(0, 255, 0), // BrightGreen - make_rgb(255, 255, 0), // Yellow - make_rgb(0, 0, 255), // BrightBlue - make_rgb(255, 0, 255), // BrightMagenta - make_rgb(0, 255, 255), // BrightCyan - make_rgb(255, 255, 255), // White - }; - return s_ansi_color[color]; +static inline Color lookup_color(unsigned color) +{ + return xterm_colors[color]; } void Terminal::escape$m(const Vector& params) { + if (params.size() == 3 && params[1] == 5) { + if (params[0] == 38) { + m_current_attribute.foreground_color = params[2]; + return; + } else if (params[0] == 48) { + m_current_attribute.background_color = params[2]; + return; + } + } for (auto param : params) { switch (param) { case 0: @@ -364,6 +337,8 @@ void Terminal::execute_xterm_command() if (ok) { switch (value) { case 0: + case 1: + case 2: set_window_title(String((const char*)m_xterm_param2.data(), m_xterm_param2.size())); break; default: @@ -384,6 +359,8 @@ void Terminal::execute_escape_sequence(byte final) bool ok; unsigned value = parse_uint(parampart, ok); if (!ok) { + m_parameters.clear_with_capacity(); + m_intermediates.clear_with_capacity(); // FIXME: Should we do something else? return; } @@ -406,8 +383,8 @@ void Terminal::execute_escape_sequence(byte final) break; } - m_parameters.clear(); - m_intermediates.clear(); + m_parameters.clear_with_capacity(); + m_intermediates.clear_with_capacity(); } void Terminal::newline() @@ -463,7 +440,7 @@ void Terminal::put_character_at(unsigned row, unsigned column, byte ch) void Terminal::on_char(byte ch) { #ifdef TERMINAL_DEBUG - dbgprintf("Terminal::on_char: %b (%c)\n", ch, ch); + dbgprintf("Terminal::on_char: %b (%c), fg=%u, bg=%u\n", ch, ch, m_current_attribute.foreground_color, m_current_attribute.background_color); #endif switch (m_escape_state) { case ExpectBracket: @@ -617,14 +594,9 @@ Rect Terminal::glyph_rect(word row, word column) Rect Terminal::row_rect(word row) { int y = row * m_line_height; - return { m_inset, y + m_inset, font().glyph_width() * m_columns, font().glyph_height() }; -} - -inline Terminal::Attribute& Terminal::attribute_at(word row, word column) -{ - ASSERT(row < m_rows); - ASSERT(column < m_columns); - return line(row).attributes[column]; + Rect rect = { m_inset, y + m_inset, font().glyph_width() * m_columns, font().glyph_height() }; + rect.inflate(0, m_line_spacing); + return rect; } bool Terminal::Line::has_only_one_background_color() const @@ -671,25 +643,29 @@ void Terminal::paint() continue; line.dirty = false; bool has_only_one_background_color = line.has_only_one_background_color(); - if (has_only_one_background_color) - painter.fill_rect(row_rect(row), line.attributes[0].background_color); + if (has_only_one_background_color) { + painter.fill_rect(row_rect(row), lookup_color(line.attributes[0].background_color)); + } for (word column = 0; column < m_columns; ++column) { bool should_reverse_fill_for_cursor = m_in_active_window && row == m_cursor_row && column == m_cursor_column; auto& attribute = line.attributes[column]; line.did_paint = true; char ch = line.characters[column]; auto character_rect = glyph_rect(row, column); - if (!has_only_one_background_color || should_reverse_fill_for_cursor) - painter.fill_rect(character_rect, ansi_color(should_reverse_fill_for_cursor ? attribute.foreground_color : attribute.background_color)); + if (!has_only_one_background_color || should_reverse_fill_for_cursor) { + auto cell_rect = character_rect; + cell_rect.inflate(0, m_line_spacing); + painter.fill_rect(cell_rect, lookup_color(should_reverse_fill_for_cursor ? attribute.foreground_color : attribute.background_color)); + } if (ch == ' ') continue; - painter.draw_glyph(character_rect.location(), ch, ansi_color(should_reverse_fill_for_cursor ? attribute.background_color : attribute.foreground_color)); + painter.draw_glyph(character_rect.location(), ch, lookup_color(should_reverse_fill_for_cursor ? attribute.background_color : attribute.foreground_color)); } } if (!m_in_active_window) { auto cursor_rect = glyph_rect(m_cursor_row, m_cursor_column); - painter.draw_rect(cursor_rect, ansi_color(line(m_cursor_row).attributes[m_cursor_column].foreground_color)); + painter.draw_rect(cursor_rect, lookup_color(line(m_cursor_row).attributes[m_cursor_column].foreground_color)); } line(m_cursor_row).did_paint = true; diff --git a/Terminal/Terminal.h b/Terminal/Terminal.h index 06d8caa484..5a81b410c9 100644 --- a/Terminal/Terminal.h +++ b/Terminal/Terminal.h @@ -63,8 +63,8 @@ private: background_color = 0; //bold = false; } - unsigned foreground_color : 4; - unsigned background_color : 4; + byte foreground_color; + byte background_color; //bool bold : 1; bool operator==(const Attribute& other) const { @@ -75,7 +75,7 @@ private: struct Line { explicit Line(word columns); ~Line(); - void clear(); + void clear(Attribute); bool has_only_one_background_color() const; byte* characters { nullptr }; Attribute* attributes { nullptr }; @@ -98,8 +98,6 @@ private: Attribute m_current_attribute; - Attribute& attribute_at(word row, word column); - void execute_escape_sequence(byte final); void execute_xterm_command(); diff --git a/Terminal/XtermColors.h b/Terminal/XtermColors.h new file mode 100644 index 0000000000..8d9239dbba --- /dev/null +++ b/Terminal/XtermColors.h @@ -0,0 +1,260 @@ +#pragma once + +static const unsigned xterm_colors[256] = { + 0x000000, + 0xcc0000, + 0x3e9a06, + 0xc4a000, + 0x3465a4, + 0x75507b, + 0x06989a, + 0xeeeeec, + 0x555753, + 0xef2929, + 0x8ae234, + 0xfce94f, + 0x729fcf, + 0xad7fa8, + 0x34e2e2, + 0xFFFFFF, + 0x000000, + 0x00005f, + 0x000087, + 0x0000af, + 0x0000d7, + 0x0000ff, + 0x005f00, + 0x005f5f, + 0x005f87, + 0x005faf, + 0x005fd7, + 0x005fff, + 0x008700, + 0x00875f, + 0x008787, + 0x0087af, + 0x0087d7, + 0x0087ff, + 0x00af00, + 0x00af5f, + 0x00af87, + 0x00afaf, + 0x00afd7, + 0x00afff, + 0x00d700, + 0x00d75f, + 0x00d787, + 0x00d7af, + 0x00d7d7, + 0x00d7ff, + 0x00ff00, + 0x00ff5f, + 0x00ff87, + 0x00ffaf, + 0x00ffd7, + 0x00ffff, + 0x5f0000, + 0x5f005f, + 0x5f0087, + 0x5f00af, + 0x5f00d7, + 0x5f00ff, + 0x5f5f00, + 0x5f5f5f, + 0x5f5f87, + 0x5f5faf, + 0x5f5fd7, + 0x5f5fff, + 0x5f8700, + 0x5f875f, + 0x5f8787, + 0x5f87af, + 0x5f87d7, + 0x5f87ff, + 0x5faf00, + 0x5faf5f, + 0x5faf87, + 0x5fafaf, + 0x5fafd7, + 0x5fafff, + 0x5fd700, + 0x5fd75f, + 0x5fd787, + 0x5fd7af, + 0x5fd7d7, + 0x5fd7ff, + 0x5fff00, + 0x5fff5f, + 0x5fff87, + 0x5fffaf, + 0x5fffd7, + 0x5fffff, + 0x870000, + 0x87005f, + 0x870087, + 0x8700af, + 0x8700d7, + 0x8700ff, + 0x875f00, + 0x875f5f, + 0x875f87, + 0x875faf, + 0x875fd7, + 0x875fff, + 0x878700, + 0x87875f, + 0x878787, + 0x8787af, + 0x8787d7, + 0x8787ff, + 0x87af00, + 0x87af5f, + 0x87af87, + 0x87afaf, + 0x87afd7, + 0x87afff, + 0x87d700, + 0x87d75f, + 0x87d787, + 0x87d7af, + 0x87d7d7, + 0x87d7ff, + 0x87ff00, + 0x87ff5f, + 0x87ff87, + 0x87ffaf, + 0x87ffd7, + 0x87ffff, + 0xaf0000, + 0xaf005f, + 0xaf0087, + 0xaf00af, + 0xaf00d7, + 0xaf00ff, + 0xaf5f00, + 0xaf5f5f, + 0xaf5f87, + 0xaf5faf, + 0xaf5fd7, + 0xaf5fff, + 0xaf8700, + 0xaf875f, + 0xaf8787, + 0xaf87af, + 0xaf87d7, + 0xaf87ff, + 0xafaf00, + 0xafaf5f, + 0xafaf87, + 0xafafaf, + 0xafafd7, + 0xafafff, + 0xafd700, + 0xafd75f, + 0xafd787, + 0xafd7af, + 0xafd7d7, + 0xafd7ff, + 0xafff00, + 0xafff5f, + 0xafff87, + 0xafffaf, + 0xafffd7, + 0xafffff, + 0xd70000, + 0xd7005f, + 0xd70087, + 0xd700af, + 0xd700d7, + 0xd700ff, + 0xd75f00, + 0xd75f5f, + 0xd75f87, + 0xd75faf, + 0xd75fd7, + 0xd75fff, + 0xd78700, + 0xd7875f, + 0xd78787, + 0xd787af, + 0xd787d7, + 0xd787ff, + 0xd7af00, + 0xd7af5f, + 0xd7af87, + 0xd7afaf, + 0xd7afd7, + 0xd7afff, + 0xd7d700, + 0xd7d75f, + 0xd7d787, + 0xd7d7af, + 0xd7d7d7, + 0xd7d7ff, + 0xd7ff00, + 0xd7ff5f, + 0xd7ff87, + 0xd7ffaf, + 0xd7ffd7, + 0xd7ffff, + 0xff0000, + 0xff005f, + 0xff0087, + 0xff00af, + 0xff00d7, + 0xff00ff, + 0xff5f00, + 0xff5f5f, + 0xff5f87, + 0xff5faf, + 0xff5fd7, + 0xff5fff, + 0xff8700, + 0xff875f, + 0xff8787, + 0xff87af, + 0xff87d7, + 0xff87ff, + 0xffaf00, + 0xffaf5f, + 0xffaf87, + 0xffafaf, + 0xffafd7, + 0xffafff, + 0xffd700, + 0xffd75f, + 0xffd787, + 0xffd7af, + 0xffd7d7, + 0xffd7ff, + 0xffff00, + 0xffff5f, + 0xffff87, + 0xffffaf, + 0xffffd7, + 0xffffff, + 0x080808, + 0x121212, + 0x1c1c1c, + 0x262626, + 0x303030, + 0x3a3a3a, + 0x444444, + 0x4e4e4e, + 0x585858, + 0x626262, + 0x6c6c6c, + 0x767676, + 0x808080, + 0x8a8a8a, + 0x949494, + 0x9e9e9e, + 0xa8a8a8, + 0xb2b2b2, + 0xbcbcbc, + 0xc6c6c6, + 0xd0d0d0, + 0xdadada, + 0xe4e4e4, + 0xeeeeee, +}; -- cgit v1.2.3