#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_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) { term_add_sz("Line too long.\n"); 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); line[0] = '\0'; return; } if (ti + (var_end - var_start) >= line + LINE_SIZE) { term_add_sz("Line too long.\n"); 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'); } else if (blockequ(line, "vars", 5)) dump_vars(); else if (blockequ(line, "quit", 5)) { del_term(active_term); __pcrt_quit(); } else if (blockequ(line, "clear", 6)) clear_term(); 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" " 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) { 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, stdio_task)) { term_add_sz("Could not run command.\n"); return; } else { ensure_color(); if (active_term->cursor_x) term_newline(); } } else ensure_color(); }