#include "vt.h" #include vt *ke_vt = 0, *home_vt = 0; vt::vt(node* parent, int ww, int hh) : node(parent, FT_TERMINAL) { w = ww; h = hh; fgcolor = TC_LIGHTGRAY; bgcolor = TC_BLACK; output = 0; cursor_visible = true; csr_l = csr_c = 0; kbd_buffer_filled = 0; kbd_waiter = 0; text = 0; if (w != 0 && h != 0) { text = (vt_char*)kmalloc(w * h * sizeof(vt_char)); clear(); } } void vt::put_at(int l, int c, int ch) { text[l * w + c].fgcolor = fgcolor; text[l * w + c].bgcolor = bgcolor; text[l * w + c].ch = ch; if (output != 0) output->text_put(l, c, ch, fgcolor, bgcolor); } void vt::put(int c) { if (text == 0) return; if (c == '\b' && csr_c != 0) { // backspace csr_c--; put_at(csr_l, csr_c, ' '); } else if (c == '\t') { // tab int csr_nc = (csr_c + 8) & ~(8 - 1); for (int i = csr_c; i < csr_nc && i < w; i++) put_at(csr_l, i, ' '); csr_c = csr_nc; } else if (c == '\r') { // carriage return csr_c = 0; } else if (c == '\n') { // new line csr_c = 0; csr_l++; } else if (c == '\f') { // form feed (new page) clear(); } else if (c >= ' ') { put_at(csr_l, csr_c, c); csr_c++; } if (csr_c >= w) { csr_c = 0; csr_l++; } if (csr_l == h) { if (output != 0 && output->connected_vt == this) { output->text_scroll(1, fgcolor, bgcolor); } for (int j = 0; j < w * (h-1); j++) { text[j] = text[j + w]; } for (int j = w * (h-1); j < w * h; j++) { text[j].fgcolor = fgcolor; text[j].bgcolor = bgcolor; text[j].ch = ' '; } csr_l--; } if (output != 0 && output->connected_vt == this) output->text_setcsr(csr_l, csr_c, cursor_visible); } void vt::clear() { for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { put_at(j, i, ' '); } } csr_c = csr_l = 0; } void vt::writeHex(uint32_t v) { int i; put('0'); put('x'); char hexdigits[] = "0123456789abcdef"; for (i = 0; i < 8; i++) { put(hexdigits[v >> 28]); v = v << 4; } } void vt::writeDec(int v) { if (v == 0) { put('0'); return; } if (v < 0) { put ('-'); v = -v; } char numbers[] = "0123456789"; while (v > 0) { int order = 1, no = 1; while (v / order > 0) order *= 10; order /= 10; put(numbers[v / order]); v = v - (v / order * order); while (v / no > 0) no *= 10; while (no < order) { put('0'); no *= 10; } } } // *************** INTERACTION void vt::outputTo(display *display) { output = display; if (output == 0) return; output->connected_vt = this; if (output->text_w() != w || output->text_h() != h) { int ow = w, oh = h; vt_char *old_text = text; w = output->text_w(); h = output->text_h(); text = (vt_char*)kmalloc(w * h * sizeof(vt_char)); for (int c = 0; c < w; c++) { for (int l = 0; l < h; l++) { if (c < ow && l < oh) { put_at(l, c, old_text[l * ow + c].ch); } else { put_at(l, c, ' '); } } } if (old_text != 0) kfree(old_text); if (csr_c >= w) csr_c = w; if (csr_l >= h) csr_l = h; } else { for (int c = 0; c < w; c++) { for (int l = 0; l < h; l++) { output->text_put(l, c, text[l*w+c].ch, text[l*w+c].fgcolor, text[l*w+c].bgcolor); } } } output->text_setcsr(csr_l, csr_c, cursor_visible); } void vt::keyboardInput(keypress kp, keyboard* from) { if (kp.command == KB_RSUPER || kp.command == KB_LSUPER) { if (this == home_vt) return; // go to home terminal home_vt->outputTo(output); from->outputTo(home_vt); output = 0; return; } // convert to sequence of chars int n = 0; char b[8]; if (kp.character >= 0x80) kp.character = '?'; // todo some day : unicode if ((kp.command == 0 || kp.command == KB_ENTER || kp.command == KB_TAB || kp.command == KB_BACKSPACE) && kp.character != 0 && kp.pressed) { b[n++] = (char)kp.character; } else if (kp.command == KB_CMD_ALT && kp.character >= 64 && kp.character <= 126 && kp.pressed) { b[n++] = 27; b[n++] = kp.character; } if (n == 0) return; if (kbd_buffer_filled + n > KBD_BUFFER_SIZE) goto wake_up; for (int i = 0; i < n; i++) { kbd_buffer[kbd_buffer_filled++] = b[i]; } wake_up: if (kbd_waiter != 0) { thread *w = kbd_waiter; kbd_waiter = 0; w->wakeUp(); } } // ********************* SYSCALLS int vt::write(size_t offset, size_t len, char* buffer) { // ignore offset // TODO: ANSI escape sequences // todo some day : unicode for (unsigned i = 0; i < len; i++) put(buffer[i]); return len; } int vt::read(size_t offset, size_t len, char* buffer) { // ignore offset unsigned c = 0; while (true) { bool end = false; if (kbd_buffer_filled > 0) { int r = 0; for (; r < kbd_buffer_filled; r++) { if (kbd_buffer[r] == '\b') { if (c > 0) { c--; put('\b'); } } else { buffer[c] = kbd_buffer[r]; put(buffer[c]); if (buffer[c] == '\n' || buffer[c] == 27) end = true; c++; } if (c == len) break; } memcpy(kbd_buffer + r, kbd_buffer, (kbd_buffer_filled - r)); kbd_buffer_filled -= r; } if (end || c == len) return c; if (kbd_waiter != 0) return c; kbd_waiter = current_thread; thread_goInactive(); } } size_t vt::get_size() { return ((w << 16) + h); } int vt::link(node* to, int mode) { if (mode == LM_OUTPUT_TO) { display *d = to->as_display(); if (d != 0) { outputTo(d); return 0; } } return E_NOT_IMPLEMENTED; }