#include #include #include #include struct term_list_entry { struct terminal term; struct term_list_entry *next; struct term_list_entry *prev; }; struct term_list_entry *last_term = 0; struct terminal *active_term = 0; struct terminal *make_term(struct font_info *font, uint32_t cols, uint32_t rows) { if (!font) return 0; struct term_list_entry *next_entry = get_block(sizeof(struct term_list_entry)); if (!next_entry) return 0; char *const cb = get_block(cols * rows); if (!cb) { free_block(next_entry); return 0; } const uint32_t w = cols * font->space_width; const uint32_t h = rows * font->space_height; uint8_t *const pb = get_block(w * h); if (!pb) { free_block(next_entry); free_block(cb); return 0; } _window_handle_t win = _new_window(w, h, pb); if (!win) { free_block(next_entry); free_block(cb); free_block(pb); return 0; } for (char *i = cb; i < cb + cols * rows; ++i) *i = ' '; for (uint8_t *i = pb; i < pb + w * h; ++i) *i = 0x10; next_entry->term.window = win; next_entry->term.pixbuf = pb; next_entry->term.window_width = w; next_entry->term.window_height = h; next_entry->term.font = font; next_entry->term.cols = cols; next_entry->term.rows = rows; next_entry->term.charbuf = cb; next_entry->term.cursor_y = 0; next_entry->term.cursor_x = 0; next_entry->term.fg = 0x0f; next_entry->term.bg = 0x10; next_entry->prev = last_term; next_entry->next = 0; if (last_term) last_term->next = next_entry; last_term = next_entry; return (struct terminal *)next_entry; } void del_term(struct terminal *term) { _delete_window(term->window); free_block(term->pixbuf); free_block(term->charbuf); free_block(term);//coincides with the term_list_entry if (active_term == term) active_term = 0; for (struct term_list_entry *i = last_term; i; i = i->prev) if (i == (struct term_list_entry *)term) { if (i->prev) i->prev->next = i->next; if (i->next) i->next->prev = i->prev; if (i == last_term) last_term = i->prev; return; } } static void draw_char(uint32_t y, uint32_t x, bool inverted) { put_char(active_term->font, active_term->charbuf[y * active_term->cols + x], active_term->pixbuf + (y * active_term->cols * active_term->font->space_height + x) * active_term->font->space_width, active_term->window_width, inverted ? active_term->fg : active_term->bg, inverted ? active_term->bg : active_term->fg); } static void draw_cursor() { draw_char(active_term->cursor_y, active_term->cursor_x, true); } void paint_term() { _paint_window(active_term->window); } void move_cursor(uint32_t new_y, uint32_t new_x) { draw_char(active_term->cursor_y, active_term->cursor_x, false); active_term->cursor_y = new_y; active_term->cursor_x = new_x; draw_cursor(); } static void redraw_term() { for (uint32_t y = 0; y < active_term->rows; ++y) for (uint32_t x = 0; x < active_term->cols; ++x) draw_char(y, x, false); draw_cursor(); } void set_color(uint8_t fg, uint8_t bg) { active_term->fg = fg; active_term->bg = bg; redraw_term(); } void clear_term() { for (char *i = active_term->charbuf, *const e = i + active_term->cols * active_term->rows; i != e; ++i) *i = ' '; for (uint8_t *i = active_term->pixbuf, *const e = i + active_term->window_width * active_term->window_height; i != e; ++i) *i = active_term->bg; move_cursor(0, 0); } void cursor_up() { draw_char(active_term->cursor_y, active_term->cursor_x, false); if (active_term->cursor_y) --active_term->cursor_y; else //eventually, maybe scroll back through a longer terminal buffer active_term->cursor_x = 0; draw_cursor(); } void cursor_left() { draw_char(active_term->cursor_y, active_term->cursor_x, false); if (active_term->cursor_x) { --active_term->cursor_x; draw_cursor(); } else { active_term->cursor_x = active_term->cols - 1; cursor_up(); } } void cursor_down() { draw_char(active_term->cursor_y, active_term->cursor_x, false); const uint32_t rows = active_term->rows; if (++active_term->cursor_y == rows) { --active_term->cursor_y; char *const cb = active_term->charbuf; uint8_t *const pb = active_term->pixbuf; const uint32_t cols = active_term->cols; const uint32_t fw = active_term->font->space_width; const uint32_t fh = active_term->font->space_height; char *to; for (to = cb; to < cb + (rows - 1) * cols; ++to) *to = *(to + cols); for (; to < cb + rows * cols; ++to) *to = ' '; uint8_t *pto; for (pto = pb; pto < pb + cols * fw * (rows - 1) * fh; ++pto) *pto = *(pto + cols * fw * fh); for (; pto < pb + cols * fw * rows * fh; ++pto) *pto = active_term->bg; } draw_cursor(); } void cursor_right() { draw_char(active_term->cursor_y, active_term->cursor_x, false); if (++active_term->cursor_x == active_term->cols) term_newline(); else draw_cursor(); } void term_newline() { draw_char(active_term->cursor_y, active_term->cursor_x, false); active_term->cursor_x = 0; cursor_down(); } void term_add_char(char ch) { if (ch == '\n') { term_newline(); return; } //char *const debug_msg = format("charbuf[%u] = '%c'", active_term->cursor_y * active_term->cols + active_term->cursor_x, ch); //_system_log(debug_msg); //free_block(debug_msg); active_term->charbuf[active_term->cursor_y * active_term->cols + active_term->cursor_x] = ch; cursor_right(); } void term_add_sz_no_ww(const char *sz) { while (*sz) term_add_char(*(sz++)); } #define MIN_TAB 3 #define TAB_STEP 4 void term_add_sz(const char *sz) { //TODO: special hyphen handling const char *word = sz; while (1) if (!*sz || (*sz == ' ') || (*sz == '\n') || (*sz == '\t')) { const uint32_t len = sz - word; if ((active_term->cursor_x + len > active_term->cols) && (len <= active_term->cols) && active_term->cols) term_newline(); for (const char *i = word; i < sz; ++i) term_add_char(*i); while ((*sz == ' ') || (*sz == '\n') || (*sz == '\t')) { if (*sz == '\n') term_newline(); else if (*sz == '\t') { for (uint8_t i = 0; i < MIN_TAB; ++i) cursor_right(); while (active_term->cursor_x % TAB_STEP) cursor_right(); } ++sz; } if (!*sz) return; if (active_term->cursor_x) term_add_char(' '); word = sz; } else ++sz; } void term_addf_no_ww_v(const char *fmt, va_list args) { char *const msg = format_v(fmt, args); term_add_sz_no_ww(msg); free_block(msg); } void term_addf_no_ww(const char *fmt, ...) { va_list args; va_start(args, fmt); term_addf_no_ww_v(fmt, args); va_end(args); } void term_addf_v(const char *fmt, va_list args) { char *const msg = format_v(fmt, args); term_add_sz(msg); free_block(msg); } void term_addf(const char *fmt, ...) { va_list args; va_start(args, fmt); term_addf_v(fmt, args); va_end(args); }