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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
#include "driver.h"
#include <camellia/syscalls.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define eprintf(fmt, ...) fprintf(stderr, "ansiterm: "fmt"\n" __VA_OPT__(,) __VA_ARGS__)
struct psf {
uint32_t magic;
uint32_t version;
uint32_t glyph_offset;
uint32_t flags;
uint32_t glyph_amt;
uint32_t glyph_size;
uint32_t h;
uint32_t w;
} __attribute__((packed));
static handle_t fb_fd;
static struct {int x, y;} cursor = {0};
static bool dirty = false;
// TODO don't hardcode size
static const size_t fb_len = 640 * 480 * 4;
static const size_t fb_width = 640;
static const size_t fb_height = 480;
static const size_t fb_pitch = 640 * 4;
static char *fb;
static struct psf font;
static void *font_data;
static void flush(void) {
size_t off = 0;
while (off < fb_len)
off += _syscall_write(fb_fd, fb + off, fb_len - off, off, 0);
dirty = false;
}
static void scroll(void) {
// TODO memmove. this is UD
size_t row_len = fb_pitch * font.h;
memcpy(fb, fb + row_len, fb_len - row_len);
memset(fb + fb_len - row_len, 0, row_len);
cursor.y--;
}
static void font_blit(size_t glyph, int x, int y) {
if (glyph >= font.glyph_amt) glyph = 0;
char *bitmap = font_data + font.glyph_size * glyph;
for (size_t i = 0; i < font.w; i++) {
for (size_t j = 0; j < font.h; j++) {
size_t idx = j * font.w + i;
char byte = bitmap[idx / 8];
byte >>= (7-(idx&7));
byte &= 1;
*((uint32_t*)&fb[fb_pitch * (y * font.h + j) + 4 * (x * font.w + i)]) = byte * 0xB0B0B0;
}
}
}
static void in_char(char c) {
switch (c) {
case '\n':
cursor.x = 0;
cursor.y++;
break;
case '\b':
if (--cursor.x < 0) cursor.x = 0;
break;
default:
font_blit(c, cursor.x, cursor.y);
cursor.x++;
}
if (cursor.x * font.w >= fb_width) {
cursor.x = 0;
cursor.y++;
}
while (cursor.y * font.h >= fb_height) scroll();
dirty = true;
}
static void font_load(void) {
FILE *f = fopen("/init/font.psf", "r");
if (!f) {
eprintf("couldn't open font file");
exit(1);
}
const size_t cap = 8 * 1024; // TODO get file size
void *buf = malloc(cap);
if (!buf) {
eprintf("out of memory");
exit(1);
}
fread(buf, 1, cap, f);
if (ferror(f)) {
eprintf("error reading file");
exit(1);
}
fclose(f);
if (memcmp(buf, "\x72\xb5\x4a\x86", 4)) {
eprintf("invalid psf header");
exit(1);
}
memcpy(&font, buf, sizeof font);
font_data = buf + font.glyph_offset;
}
void ansiterm_drv(void) {
fb = malloc(fb_len);
fb_fd = _syscall_open("/kdev/video/b", 13, 0);
font_load();
cursor.x = 0;
cursor.y = 0;
flush();
static char buf[512];
struct fs_wait_response res;
while (!_syscall_fs_wait(buf, sizeof buf, &res)) {
switch (res.op) {
case VFSOP_OPEN:
// TODO check path
_syscall_fs_respond(NULL, 0, 0);
break;
case VFSOP_WRITE:
if (res.flags) {
_syscall_fs_respond(NULL, -1, 0);
} else {
for (size_t i = 0; i < res.len; i++)
in_char(buf[i]);
flush();
_syscall_fs_respond(NULL, res.len, 0);
}
break;
default:
_syscall_fs_respond(NULL, -1, 0);
break;
}
}
exit(1);
}
|