summaryrefslogtreecommitdiff
path: root/kernel/terminal.cpp
blob: 7a878ee664bfc726adf2d2eb1380b7a9d3065dbc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <mercury/kernel/framebuffer.hpp>
#include <mercury/kernel/terminal.hpp>

namespace mercury::kernel::terminal {

  uint8_t *termfont;
  uint64_t termfont_len;

  int width;
  int height;

  int cursor_x;
  int cursor_y;

  framebuffer::color bg_color;
  framebuffer::color fg_color;

  static uint8_t glyph_height;

  void init_terminal() {
    //TODO - verify that termfont fits inside termfont_len (i.e. that no other
    //       functions in this file will try to access memory outside termfont)
    //TODO - check magic header to verify that this is actually a font and to
    //       see whether this is a psf1 font or a psf2 font.
    //TODO - support psf2 fonts. currently psf1 is assumed.
    //TODO - read unicode table if there is one. currently it is assumed that
    //       all 256 codepoints have glyphs, and that they appear in order.

    glyph_height = termfont[3];
    width = framebuffer::width / 8;
    height = framebuffer::height / glyph_height;
    cursor_x = 0;
    cursor_y = 0;
    bg_color = framebuffer::encode_color(0, 0, 0);
    fg_color = framebuffer::encode_color(255, 255, 255);

  }

  static void cursor_down() {
    if (++cursor_y == height) {
      --cursor_y;
      framebuffer::move_region(
        0, glyph_height, width * 8, height * glyph_height, 0, 0);
      framebuffer::fill_region(0, (height - 1) * glyph_height,
        width * 8, height * glyph_height, bg_color);
    }
  }

  static void cursor_right() {
    if (++cursor_x == width) {
      cursor_x = 0;
      cursor_down();
    }
  }

  void draw_char(char ch, int x, int y) {
    const uint8_t *glyph = termfont + 4 + glyph_height * (unsigned)ch;
    for (int i = 0; i < glyph_height; ++i)
      for (int j = 0; j < 8; ++j)
        framebuffer::set_pixel(x * 8 + j, y * glyph_height + i,
          ((glyph[i] << j) & 0x80) ? fg_color : bg_color);
  }

  void put_char(char ch) {
    switch (ch) {
    case '\n':
      cursor_x = 0;
      cursor_down();
      break;
    default:
      draw_char(ch, cursor_x, cursor_y);
      cursor_right();
      break;
    }
  }

  void put_string(const char *str, size_t len) {
    for (size_t i = 0; i < len; ++i)
      put_char(str[i]);
  }

  void put_string_sz(const char *str) {
    for (size_t i = 0; str[i]; ++i)
      put_char(str[i]);
  }

  void put_int_decimal(uint64_t n, bool with_commas) {

    if (n == 0) {
      put_char('0');
      return;
    }

    uint64_t d = 1;
    int i = 0;
    while (d <= n / 10) {
      d *= 10;
      ++i;
    }

    while (d) {
      put_char('0' + ((n / d) % 10));
      d /= 10;
      if (with_commas && (i % 3 == 0) && (i != 0))
        put_char(',');
      --i;
    }

  }

}