#include #include #include #include #include "cmds.h" #include "term.h" #include "vars.h" #define LINE_SIZE 4096 static char line[LINE_SIZE]; static inline uint8_t hex_digit_to_int(char ch) { return ch - (ch <= '9' ? '0' : 'a' - 10); } static inline uint8_t hex_byte_to_int(const char *ch) { return (hex_digit_to_int(ch[0]) << 4) | hex_digit_to_int(ch[1]); } static inline _pixel_t hex_to_pixel(const char *ch) { return (_pixel_t){ .r = hex_byte_to_int(ch), .g = hex_byte_to_int(ch + 2), .b = hex_byte_to_int(ch + 4) }; } void ensure_color() { const struct no_null_sn *color; get_color: color = get_var((struct no_null_sn){.data = "_color", .length = 6}); if (color && (color->length == 12)) //rgb, fgbg term_set_color(hex_to_pixel(color->data), hex_to_pixel(color->data + 6)); else { new_color(); goto get_color; } } static void line_replace(const char *from) { const char *fi = from; char *ti = line; while (*fi) { if (ti == line + LINE_SIZE) { term_add_sz("Line too long.\n"); term_paint(); line[0] = '\0'; return; } if (*fi != '$') { *ti = *fi; ++ti; ++fi; continue; } const char *var_start = ++fi; const char *var_end = var_start; while (*var_end != '$') if (!*var_end++) { if (var_end - fi > 10) term_addf("Unterminated variable at\"%10s...\".\n", fi); else term_addf("Unterminated variable at \"%s\".\n", fi); term_paint(); line[0] = '\0'; return; } if (ti + (var_end - var_start) >= line + LINE_SIZE) { term_add_sz("Line too long.\n"); term_paint(); line[0] = '\0'; return; } struct no_null_sn vname = { .data = var_start, .length = var_end - var_start }; const struct no_null_sn *vval = get_var(vname); if (!vval) vval = &vname; blockcpy(ti, vval->data, vval->length); ti += vval->length; fi = var_end + 1; } *ti = '\0'; } void run_line(const char *original_line) { line_replace(original_line); if (!*line) return; const char *space; for (space = line; *space && (*space != ' '); ++space) ; if (blockequ(line, "source ", 7)) source(space + 1); else if (blockequ(line, "set ", 4)) { set(space + 1); ensure_color(); } else if (blockequ(line, "echo ", 5)) { term_add_sz(space + 1); term_add_char('\n'); term_paint(); } else if (blockequ(line, "vars", 5)) dump_vars(); else if (blockequ(line, "quit", 5)) __pcrt_quit(); else if (blockequ(line, "clear", 6)) { term_clear(); term_paint(); } else if (blockequ(line, "color", 6)) { new_color(); ensure_color(); term_paint(); } else if (blockequ(line, "help", 5)) { 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" " set VAR VALUE\t" "set $VAR$ to VALUE\n" " color\t\t\t" "new color scheme\n" " clear\t\t\t" "clear the screen\n" " vars\t\t\t" "dump variables\n" " echo STRING\t" "print STRING\n" " quit\t\t\t" "exit highway\n" " help\t\t\t" "show this\n"); term_paint(); } 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) { term_add_sz("Could not run command.\n"); term_paint(); 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, stdio_task)) { term_add_sz("Could not run command.\n"); term_paint(); return; } else { _yield_task(); term_add_char('\n'); ensure_color(); } } else { _yield_task(); ensure_color(); } }