summaryrefslogtreecommitdiff
path: root/src/user
diff options
context:
space:
mode:
authorBenji Dial <benji6283@gmail.com>2021-01-24 12:00:11 -0500
committerBenji Dial <benji6283@gmail.com>2021-01-24 12:00:11 -0500
commitbce944d1498eaa3b6940ee234c863b3548a66b37 (patch)
treeea40c087ab4f0f236aee8d158cf68550f5209f72 /src/user
parentca731aa747214919df7b3dfe3478dbe787ce5b68 (diff)
downloadportland-os-bce944d1498eaa3b6940ee234c863b3548a66b37.tar.gz
graphics!
Diffstat (limited to 'src/user')
-rw-r--r--src/user/dirinfo/dirinfo.c49
-rw-r--r--src/user/dumphex/dumphex.c81
-rw-r--r--src/user/dumptext/dumptext.c15
-rw-r--r--src/user/fileman/fileman.c130
-rw-r--r--src/user/hello/hello.asm14
-rw-r--r--src/user/highway/cmds.c10
-rw-r--r--src/user/highway/line.c85
-rw-r--r--src/user/highway/line.h1
-rw-r--r--src/user/highway/main.c31
-rw-r--r--src/user/highway/vars.c28
-rw-r--r--src/user/include/knob/block.h5
-rw-r--r--src/user/include/knob/env.h9
-rw-r--r--src/user/include/knob/format.h27
-rw-r--r--src/user/include/knob/ipc.h16
-rw-r--r--src/user/include/knob/key.h8
-rw-r--r--src/user/include/knob/panic.h9
-rw-r--r--src/user/include/knob/task.h7
-rw-r--r--src/user/include/knob/user.h22
-rw-r--r--src/user/include/libfont/fonts.h21
-rw-r--r--src/user/include/pland/pcrt.h7
-rw-r--r--src/user/include/pland/syscall.h206
-rw-r--r--src/user/include/popups/info.h14
-rw-r--r--src/user/include/popups/popup.h23
-rw-r--r--src/user/include/terminal/readline.h10
-rw-r--r--src/user/include/terminal/terminal.h57
-rw-r--r--src/user/init/init.c29
-rw-r--r--src/user/knob/block.c24
-rw-r--r--src/user/knob/env.c3
-rw-r--r--src/user/knob/file.c26
-rw-r--r--src/user/knob/format.c257
-rw-r--r--src/user/knob/heap.c32
-rw-r--r--src/user/knob/ipc.c45
-rw-r--r--src/user/knob/key.c67
-rw-r--r--src/user/knob/panic.c12
-rw-r--r--src/user/knob/task.c20
-rw-r--r--src/user/knob/user.c299
-rw-r--r--src/user/libfont/bdf.c99
-rw-r--r--src/user/libfont/bdf.h8
-rw-r--r--src/user/libfont/filist.c33
-rw-r--r--src/user/libfont/filist.h8
-rw-r--r--src/user/libfont/fonts.c66
-rw-r--r--src/user/manual/manual.c303
-rw-r--r--src/user/meminfo/meminfo.c41
-rw-r--r--src/user/popups/info.c99
-rw-r--r--src/user/popups/popup.c45
-rw-r--r--src/user/runtimes/c/elf.ld1
-rw-r--r--src/user/runtimes/c/pcrt.asm (renamed from src/user/runtimes/c/entry.asm)11
-rw-r--r--src/user/terminal/readline.c104
-rw-r--r--src/user/terminal/terminal.c284
49 files changed, 1541 insertions, 1260 deletions
diff --git a/src/user/dirinfo/dirinfo.c b/src/user/dirinfo/dirinfo.c
deleted file mode 100644
index 21afcc7..0000000
--- a/src/user/dirinfo/dirinfo.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include <pland/syscall.h>
-#include <knob/format.h>
-#include <knob/file.h>
-#include <knob/user.h>
-
-#define MAX_DIR_ENTRIES 20
-
-void main(const char *arg) {
- uint8_t dn;
- const char *path = remove_prefix(arg, &dn);
-
- tell_user_sz("Directory info for ");
- tell_user_sz(*arg ? arg : "drive root");
- tell_user_sz("\n");
-
- _dir_info_entry_t infos[MAX_DIR_ENTRIES];
- uint8_t count = _enumerate_dir(dn, path, infos, MAX_DIR_ENTRIES);
- tell_user_sz(
- count == MAX_DIR_ENTRIES
- ? "Truncated to 20 entries.\n\n"
- : "\n"
- );
-
- uint32_t total_size = 0;
-
- if (!count)
- tell_user_sz("(none)\n");
-
- for (uint8_t i = 0; i < count; ++i) {
- tell_user_sz(infos[i].name);
- tell_user_sz(": ");
- if (infos[i].is_dir)
- tell_user_sz("dir");
- else {
- char nbuf[11];
- itosz(infos[i].size, nbuf);
- tell_user_sz(nbuf);
- tell_user_sz(" bytes");
- total_size += infos[i].size;
- }
- tell_user_sz("\n");
- }
-
- tell_user_sz("\nTotal size without subdirectories: ");
- char nbuf[11];
- itosz(total_size, nbuf);
- tell_user_sz(nbuf);
- tell_user_sz(" bytes\n");
-} \ No newline at end of file
diff --git a/src/user/dumphex/dumphex.c b/src/user/dumphex/dumphex.c
deleted file mode 100644
index 2944a2f..0000000
--- a/src/user/dumphex/dumphex.c
+++ /dev/null
@@ -1,81 +0,0 @@
-#include <knob/file.h>
-#include <knob/user.h>
-#include <knob/format.h>
-
-#define LINE_LEN 16
-
-void print_zero_line(uint32_t offset) {
-}
-
-void main(const char *path) {
- struct file *f = open_file(path);
- if (!f) {
- tell_user_sz("Couldn't open file.\n");
- return;
- }
-
- uint8_t line[LINE_LEN + 2];
- uint8_t len;
- uint32_t offset = -LINE_LEN;
-
- enum {
- ZR_NO,
- ZR_FIRST,
- ZR_REST
- } zero_run;
-
- char nbuf[9];
-
- while ((len = read_from_file(f, LINE_LEN, line))) {
- offset += LINE_LEN;
-
- for (uint8_t i = 0; i < LINE_LEN; ++i)
- if (line[i]) {
- zero_run = ZR_NO;
- goto print_normal;
- }
-
- switch (zero_run) {
- case ZR_NO:
- zero_run = ZR_FIRST;
- _log_string("0x");
- itosz_h32(offset, nbuf);
- _log_string(nbuf);
- _log_string(" | 00 00 00 00 00 00 00 00 "
- "00 00 00 00 00 00 00 00 |\n");
- continue;
- case ZR_FIRST:
- zero_run = ZR_REST;
- tell_user_sz("...\n");
- case ZR_REST:
- continue;
- }
-
- print_normal:
- _log_string("0x");
- itosz_h32(offset, nbuf);
- _log_string(nbuf);
- _log_string(" |");
-
- nbuf[0] = ' ';
- for (uint8_t i = 0; i < len; ++i) {
- itosz_h8(line[i], nbuf + 1);
- _log_string(nbuf);
- }
-
- for (uint8_t i = len; i < LINE_LEN; ++i)
- _log_string(" ");
-
- _log_string(" | ");
-
- for (uint8_t i = 0; i < len; ++i)
- if ((line[i] < 0x20) || (line[i] > 0x7e))
- line[i] = ' ';
- line[len] = '\n';
- line[len + 1] = '\0';
-
- _log_string(line);
- }
-
- close_file(f);
-} \ No newline at end of file
diff --git a/src/user/dumptext/dumptext.c b/src/user/dumptext/dumptext.c
deleted file mode 100644
index b10375c..0000000
--- a/src/user/dumptext/dumptext.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <knob/file.h>
-#include <knob/user.h>
-
-void main(const char *path) {
- struct file *f = open_file(path);
- if (!f) {
- tell_user_sz("Couldn't open file.\n");
- return;
- }
- char buf[] = { '\0', '\0' };
- while (read_from_file(f, 1, buf))
- tell_user_sz(buf);
- tell_user_sz("\n");
- close_file(f);
-} \ No newline at end of file
diff --git a/src/user/fileman/fileman.c b/src/user/fileman/fileman.c
deleted file mode 100644
index 0b28d1d..0000000
--- a/src/user/fileman/fileman.c
+++ /dev/null
@@ -1,130 +0,0 @@
-#include <pland/syscall.h>
-#include <knob/block.h>
-#include <knob/file.h>
-#include <knob/heap.h>
-#include <knob/task.h>
-
-char path_sz[1024] = "";
-uint32_t path_len = 0;
-
-_dir_info_entry_t *dir_info;
-uint32_t dir_info_len;
-
-uint32_t scroll;
-uint32_t selected;
-#define MAX_PER_SCREEN 18
-
-void paint_screen() {
- _clear_screen();
-
- _set_color(0x70);
- _print_at(0, 0, path_sz);
- _log_string("/");
- _set_color(0x07);
-
- for (uint32_t i = scroll, row = 2; (i < dir_info_len) && (row < MAX_PER_SCREEN + 2); ++i, ++row) {
- if (i == selected)
- _set_color(0x17);
- _print_at(row, 0, dir_info[i].name);
- if (dir_info[i].is_dir)
- _log_string("/");
- if (i == selected)
- _set_color(0x07);
- }
-
- _print_at(21, 0, "keybindings:\n"
- "UP, DOWN, PAGE UP, PAGE DOWN, HOME, END: move selection\n"
- "ENTER: enter selected directory, run selected program\n"
- "ESC: go up a directory Q: quit");
-}
-
-void load_dir() {
- free_block(dir_info);
- dir_info = get_directory_info(path_sz, &dir_info_len);
- scroll = 0;
- selected = 0;
-}
-
-void main(const char *sz) {
- path_len = strcpy(path_sz, sz);
- dir_info = get_directory_info(sz, &dir_info_len);
-
- paint_screen();
-
- while (true) {
- _key_code_t key;
- switch (key = _get_key()) {
- case 0:
- _yield_task();
- continue;
- case '\n':
- {
- uint32_t old_len = path_len;
- if (path_len)
- path_sz[path_len++] = '/';
- path_len += strcpy(path_sz + path_len, dir_info[selected].name);
- if (dir_info[selected].is_dir)
- load_dir();
- else {
- try_run_command_blocking(path_sz);
- //TODO: handle error
- path_sz[old_len] = '\0';
- path_len = old_len;
- }
- }
- break;
- case _KEY_ESC:
- {
- char *cutoff = path_sz;
- for (char *i = path_sz + path_len - 1; i >= path_sz; --i)
- if (*i == '/') {
- cutoff = i;
- break;
- }
- *cutoff = '\0';
- path_len = cutoff - path_sz;
- load_dir();
- }
- break;
- case _KEY_HOME:
- scroll = 0;
- selected = 0;
- break;
- case _KEY_END:
- selected = dir_info_len - 1;
- scroll = dir_info_len >= MAX_PER_SCREEN
- ? dir_info_len - MAX_PER_SCREEN : 0;
- break;
- case _KEY_UP:
- if (!selected)
- continue;
- if (--selected < scroll)
- scroll = selected;
- break;
- case _KEY_DOWN:
- if (selected == dir_info_len - 1)
- continue;
- if (++selected >= scroll + MAX_PER_SCREEN)
- ++scroll;
- break;
- case _KEY_PUP:
- selected = selected >= MAX_PER_SCREEN
- ? selected - MAX_PER_SCREEN : 0;
- scroll = scroll >= MAX_PER_SCREEN
- ? scroll - MAX_PER_SCREEN : 0;
- break;
- case _KEY_PDOWN:
- if ((selected += MAX_PER_SCREEN) >= dir_info_len)
- selected = dir_info_len - 1;
- if ((scroll += MAX_PER_SCREEN) > selected)
- scroll = selected;
- break;
- case 'q':
- _clear_screen();
- return;
- default:
- continue;
- }
- paint_screen();
- }
-} \ No newline at end of file
diff --git a/src/user/hello/hello.asm b/src/user/hello/hello.asm
deleted file mode 100644
index 65d32be..0000000
--- a/src/user/hello/hello.asm
+++ /dev/null
@@ -1,14 +0,0 @@
-bits 32
-
-global _entry
-
-section .text
-_entry:
- mov eax, 0x5
- mov ebx, hello
- int 0x30
-
- int 0x38
-
-section .data
-hello db "Hello, world!", 0x0a, 0 \ No newline at end of file
diff --git a/src/user/highway/cmds.c b/src/user/highway/cmds.c
index d7a89d1..0420ae1 100644
--- a/src/user/highway/cmds.c
+++ b/src/user/highway/cmds.c
@@ -1,12 +1,16 @@
+#include <terminal/terminal.h>
+
#include <knob/file.h>
-#include <knob/user.h>
+
#include "line.h"
#include "vars.h"
void source(const char *path) {
struct file *f = open_file(path);
- if (!f)
- tell_user_sz("couldn't open file.\n");
+ if (!f) {
+ term_addf("Could not open %s.\n", path);
+ return;
+ }
char buf[128];
while (read_line_from_file(f, buf, 127))
run_line(buf);
diff --git a/src/user/highway/line.c b/src/user/highway/line.c
index c8e5c60..bf171e5 100644
--- a/src/user/highway/line.c
+++ b/src/user/highway/line.c
@@ -1,19 +1,37 @@
-#include <pland/pcrt.h>
+#include <terminal/terminal.h>
+
#include <knob/block.h>
#include <knob/task.h>
-#include <knob/user.h>
+
+#include <pland/pcrt.h>
+
#include "cmds.h"
+#include "term.h"
#include "vars.h"
#define LINE_SIZE 4096
static char line[LINE_SIZE];
+static inline uint8_t hex_to_int(char ch) {
+ return ch - (ch <= '9' ? '0' : 'a' - 10);
+}
+
+void ensure_color() {
+ const struct no_null_sn *fg = get_var((struct no_null_sn){.data = "_color_fg", .length = 9});
+ const struct no_null_sn *bg = get_var((struct no_null_sn){.data = "_color_bg", .length = 9});
+ if (fg && bg)
+ set_color(
+ (hex_to_int(fg->data[0]) << 4) | hex_to_int(fg->data[1]),
+ (hex_to_int(bg->data[0]) << 4) | hex_to_int(bg->data[1])
+ );
+}
+
static void line_replace(const char *from) {
const char *fi = from;
char *ti = line;
while (*fi) {
if (ti == line + LINE_SIZE) {
- tell_user_sz("Line too long.\n");
+ term_add_sz("Line too long.\n");
line[0] = '\0';
return;
}
@@ -27,12 +45,15 @@ static void line_replace(const char *from) {
const char *var_end = var_start;
while (*var_end != '$')
if (!*var_end++) {
- tell_user_sz("Unterminated variable name.\n");
+ if (var_end - fi > 10)
+ term_addf("Unterminated variable at\"%10s...\".\n", fi);
+ else
+ term_addf("Unterminated variable at \"%s\".\n", fi);
line[0] = '\0';
return;
}
if (ti + (var_end - var_start) >= line + LINE_SIZE) {
- tell_user_sz("Line too long.\n");
+ term_add_sz("Line too long.\n");
line[0] = '\0';
return;
}
@@ -59,46 +80,50 @@ void run_line(const char *original_line) {
;
if (blockequ(line, "source ", 7))
source(space + 1);
- else if (blockequ(line, "set ", 4))
+ else if (blockequ(line, "set ", 4)) {
set(space + 1);
+ ensure_color();
+ }
else if (blockequ(line, "echo ", 5)) {
- tell_user_sz(space + 1);
- tell_user_sz("\n");
+ term_add_sz(space + 1);
+ term_add_char('\n');
}
else if (blockequ(line, "vars", 5))
dump_vars();
- else if (blockequ(line, "quit", 5))
+ else if (blockequ(line, "quit", 5)) {
+ del_term(active_term);
__pcrt_quit();
+ }
else if (blockequ(line, "clear", 6))
- _clear_screen();
+ clear_term();
else if (blockequ(line, "help", 5))
- tell_user_sz("Highway is a command shell for Portland OS. It includes variables and a couple\n"
- "of pseudo-commands. Variables are addressed by surrounding with \"$\". The\n"
- "following list shows each of the pseudo-commands.\n\n"
- " source FILE run each command in FILE\n"
- " clear clear the screen\n"
- " echo STRING print STRING\n"
- " set VAR VALUE set $VAR$ to VALUE\n"
- " vars dump variables\n"
- " quit exit highway\n"
- " help show this\n");
- else if (!try_run_command_blocking(line)) {
- struct no_null_sn arg = {
- .data = "_path",
- .length = 5
- };
- const struct no_null_sn *path = get_var(arg);
+ term_add_sz("Highway is a command shell for Portland OS. It includes variable support and a couple of pseudo-commands. Variables are addressed by surrounding with \"$\". The following list shows each of the pseudo-commands.\n\n"
+ " source FILE\t" "run each command in FILE\n"
+ " clear\t\t\t" "clear the screen\n"
+ " echo STRING\t" "print STRING\n"
+ " set VAR VALUE\t" "set $VAR$ to VALUE\n"
+ " vars\t\t\t" "dump variables\n"
+ " quit\t\t\t" "exit highway\n"
+ " help\t\t\t" "show this\n");
+ else if (!try_run_command_blocking(line, stdio_task)) {
+ const struct no_null_sn *path = get_var((struct no_null_sn){.data = "_path", .length = 5});
if (!path->length) {
- tell_user_sz("Could not run command.\n");
+ term_add_sz("Could not run command.\n");
return;
}
for (uint16_t to_i = LINE_SIZE - 1; to_i >= path->length; --to_i)
line[to_i] = line[to_i - path->length];
blockcpy(line, path->data, path->length);
- if (!try_run_command_blocking(line)) {
- tell_user_sz("Could not run command.\n");
+ if (!try_run_command_blocking(line, stdio_task)) {
+ term_add_sz("Could not run command.\n");
return;
}
+ else {
+ ensure_color();
+ if (active_term->cursor_x)
+ term_newline();
+ }
}
- _set_color(0x07);
+ else
+ ensure_color();
} \ No newline at end of file
diff --git a/src/user/highway/line.h b/src/user/highway/line.h
index 4785034..fc131ec 100644
--- a/src/user/highway/line.h
+++ b/src/user/highway/line.h
@@ -2,5 +2,6 @@
#define LINE_H
void run_line(const char *line);
+void ensure_color();
#endif \ No newline at end of file
diff --git a/src/user/highway/main.c b/src/user/highway/main.c
index 4599315..60d5a69 100644
--- a/src/user/highway/main.c
+++ b/src/user/highway/main.c
@@ -1,17 +1,36 @@
-#include <knob/user.h>
+#include <terminal/terminal.h>
+#include <terminal/readline.h>
+
+#include <libfont/fonts.h>
+
+#include <knob/format.h>
+#include <knob/heap.h>
#include <knob/task.h>
+
#include "cmds.h"
#include "line.h"
+#define FONT_NAME "berry"
+
void main(const char *arg) {
+ struct font_info *f = get_font(FONT_NAME);
+
+ if (!f)
+ return;
+
+ active_term = make_term(f, 50, 18);
+ if (!active_term)
+ return;
+
source(*arg ? arg : "user/default.rc");
+ ensure_color();
+
+ term_add_sz("Portland Highway\nType \"help\" for help.\n");
+ paint_term();
+
char cmd_buf[128];
- yield_task();
- struct history *cmd_hs = new_history(128);
- tell_user_sz("Portland Highway\nType \"help\" for help.\n");
while (1) {
- tell_user_sz("\n> ");
- ask_user_line_sz_with_history(cmd_buf, 127, cmd_hs);
+ read_line(cmd_buf, 127, "> ");
run_line(cmd_buf);
}
} \ No newline at end of file
diff --git a/src/user/highway/vars.c b/src/user/highway/vars.c
index 6090b76..5f56621 100644
--- a/src/user/highway/vars.c
+++ b/src/user/highway/vars.c
@@ -1,6 +1,10 @@
+#include <terminal/terminal.h>
+
+#include <knob/format.h>
#include <knob/block.h>
#include <knob/heap.h>
-#include <knob/user.h>
+
+#include <pland/pcrt.h>
struct no_null_sn {
char *data;
@@ -73,26 +77,6 @@ void del_var(struct no_null_sn name) {
void dump_vars() {
for (struct var_dict_node *node = var_dict_start; node; node = node->next) {
- tell_user_sz("$");
-
- char *buf = get_block(node->name.length + 1);
- blockcpy(buf, node->name.data, node->name.length);
- buf[node->name.length] = '\0';
-
- tell_user_sz(buf);
-
- free_block(buf);
-
- tell_user_sz("$ = ");
-
- buf = get_block(node->value.length + 1);
- blockcpy(buf, node->value.data, node->value.length);
- buf[node->value.length] = '\0';
-
- tell_user_sz(buf);
-
- free_block(buf);
-
- tell_user_sz("\n");
+ term_addf_no_ww("$%ns$ = %ns\n", node->name.length, node->name.data, node->value.length, node->value.data);
}
} \ No newline at end of file
diff --git a/src/user/include/knob/block.h b/src/user/include/knob/block.h
index 56d3740..f77709d 100644
--- a/src/user/include/knob/block.h
+++ b/src/user/include/knob/block.h
@@ -13,4 +13,9 @@ uint32_t strcpy(char *to, const char *from);
//allocates new memory
char *strdup(const char *from);
+//without null-terminator
+uint32_t strlen(const char *str) __attribute__ ((pure));
+
+bool strequ(const char *a, const char *b) __attribute__ ((pure));
+
#endif \ No newline at end of file
diff --git a/src/user/include/knob/env.h b/src/user/include/knob/env.h
deleted file mode 100644
index 6d750ae..0000000
--- a/src/user/include/knob/env.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef KNOB_ENV_H
-#define KNOB_ENV_H
-
-#include <stdint.h>
-
-//not implemented yet
-extern uint32_t current_drive;
-
-#endif \ No newline at end of file
diff --git a/src/user/include/knob/format.h b/src/user/include/knob/format.h
index d55036c..fed31c7 100644
--- a/src/user/include/knob/format.h
+++ b/src/user/include/knob/format.h
@@ -1,12 +1,29 @@
#ifndef KNOB_FORMAT_H
#define KNOB_FORMAT_H
-#include <stdbool.h>
+#include <knob/heap.h>
+
#include <stdint.h>
+#include <stdarg.h>
+
+//allocates new memory
+char *format_v(const char *fmt, va_list args);
+
+//allocates new memory
+char *format(const char *fmt, ...);
+
+void syslogf_v(const char *fmt, va_list args);
+
+void syslogf(const char *fmt, ...);
+
+//reads a unsigned decimal terminated by either null or whitespace
+//returns length of string plus length of whitespace
+//returns 0 on failure
+uint32_t try_swtou(const char *from, uint32_t *i_out);
-bool try_sntoi(const char *s, uint32_t n, uint32_t *out);
-void itosz(uint32_t i, char *out) __attribute__ ((access (write_only, 2)));
-void itosz_h8(uint8_t i, char *out) __attribute__ ((access (write_only, 2)));
-void itosz_h32(uint32_t i, char *out) __attribute__ ((access (write_only, 2)));
+//reads a hexadecimal terminated by either null or whitespace
+//returns length of string plus length of whitespace
+//returns 0 on failure
+uint32_t try_swtoh(const char *from, uint32_t *i_out);
#endif \ No newline at end of file
diff --git a/src/user/include/knob/ipc.h b/src/user/include/knob/ipc.h
new file mode 100644
index 0000000..3eab562
--- /dev/null
+++ b/src/user/include/knob/ipc.h
@@ -0,0 +1,16 @@
+#ifndef KNOB_IPC_H
+#define KNOB_IPC_H
+
+#include <pland/syscall.h>
+
+//blocking, returns early if other process is dead.
+//return value is number of bytes written.
+uint32_t try_send_ipc(_task_handle_t to, void *buffer, uint32_t size);
+
+//blocking, returns early if other process is dead.
+//return value is number of bytes read.
+uint32_t try_read_ipc(_task_handle_t from, void *buffer, uint32_t size);
+
+void flush_ipc(_task_handle_t from);
+
+#endif \ No newline at end of file
diff --git a/src/user/include/knob/key.h b/src/user/include/knob/key.h
new file mode 100644
index 0000000..90509fc
--- /dev/null
+++ b/src/user/include/knob/key.h
@@ -0,0 +1,8 @@
+#ifndef KNOB_KEY_H
+#define KNOB_KEY_H
+
+#include <keypack.h>
+
+char key_to_char(struct key_packet kp) __attribute__ ((pure));
+
+#endif \ No newline at end of file
diff --git a/src/user/include/knob/panic.h b/src/user/include/knob/panic.h
new file mode 100644
index 0000000..1dd33a0
--- /dev/null
+++ b/src/user/include/knob/panic.h
@@ -0,0 +1,9 @@
+#ifndef KNOB_PANIC_H
+#define KNOB_PANIC_H
+
+#include <stdint.h>
+
+#define PANIC(msg) panic(__FILE__, __LINE__, msg)
+void panic(const char *filename, uint32_t line, const char *message) __attribute__ ((noreturn));
+
+#endif \ No newline at end of file
diff --git a/src/user/include/knob/task.h b/src/user/include/knob/task.h
index 6539a00..cd51c37 100644
--- a/src/user/include/knob/task.h
+++ b/src/user/include/knob/task.h
@@ -1,11 +1,12 @@
#ifndef KNOB_TASK_H
#define KNOB_TASK_H
+#include <pland/syscall.h>
+
#include <stdint.h>
#include <stdbool.h>
-uint32_t run_command(const char *path);
-bool try_run_command_blocking(const char *path);
-void yield_task();
+uint32_t run_command(const char *path, _task_handle_t stdio_task);
+bool try_run_command_blocking(const char *path, _task_handle_t stdio_task);
#endif \ No newline at end of file
diff --git a/src/user/include/knob/user.h b/src/user/include/knob/user.h
deleted file mode 100644
index fb11c9b..0000000
--- a/src/user/include/knob/user.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef KNOB_USER_H
-#define KNOB_USER_H
-
-#include <stdint.h>
-#include <pland/syscall.h>
-
-struct history;
-
-char key_to_char(_key_code_t key) __attribute__ ((const));
-
-void tell_user_sz(const char *sz);
-
-//return value and max_length don't include null terminator
-//returns the real length of the string
-uint32_t ask_user_line_sz(char *sz, uint32_t max_length);
-
-struct history *new_history(uint32_t max_entries);
-void del_history(struct history *hs);
-
-uint32_t ask_user_line_sz_with_history(char *sz, uint32_t max_length, struct history *hs);
-
-#endif \ No newline at end of file
diff --git a/src/user/include/libfont/fonts.h b/src/user/include/libfont/fonts.h
new file mode 100644
index 0000000..b66659f
--- /dev/null
+++ b/src/user/include/libfont/fonts.h
@@ -0,0 +1,21 @@
+#ifndef LIBFONT_FONTS_H
+#define LIBFONT_FONTS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct font_info {
+ uint32_t space_width;
+ uint32_t space_height;
+ uint32_t char_width;
+ uint32_t char_height;
+ bool *bitmaps[256];//left to right then top to bottom
+ //null pointer for unsupported character
+ //unsupported characters drawn as bitmaps[0]
+};
+
+struct font_info *get_font(const char *name);
+
+void put_char(const struct font_info *font, char ch, uint8_t *pb_ptr, uint32_t pb_pitch, uint8_t bg, uint8_t fg);
+
+#endif \ No newline at end of file
diff --git a/src/user/include/pland/pcrt.h b/src/user/include/pland/pcrt.h
index 07ad453..42158cd 100644
--- a/src/user/include/pland/pcrt.h
+++ b/src/user/include/pland/pcrt.h
@@ -1,6 +1,8 @@
#ifndef PLAND_PCRT_H
#define PLAND_PCRT_H
+#include <pland/syscall.h>
+
#define BEFORE_MAIN(f) \
__attribute__ ((section (".__pcrt_before_main"))) \
__attribute__ ((unused)) \
@@ -13,4 +15,7 @@
void __pcrt_quit() __attribute__ ((noreturn));
-#endif \ No newline at end of file
+extern _task_handle_t calling_task;
+extern _task_handle_t stdio_task;
+
+#endif
diff --git a/src/user/include/pland/syscall.h b/src/user/include/pland/syscall.h
index ead5fea..6d327d5 100644
--- a/src/user/include/pland/syscall.h
+++ b/src/user/include/pland/syscall.h
@@ -4,119 +4,12 @@
#include <stdint.h>
#include <stdbool.h>
+#include <winact.h>
+
typedef uint32_t _file_handle_t;
typedef uint32_t _task_handle_t;
typedef uint32_t _drive_number_t;
-typedef uint32_t _process_handle_t;
-
-typedef enum {
- _KEY_LSHIFT = 0x00000100,
- _KEY_RSHIFT = 0x00000200,
- _KEY_CAPS = 0x00000400,
- _KEY_INSERT = 0x00000800,
- _KEY_NUM = 0x00001000,
- _KEY_SCROLL = 0x00002000,
- _KEY_LALT = 0x00004000,
- _KEY_RALT = 0x00008000,
- _KEY_LCTRL = 0x00010000,
- _KEY_RCTRL = 0x00020000,
- _KEY_LMETA = 0x00040000,
- _KEY_RMETA = 0x00080000,
-
- _KEY_SHIFT = 0x00000300,
- _KEY_SCAPS = 0x00000700,
- _KEY_ALT = 0x0000c000,
- _KEY_CTRL = 0x00030000,
- _KEY_META = 0x000c0000,
-
- _KEY_BEGIN_CAPS = 0x80,
- _KEY_BEGIN_INSERT,
- _KEY_BEGIN_NUM,
- _KEY_BEGIN_SCROLL,
- _KEY_BEGIN_LSHIFT,
- _KEY_BEGIN_RSHIFT,
- _KEY_BEGIN_LALT,
- _KEY_BEGIN_RALT,
- _KEY_BEGIN_LCTRL,
- _KEY_BEGIN_RCTRL,
- _KEY_BEGIN_LMETA,
- _KEY_BEGIN_RMETA,
- /* 0x8c - 0x97 reserved */
- /* 0x98 - 0x9f unassigned */
- _KEY_F1 = 0xa0,
- _KEY_F2,
- _KEY_F3,
- _KEY_F4,
- _KEY_F5,
- _KEY_F6,
- _KEY_F7,
- _KEY_F8,
- _KEY_F9,
- _KEY_F10,
- _KEY_F11,
- _KEY_F12,
- /* 0xac - 0xaf unassigned */
- _KEY_NUM0 = 0xb0,
- _KEY_NUM1,
- _KEY_NUM2,
- _KEY_NUM3,
- _KEY_NUM4,
- _KEY_NUM5,
- _KEY_NUM6,
- _KEY_NUM7,
- _KEY_NUM8,
- _KEY_NUM9,
- _KEY_NTIMES,
- _KEY_NPLUS,
- _KEY_NENTER,
- _KEY_NMINUS,
- _KEY_NDOT,
- _KEY_NSLASH,
- /* 0xc0 unassigned */
- _KEY_DELETE = 0xc1,
- _KEY_HOME,
- _KEY_END,
- _KEY_PUP,
- _KEY_PDOWN,
- _KEY_UP,
- _KEY_DOWN,
- _KEY_LEFT,
- _KEY_RIGHT,
- _KEY_ESC,
- _KEY_MENU,
- _KEY_PAUSE,
- _KEY_PRSCR,
- /* 0xce - 0xef unassigned */
-} _key_code_t;
-
-typedef enum {
- _COLOR_FG_BLACK = 0x00,
- _COLOR_FG_BLUE = 0x01,
- _COLOR_FG_GREEN = 0x02,
- _COLOR_FG_CYAN = 0x03,
- _COLOR_FG_RED = 0x04,
- _COLOR_FG_MAGENTA = 0x05,
- _COLOR_FG_BROWN = 0x06,
- _COLOR_FG_LGRAY = 0x07,
-
- _COLOR_FG_DGRAY = 0x08,
- _COLOR_FG_LBLUE = 0x09,
- _COLOR_FG_LGREEN = 0x0a,
- _COLOR_FG_LCYAN = 0x0b,
- _COLOR_FG_LRED = 0x0c,
- _COLOR_FG_PINK = 0x0d,
- _COLOR_FG_YELLOW = 0x0e,
- _COLOR_FG_WHITE = 0x0f,
-
- _COLOR_BG_BLACK = 0x00,
- _COLOR_BG_BLUE = 0x10,
- _COLOR_BG_GREEN = 0x20,
- _COLOR_BG_CYAN = 0x30,
- _COLOR_BG_RED = 0x40,
- _COLOR_BG_MAGENTA = 0x50,
- _COLOR_BG_BROWN = 0x60,
- _COLOR_BG_LGRAY = 0x70
-} _vga_color_t;
+typedef void *_window_handle_t;
typedef struct __attribute__ ((packed)) {
char name[100];
@@ -131,17 +24,26 @@ enum _scn {
_SCN_FILE_READ,
_SCN_FILE_SIZE,
_SCN_START_TASK,
- _SCN_LOG_STRING,
- _SCN_GET_KEY,
+ _SCN_IPC_SEND,
+ _SCN_IPC_READ,
_SCN_ALLOCATE_RAM,
_SCN_MEMORY_INFO,
_SCN_WAIT_FOR_TASK,
_SCN_ENUMERATE_DIR,
- _SCN_PRINT_AT,
+ _SCN_SYSTEM_LOG,
_SCN_COUNT_OF_DIR,
- _SCN_CLEAR_SCREEN,
- _SCN_SET_COLOR,
- _SCN_SWAP_COLOR
+ _SCN_NEW_WINDOW,
+ _SCN_DELETE_WINDOW,
+ _SCN_RESIZE_WINDOW,
+ _SCN_REASSIGN_PIXBUF,
+ _SCN_PAINT_WINDOW,
+ _SCN_GET_WIN_ACTION,
+ _SCN_WAIT_FOR_ACTION,
+ _SCN_WAIT_IPC_SEND,
+ _SCN_WAIT_FOR_ANY_IPC,
+ _SCN_FIND_UNREAD_IPC,
+ _SCN_WAIT_IPC_READ,
+ _SCN_IS_TASK_RUNNING
};
static inline uint32_t _sc0(enum _scn eax) {
@@ -211,7 +113,7 @@ static inline void _exit_task() {
}
static inline _file_handle_t _open_file(_drive_number_t drive_number, const char *path) {
- return _sc2(_SCN_OPEN_FILE, drive_number, (uint32_t)path);
+ return (_file_handle_t)_sc2(_SCN_OPEN_FILE, drive_number, (uint32_t)path);
}
static inline void _close_file(_file_handle_t handle) {
@@ -226,16 +128,16 @@ static inline uint32_t _file_size(_file_handle_t handle) {
return _sc1(_SCN_FILE_SIZE, handle);
}
-static inline _process_handle_t _start_task(_drive_number_t drive_number, const char *path, const char *pass) {
- return _sc3(_SCN_START_TASK, drive_number, (uint32_t)path, (uint32_t)pass);
+static inline _task_handle_t _start_task(_drive_number_t drive_number, const char *path, const char *pass, _task_handle_t stdio_task) {
+ return (_task_handle_t)_sc4(_SCN_START_TASK, drive_number, (uint32_t)path, (uint32_t)pass, (uint32_t)stdio_task);
}
-static inline void _log_string(const char *sz) {
- _sc1(_SCN_LOG_STRING, (uint32_t)sz);
+static inline uint32_t _ipc_send(_task_handle_t handle, uint32_t count, const void *buffer) {
+ return _sc3(_SCN_IPC_SEND, handle, count, (uint32_t)buffer);
}
-static inline _key_code_t _get_key() {
- return _sc0(_SCN_GET_KEY);
+static inline uint32_t _ipc_read(_task_handle_t handle, uint32_t count, void *buffer) {
+ return _sc3(_SCN_IPC_SEND, handle, count, (uint32_t)buffer);
}
static inline void *_allocate_ram(uint32_t pages) {
@@ -262,7 +164,7 @@ static inline uint32_t _this_process_memory_left() {
return _sc1(_SCN_MEMORY_INFO, 0x4);
}
-static inline void _wait_for_task(_process_handle_t handle) {
+static inline void _wait_for_task(_task_handle_t handle) {
_sc1(_SCN_WAIT_FOR_TASK, handle);
}
@@ -270,24 +172,60 @@ static inline uint32_t _enumerate_dir(_drive_number_t drive_number, const char *
return _sc4(_SCN_ENUMERATE_DIR, drive_number, (uint32_t)path, (uint32_t)buffer, max_count);
}
-static inline void _print_at(uint8_t row, uint8_t col, const char *sz) {
- _sc2(_SCN_PRINT_AT, (row << 8) | col, (uint32_t)sz);
-}
-
static inline uint32_t _count_of_dir(uint8_t drive_number, const char *path) {
return _sc2(_SCN_COUNT_OF_DIR, drive_number, (uint32_t)path);
}
-static inline void _clear_screen() {
- _sc0(_SCN_CLEAR_SCREEN);
+static inline _window_handle_t _new_window(uint16_t width, uint16_t height, void *pixel_buffer) {
+ return (_window_handle_t)_sc3(_SCN_NEW_WINDOW, width, height, (uint32_t)pixel_buffer);
+}
+
+static inline void _delete_window(_window_handle_t window) {
+ _sc1(_SCN_DELETE_WINDOW, (uint32_t)window);
+}
+
+static inline void _resize_window(_window_handle_t window, uint16_t width, uint16_t height) {
+ _sc3(_SCN_RESIZE_WINDOW, (uint32_t)window, width, height);
+}
+
+static inline void _reassign_pixbuf(_window_handle_t window, void *pixel_buffer) {
+ _sc2(_SCN_REASSIGN_PIXBUF, (uint32_t)window, (uint32_t)pixel_buffer);
+}
+
+static inline void _paint_window(_window_handle_t window) {
+ _sc1(_SCN_PAINT_WINDOW, (uint32_t)window);
+}
+
+static inline void _get_win_action(_window_handle_t window, struct window_action *action_pointer) {
+ _sc2(_SCN_GET_WIN_ACTION, (uint32_t)window, (uint32_t)action_pointer);
+}
+
+static inline void _wait_for_action() {
+ _sc0(_SCN_WAIT_FOR_ACTION);
+}
+
+static inline void _wait_ipc_send(_task_handle_t sending_task) {
+ _sc1(_SCN_WAIT_IPC_SEND, sending_task);
+}
+
+static inline void _system_log(const char *sz) {
+ _sc1(_SCN_SYSTEM_LOG, (uint32_t)sz);
+}
+
+static inline void _wait_for_any_ipc() {
+ _sc0(_SCN_WAIT_FOR_ANY_IPC);
+}
+
+static inline _task_handle_t _find_unread_ipc() {
+ return _sc0(_SCN_FIND_UNREAD_IPC);
}
-static inline void _set_color(_vga_color_t color) {
- _sc1(_SCN_SET_COLOR, color);
+static inline void _wait_ipc_read(_task_handle_t reading_task) {
+ _sc1(_SCN_WAIT_IPC_READ, reading_task);
}
-static inline void _swap_color(uint8_t row, uint8_t col) {
- _sc1(_SCN_SWAP_COLOR, (row << 8) | col);
+static inline bool _is_task_running(_task_handle_t handle) {
+ return (bool)_sc1(_SCN_IS_TASK_RUNNING, handle);
}
#endif \ No newline at end of file
diff --git a/src/user/include/popups/info.h b/src/user/include/popups/info.h
new file mode 100644
index 0000000..2c4e83f
--- /dev/null
+++ b/src/user/include/popups/info.h
@@ -0,0 +1,14 @@
+#ifndef POPUPS_INFO_H
+#define POPUPS_INFO_H
+
+#include <popups/popup.h>
+
+#include <pland/syscall.h>
+
+#include <stdarg.h>
+
+void info_popup(struct popup *into, const char *text, uint8_t fg, uint8_t bg);
+void info_popupf(struct popup *into, const char *text, uint8_t fg, uint8_t bg, ...);
+void info_popupf_v(struct popup *into, const char *text, uint8_t fg, uint8_t bg, va_list args);
+
+#endif \ No newline at end of file
diff --git a/src/user/include/popups/popup.h b/src/user/include/popups/popup.h
new file mode 100644
index 0000000..1a3c531
--- /dev/null
+++ b/src/user/include/popups/popup.h
@@ -0,0 +1,23 @@
+#ifndef POPUPS_POPUP_H
+#define POPUPS_POPUP_H
+
+#include <pland/syscall.h>
+
+struct popup {
+ _window_handle_t handle;
+ uint8_t *pixbuf;
+
+ bool has_quit;
+ struct key_packet quit_as;
+
+ //terminated by one with .key_id == 0
+ struct key_packet *quit_binds;
+ bool free_quit_binds;
+};
+
+void handle_actions(struct popup *p);
+//deletes popup before returning
+void make_modal(struct popup *p);
+void delete_popup(struct popup *p);
+
+#endif \ No newline at end of file
diff --git a/src/user/include/terminal/readline.h b/src/user/include/terminal/readline.h
new file mode 100644
index 0000000..9046610
--- /dev/null
+++ b/src/user/include/terminal/readline.h
@@ -0,0 +1,10 @@
+#ifndef TERMINAL_READLINE_H
+#define TERMINAL_READLINE_H
+
+#include <stdint.h>
+
+//returns length of string without null terminator
+//max_length doesn't include null terminator
+uint32_t read_line(char *sz, uint32_t max_length, const char *prompt);
+
+#endif \ No newline at end of file
diff --git a/src/user/include/terminal/terminal.h b/src/user/include/terminal/terminal.h
new file mode 100644
index 0000000..1782173
--- /dev/null
+++ b/src/user/include/terminal/terminal.h
@@ -0,0 +1,57 @@
+#ifndef TERMINAL_TERMINAL_H
+#define TERMINAL_TERMINAL_H
+
+#include <libfont/fonts.h>
+
+#include <pland/syscall.h>
+
+#include <stdarg.h>
+#include <stdint.h>
+
+struct terminal {
+ _window_handle_t window;
+ uint8_t *pixbuf;
+ uint32_t window_width;
+ uint32_t window_height;
+
+ struct font_info *font;
+
+ uint32_t cols;
+ uint32_t rows;
+ char *charbuf;
+
+ uint32_t cursor_y;
+ uint32_t cursor_x;
+
+ uint8_t fg;
+ uint8_t bg;
+};
+
+struct terminal *make_term(struct font_info *font, uint32_t cols, uint32_t rows);
+void del_term(struct terminal *term);
+
+extern struct terminal *active_term;
+
+void paint_term();
+
+void set_color(uint8_t fg, uint8_t bg);
+void clear_term();
+
+void move_cursor(uint32_t new_y, uint32_t new_x);
+
+void cursor_left();
+void cursor_right();
+void cursor_up();
+void cursor_down();
+
+void term_newline();
+void term_add_char(char ch);
+void term_add_sz_no_ww(const char *sz);
+void term_add_sz(const char *sz);
+
+void term_addf_no_ww_v(const char *fmt, va_list args);
+void term_addf_no_ww(const char *fmt, ...);
+void term_addf_v(const char *fmt, va_list args);
+void term_addf(const char *fmt, ...);
+
+#endif \ No newline at end of file
diff --git a/src/user/init/init.c b/src/user/init/init.c
index fb231e0..860c45f 100644
--- a/src/user/init/init.c
+++ b/src/user/init/init.c
@@ -1,32 +1,29 @@
-#include <knob/user.h>
#include <knob/file.h>
#include <knob/task.h>
#define STARTUP_FILE_PATH "sys/startup.rc"
+#define CMD_BUF_LEN 1024
+
+char cmdbuf[CMD_BUF_LEN];
void main() {
struct file *f = open_file(STARTUP_FILE_PATH);
if (!f) {
- tell_user_sz("Could not open " STARTUP_FILE_PATH ".\n");
+ _system_log("Could not open " STARTUP_FILE_PATH ".\n");
return;
}
- tell_user_sz("[init] Reading from " STARTUP_FILE_PATH ".\n");
-
- char cmdbuf[128];
- while (read_line_from_file(f, cmdbuf, 127)) {
- tell_user_sz("[init] Starting ");
- tell_user_sz(cmdbuf);
- tell_user_sz(": ");
- if (run_command(cmdbuf)) {
- tell_user_sz("Succeded.\n");
- yield_task();
- }
- else
- tell_user_sz("Failed.\n");
+ while (read_line_from_file(f, cmdbuf, CMD_BUF_LEN - 1)) {
+ if (cmdbuf[0] == '#')
+ continue;
+ //syslogf(run_command(cmdbuf)
+ // ? "[init] Started %s."
+ // : "[init] Could not run %s."
+ //, cmdbuf);
+ run_command(cmdbuf, 0);
}
close_file(f);
- tell_user_sz("[init] Done starting programs.\n");
+ _system_log("Done starting startup tasks.");
}
diff --git a/src/user/knob/block.c b/src/user/knob/block.c
index 94bd073..90f79e3 100644
--- a/src/user/knob/block.c
+++ b/src/user/knob/block.c
@@ -33,4 +33,28 @@ char *strdup(const char *from) {
char *buf = get_block(end - from);
blockcpy(buf, from, end - from);
return buf;
+}
+
+__attribute__ ((pure))
+bool strequ(const char *a, const char *b) {
+ while (true) {
+ if ((*a == '\0') != (*b == '\0'))
+ return false;
+ if (*a == '\0')
+ return true;
+ if (*a != *b)
+ return false;
+ ++a;
+ ++b;
+ }
+}
+
+__attribute__ ((pure))
+uint32_t strlen(const char *str) {
+ uint32_t len = 0;
+ while (*str) {
+ ++len;
+ ++str;
+ }
+ return len;
} \ No newline at end of file
diff --git a/src/user/knob/env.c b/src/user/knob/env.c
deleted file mode 100644
index 952ab86..0000000
--- a/src/user/knob/env.c
+++ /dev/null
@@ -1,3 +0,0 @@
-#include <stdint.h>
-
-uint32_t current_drive; \ No newline at end of file
diff --git a/src/user/knob/file.c b/src/user/knob/file.c
index f1a039d..3083503 100644
--- a/src/user/knob/file.c
+++ b/src/user/knob/file.c
@@ -1,8 +1,9 @@
-#include <pland/syscall.h>
-#include <pland/pcrt.h>
#include <knob/format.h>
+#include <knob/panic.h>
#include <knob/heap.h>
-#include <knob/env.h>
+
+#include <pland/syscall.h>
+#include <pland/pcrt.h>
struct ofl_node {
struct ofl_node *next;
@@ -27,23 +28,10 @@ struct file {
};
const char *remove_prefix(const char *path, uint8_t *dn_out) {
- if ((path[0] != 's') || (path[1] != 'd'))
- goto no_prefix;
-
- const char *num_part = path + 2;
- for (uint32_t i = 0; num_part[i]; ++i)
- if (num_part[i] == ':') {
-
- uint32_t dn_large;
- if (!try_sntoi(num_part, i, &dn_large) || dn_large > 255)
- goto no_prefix;
-
- *dn_out = (uint8_t)dn_large;
- return num_part + i + 1;
- }
+ if ((path[0] == 's') && (path[1] == 'd'))
+ PANIC("remove_prefix not fully implemented");
-no_prefix:
- *dn_out = current_drive;
+ *dn_out = 0;//change this later to an "active drive" or something
return path;
}
diff --git a/src/user/knob/format.c b/src/user/knob/format.c
index 593b20c..54d50ef 100644
--- a/src/user/knob/format.c
+++ b/src/user/knob/format.c
@@ -1,48 +1,231 @@
-#include <stdbool.h>
-#include <stdint.h>
-
-bool try_sntoi(const char *s, uint32_t n, uint32_t *out) {
- uint32_t calc = 0;
- for (uint32_t i = 0; i < n; ++i) {
- if ((s[i] < '0') || (s[i] > '9'))
- return false;
- calc = calc * 10 + s[i] - '0';
- }
- *out = calc;
- return true;
-}
+#include <knob/block.h>
+#include <knob/panic.h>
+#include <knob/heap.h>
+
+#include <pland/syscall.h>
+#include <pland/pcrt.h>
+
+#include <stdarg.h>
+
+#define FORMAT_BUF_INIT_SIZE 200
+#define FORMAT_BUF_CHUNK_SIZE 50
-__attribute__ ((access (write_only, 2)))
-void itosz(uint32_t i, char *out) {
- if (!i) {
- *(uint16_t *)out = (uint16_t)'0';
+#define BAD_SPEC "%%UNKNOWN FORMAT SPEC%%"
+#define BAD_SPEC_LEN 23
+
+static char *buf;
+static uint32_t buf_s;
+static char *buf_i;
+
+static const char *const hextab = "0123456789abcdef";
+
+static void ensure(uint32_t extra) {
+ const uint32_t total_len = buf_i - buf + extra;
+ if (total_len < buf_s)
return;
+
+ buf_s = (total_len / FORMAT_BUF_CHUNK_SIZE + 1) * FORMAT_BUF_CHUNK_SIZE;
+
+ char *const new_buf = get_block(buf_s);
+ if (!new_buf)
+ PANIC("out of memory in knob format");
+ blockcpy(new_buf, buf, buf_i - buf);
+ free_block(buf);
+ buf_i += new_buf - buf;
+ buf = new_buf;
+}
+
+struct format_spec {
+ uint32_t len;
+ enum {
+ UNKNOWN,
+ CHAR,
+ STRING,
+ UNSIGNED_DECIMAL,
+ HEXADECIMAL
+ //TODO: signed decimal
+ } kind;
+};
+
+static const char *get_format(const char *from, struct format_spec *format_out) {
+ if (*from == 'n') {
+ ++from;
+ format_out->len = -1;
}
- bool zero = false;
- for (uint32_t m = 1000000000; m; m /= 10) {
- uint8_t d = (i / m) % 10;
- if (zero)
- *(out++) = d + '0';
- else if (d) {
- zero = true;
- *(out++) = d + '0';
+ else {
+ uint32_t len = 0;
+ while ((*from >= '0') && (*from <= '9'))
+ len = len * 10 + *(from++) - '0';
+ format_out->len = len;
+ }
+
+ switch (*from) {
+ case 'c':
+ format_out->kind = CHAR;
+ break;
+ case 's':
+ format_out->kind = STRING;
+ break;
+ case 'u':
+ format_out->kind = UNSIGNED_DECIMAL;
+ break;
+ case 'h':
+ case 'x':
+ format_out->kind = HEXADECIMAL;
+ break;
+ default:
+ format_out->kind = UNKNOWN;
+ break;
+ }
+
+ return from + 1;
+}
+
+//allocates new memory
+char *format_v(const char *fmt, va_list args) {
+ buf = get_block(FORMAT_BUF_INIT_SIZE);
+ if (!buf)
+ PANIC("out of memory in knob format");
+ buf_s = FORMAT_BUF_INIT_SIZE;
+ buf_i = buf;
+
+ while (*fmt) {
+ if (*fmt != '%') {
+ ensure(1);
+ *(buf_i++) = *(fmt++);
+ }
+ else if (fmt[1] == '%') {
+ ensure(1);
+ *(buf_i++) = '%';
+ fmt += 2;
+ }
+ else {
+ struct format_spec form;
+ fmt = get_format(fmt + 1, &form);
+ if (form.len == -1)
+ //should passing zero still have the special meaning?
+ form.len = va_arg(args, uint32_t);
+ switch (form.kind) {
+ case UNKNOWN:
+ ensure(BAD_SPEC_LEN);
+ blockcpy(buf_i, BAD_SPEC, BAD_SPEC_LEN);
+ buf_i += BAD_SPEC_LEN;
+ continue;
+
+ uint32_t ch;
+ case CHAR:
+ ch = va_arg(args, uint32_t);
+ ensure(1);
+ *(buf_i++) = (char)ch;
+ continue;
+
+ const char *str;
+ case STRING:
+ str = va_arg(args, const char *);
+ if (!form.len)
+ form.len = strlen(str);
+ ensure(form.len);
+ blockcpy(buf_i, str, form.len);
+ buf_i += form.len;
+ continue;
+
+ uint32_t k;
+ case UNSIGNED_DECIMAL:
+ k = va_arg(args, uint32_t);
+ if (!form.len) {
+ uint32_t n = 10;
+ ++form.len;
+ while (k >= n) {
+ ++form.len;
+ n *= 10;
+ }
+ }
+ ensure(form.len);
+ const uint32_t len_backup = form.len;
+ while (form.len--) {
+ buf_i[form.len] = (k % 10) + '0';
+ k /= 10;
+ }
+ buf_i += len_backup;
+ continue;
+
+ case HEXADECIMAL:
+ k = va_arg(args, uint32_t);
+ if (!form.len)
+ form.len = 8;
+ ensure(form.len);
+ const uint32_t hlen_backup = form.len;
+ while (form.len--) {
+ buf_i[form.len] = hextab[k % 16];
+ k >>= 4;
+ }
+ buf_i += hlen_backup;
+ continue;
+ }
}
}
- *out = '\0';
+
+ *buf_i = '\0';
+ return buf;
+}
+
+//allocates new memory
+char *format(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ char *const res = format_v(fmt, args);
+ va_end(args);
+ return res;
+}
+
+void syslogf_v(const char *fmt, va_list args) {
+ char *const msg = format_v(fmt, args);
+ _system_log(msg);
+ free_block(msg);
}
-const char *const hex_digits = "0123456789abcdef";
+void syslogf(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ syslogf_v(fmt, args);
+ va_end(args);
+}
-__attribute__ ((access (write_only, 2)))
-void itosz_h8(uint8_t i, char *out) {
- out[0] = hex_digits[i >> 4];
- out[1] = hex_digits[i & 0xf];
- out[2] = '\0';
+//reads a unsigned decimal terminated by either null or whitespace
+//returns length of string plus length of whitespace
+//returns 0 on failure
+uint32_t try_swtou(const char *from, uint32_t *i_out) {
+ const char *const old_from = from;
+ uint32_t v = 0;
+ while (*from && (*from != '\n') && (*from != ' ')) {
+ if ((*from < '0') || (*from > '9'))
+ return 0;
+ v = v * 10 + *(from++) - '0';
+ }
+ *i_out = v;
+ while ((*from == '\n') || (*from == ' '))
+ ++from;
+ return from - old_from;
}
-__attribute__ ((access (write_only, 2)))
-void itosz_h32(uint32_t i, char *out) {
- for (uint8_t digit = 0; digit < 8; ++digit)
- out[digit] = hex_digits[(i >> (28 - digit * 4)) & 0xf];
- out[8] = '\0';
+//reads a hexadecimal terminated by either null or whitespace
+//returns length of string plus length of whitespace
+//returns 0 on failure
+uint32_t try_swtoh(const char *from, uint32_t *i_out) {
+ const char *const old_from = from;
+ uint32_t v = 0;
+ while (*from && (*from != '\n') && (*from != ' ')) {
+ if ((*from >= '0') && (*from <= '9'))
+ v = v * 16 + *(from++) - '0';
+ else if ((*from >= 'a') && (*from <= 'f'))
+ v = v * 16 + *(from++) - 'a' + 10;
+ else if ((*from >= 'A') && (*from <= 'F'))
+ v = v * 16 + *(from++) - 'A' + 10;
+ else
+ return 0;
+ }
+ *i_out = v;
+ while ((*from == '\n') || (*from == ' '))
+ ++from;
+ return from - old_from;
} \ No newline at end of file
diff --git a/src/user/knob/heap.c b/src/user/knob/heap.c
index 49f9339..b770542 100644
--- a/src/user/knob/heap.c
+++ b/src/user/knob/heap.c
@@ -1,4 +1,7 @@
+#include <knob/format.h>
+
#include <pland/syscall.h>
+
#include <stdbool.h>
#include <stdint.h>
@@ -24,23 +27,8 @@ static void add_header(struct block_header *bh) {
__attribute__ ((malloc))
void *get_block(uint32_t bytes) {
-//char nbuf[11];
-//tell_user_sz("[heap::get_block]\n first_block = 0x");
-//itosz_h32((uint32_t)first_block, nbuf);
-//tell_user_sz(nbuf);
-//tell_user_sz("\n");
struct block_header *header = 0;
-
for (struct block_header *ptr = first_block; ptr; ptr = ptr->next) {
- //tell_user_sz(" ptr = 0x");
- //itosz_h32((uint32_t)ptr, nbuf);
- //tell_user_sz(nbuf);
- //tell_user_sz("\n &ptr->allocated = 0x");
- //itosz_h32((uint32_t)&ptr->allocated, nbuf);
- //tell_user_sz(nbuf);
- //tell_user_sz("\n ptr->allocated = ");
- //tell_user_sz(ptr->allocated ? "true\n" : "false\n");
-
if (ptr->allocated)
continue;
if (ptr->length == bytes) {
@@ -63,14 +51,7 @@ void *get_block(uint32_t bytes) {
if (!header) {
uint32_t size_with_header = bytes + sizeof(struct block_header);
if (!(size_with_header % 4096)) {
- //tell_user_sz(" allocate ");
- //itosz(size_with_header / 4096, nbuf);
- //tell_user_sz(nbuf);
- //tell_user_sz(" pages = 0x");
header = _allocate_ram(size_with_header / 4096);
- //itosz_h32((uint32_t)header, nbuf);
- //tell_user_sz(nbuf);
- //tell_user_sz("\n");
if (!header)
return 0;
header->length = bytes;
@@ -78,14 +59,7 @@ void *get_block(uint32_t bytes) {
}
else {
uint32_t pages = (bytes + sizeof(struct block_header) * 2) / 4096 + 1;
- //tell_user_sz(" allocate ");
- //itosz(pages, nbuf);
- //tell_user_sz(nbuf);
- //tell_user_sz(" pages = 0x");
header = _allocate_ram(pages);
- //itosz_h32((uint32_t)header, nbuf);
- //tell_user_sz(nbuf);
- //tell_user_sz("\n");
if (!header)
return 0;
header->length = bytes;
diff --git a/src/user/knob/ipc.c b/src/user/knob/ipc.c
new file mode 100644
index 0000000..dbf1a22
--- /dev/null
+++ b/src/user/knob/ipc.c
@@ -0,0 +1,45 @@
+#include <pland/syscall.h>
+
+//blocking, returns early if other process is dead.
+//return value is number of bytes written.
+uint32_t try_send_ipc(_task_handle_t to, void *buffer, uint32_t size) {
+ const uint32_t size_backup = size;
+ while (size) {
+ uint32_t res = _ipc_send(to, size, buffer);
+ if (!res) {
+ _wait_ipc_read(to);
+ _yield_task();
+ }
+ else if (res == -1)
+ return size_backup - size;
+ else {
+ size -= res;
+ buffer += res;
+ }
+ }
+}
+
+//blocking, returns early if other process is dead.
+//return value is number of bytes read.
+uint32_t read_ipc(_task_handle_t from, void *buffer, uint32_t size) {
+ const uint32_t size_backup = size;
+ while (size) {
+ uint32_t res = _ipc_read(from, size, buffer);
+ if (!res) {
+ _wait_ipc_send(from);
+ _yield_task();
+ }
+ else if (res == -1)
+ return size_backup - size;
+ else {
+ size -= res;
+ buffer += res;
+ }
+ }
+}
+
+void flush_ipc(_task_handle_t from) {
+ uint8_t buf[4096];
+ while (_ipc_read(from, 4096, buf))
+ ;
+} \ No newline at end of file
diff --git a/src/user/knob/key.c b/src/user/knob/key.c
new file mode 100644
index 0000000..1506f3b
--- /dev/null
+++ b/src/user/knob/key.c
@@ -0,0 +1,67 @@
+#include <keypack.h>
+
+static const char no_mod[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, '\t','\n', 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ' ', 0, 0, 0, 0, 0, 0, '\'', 0, 0, 0, 0, ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, ';', 0, '=', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[','\\', ']', 0, 0,
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0
+};
+
+static const char shifted[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, '\t','\n', 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ' ', 0, 0, 0, 0, 0, 0, '"', 0, 0, 0, 0, '<', '_', '>', '?',
+ ')', '!', '@', '#', '$', '%', '^', '&', '*', '(', 0, ':', 0, '+', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '{', '|', '}', 0, 0,
+ '~', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0, 0, 0, 0, 0
+};
+
+static const char caps[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, '\t','\n', 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ' ', 0, 0, 0, 0, 0, 0, '\'', 0, 0, 0, 0, ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, ';', 0, '=', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[','\\', ']', 0, 0,
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0, 0, 0, 0, 0
+};
+
+static const char sh_caps[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, '\t','\n', 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ' ', 0, 0, 0, 0, 0, 0, '"', 0, 0, 0, 0, '<', '_', '>', '?',
+ ')', '!', '@', '#', '$', '%', '^', '&', '*', '(', 0, ':', 0, '+', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '{', '|', '}', 0, 0,
+ '~', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0
+};
+
+static const char num[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '+', '\n', '-', '.', '/'
+};
+
+__attribute__ ((pure))
+char key_to_char(struct key_packet kp) {
+ if (kp.key_id < 0x80) {
+ const char ch = (kp.modifiers & SHIFTS
+ ? kp.modifiers & CAPS
+ ? sh_caps : shifted
+ : kp.modifiers & CAPS
+ ? caps : no_mod)[kp.key_id];
+ return ch ? kp.modifiers & ALTS ? 0x80 & ch : ch : 0;
+ }
+
+ else if ((kp.modifiers & NUM) && ((kp.key_id & 0xf0) == 0xb0))
+ return num[kp.key_id & 0x0f];
+
+ else
+ return 0;
+} \ No newline at end of file
diff --git a/src/user/knob/panic.c b/src/user/knob/panic.c
new file mode 100644
index 0000000..1ff663c
--- /dev/null
+++ b/src/user/knob/panic.c
@@ -0,0 +1,12 @@
+#include <knob/format.h>
+
+#include <pland/syscall.h>
+#include <pland/pcrt.h>
+
+#include <stdint.h>
+
+__attribute__ ((noreturn))
+void panic(const char *filename, uint32_t line, const char *message) {
+ _system_log(format("panic in %s on line %u: %s", filename, line, message));
+ __pcrt_quit();
+} \ No newline at end of file
diff --git a/src/user/knob/task.c b/src/user/knob/task.c
index df5d38f..3bf3e85 100644
--- a/src/user/knob/task.c
+++ b/src/user/knob/task.c
@@ -4,7 +4,7 @@
#include <knob/heap.h>
#include <knob/block.h>
-_task_handle_t run_command(const char *path) {
+_task_handle_t run_command(const char *path, _task_handle_t stdio_task) {
uint8_t dn;
path = remove_prefix(path, &dn);
@@ -14,23 +14,21 @@ _task_handle_t run_command(const char *path) {
blockcpy(new_path, path, ptr - path);
new_path[ptr - path] = '\0';
- bool succeded = _start_task(dn, new_path, ptr + 1);
+ bool succeded = _start_task(dn, new_path, ptr + 1, stdio_task);
free_block(new_path);
return succeded;
}
- return _start_task(dn, path, "");
+ return _start_task(dn, path, "", stdio_task);
}
-bool try_run_command_blocking(const char *path) {
- _task_handle_t handle = run_command(path);
+bool try_run_command_blocking(const char *path, _task_handle_t stdio_task) {
+ _task_handle_t handle = run_command(path, stdio_task);
if (!handle)
return false;
- _wait_for_task(handle);
- _yield_task();
+ while (_is_task_running(handle)) {
+ _wait_for_task(handle);
+ _yield_task();
+ }
return true;
-}
-
-void yield_task() {
- _yield_task();
} \ No newline at end of file
diff --git a/src/user/knob/user.c b/src/user/knob/user.c
deleted file mode 100644
index 1e273bb..0000000
--- a/src/user/knob/user.c
+++ /dev/null
@@ -1,299 +0,0 @@
-#include <pland/syscall.h>
-#include <knob/block.h>
-#include <knob/heap.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-static const uint8_t caps_and_shift[] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x22,
- 0x28, 0x29, 0x2a, 0x2b, 0x3c, 0x5f, 0x3e, 0x3f,
- 0x29, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5e, 0x26,
- 0x2a, 0x28, 0x3a, 0x3a, 0x3c, 0x2d, 0x3e, 0x3f,
-
- 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- 0x78, 0x79, 0x7a, 0x57, 0x7c, 0x7d, 0x5e, 0x5f,
- 0x7e, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x00,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static const uint8_t caps_no_shift[] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
- 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
- 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x00,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static const uint8_t shifted[] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x22,
- 0x28, 0x29, 0x2a, 0x2b, 0x3c, 0x5f, 0x3e, 0x3f,
- 0x29, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5e, 0x26,
- 0x2a, 0x28, 0x3a, 0x3a, 0x3c, 0x2d, 0x3e, 0x3f,
-
- 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- 0x78, 0x79, 0x7a, 0x57, 0x7c, 0x7d, 0x5e, 0x5f,
- 0x7e, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x00,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-__attribute__ ((const))
-char key_to_char(_key_code_t key) {
- return
- key & _KEY_CAPS
- ? key & _KEY_SHIFT
- ? caps_and_shift[key & 0xff]
- : caps_no_shift[key & 0xff]
- : key & _KEY_SHIFT
- ? shifted[key & 0xff]
- : key & 0xff;
-}
-
-static char get_key_char() {
- _key_code_t key;
- while (!(key = _get_key()))
- _yield_task();
- return key_to_char(key);
-}
-
-void tell_user_sz(const char *sz) {
- _log_string(sz);
-}
-
-//return value and max_length don't include null terminator
-uint32_t ask_user_line_sz(char *sz, uint32_t max_length) {
- char log_buf[2];
- log_buf[1] = '\0';
-
- uint32_t i;
- for (i = 0; i != max_length; ++i) {
- char key;
- replace:
- key = get_key_char();
- if (!key)
- goto replace;
- if (key & 0x80)
- goto replace;//TODO
- if (key == '\b') {
- if (i) {
- --i;
- _log_string("\b");
- }
- goto replace;
- }
-
- log_buf[0] = key;
- _log_string(log_buf);
-
- if (key == '\n')
- break;
- sz[i] = key;
- }
-
- sz[i] = '\0';
- return i;
-}
-
-struct history_entry {
- struct history_entry *prev;
- struct history_entry *next;
- const char *contents;
-};
-
-struct history {
- struct history_entry *earliest_history_item;
- struct history_entry *latest_history_item;
- uint32_t max_entries;
- uint32_t cur_entries;
-};
-
-struct history *new_history(uint32_t max_entries) {
- struct history *new = get_block(sizeof(struct history));
- new->latest_history_item = 0;
- new->earliest_history_item = 0;
- new->max_entries = max_entries;
- new->cur_entries = 0;
- return new;
-}
-
-void del_history(struct history *hs) {
- free_block(hs);
- for (struct history_entry *he = hs->latest_history_item; he; he = he->prev) {
- free_block(he);
- free_block(he->contents);
- }
-}
-
-//return value and max_length don't include null terminator
-uint32_t ask_user_line_sz_with_history(char *sz, uint32_t max_length, struct history *hs) {
- char log_buf[2];
- log_buf[1] = '\0';
- struct history_entry *cur_he = 0;
-
- uint32_t i;
- for (i = 0; i != max_length; ++i) {
- char key;
- replace:
- key = get_key_char();
- if (!key)
- goto replace;
- if (key == (char)_KEY_UP) {
- struct history_entry *new_cur_he = cur_he ? cur_he->prev : hs->latest_history_item;
- if (new_cur_he) {
- cur_he = new_cur_he;
- for (uint32_t j = 0; j < i; ++j)
- _log_string("\b");
- i = strcpy(sz, cur_he->contents);
- _log_string(sz);
- }
- goto replace;
- }
- if (key == (char)_KEY_DOWN) {
- cur_he = cur_he ? cur_he->next : 0;
- for (uint32_t j = 0; j < i; ++j)
- _log_string("\b");
- if (cur_he) {
- i = strcpy(sz, cur_he->contents);
- _log_string(sz);
- }
- else
- i = 0;
- goto replace;
- }
- if (key & 0x80)
- goto replace;//TODO
- if (key == '\b') {
- if (i) {
- --i;
- _log_string("\b");
- }
- goto replace;
- }
-
- log_buf[0] = key;
- _log_string(log_buf);
-
- if (key == '\n')
- break;
- sz[i] = key;
- }
-
- sz[i] = '\0';
-
- struct history_entry *new_he = get_block(sizeof(struct history_entry));
- new_he->contents = strdup(sz);
-
- new_he->next = 0;
- if (hs->latest_history_item) {
- new_he->prev = hs->latest_history_item;
- hs->latest_history_item->next = new_he;
- }
- else
- new_he->prev = 0;
- hs->latest_history_item = new_he;
- if (!hs->earliest_history_item)
- hs->earliest_history_item = new_he;
- if (hs->max_entries == hs->cur_entries) {
- free_block(hs->earliest_history_item);
- free_block(hs->earliest_history_item->contents);
- hs->earliest_history_item->next->prev = 0;
- hs->earliest_history_item = hs->earliest_history_item->next;
- }
- else
- ++(hs->cur_entries);
-
- for (struct history_entry *check_he = hs->latest_history_item->prev; check_he; check_he = check_he->prev) {
- if (blockequ(check_he->contents, sz, i + 1)) {
- check_he->next->prev = check_he->prev;
- if (check_he->prev)
- check_he->prev->next = check_he->next;
- else
- hs->earliest_history_item = check_he->next;
- free_block(check_he);
- free_block(check_he->contents);
- }
- }
-
- return i;
-} \ No newline at end of file
diff --git a/src/user/libfont/bdf.c b/src/user/libfont/bdf.c
new file mode 100644
index 0000000..2c19a15
--- /dev/null
+++ b/src/user/libfont/bdf.c
@@ -0,0 +1,99 @@
+#include <libfont/fonts.h>
+
+#include <knob/format.h>
+#include <knob/panic.h>
+#include <knob/block.h>
+#include <knob/heap.h>
+#include <knob/file.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define LINE_BUF_SIZE 1000
+char line_buf[LINE_BUF_SIZE];
+
+static inline uint8_t hex_to_n(char ch) {
+ return ch - (ch >= 'A' ? 'A' - 10 : '0');
+}
+
+//very minimal implementation
+bool try_load_bdf(const char *path, struct font_info *into) {
+ struct file *f = open_file(path);
+ if (!f)
+ PANIC("Can't open font file sent by get_font.");
+
+ read_line_from_file(f, line_buf, LINE_BUF_SIZE - 1);
+ if (!strequ(line_buf, "STARTFONT 2.1")) {
+ close_file(f);
+ return false;
+ }
+
+ for (uint16_t i = 0; i < 256; ++i)
+ into->bitmaps[i] = 0;
+ into->space_height = -1;
+ into->space_width = -1;
+ into->char_height = -1;
+ into->char_width = -1;
+
+ uint32_t current = 0;
+
+ while (read_line_from_file(f, line_buf, LINE_BUF_SIZE - 1)) {
+ if (blockequ(line_buf, "FONTBOUNDINGBOX ", 16)) {
+ uint32_t n;
+ uint32_t l = try_swtou(line_buf + 16, &n);
+ if (!l)
+ goto bad_format;
+ into->space_width = n;
+ into->char_width = n;
+ l = try_swtou(line_buf + 16 + l, &n);
+ if (!l)
+ goto bad_format;
+ into->space_height = n;
+ into->char_height = n;
+ }
+ else if (blockequ(line_buf, "ENCODING ", 9)) {
+ if (!try_swtou(line_buf + 9, &current))
+ goto bad_format;
+ }
+ else if (strequ(line_buf, "BITMAP")) {
+ if (current >= 256)
+ continue;
+ bool *bm = get_block(into->char_height * into->char_width);
+ if (!bm)
+ PANIC("could not allocate memory for font character bitmap");
+ into->bitmaps[current] = bm;
+
+ for (uint32_t y = 0; y < into->char_height; ++y) {
+ read_line_from_file(f, line_buf, LINE_BUF_SIZE - 1);
+ for (uint32_t x = 0; x < into->char_width; ++x)
+ bm[y * into->char_width + x] = (hex_to_n(line_buf[x / 4]) >> (3 - x % 4)) & 1;
+ }
+ }
+ }
+
+ close_file(f);
+ f = 0;
+
+ if ((into->char_height == -1) ||
+ (into->char_width == -1) ||
+ (into->space_height == -1) ||
+ (into->space_width == -1))
+ goto bad_format;
+
+ if (!into->bitmaps[0]) {
+ const uint32_t bytes = (into->char_height * into->char_width - 1) / 8 + 1;
+ into->bitmaps[0] = get_block(bytes);
+ for (uint32_t i = 0; i < bytes; ++i)
+ into->bitmaps[0][i] = 0b01011010;
+ }
+
+ return true;
+
+bad_format:
+ if (f)
+ close_file(f);
+ for (uint16_t i = 0; i < 256; ++i)
+ if (into->bitmaps[i])
+ free_block(into->bitmaps[i]);
+ return false;
+} \ No newline at end of file
diff --git a/src/user/libfont/bdf.h b/src/user/libfont/bdf.h
new file mode 100644
index 0000000..4ed4189
--- /dev/null
+++ b/src/user/libfont/bdf.h
@@ -0,0 +1,8 @@
+#ifndef LIBFONT_BDF_H
+#define LIBFONT_BDF_H
+
+#include <stdbool.h>
+
+bool try_load_bdf(const char *path, struct font_info *into);
+
+#endif \ No newline at end of file
diff --git a/src/user/libfont/filist.c b/src/user/libfont/filist.c
new file mode 100644
index 0000000..ae24429
--- /dev/null
+++ b/src/user/libfont/filist.c
@@ -0,0 +1,33 @@
+#include <libfont/fonts.h>
+#include <knob/block.h>
+#include <knob/heap.h>
+
+struct dict_entry {
+ char *name;
+ struct font_info *fi;
+ struct dict_entry *prev;
+} *last_entry = 0;
+
+__attribute__ ((pure))
+struct font_info *find_entry(const char *name) {
+ for (struct dict_entry *i = last_entry; i; i = i->prev)
+ if (strequ(i->name, name))
+ return i->fi;
+ return 0;
+}
+
+struct font_info *new_entry(const char *name) {
+ struct dict_entry *const nde = get_block(sizeof(struct dict_entry));
+ nde->name = strdup(name);
+ nde->fi = get_block(sizeof(struct font_info));
+ nde->prev = last_entry;
+ last_entry = nde;
+ return nde->fi;
+}
+
+void del_last() {//only called when last_entry isn't 0
+ free_block(last_entry->name);
+ free_block(last_entry->fi);
+ free_block(last_entry);
+ last_entry = last_entry->prev;
+} \ No newline at end of file
diff --git a/src/user/libfont/filist.h b/src/user/libfont/filist.h
new file mode 100644
index 0000000..c78c640
--- /dev/null
+++ b/src/user/libfont/filist.h
@@ -0,0 +1,8 @@
+#ifndef LIBFONT_FILIST_H
+#define LIBFONT_FILIST_H
+
+struct font_info *find_entry(const char *name) __attribute__ ((pure));
+struct font_info *new_entry(const char *name);
+void del_last();
+
+#endif \ No newline at end of file
diff --git a/src/user/libfont/fonts.c b/src/user/libfont/fonts.c
new file mode 100644
index 0000000..1692992
--- /dev/null
+++ b/src/user/libfont/fonts.c
@@ -0,0 +1,66 @@
+#include <libfont/fonts.h>
+#include <knob/format.h>
+#include <knob/block.h>
+#include <knob/heap.h>
+#include <knob/file.h>
+
+#include "filist.h"
+#include "bdf.h"
+
+#define FONT_PATH "fonts/"
+#define FONT_PATH_L 6
+
+struct font_loader_t {
+ const char *ext;
+ bool (*func)(const char *, struct font_info *);
+} font_loaders[] = {
+ { .ext = ".bdf",
+ .func = try_load_bdf
+ },
+ { .ext = ""
+ }
+};
+
+struct font_info *get_font(const char *name) {
+ struct font_info *font = find_entry(name);
+ if (font)
+ return font;
+ font = new_entry(name);
+ if (!font)
+ return 0;//out of memory?
+
+ const uint32_t name_len = strlen(name);
+ for (struct font_loader_t *i = font_loaders; i->ext[0]; ++i) {
+ char *buf = get_block(FONT_PATH_L + name_len + strlen(i->ext) + 1);
+ blockcpy(buf, FONT_PATH, FONT_PATH_L);
+ blockcpy(buf + FONT_PATH_L, name, name_len);
+ strcpy(buf + FONT_PATH_L + name_len, i->ext);
+ struct file *f = open_file(buf);
+ if (!f) {
+ free_block(buf);
+ continue;
+ }
+ syslogf("[libfont] Loading %s%s...", name, i->ext);
+ if (i->func(buf, font)) {
+ close_file(f);
+ free_block(buf);
+ syslogf("[libfont] Loaded %s%s.", name, i->ext);
+ return font;
+ }
+ close_file(f);
+ free_block(buf);
+ syslogf("[libfont] Failed to load %s%s.", name, i->ext);
+ }
+ del_last();
+ return 0;
+}
+
+void put_char(const struct font_info *font, char ch, uint8_t *pb_ptr, uint32_t pb_pitch, uint8_t bg, uint8_t fg) {
+//char *const msg = format("put_char(font = 0x%x, ch = '%c', pb_ptr = 0x%x, pb_pitch = %u, bg = 0x%2x, fg = 0x%2x);", font, ch, pb_ptr, pb_pitch, bg, fg);
+//_system_log(msg);
+//free_block(msg);
+ const bool *const bitmap = font->bitmaps[(uint8_t)ch] ? font->bitmaps[(uint8_t)ch] : font->bitmaps[0];
+ for (uint32_t y = 0; y < font->char_height; ++y)
+ for (uint32_t x = 0; x < font->char_width; ++x)
+ pb_ptr[y * pb_pitch + x] = bitmap[y * font->char_width + x] ? fg : bg;
+} \ No newline at end of file
diff --git a/src/user/manual/manual.c b/src/user/manual/manual.c
deleted file mode 100644
index d1af406..0000000
--- a/src/user/manual/manual.c
+++ /dev/null
@@ -1,303 +0,0 @@
-#include <knob/heap.h>
-#include <knob/file.h>
-#include <knob/block.h>
-#include <knob/format.h>
-#include <pland/syscall.h>
-
-#define ERROR_COLOR _COLOR_BG_LGRAY | _COLOR_FG_RED
-#define UI_COLOR _COLOR_BG_LGRAY | _COLOR_FG_BLACK
-#define DEFAULT_TEXT_COLOR _COLOR_BG_BLACK | _COLOR_FG_WHITE
-
-#define MAN_ROOT "man/"
-#define MRL 4
-#define MAN_EXT "man"
-
-#define MAX_PATH_LEN 255
-
-#define SP80 " "
-#define SP79 " "
-#define SP69 " "
-#define SP10 " "
-
-struct file *cur_file = 0;
-
-char *name_backup = 0;
-
-uint32_t *line_offsets = 0;
-uint32_t n_lines;
-
-struct link {
- uint32_t line;
- uint8_t col;
- uint8_t len;
- char *lto;
-};
-
-struct link *link_table_start = 0;
-struct link *link_table_end;
-
-struct link *cur_link = 0;
-
-uint32_t line_on;
-
-#define DATA_BUF_SIZE 2000
-
-void print_page() {
- uint8_t buf[DATA_BUF_SIZE];//1840 + up to 160 color codes
- seek_file_to(cur_file, line_offsets[line_on]);
- uint8_t *bufp = buf + DATA_BUF_SIZE;
- uint8_t *bufend;
- uint8_t row = 1, col = 0;
-
- _set_color(DEFAULT_TEXT_COLOR);
- while (row != 24) {
- if (bufp == buf + DATA_BUF_SIZE) {
- bufp = buf;
- uint16_t bl = read_from_file(cur_file, DATA_BUF_SIZE, buf);
- bufend = bl == DATA_BUF_SIZE ? 0 : buf + bl;
- }
- if (bufp == bufend) {
- uint32_t *i = buf;
- uint16_t l = 80 - col + (23 - row) * 80;
- uint32_t *e = i + l / 4 + 1;
- while (i != e)
- *(i++) = 0x20202020;
- buf[l] = '\0';
- _print_at(row, col, buf);
- break;
- }
- if (*bufp & 0x80)
- _set_color(*bufp & 0x7f);
- else {
- char bufpb[2] = {*bufp, '\0'};
- _print_at(row, col, bufpb);
- if (++col == 80) {
- col = 0;
- ++row;
- }
- }
- ++bufp;
- }
-
- if (cur_link)
- for (uint8_t c = cur_link->col; c < cur_link->col + cur_link->len; ++c)
- _swap_color(cur_link->line - line_on + 1, c);
-}
-
-void scroll_to(uint32_t n) {
- if (n > n_lines - 23)
- n = n_lines - 23;
-
- if (cur_link && ((cur_link->line < n) || (cur_link->line >= n + 23)))
- cur_link = 0;
-
- line_on = n;
- print_page();
-
- char b[16] = "Line ";
- itosz(line_on, b + 5);
-
- _set_color(UI_COLOR);
- _print_at(24, 0, SP69);
- _print_at(24, 0, b);
-}
-
-void scroll_link() {
- if (cur_link->line < line_on)
- scroll_to(cur_link->line);
- else if (cur_link->line >= line_on + 23)
- scroll_to(cur_link->line - 22);
- else
- print_page();
-}
-
-void load_file(const char *name) {
- static char cur_page[MAX_PATH_LEN + 1] = MAN_ROOT;
- uint32_t name_len = strcpy(cur_page + MRL, name);
- strcpy(cur_page + MRL + name_len, "." MAN_EXT);
-
- struct file *new_file = open_file(cur_page);
- if (!new_file) {
- _set_color(ERROR_COLOR);
- _print_at(24, 0, SP79);
- _print_at(24, 0, "Could not open file.");
- return;
- }
-
- if (name_backup)
- free_block(name_backup);
- name_backup = strdup(name);
-
- if (cur_file)
- close_file(cur_file);
- cur_file = new_file;
-
- uint32_t tlen;
- read_from_file(cur_file, 4, &tlen);
- char title[81];
- read_from_file(cur_file, tlen + 1, title);
-
- _set_color(UI_COLOR);
- _print_at(0, 0, SP80);
- _print_at(0, 0, title);
-
- if (link_table_start) {
- for (struct link *l = link_table_start; l != link_table_end; ++l)
- free_block(l->lto);
- free_block(link_table_start);
- }
-
- uint32_t linktc;
- read_from_file(cur_file, 4, &linktc);
- if (linktc) {
- link_table_start = get_block(sizeof(struct link) * linktc);
- link_table_end = link_table_start + linktc;
- read_from_file(cur_file, 4, &linktc);//dummy
-
- for (struct link *l = link_table_start; l != link_table_end; ++l) {
- read_from_file(cur_file, 4, &l->line);
- read_from_file(cur_file, 1, &l->col);
- read_from_file(cur_file, 1, &l->len);
- uint32_t lto_l;
- read_from_file(cur_file, 4, &lto_l);
- l->lto = get_block(lto_l + 1);
- read_from_file(cur_file, lto_l + 1, l->lto);
- }
- }
- else {
- link_table_start = 0;
- read_from_file(cur_file, 4, &linktc);//dummy
- }
-
- cur_link = 0;
-
- if (line_offsets)
- free_block(line_offsets);
-
- read_from_file(cur_file, 4, &n_lines);
- line_offsets = get_block(n_lines * 4);
- read_from_file(cur_file, n_lines * 4, line_offsets);
-
- char b[11];
- itosz(n_lines, b);
-
- _set_color(UI_COLOR);
- _print_at(24, 69, SP10);
- _print_at(24, 69, b);
-
- scroll_to(0);
-}
-
-struct stack_entry {
- struct stack_entry *down;
- char *name;
- uint32_t line;
-};
-
-struct stack_entry *stack_top = 0;
-
-void push() {
- struct stack_entry *new_entry = get_block(sizeof(struct stack_entry));
- new_entry->down = stack_top;
- new_entry->name = strdup(name_backup);
- new_entry->line = line_on;
- stack_top = new_entry;
-}
-
-void pop() {
- if (stack_top) {
- load_file(stack_top->name);
- scroll_to(stack_top->line);
- free_block(stack_top->name);
- free_block(stack_top);
- stack_top = stack_top->down;
- }
-}
-
-void main() {
- _set_color(UI_COLOR);
- _print_at(24, 79, " ");
-
- load_file("index");
-
- while (true) {
- switch (_get_key()) {
- case 0:
- default:
- _yield_task();
- break;
- case _KEY_UP:
- if (n_lines <= 23)
- break;
- if (line_on)
- scroll_to(line_on - 1);
- break;
- case _KEY_DOWN:
- if (n_lines <= 23)
- break;
- if (line_on < n_lines - 23)
- scroll_to(line_on + 1);
- break;
- case _KEY_PUP:
- if (n_lines <= 23)
- break;
- scroll_to(line_on <= 22 ? 0 : line_on - 22);
- break;
- case _KEY_PDOWN:
- if (n_lines <= 23)
- break;
- scroll_to(line_on + 22);
- break;
- case _KEY_LEFT:
- if (cur_link == link_table_start)
- break;
- if (cur_link) {
- --cur_link;
- scroll_link();
- }
- else if (link_table_start) {
- struct link *l = link_table_end;
- while (l != link_table_start) {
- --l;
- if (l->line <= line_on + 22)
- break;
- }
- cur_link = l;
- scroll_link();
- }
- break;
- case _KEY_RIGHT:
- if (cur_link == link_table_end - 1)
- break;
- if (cur_link) {
- ++cur_link;
- scroll_link();
- }
- else if (link_table_start) {
- struct link *l = link_table_start;
- while (l != link_table_end) {
- if (l->line >= line_on)
- break;
- ++l;
- }
- cur_link = l;
- scroll_link();
- }
- break;
- case ' ':
- case '\n':
- case _KEY_NENTER:
- if (cur_link) {
- push();
- load_file(cur_link->lto);
- }
- break;
- case _KEY_ESC:
- if (stack_top)
- pop();
- break;
- case 'q':
- return;
- }
- }
-} \ No newline at end of file
diff --git a/src/user/meminfo/meminfo.c b/src/user/meminfo/meminfo.c
index dd1d371..124a136 100644
--- a/src/user/meminfo/meminfo.c
+++ b/src/user/meminfo/meminfo.c
@@ -1,19 +1,30 @@
-#include <pland/syscall.h>
-#include <knob/user.h>
-#include <knob/format.h>
-
-void main() {
- char nbuf[11];
+#include <popups/info.h>
- tell_user_sz("Kernel dynamic memory remaining: ");
-
- itosz(_kernel_dynamic_area_left() * 4, nbuf);
- tell_user_sz(nbuf);
- tell_user_sz("k\n");
+#include <pland/syscall.h>
- tell_user_sz("Userspace memory remaining: ");
+static const struct key_packet meminfo_quits[] = {
+ { .key_id = KEY_ESCAPE, .modifiers = NO_MODS },
+ { .key_id = KEY_F5, .modifiers = NO_MODS },
+ { .key_id = 0 }
+};
- itosz(_total_userspace_left() * 4, nbuf);
- tell_user_sz(nbuf);
- tell_user_sz("k\n");
+void main() {
+ struct popup p;
+redo:
+ info_popupf(&p,
+ "kernel memory free: %uk\n"
+ "userspace memory free: %uk / %uk\n"
+ "Escape to quit, F5 to refresh.",
+ 0x10, 0x08,
+ _kernel_dynamic_area_left() * 4,
+ _total_userspace_left() * 4,
+ _total_userspace_size() * 4
+ );
+ //hacky, i should really make info_popup take an arg
+ p.quit_binds = meminfo_quits;
+ make_modal(&p);
+ if (p.quit_as.key_id == KEY_F5)
+ //i should make popups have changable text
+ //(make a new pixbuf but reuse the window)
+ goto redo;
} \ No newline at end of file
diff --git a/src/user/popups/info.c b/src/user/popups/info.c
new file mode 100644
index 0000000..81a09e9
--- /dev/null
+++ b/src/user/popups/info.c
@@ -0,0 +1,99 @@
+#include <popups/popup.h>
+
+#include <libfont/fonts.h>
+
+#include <knob/format.h>
+#include <knob/heap.h>
+
+#include <stdint.h>
+#include <stdarg.h>
+
+#define BORDER_SIZE 2
+//includes border
+#define PADDING 8
+#define FONT "berry"
+
+#define BORDER_COLOR 0x10
+#define BG_COLOR 0x07
+#define FG_COlOR 0x10
+
+static const struct font_info *info_font = 0;
+
+static const struct key_packet info_quits[] = {
+ { .key_id = KEY_ESCAPE, .modifiers = NO_MODS },
+ { .key_id = 0 }
+};
+
+void info_popup(struct popup *into, const char *msg, uint8_t fg, uint8_t bg) {
+ if (!info_font)
+ info_font = get_font(FONT);
+
+ uint32_t w = 0, h = 1, lw = 0;
+ for (const char *i = msg; *i; ++i)
+ if (*i == '\n') {
+ ++h;
+ if (lw > w)
+ w = lw;
+ lw = 0;
+ }
+ else
+ ++lw;
+ if (lw > w)
+ w = lw;
+
+ into->has_quit = false;
+ into->quit_binds = (struct key_packet *)info_quits;
+ into->free_quit_binds = false;
+
+ const uint32_t pitch = info_font->space_width * w + 2 * PADDING;
+ const uint32_t height = info_font->space_height * h + 2 * PADDING;
+
+ uint8_t *const pixbuf = get_block(pitch * height);
+
+ for (uint32_t i = 0; i < pitch * BORDER_SIZE; ++i)
+ pixbuf[i] = BORDER_COLOR;
+ for (uint32_t y = BORDER_SIZE; y < height - BORDER_SIZE; ++y) {
+ for (uint32_t x = 0; x < BORDER_SIZE; ++x)
+ pixbuf[y * pitch + x] = BORDER_COLOR;
+ for (uint32_t x = pitch - BORDER_SIZE; x < pitch; ++x)
+ pixbuf[y * pitch + x] = BORDER_COLOR;
+ }
+ for (uint32_t i = 0; i < pitch * BORDER_SIZE; ++i)
+ pixbuf[(height - BORDER_SIZE) * pitch + i] = BORDER_COLOR;
+
+ for (uint32_t y = BORDER_SIZE; y < height - BORDER_SIZE; ++y)
+ for (uint32_t x = BORDER_SIZE; x < pitch - BORDER_SIZE; ++x)
+ pixbuf[y * pitch + x] = BG_COLOR;
+
+ uint32_t my = 0;
+ uint32_t mx = 0;
+ --msg;
+ while (*++msg) {
+ if (*msg == '\n') {
+ ++my;
+ mx = 0;
+ }
+ else {
+ //syslogf("calling put_char(0x%x, '%c', pixbuf + %u, %u, 0x%2x, 0x%2x)", info_font, *msg,
+ // (my * info_font->space_height + PADDING) * pitch + mx * info_font->space_width + PADDING,
+ // pitch, BG_COLOR, FG_COlOR);
+ put_char(info_font, *msg, pixbuf + (my * info_font->space_height + PADDING) * pitch + mx++ * info_font->space_width + PADDING, pitch, BG_COLOR, FG_COlOR);
+ }
+ }
+
+ into->pixbuf = pixbuf;
+ into->handle = _new_window(pitch, height, pixbuf);
+}
+
+void info_popupf_v(struct popup *into, const char *text, uint8_t fg, uint8_t bg, va_list args) {
+ char *const msg = format_v(text, args);
+ info_popup(into, msg, fg, bg);
+ free_block(msg);
+}
+
+void info_popupf(struct popup *into, const char *text, uint8_t fg, uint8_t bg, ...) {
+ va_list args;
+ va_start(args, bg);
+ info_popupf_v(into, text, fg, bg, args);
+ va_end(args);
+} \ No newline at end of file
diff --git a/src/user/popups/popup.c b/src/user/popups/popup.c
new file mode 100644
index 0000000..d214f81
--- /dev/null
+++ b/src/user/popups/popup.c
@@ -0,0 +1,45 @@
+#include <popups/popup.h>
+
+#include <knob/format.h>
+#include <knob/heap.h>
+
+#include <pland/syscall.h>
+
+void handle_actions(struct popup *p) {
+ if (p->has_quit)
+ return;
+ struct window_action a;
+ while (1) {
+ _get_win_action(p->handle, &a);
+ if (a.action_type == NOT_READY)
+ return;
+ if ((a.action_type == KEY_DOWN)) {
+ //syslogf("got key 0x%2x, 0x%3x", a.as_key.key_id, a.as_key.modifiers);
+ for (const struct key_packet *kp = p->quit_binds; kp->key_id; ++kp) {
+ //syslogf("checking against 0x%2x, 0x%3x", kp->key_id, kp->modifiers);
+ if ((a.as_key.key_id == kp->key_id) && (a.as_key.modifiers == kp->modifiers)) {
+ p->has_quit = true;
+ p->quit_as = a.as_key;
+ return;
+ }
+ }
+ }
+ }
+}
+
+void delete_popup(struct popup *p) {
+ _delete_window(p->handle);
+ free_block(p->pixbuf);
+ if (p->free_quit_binds)
+ free_block(p->quit_binds);
+}
+
+void make_modal(struct popup *p) {
+ handle_actions(p);
+ while (!p->has_quit) {
+ _wait_for_action();
+ _yield_task();
+ handle_actions(p);
+ }
+ delete_popup(p);
+} \ No newline at end of file
diff --git a/src/user/runtimes/c/elf.ld b/src/user/runtimes/c/elf.ld
index f321be2..3e9a034 100644
--- a/src/user/runtimes/c/elf.ld
+++ b/src/user/runtimes/c/elf.ld
@@ -11,6 +11,7 @@ SECTIONS {
.__pcrt_before_main : {
__pcrt_before_main_start = .;
*(.__pcrt_before_main)
+ *(.init_array)
__pcrt_before_main_end = .;
}
diff --git a/src/user/runtimes/c/entry.asm b/src/user/runtimes/c/pcrt.asm
index bba8060..85c898c 100644
--- a/src/user/runtimes/c/entry.asm
+++ b/src/user/runtimes/c/pcrt.asm
@@ -2,6 +2,8 @@ bits 32
global __pcrt_entry
global __pcrt_quit
+global calling_task
+global stdio_task
extern main
extern __pcrt_before_main_start
@@ -11,7 +13,8 @@ extern __pcrt_before_quit_end
section .text
__pcrt_entry:
- mov esp, stack
+ mov dword [calling_task], esi
+ mov dword [stdio_task], edi
push edx
mov ebx, __pcrt_before_main_start
@@ -37,6 +40,6 @@ __pcrt_quit:
.end_task:
int 0x38
-section .stack nobits alloc noexec write align=16
-resb 4096
-stack: \ No newline at end of file
+section .bss
+calling_task resd 1
+stdio_task resd 1 \ No newline at end of file
diff --git a/src/user/terminal/readline.c b/src/user/terminal/readline.c
new file mode 100644
index 0000000..37ef54b
--- /dev/null
+++ b/src/user/terminal/readline.c
@@ -0,0 +1,104 @@
+#include <terminal/terminal.h>
+
+#include <knob/format.h>
+#include <knob/heap.h>
+#include <knob/key.h>
+
+#include <pland/syscall.h>
+
+#include <stdint.h>
+
+//returns length of string without null terminator
+//max_length doesn't include null terminator
+uint32_t read_line(char *sz, uint32_t max_length, const char *prompt) {
+ uint32_t i = 0;
+ uint32_t l = 0;
+
+ term_add_sz_no_ww(prompt);
+ paint_term();
+
+ const _window_handle_t handle = active_term->window;
+ struct window_action action;
+ while (1) {
+ _get_win_action(handle, &action);
+ switch (action.action_type) {
+ case NOT_READY:
+ _wait_for_action();
+ _yield_task();
+ continue;
+ case KEY_DOWN:
+ //;char *const debug_msg = format("got key 0x%2x, 0x%3x", action.as_key.key_id, action.as_key.modifiers);
+ // _system_log(debug_msg);
+ // free_block(debug_msg);
+ switch (action.as_key.key_id) {
+ case KEY_DELETE:
+ if (i != l) {
+ cursor_right();
+ ++i;
+ }
+ case KEY_BSPACE:
+ if (!i)
+ continue;
+ --l;
+ --i;
+ for (uint8_t j = i; j < l; ++j)
+ sz[j] = sz[j + 1];
+ sz[l] = '\0';
+ cursor_left();
+ uint32_t cursor_backup_x = active_term->cursor_x;
+ uint32_t cursor_backup_y = active_term->cursor_y;
+ term_add_sz_no_ww(sz + i);
+ term_add_char(' ');
+ move_cursor(cursor_backup_y, cursor_backup_x);
+ paint_term();
+ continue;
+ case KEY_ENTER:
+ term_newline();
+ paint_term();
+ sz[l] = '\0';
+ return l;
+ case KEY_HOME:
+ case KEY_UP_ARROW:
+ for (; i; --i)
+ cursor_left();
+ paint_term();
+ continue;
+ case KEY_END:
+ case KEY_DOWN_ARROW:
+ for (; i != l; ++i)
+ cursor_right();
+ paint_term();
+ continue;
+ case KEY_LEFT_ARROW:
+ if (i) {
+ cursor_left();
+ paint_term();
+ --i;
+ }
+ continue;
+ case KEY_RIGHT_ARROW:
+ if (i != l) {
+ cursor_right();
+ paint_term();
+ ++i;
+ }
+ continue;
+ default:
+ if (i == max_length)
+ continue;
+ char ch = key_to_char(action.as_key);
+ if (ch) {
+ term_add_char(ch);
+ paint_term();
+ sz[i] = ch;
+ if (i == l)
+ ++l;
+ ++i;
+ }
+ continue;
+ }
+ default:
+ continue;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/user/terminal/terminal.c b/src/user/terminal/terminal.c
new file mode 100644
index 0000000..7961fd5
--- /dev/null
+++ b/src/user/terminal/terminal.c
@@ -0,0 +1,284 @@
+#include <terminal/terminal.h>
+
+#include <libfont/fonts.h>
+
+#include <knob/format.h>
+#include <knob/heap.h>
+
+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);
+} \ No newline at end of file