summaryrefslogtreecommitdiff
path: root/src/cmd/vterm
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/vterm')
-rw-r--r--src/cmd/vterm/draw.c17
-rw-r--r--src/cmd/vterm/font.c76
-rw-r--r--src/cmd/vterm/vterm.c72
-rw-r--r--src/cmd/vterm/vterm.h39
4 files changed, 204 insertions, 0 deletions
diff --git a/src/cmd/vterm/draw.c b/src/cmd/vterm/draw.c
new file mode 100644
index 0000000..ee36a0f
--- /dev/null
+++ b/src/cmd/vterm/draw.c
@@ -0,0 +1,17 @@
+#include "vterm.h"
+#include <camellia/execbuf.h>
+#include <camellia/syscalls.h>
+#include <string.h>
+
+struct framebuf fb;
+struct rect dirty;
+
+void scroll(void) {
+ size_t row_len = fb.pitch * font.h;
+ memmove(fb.b, fb.b + row_len, fb.len - row_len);
+ memset(fb.b + fb.len - row_len, 0, row_len);
+ cursor.y--;
+
+ dirty.x1 = 0; dirty.y1 = 0;
+ dirty.x2 = ~0; dirty.y2 = ~0;
+}
diff --git a/src/cmd/vterm/font.c b/src/cmd/vterm/font.c
new file mode 100644
index 0000000..777b094
--- /dev/null
+++ b/src/cmd/vterm/font.c
@@ -0,0 +1,76 @@
+#include "vterm.h"
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct psf2 font;
+void *font_data;
+
+void font_load(const char *path) {
+ FILE *f = fopen(path, "r");
+ if (!f) {
+ err(1, "couldn't open font \"%s\"", path);
+ }
+
+ void *buf;
+ long buflen;
+
+ fseek(f, 0, SEEK_END);
+ buflen = ftell(f);
+ if (buflen < 0) {
+ errx(1, "can't get the size of \"%s\"", path);
+ }
+
+ buf = malloc(buflen);
+ if (!buf) {
+ err(1, "out of memory");
+ }
+
+ fseek(f, 0, SEEK_SET);
+ fread(buf, 1, buflen, f);
+ if (ferror(f)) {
+ err(1, "error reading font");
+ }
+ fclose(f);
+
+ if (!memcmp(buf, "\x72\xb5\x4a\x86", 4)) {
+ memcpy(&font, buf, sizeof font);
+ font_data = buf + font.glyph_offset;
+ } else if (!memcmp(buf, "\x36\x04", 2)) {
+ struct psf1 *hdr = buf;
+ font = (struct psf2){
+ .glyph_amt = 256,
+ .glyph_size = hdr->h,
+ .h = hdr->h,
+ .w = 8,
+ };
+ font_data = buf + 4;
+ } else {
+ errx(1, "invalid psf header");
+ }
+}
+
+void font_blit(uint32_t glyph, int x, int y) {
+ if (glyph >= font.glyph_amt) glyph = 0;
+ if (x < 0 || (x+1) * font.w >= fb.width ||
+ y < 0 || (y+1) * font.h >= fb.height)
+ {
+ return;
+ }
+
+ dirty_mark(&dirty, x * font.w, y * font.h);
+ dirty_mark(&dirty, (x+1) * font.w - 1, (y+1) * font.h - 1);
+
+ 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.b[fb.pitch * (y * font.h + j) + 4 * (x * font.w + i)]) = byte * 0xB0B0B0;
+ }
+ }
+ return;
+}
diff --git a/src/cmd/vterm/vterm.c b/src/cmd/vterm/vterm.c
new file mode 100644
index 0000000..f365f6b
--- /dev/null
+++ b/src/cmd/vterm/vterm.c
@@ -0,0 +1,72 @@
+#include "vterm.h"
+#include <camellia/syscalls.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <camellia/compat.h>
+
+struct point cursor = {0};
+
+void in_char(char c) {
+ switch (c) {
+ case '\n':
+ cursor.x = 0;
+ cursor.y++;
+ break;
+ case '\b':
+ if (cursor.x > 0) cursor.x--;
+ break;
+ case '\t':
+ /* rounds down to nearest multiple of 8 and adds 8
+ = adding 1 and rounding up to the nearest multiple of 8 */
+ cursor.x = (cursor.x & ~7) + 8;
+ 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 + 1) * font.h >= fb.height) scroll();
+}
+
+int main(void) {
+ if (fb_setup(&fb, "/kdev/video/") < 0) {
+ eprintf("fb_setup error");
+ return 1;
+ }
+ font_load("/init/usr/share/fonts/spleen/spleen-8x16.psfu");
+
+ static char buf[512];
+ struct ufs_request res;
+ while (!c0_fs_wait(buf, sizeof buf, &res)) {
+ switch (res.op) {
+ case VFSOP_OPEN:
+ // TODO check path
+ c0_fs_respond(NULL, 0, 0);
+ break;
+
+ case VFSOP_WRITE:
+ if (res.flags) {
+ c0_fs_respond(NULL, -1, 0);
+ } else {
+ for (size_t i = 0; i < res.len; i++)
+ in_char(buf[i]);
+ dirty_flush(&dirty, &fb);
+ c0_fs_respond(NULL, res.len, 0);
+ }
+ break;
+
+ default:
+ c0_fs_respond(NULL, -1, 0);
+ break;
+ }
+ }
+
+ return 1;
+}
diff --git a/src/cmd/vterm/vterm.h b/src/cmd/vterm/vterm.h
new file mode 100644
index 0000000..026e71a
--- /dev/null
+++ b/src/cmd/vterm/vterm.h
@@ -0,0 +1,39 @@
+#pragma once
+#include <camellia/types.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <draw.h>
+
+#define eprintf(fmt, ...) fprintf(stderr, "vterm: "fmt"\n" __VA_OPT__(,) __VA_ARGS__)
+
+
+struct psf1 {
+ uint16_t magic;
+ uint8_t mode;
+ uint8_t h;
+} __attribute__((packed));
+struct psf2 {
+ 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));
+extern struct psf2 font;
+extern void *font_data;
+void font_load(const char *path);
+void font_blit(uint32_t glyph, int x, int y);
+
+extern struct framebuf fb;
+
+extern struct rect dirty;
+void vdirty_mark(uint32_t x, uint32_t y);
+void flush(void);
+void scroll(void);
+
+struct point {uint32_t x, y;};
+extern struct point cursor;
+void in_char(char c);