diff options
Diffstat (limited to 'src/user')
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, ¤t)) + 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, <o_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 |