From 47513bd32c256c4f35e3a8ced7d9fd7e15903530 Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Tue, 16 Feb 2021 20:38:53 -0500 Subject: terminal application with ipc, shift+pause state dumper, hello world for terminal, meminfo popup program --- src/user/terminal/main.c | 373 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 src/user/terminal/main.c (limited to 'src/user/terminal/main.c') diff --git a/src/user/terminal/main.c b/src/user/terminal/main.c new file mode 100644 index 0000000..15ca6a1 --- /dev/null +++ b/src/user/terminal/main.c @@ -0,0 +1,373 @@ +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#define FONT_HARDCODE "berry" + +_window_handle_t window; +uint8_t *pixbuf; +char *termbuf; +struct font_info *font; + +uint32_t width; +uint32_t height; +uint32_t cols = 50; +uint32_t rows = 15; + +uint32_t cursor_y = 0; +uint32_t cursor_x = 0; + +uint8_t bg_color = 0x10; +uint8_t fg_color = 0x07; + +struct waiting_for_key_record { + _task_handle_t task; + struct waiting_for_key_record *next; +} *first_key_waiting = 0, *last_key_waiting = 0; + +static void draw_char(uint32_t y, uint32_t x, bool inverted) { +//syslogf("drawing 0x%2h%s at %u, %u", termbuf[y * cols + x], inverted ? " inverted" : "", y, x); + put_char(font, termbuf[y * cols + x], pixbuf + y * font->space_height * width + x * font->space_width, width, inverted ? fg_color : bg_color, inverted ? bg_color : fg_color); +} + +static void clear() { + for (uint32_t i = 0; i < cols * rows; ++i) + termbuf[i] = ' '; + for (uint32_t i = 0; i < width * height; ++i) + pixbuf[i] = bg_color; +} + +static void scroll_fw() { + uint32_t i; + for (i = 0; i < cols * (rows - 1); ++i) + termbuf[i] = termbuf[i + cols]; + for (; i < cols * rows; ++i) + termbuf[i] = ' '; + const uint32_t row_height = font->space_height; + for (i = 0; i < width * (height - row_height); ++i) + pixbuf[i] = pixbuf[i + width * row_height]; + for (; i < width * height; ++i) + pixbuf[i] = bg_color; +} + +static void cursor_down() { + if (cursor_y == rows - 1) + scroll_fw(); + else + ++cursor_y; +} + +static void cursor_right() { + if (cursor_x == cols - 1) { + cursor_x = 0; + cursor_down(); + } + else + ++cursor_x; +} + +__attribute__ ((pure)) +static uint32_t word_len(const char *sz) { + const char *const back = sz; + while ((*sz != ' ') && (*sz != '\n') && *sz && (*sz != '\t')) + ++sz; + return sz - back; +} + +#define MIN_TAB 3 +#define TAB_STOP 4 + +static void on_newline() { + draw_char(cursor_y, cursor_x, false); + cursor_x = 0; + cursor_down(); +} + +static void add_char(char ch); + +static void on_tab() { + for (uint32_t i = 0; i < MIN_TAB; ++i) + add_char(' '); + while (cursor_x % TAB_STOP) + add_char(' '); +} + +static void add_char(char ch) { + if (ch == '\n') + on_newline(); + else if (ch == '\t') + on_tab(); + else { + termbuf[cursor_y * cols + cursor_x] = ch; + draw_char(cursor_y, cursor_x, false); + cursor_right(); + } +} + +static void add_sz_no_ww(const char *sz) { + while (*sz) + add_char(*(sz++)); +} + +static void add_sn_no_ww(const char *sz, uint32_t l) { + for (uint32_t i = 0; i < l; ++i) + add_char(sz[i]); +} + +static void add_sz_ww(const char *sz) { + while (*sz) { + if (*sz == ' ') { + ++sz; + continue; + } + if (*sz == '\n') { + on_newline(); + ++sz; + continue; + } + if (*sz == '\t') { + on_tab(); + ++sz; + continue; + } + + if (cursor_x) + add_char(' '); + + const uint32_t len = word_len(sz); + + if ((len > cols - cursor_x) && (len <= cols)) { + cursor_x = 0; + cursor_down(); + } + add_sn_no_ww(sz, len); + + sz += len; + } +} + +char *const sz_empty_backup = ""; +char *sz_from_task = 0; +uint32_t sz_buf_size = 0; + +#define BUF_INCREMENTS 1024 + +static void get_sn(uint32_t len, _task_handle_t from) { + if (sz_buf_size <= len) { + if (sz_from_task && (sz_from_task != sz_empty_backup)) + free_block(sz_from_task); + sz_from_task = get_block(sz_buf_size += 1024); + if (!sz_from_task) { + add_sz_ww("Could not allocate enough memory for sent string. Treating as empty string.\n"); + sz_buf_size = 0; + sz_from_task = sz_empty_backup; + return; + } + } + + const uint32_t real_len = try_read_ipc(from, sz_from_task, len); + sz_from_task[real_len] = '\0'; +} + +static void set_dimensions(uint32_t new_rows, uint32_t new_cols) { + free_block(termbuf); + free_block(pixbuf); + //from here until _resize, the kernel may draw garbage if it + // needs to redraw the window. it won't page fault though. + + rows = new_rows; + cols = new_cols; + termbuf = get_block(rows * cols); + + width = cols * font->space_width; + height = cols * font->space_height; + pixbuf = get_block(width * height); + + cursor_y = 0; + cursor_x = 0; + clear(); + + _resize_window(window, width, height, pixbuf); +} + +void draw_all() { + for (uint32_t y = 0; y < rows; ++y) + for (uint32_t x = 0; x < cols; ++x) + draw_char(y, x, false); + draw_char(cursor_y, cursor_x, true); +} + +//#include + +void main(const char *cmd) { +//syslogf(" this task: 0x%2h", this_task); +//syslogf(" stdio task: 0x%2h", stdio_task); +//syslogf("calling task: 0x%2h", calling_task); + + font = get_font(FONT_HARDCODE); + if (!font) + return; + + termbuf = get_block(cols * rows); + width = cols * font->space_width; + height = rows * font->space_height; + pixbuf = get_block(width * height); + clear(); + add_sz_ww("Portland Terminal\n"); + window = _new_window(width, height, pixbuf); + _paint_window(window); + + _task_handle_t child_handle = run_command(cmd, this_task); + if (!child_handle) { + add_sz_ww("Failed to run passed command. Press any key to close.\n"); + _paint_window(window); + while (1) { + struct window_action action; + _get_win_action(window, &action); + if (action.action_type == NOT_READY) { + _wait_for_action(); + _yield_task(); + } + else if (action.action_type == KEY_DOWN) + return; + } + } + + while (1) { + if (first_key_waiting) { + struct window_action action; + _get_win_action(window, &action); + if (action.action_type == KEY_DOWN) { + union terminal_response rs = { + .as_key = action.as_key + }; + try_send_ipc(first_key_waiting->task, &rs, sizeof(union terminal_response)); + free_block(first_key_waiting); + first_key_waiting = first_key_waiting->next; + if (!first_key_waiting) + last_key_waiting = 0; + continue; + } + } + + _task_handle_t from = _find_unread_ipc(); + if (!from) { + if (!_is_task_running(child_handle)) + return; + + _wait_for_action(); + _wait_for_any_ipc_sent(); + _wait_for_task(child_handle); + _yield_task(); + continue; + } + + struct terminal_command request; + const uint32_t read = try_read_ipc(from, &request, sizeof(struct terminal_command)); + if (read != sizeof(struct terminal_command)) { + syslogf("received %u / %u bytes of a command from 0x%2x", read, sizeof(struct terminal_command), from); + continue; + } + //syslogf("received full command from 0x%2x", from); + + switch (request.kind) { + case SET_DIMENSIONS: + set_dimensions(request.as_coords.y, request.as_coords.x); + continue; + union terminal_response rs; + case GET_DIMENSIONS: + rs.as_coords.y = rows; + rs.as_coords.x = cols; + try_send_ipc(from, &rs, sizeof(union terminal_response)); + continue; + case PAINT: + _paint_window(window); + continue; + case CLEAR: + clear(); + cursor_y = 0; + cursor_x = 0; + draw_char(0, 0, true); + continue; + case SET_COLOR: + fg_color = request.as_color.fg; + bg_color = request.as_color.bg; + draw_all(); + continue; + case SET_CURSOR: + draw_char(cursor_y, cursor_x, false); + cursor_y = request.as_coords.y; + cursor_x = request.as_coords.x; + draw_char(cursor_y, cursor_x, true); + continue; + case CURSOR_LEFT: + draw_char(cursor_y, cursor_x, false); + if (cursor_x) + --cursor_x; + else if (cursor_y) { + cursor_x = cols - 1; + --cursor_y; + } + draw_char(cursor_y, cursor_x, true); + continue; + case CURSOR_RIGHT: + draw_char(cursor_y, cursor_x, false); + cursor_right(); + draw_char(cursor_y, cursor_x, true); + continue; + case CURSOR_UP: + if (cursor_y) { + draw_char(cursor_y, cursor_x, false); + --cursor_y; + draw_char(cursor_y, cursor_x, true); + } + continue; + case CURSOR_DOWN: + draw_char(cursor_y, cursor_x, false); + if (cursor_y == rows - 1) + scroll_fw(); + else + ++cursor_y; + draw_char(cursor_y, cursor_x, true); + continue; + case ADD_CHAR: + add_char(request.as_char); + draw_char(cursor_y, cursor_x, true); + continue; + case ADD_SN: + draw_char(cursor_y, cursor_x, false); + get_sn(request.as_uint, from); + add_sz_ww(sz_from_task); + draw_char(cursor_y, cursor_x, true); + continue; + case ADD_SN_NO_WORDWRAP: + draw_char(cursor_y, cursor_x, false); + get_sn(request.as_uint, from); + add_sz_no_ww(sz_from_task); + draw_char(cursor_y, cursor_x, true); + continue; + struct waiting_for_key_record *new_record; + case GET_KEY: + new_record = get_block(sizeof(struct waiting_for_key_record)); + if (last_key_waiting) + last_key_waiting->next = new_record; + else + first_key_waiting = new_record; + last_key_waiting = new_record; + new_record->task = from; + new_record->next = 0; + continue; + default: + add_sz_ww("Bad terminal command received, ignoring.\n"); + continue; + } + } +} \ No newline at end of file -- cgit v1.2.3