From 7b466345af0d3a7dc5622617ce443a90c64e34a4 Mon Sep 17 00:00:00 2001 From: Alex AUVOLAT Date: Sat, 19 May 2012 09:23:48 +0200 Subject: Added ANSI support, minimal readline-like library. --- doc/syscalls.txt | 2 + doc/terminal.txt | 14 +++ src/include/tce/syscalls.h | 1 + src/kernel/config.h | 4 +- src/kernel/core/kmain.cpp | 5 + src/kernel/dev/display.h | 2 + src/kernel/dev/vgatxt.cpp | 22 ++-- src/kernel/task/syscall.cpp | 4 +- src/kernel/task/task.cpp | 15 ++- src/kernel/task/task.h | 5 +- src/kernel/ui/vt.cpp | 211 ++++++++++++++++++++++++++++++++----- src/kernel/ui/vt.h | 5 +- src/kernel/vfs/node.cpp | 1 + src/user/init/main.c | 8 +- src/user/lib/Makefile | 2 +- src/user/lib/include/readline.h | 16 +++ src/user/lib/include/stdio.h | 4 +- src/user/lib/include/tce/syscall.h | 4 +- src/user/lib/std/readline.c | 139 ++++++++++++++++++++++++ src/user/lib/std/stdio.c | 124 ++++++++++------------ src/user/lib/tce/syscall.c | 8 +- src/user/test/main.c | 56 +--------- src/user/yosh/main.c | 200 +++++++++++++++++++++++------------ 23 files changed, 606 insertions(+), 246 deletions(-) create mode 100644 doc/terminal.txt create mode 100644 src/user/lib/include/readline.h create mode 100644 src/user/lib/std/readline.c diff --git a/doc/syscalls.txt b/doc/syscalls.txt index 833041a..6b54fb8 100644 --- a/doc/syscalls.txt +++ b/doc/syscalls.txt @@ -23,7 +23,9 @@ id=eax Name Parameters Description 14 run ebx: char* filename spans a new process and run the executable filename ecx: char** args + edx: file zero_fd 15 waitpid ebx: int pid wait for a process to exit, returns retval. + ecx: block 20 open ebx: char* filename open a file, returns a descriptor ecx: mode diff --git a/doc/terminal.txt b/doc/terminal.txt new file mode 100644 index 0000000..ebdc898 --- /dev/null +++ b/doc/terminal.txt @@ -0,0 +1,14 @@ +The virtual terminals support some ANSI escape sequences. + +By default, the keyboard input is NOT echoed to the screen. +Keyboard echoing can be enabled by sending 0x1b[e and disabled by sending 0x1b[h. + +When keyboard echo is enabled: +- what is written to keyboard is echoed ONLY IF A PROCESS IS CURRENTLY READING THE INPUT +- escape sequences are ignored (arrows, commands, etc.) +- backspaces are taken into account, so that they don't need post-processing +- read returns when a newline is read from keyboard +When keyboard echo is disabled: +- what is written to keyboard is NEVER ECHOED +- read returns after each keystroke (can also be an escape sequence) +Default is keyboard echo disabled. diff --git a/src/include/tce/syscalls.h b/src/include/tce/syscalls.h index 26021a0..76a5ba2 100644 --- a/src/include/tce/syscalls.h +++ b/src/include/tce/syscalls.h @@ -37,5 +37,6 @@ #define E_TOO_SHORT -4 // not enough space for data to be copied to #define E_INVALID_RANGE -5 #define E_INVALID -6 // anything went wrong - invalid parameter, usually +#define E_NOT_FINISHED -7 // nonblocking waitpid on process that hasn't finished #endif diff --git a/src/kernel/config.h b/src/kernel/config.h index 21035ba..5a6c629 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -2,7 +2,7 @@ #define DEF_CONFIG_H #define K_OS_NAME "T/CE" -#define K_OS_VER "0.1.1" -#define K_OS_CODENAME "executify" +#define K_OS_VER "0.1.2" +#define K_OS_CODENAME "Make Your Terminal ANSI" #endif diff --git a/src/kernel/core/kmain.cpp b/src/kernel/core/kmain.cpp index 0aa047a..05d7966 100644 --- a/src/kernel/core/kmain.cpp +++ b/src/kernel/core/kmain.cpp @@ -61,6 +61,10 @@ extern "C" void kmain(multiboot_info_t* mbd, int32_t magic) { ke_vt->outputTo(text_display); home_vt = new vt(dot_ui, 80, 25); dot_ui->add_child("home", home_vt); + dot_ui->add_child("vt1", new vt(dot_ui, 80, 25)); + dot_ui->add_child("vt2", new vt(dot_ui, 80, 25)); + dot_ui->add_child("vt3", new vt(dot_ui, 80, 25)); + dot_ui->add_child("vt4", new vt(dot_ui, 80, 25)); // Say hello ke_vt->fgcolor = TC_LIGHTGRAY; @@ -105,6 +109,7 @@ extern "C" void kmain(multiboot_info_t* mbd, int32_t magic) { if (pr == 0) { *ke_vt << "Error loading\n"; } else { + pr->fd.set(0, ke_vt); *ke_vt << "OK, pid=" << (int)pr->pid << "\n"; } } else if (initrd_check((uint8_t*)mods[i].mod_start) == 0) { diff --git a/src/kernel/dev/display.h b/src/kernel/dev/display.h index 6960b7d..ec67e7e 100644 --- a/src/kernel/dev/display.h +++ b/src/kernel/dev/display.h @@ -11,6 +11,8 @@ #define TC_PURPLE 5 #define TC_BROWN 6 #define TC_LIGHTGRAY 7 +#define TC_MAKE_LIGHT 8 +#define TC_MAKE_DARK (~8) #define TC_WHITE 15 class vt; diff --git a/src/kernel/dev/vgatxt.cpp b/src/kernel/dev/vgatxt.cpp index 75071fb..eb57eb9 100644 --- a/src/kernel/dev/vgatxt.cpp +++ b/src/kernel/dev/vgatxt.cpp @@ -35,16 +35,20 @@ void vgatxt::text_put(int l, int c, int ch, uint8_t fgcolor, uint8_t bgcolor) { void vgatxt::text_scroll(int n, uint8_t fgcolor, uint8_t bgcolor) { //TODO: optimize - for (int i = 0; i < n; i++) { + if (n > 0) { + for (int i = 0; i < n; i++) { + + uint16_t blank = (((bgcolor << 4) | fgcolor) << 8) | 0x20; + int j; + for (j = 0; j < 80*24; j++) { + video_memory[j] = video_memory[j+80]; + } + for (j = 80*24; j < 80*25; j++) { + video_memory[j] = blank; + } - uint16_t blank = (((bgcolor << 4) | fgcolor) << 8) | 0x20; - int j; - for (j = 0; j < 80*24; j++) { - video_memory[j] = video_memory[j+80]; } - for (j = 80*24; j < 80*25; j++) { - video_memory[j] = blank; - } - + } else if (n < 0) { + // TODO } } diff --git a/src/kernel/task/syscall.cpp b/src/kernel/task/syscall.cpp index 4eddb61..9e7c089 100644 --- a/src/kernel/task/syscall.cpp +++ b/src/kernel/task/syscall.cpp @@ -28,7 +28,7 @@ CALL1V(idt_waitIrq, irq_wait_sc); CALL0(proc_priv, proc_priv_sc); CALL1(process_sbrk, proc_sbrk_sc); CALL1V(process_brk, proc_brk_sc); -CALL1(process_waitpid, waitpid_sc); +CALL2(process_waitpid, waitpid_sc); CALL1V(close, close_sc); @@ -43,7 +43,7 @@ static void thread_new_sc(registers* r) { } static void run_sc(registers *r) { - r->eax = process_run((char*)r->ebx, (char**)r->ecx); + r->eax = process_run((char*)r->ebx, (char**)r->ecx, (int)r->edx); } static void open_sc(registers *r) { diff --git a/src/kernel/task/task.cpp b/src/kernel/task/task.cpp index 98204d6..7eb2b36 100644 --- a/src/kernel/task/task.cpp +++ b/src/kernel/task/task.cpp @@ -295,8 +295,6 @@ process::process(process* _parent, uint32_t _uid, uint32_t _privilege) : fd(12, data = 0; dataseg = 0; - fd.add((node*)-1); // descriptor #0 must not be used - stack = 0; if (privilege >= PL_USER) { //We are running in user mode size_t stacksBottom = K_HIGHHALF_ADDR - 0x01000000; @@ -431,7 +429,7 @@ void process_brk(size_t ptr) { current_process->sbrk(ptr - current_process->data); } -int process_run(char* file, char** args) { +int process_run(char* file, char** args, FILE zero_fd) { node* bin = vfs_find(root, file); if (bin == 0) return E_NOT_FOUND; if ((bin->type & FT_FILE) == 0) return E_INVALID; @@ -467,14 +465,21 @@ int process_run(char* file, char** args) { kfree(v); for (int i = 0; arg_data[i] != 0; i++) kfree(arg_data[i]); kfree(arg_data); - return (p == 0 ? E_INVALID : p->pid); + if (p == 0) { + return E_INVALID; + } else { + p->fd.set(0, current_process->fd.at((zero_fd < 0 ? 0 : zero_fd))); + return p->pid; + } } -int process_waitpid(int pid) { +int process_waitpid(int pid, int block) { if (pid <= 0) return E_INVALID_RANGE; process *p = proc_by_pid->at(pid); if (p != 0) { + if (block == 0) return E_NOT_FINISHED; + current_thread->queue_next = p->threads_waiting; p->threads_waiting = current_thread; thread_goInactive(); diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h index 2ebb66e..8a0e94a 100644 --- a/src/kernel/task/task.h +++ b/src/kernel/task/task.h @@ -6,6 +6,7 @@ #include "idt.h" #include +#include #define TS_RUNNING 0 #define TS_WAKEWAIT 2 //Waiting to be waked up by something precise (thread currently blocked) @@ -82,7 +83,7 @@ void thread_exit(); void process_exit(size_t retval); size_t process_sbrk(size_t size); void process_brk(size_t ptr); -int process_run(char* file, char** args); -int process_waitpid(int pid); +int process_run(char* file, char** args, FILE zero_fd); +int process_waitpid(int pid, int block); #endif diff --git a/src/kernel/ui/vt.cpp b/src/kernel/ui/vt.cpp index 34dfbe9..9b0bdf0 100644 --- a/src/kernel/ui/vt.cpp +++ b/src/kernel/ui/vt.cpp @@ -3,12 +3,22 @@ vt *ke_vt = 0, *home_vt = 0; +static char *kb_cmd_esc[] = { + /* 00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 20 */ 0, 0, 0, 0, 0, 0, 0, 0, "\x1b[B", 0, + /* 30 */ "\x1b[D", 0, "\x1b[C", 0, "\x1b[A", 0, 0, 0, 0, 0, + /* 40 */ 0, 0, 0, 0, 0, 0, "\x1b[B", "\x1b[A", "\x1b[D", "\x1b[C", + /* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 60 */ 0, 0, 0, 0 }; + vt::vt(node* parent, int ww, int hh) : node(parent, FT_TERMINAL) { w = ww; h = hh; fgcolor = TC_LIGHTGRAY; bgcolor = TC_BLACK; output = 0; cursor_visible = true; + keyboard_echo = false; csr_l = csr_c = 0; kbd_buffer_filled = 0; @@ -34,6 +44,25 @@ void vt::put_at(int l, int c, int ch) { } } +void vt::scroll(int n) { + if (output != 0 && output->connected_vt == this) { + output->text_scroll(n, fgcolor, bgcolor); + } + if (n > 0) { + for (int j = 0; j < w * (h-n); j++) { + text[j] = text[j + w]; + } + for (int j = w * (h-n); j < w * h; j++) { + text[j].fgcolor = fgcolor; + text[j].bgcolor = bgcolor; + text[j].ch = ' '; + } + } else if (n < 0) { + //TODO + } + csr_l -= n; +} + void vt::put(int c) { if (text == 0) return; @@ -60,18 +89,7 @@ void vt::put(int c) { csr_l++; } if (csr_l == h) { - if (output != 0 && output->connected_vt == this) { - output->text_scroll(1, fgcolor, bgcolor); - } - for (int j = 0; j < w * (h-1); j++) { - text[j] = text[j + w]; - } - for (int j = w * (h-1); j < w * h; j++) { - text[j].fgcolor = fgcolor; - text[j].bgcolor = bgcolor; - text[j].ch = ' '; - } - csr_l--; + scroll(1); } if (output != 0 && output->connected_vt == this) output->text_setcsr(csr_l, csr_c, cursor_visible); } @@ -179,6 +197,11 @@ void vt::keyboardInput(keypress kp, keyboard* from) { } else if (kp.command == KB_CMD_ALT && kp.character >= 64 && kp.character <= 126 && kp.pressed) { b[n++] = 27; b[n++] = kp.character; + } else if (kb_cmd_esc[kp.command & 0x3F] != 0 && kp.pressed) { + int i; + for (i = 0; kb_cmd_esc[kp.command & 0x3F][i] != 0; i++) { + b[n++] = kb_cmd_esc[kp.command & 0x3F][i]; + } } if (n == 0) return; if (kbd_buffer_filled + n > KBD_BUFFER_SIZE) goto wake_up; @@ -200,7 +223,136 @@ int vt::write(size_t offset, size_t len, char* buffer) { // ignore offset // TODO: ANSI escape sequences // todo some day : unicode - for (unsigned i = 0; i < len; i++) put(buffer[i]); + for (unsigned i = 0; i < len; i++) { + if (buffer[i] == 27) { + i++; + if (buffer[i++] == '[') { + int n = -1, m = -1; + while (buffer[i] >= '0' && buffer[i] <= '9') { + if (n == -1) n = 0; + n *= 10; + n += buffer[i] - '0'; + i++; + } + if (buffer[i] == ';') { + i++; + while (buffer[i] >= '0' && buffer[i] <= '9') { + if (m == -1) m = 0; + m *= 10; + m += buffer[i] - '0'; + i++; + } + } + if (buffer[i] == 'A') { // move cursor up + if (n == -1) n = 1; + csr_l -= n; + } else if (buffer[i] == 'B') { // move cursor down + if (n == -1) n = 1; + csr_l += n; + } else if (buffer[i] == 'C') { // move cursor forward + if (n == -1) n = 1; + csr_c += n; + } else if (buffer[i] == 'D') { // move cursor back + if (n == -1) n = 1; + csr_c -= n; + } else if (buffer[i] == 'E') { // move cursor n lines down, to beginning of line + if (n == -1) n = 1; + csr_l += n; + csr_c = 0; + } else if (buffer[i] == 'F') { // move cursor to beginning of line, n lines up + if (n == -1) n = 1; + csr_l -= n; + csr_c = 0; + } else if (buffer[i] == 'H' || buffer[i] == 'f') { // set cursor position + if (n == -1) n = 1; + if (m == -1) m = 1; + csr_l = n - 1; + csr_c = m - 1; + } else if (buffer[i] == 'J' || buffer[i] == 'K') { // erase data / erase line + if (n == -1) n = 0; + int start = 0, end = 0; + if (n == 0) { + start = csr_c; end = w; + } else if (n == 1) { + start = 0; end = csr_c; + } else if (n == 2) { + start = 0; end = w; + } + for (int p = start; p < end; p++) put_at(csr_l, p, ' '); + if (buffer[i] == 'J') { // erase data + if (n == 0) { + start = csr_l + 1; end = h; + } else if (n == 1) { + start = 0; end = csr_l; + } else if (n == 2) { + start = 0; end = h; + } + for (int l = start; l < end; l++) { + for (int c = 0; c < w; c++) put_at(l, c, ' '); + } + } + } else if (buffer[i] == 'S') { // scroll up + if (n == -1) n = 1; + scroll(n); + } else if (buffer[i] == 'T') { // scroll down + if (n == -1) n = 1; + scroll(-n); + } else if (buffer[i] == 'm') { // select graphic rendition + if (n == -1) n = 0; + if (n == 0) { + fgcolor = 7; + bgcolor = 0; + } else if (n == 1) { + fgcolor |= TC_MAKE_LIGHT; + } else if (n == 22) { + fgcolor &= TC_MAKE_DARK; + } else if (n >= 30 && n <= 37) { + fgcolor = (fgcolor & TC_MAKE_LIGHT) | (n - 30); + } else if (n >= 40 && n <= 47) { + bgcolor = (n - 40); + } else { + // others to do. + } + } else if (buffer[i] == 'n') { // device status report + kbd_buffer[kbd_buffer_filled++] = 27; + kbd_buffer[kbd_buffer_filled++] = '['; + if (csr_l >= 100) kbd_buffer[kbd_buffer_filled++] = ((csr_l / 100) % 10) + '0'; + if (csr_l >= 10) kbd_buffer[kbd_buffer_filled++] = ((csr_l / 10) % 10) + '0'; + kbd_buffer[kbd_buffer_filled++] = (csr_l % 10) + '0'; + kbd_buffer[kbd_buffer_filled++] = ';'; + if (csr_c >= 100) kbd_buffer[kbd_buffer_filled++] = ((csr_c / 100) % 10) + '0'; + if (csr_c >= 10) kbd_buffer[kbd_buffer_filled++] = ((csr_c / 10) % 10) + '0'; + kbd_buffer[kbd_buffer_filled++] = (csr_c % 10) + '0'; + kbd_buffer[kbd_buffer_filled++] = 'R'; + } else if (buffer[i] == 's') { // save cursor position + save_csr_l = csr_l; + save_csr_c = csr_c; + } else if (buffer[i] == 'p') { // restore cursor position + csr_l = save_csr_l; + csr_c = save_csr_c; + } else if (buffer[i] == 'e') { // CUSTOM : enable keyboard echo + keyboard_echo = true; + } else if (buffer[i] == 'h') { // CUSTOM : disable keyboard echo + keyboard_echo = false; + } else if (buffer[i] == '?') { + if (buffer[++i] == '2' && buffer[++i] == '5') { + if (buffer[++i] == 'l') cursor_visible = false; + else cursor_visible = true; + } + } else { + } + if (csr_l < 0) csr_l = 0; + if (csr_c < 0) csr_c = 0; + if (csr_l >= h) csr_l = h - 1; + if (csr_c >= w) csr_c = w - 1; + if (output != 0 && output->connected_vt == this) output->text_setcsr(csr_l, csr_c, cursor_visible); + } else { + // ignore it. + } + } else { + put(buffer[i]); + } + } return len; } @@ -212,19 +364,30 @@ int vt::read(size_t offset, size_t len, char* buffer) { bool end = false; if (kbd_buffer_filled > 0) { int r = 0; - for (; r < kbd_buffer_filled; r++) { - if (kbd_buffer[r] == '\b') { - if (c > 0) { - c--; - put('\b'); + if (keyboard_echo) { + for (; r < kbd_buffer_filled; r++) { + if (kbd_buffer[r] == '\b') { + if (c > 0) { + c--; + put('\b'); + } + } else if (kbd_buffer[r] == '\n') { + buffer[c++] = '\n'; + c++; + put('\n'); + end = true; + break; + } else if (kbd_buffer[r] >= ' ') { + buffer[c++] = kbd_buffer[r]; + put(buffer[c]); } - } else { - buffer[c] = kbd_buffer[r]; - put(buffer[c]); - if (buffer[c] == '\n' || buffer[c] == 27) end = true; - c++; + if (c == len) break; + } + } else { + for (; r < kbd_buffer_filled && c < len; r++) { + buffer[c++] = kbd_buffer[r]; } - if (c == len) break; + end = true; } memcpy(kbd_buffer + r, kbd_buffer, (kbd_buffer_filled - r)); kbd_buffer_filled -= r; diff --git a/src/kernel/ui/vt.h b/src/kernel/ui/vt.h index a80452b..a29716f 100644 --- a/src/kernel/ui/vt.h +++ b/src/kernel/ui/vt.h @@ -15,11 +15,11 @@ struct vt_char { class vt : public node { private: display *output; - int w, h, csr_l, csr_c; + int w, h, csr_l, csr_c, save_csr_l, save_csr_c; vt_char *text; void put_at(int l, int c, int ch); - bool cursor_visible; + bool cursor_visible, keyboard_echo; int kbd_buffer_filled; char kbd_buffer[KBD_BUFFER_SIZE]; @@ -35,6 +35,7 @@ class vt : public node { // internal use void put(int c); void clear(); + void scroll(int l); void writeStr(char* str) { write(0, strlen(str), str); } void writeHex(uint32_t v); void writeDec(int v); diff --git a/src/kernel/vfs/node.cpp b/src/kernel/vfs/node.cpp index c517aae..0b753af 100644 --- a/src/kernel/vfs/node.cpp +++ b/src/kernel/vfs/node.cpp @@ -54,6 +54,7 @@ node* vfs_find(node* root, char* fn) { } node* vfs_read_fd(FILE d) { + if (d < 0) return 0; return current_process->fd.at(d); } diff --git a/src/user/init/main.c b/src/user/init/main.c index 54dd4b6..7300efe 100644 --- a/src/user/init/main.c +++ b/src/user/init/main.c @@ -5,19 +5,19 @@ int main(char** args) { int i; - term = open("/.ui/klog", 0); - if (term <= 0) return -1; + FILE home_term = open("/.ui/home", 0); + if (home_term < 0) return -1; print("(init) Trivial/Computing Environment says hello. Press super to go home.\n"); for (i = 0; args[i] != 0; i++) { if (i == 0) continue; printf("(init) Spawning %s...\n", args[i]); - int pid = run(args[i], 0); + int pid = run(args[i], 0, home_term); if (pid < 0) { print("(init) Error. Sorry.\n"); } else { - waitpid(pid); + waitpid(pid, 1); } } print("(init) Goodbye.\n"); diff --git a/src/user/lib/Makefile b/src/user/lib/Makefile index 9111ff5..c2630c4 100644 --- a/src/user/lib/Makefile +++ b/src/user/lib/Makefile @@ -1,6 +1,6 @@ Out = _user.o Obj = tce/syscall.o std/_dlmalloc.o \ - std/stdio.o std/stdlib.o std/string.o std/sched.o \ + std/stdio.o std/stdlib.o std/string.o std/sched.o std/readline.o \ start.o include $(SrcPath)/common.make diff --git a/src/user/lib/include/readline.h b/src/user/lib/include/readline.h new file mode 100644 index 0000000..53193d7 --- /dev/null +++ b/src/user/lib/include/readline.h @@ -0,0 +1,16 @@ +#ifndef DEF_READLINE_H +#define DEF_READLINE_H + +#include + +char* freadln(FILE f); // minimal line-reading function. user must free the returned value. + +typedef struct _rdln_hist { + int max; + int n; + char **str; +} readline_history; +char* readline(FILE f, readline_history *h); + +#endif + diff --git a/src/user/lib/include/stdio.h b/src/user/lib/include/stdio.h index 6c3a974..099746e 100644 --- a/src/user/lib/include/stdio.h +++ b/src/user/lib/include/stdio.h @@ -2,6 +2,7 @@ #define DEF_STDIO_H #include +#include extern FILE term; @@ -14,8 +15,7 @@ void fprint_int(FILE f, int number); void fprint_hex(FILE f, unsigned number); void fprintf(FILE f, char *s, ...); -void vsfprintf(FILE f, char *s, va_list arg); +void vfprintf(FILE f, char *s, va_list arg); -char* freadln(FILE f); #endif diff --git a/src/user/lib/include/tce/syscall.h b/src/user/lib/include/tce/syscall.h index 1811422..c182f40 100644 --- a/src/user/lib/include/tce/syscall.h +++ b/src/user/lib/include/tce/syscall.h @@ -19,8 +19,8 @@ int proc_priv(); void* sbrk(size_t size); void brk(void* ptr); -int run(char* file, char** args); -int waitpid(int pid); +int run(char* file, char** args, FILE zero_fd); +int waitpid(int pid, int block); FILE open(char* filename, int mode); FILE open_relative(FILE root, char* filename, int mode); diff --git a/src/user/lib/std/readline.c b/src/user/lib/std/readline.c new file mode 100644 index 0000000..a3beefa --- /dev/null +++ b/src/user/lib/std/readline.c @@ -0,0 +1,139 @@ +#include +#include + +char* freadln(FILE f) { + fprint(f, "\x1b[e"); // enable keyboard echo + int i; + + char *p = (char*)malloc(256); + char *b = p; + + while (1) { + int l = read(f, 0, 255, b); + if (l < 0) { + free(b); + return 0; + } + + for (i = 0; i < l; i++) { + if (b[i] == '\n') { + b[i+1] = 0; + return p; + } else if (b[i] == 27) { // ignore escape sequences + b[i] = 0; + l = i; + } + } + + int d = b - p + l; + + char* newp = (char*)malloc(d + 256); + memcpy(newp, p, d); + free(p); + p = newp; + b = p + d; + } +} + + +// ** READLINE + +char *readline(FILE f, readline_history *h) { + int i; + fprint(f, "\x1b[h"); // disable keyboard echo + + if (h->str == 0) { + h->str = (char**)malloc(h->max * sizeof(char*)); + for (i = 0; i < h->max; i++) h->str[i] = 0; + h->n = 0; + } + + int lid; + if (h->n < h->max) { + lid = h->n++; + } else { + free(h->str[0]); + int i; + for (i = 0; i < h->max - 1; i++) { + h->str[i] = h->str[i+1]; + } + lid = h->max - 1; + h->str[lid] = 0; + } + + if (h->str[lid] == 0) h->str[lid] = (char*)malloc(256); + + char *str = h->str[lid]; + str[0] = 0; + char *cur = str; // position in string + int len = 0; // string length + + while (1) { + int finished = 0; + + int te = cur - str; + + char buf[16]; + int l = read(f, 0, 16, buf); + if (l < 0) return 0; + + if (buf[0] == 27) { + if (buf[1] == '[') { + if (buf[2] == 'A') { // up + if (lid > 0) { + lid--; + str = h->str[lid]; + len = strlen(str); + cur = str + len; + } + } else if (buf[2] == 'B') { // down + if (lid < h->n - 1) { + lid++; + str = h->str[lid]; + len = strlen(str); + cur = str + len; + } + } else if (buf[2] == 'C') { // forward (right) + if (cur < str + len) cur++; + } else if (buf[2] == 'D') { // back (left) + if (cur > str) cur--; + } + } else { + // ALT sequence - ignore + } + } else if (buf[0] == '\n') { + finished = 1; + cur = str + len; + } else if (buf[0] == '\b') { + if (cur > str) { + cur--; + len--; + char* c; + for (c = cur; *c != 0; c++) c[0] = c[1]; + } + } else if (buf[0] == '\t') { + // ignore tabs -- todo: tab completion???? haha + } else if (buf[0] >= ' ') { + if (l < 255) { + char* c; + for (c = cur + len; c >= cur; c--) c[1] = c[0]; + cur[0] = buf[0]; + cur++; + len++; + } + } + + // ASSUMPTION : everything will fit on one line... + if (te > 0) fprintf(f, "\x1b[%iD", te); + fprintf(f, "\x1b[K%s", str); + te = len - (cur - str); + if (te > 0) fprintf(f, "\x1b[%iD", te); + + + if (finished) { + fprintf(f, "\n"); + if (h->str[h->n-1][0] == 0) h->n--; + return str; + } + } +} diff --git a/src/user/lib/std/stdio.c b/src/user/lib/std/stdio.c index 1628a78..b1778d6 100644 --- a/src/user/lib/std/stdio.c +++ b/src/user/lib/std/stdio.c @@ -7,7 +7,7 @@ void print(char *s) { fprint(term, s); } void printf(char *format, ...) { va_list ap; va_start(ap, format); - vsfprintf(term, format, ap); + vfprintf(term, format, ap); va_end(ap); } char* readln() { return freadln(term); } @@ -15,25 +15,22 @@ char* readln() { return freadln(term); } void fprintf(FILE f, char* format, ...) { va_list ap; va_start(ap, format); - vsfprintf(f, format, ap); + vfprintf(f, format, ap); va_end(ap); } +// INTERNAL, FOR FORMATTING -void fprint(FILE f, char *s) { - write(f, 0, strlen(s), s); -} - -void fprint_int(FILE f, int number) { +static char* format_int(char* buf, int number) { if (number == 0) { - fprint(f, "0"); - return; + *(buf++) = '0'; + return buf; } - int negative = 0; if (number < 0) { - negative = 1; + *(buf++) = '-'; number = 0 - number; } + int order = 0, temp = number, i; char numbers[] = "0123456789"; while (temp > 0) { @@ -41,86 +38,81 @@ void fprint_int(FILE f, int number) { temp /= 10; } - char s[32], *r; - if (negative) { - s[0] = '-'; - r = s + 1; - } else { - r = s; - } - for (i = order; i > 0; i--) { - r[i - 1] = numbers[number % 10]; + buf[i - 1] = numbers[number % 10]; number /= 10; } - r[order] = 0; - fprint(f, s); + return buf + order; } -void fprint_hex(FILE f, unsigned v) { - char s[11] = {'0', 'x', 0}; +static char* format_hex(char *buf, unsigned v) { + *(buf++) = '0'; + *(buf++) = 'x'; int i; - char hexdigits[] = "0123456789ABCDEF"; - for (i = 0; i < 8; i++) { - s[i + 2] = (hexdigits[v >> 28]); + *(buf++) = hexdigits[v >> 28]; v = v << 4; } - s[11] = 0; + return buf; +} + + +// FUNCTIONS + +void fprint(FILE f, char *s) { + write(f, 0, strlen(s), s); +} + +void fprint_int(FILE f, int number) { + char s[32]; + char *v = format_int(s, number); + *v = 0; + fprint(f, s); +} + +void fprint_hex(FILE f, unsigned v) { + char s[11]; + char *e = format_hex(s, v); + *e = 0; fprint(f, s); } -void vsfprintf(FILE f, char *format, va_list ap) { - char* start = format; +void vfprintf(FILE f, char *format, va_list ap) { + char bb[256]; + int bufl = 256; + + char *buf = bb; + char *end = buf; while (*format) { if (*format == '%') { - if (start != format) write(f, 0, format - start, start); + // ASSUMPTION : (TODO) WE HAVE ENOUGH SPACE - NOT THE CASE!!! format++; if (*format == 'd' || *format == 'i') { - fprint_int(f, va_arg(ap, int)); + end = format_int(end, va_arg(ap, int)); } else if (*format == 'p') { - fprint_hex(f, va_arg(ap, uint32_t)); + end = format_hex(end, va_arg(ap, uint32_t)); } else if (*format == 's') { - fprint(f, va_arg(ap, char*)); + char *s = va_arg(ap, char*); + strcpy(end, s); + end += strlen(s); } format++; - start = format; } else { - format++; + *(end++) = *(format++); } - } - if (start != format) write(f, 0, format - start, start); -} - -char* freadln(FILE f) { - int i; - - char *p = (char*)malloc(256); - char *b = p; - - while (1) { - int l = read(f, 0, 255, b); - if (l < 0) { - free(b); - return 0; + if (end - buf > bufl - 2) { + bufl *= 2; + char *nbuf = (char*)malloc(bufl); + memcpy(nbuf, buf, end - buf); + end = nbuf + (end - buf); + if (buf != bb) free(buf); + buf = nbuf; } - - for (i = 0; i < l; i++) { - if (b[i] == '\n') { - b[i+1] = 0; - return p; - } - } - - int d = b - p + l; - - char* newp = (char*)malloc(d + 256); - memcpy(newp, p, d); - free(p); - p = newp; - b = p + d; } + *end = 0; + fprint(f, buf); + if (buf != bb) free(buf); } diff --git a/src/user/lib/tce/syscall.c b/src/user/lib/tce/syscall.c index bc8bfd8..4304840 100644 --- a/src/user/lib/tce/syscall.c +++ b/src/user/lib/tce/syscall.c @@ -75,12 +75,12 @@ void brk(void* ptr) { // ********** proc -int run(char* filename, char** args) { - return call(SC_RUN, (unsigned)filename, (unsigned)args, 0, 0, 0); +int run(char* filename, char** args, FILE zero_fd) { + return call(SC_RUN, (unsigned)filename, (unsigned)args, (unsigned)zero_fd, 0, 0); } -int waitpid(int p) { - return call(SC_WAITPID, p, 0, 0, 0, 0); +int waitpid(int p, int block) { + return call(SC_WAITPID, p, block, 0, 0, 0); } // ********** file diff --git a/src/user/test/main.c b/src/user/test/main.c index 3457ac3..7ca4802 100644 --- a/src/user/test/main.c +++ b/src/user/test/main.c @@ -34,57 +34,6 @@ void thread_cascade(void* d) { threads--; } -void list_dir(FILE f, int lv) { - char buf[256]; - int i = 0, k; - int r; - file_info info; - - while ((r = read(f, i, 256, buf)) > 0) { - if (strcmp(buf, ".") == 0 || strcmp(buf, "..") == 0) { - i++; - continue; - } - for (k = 0; k < lv; k++) print(" "); - print(buf); - stat_relative(f, buf, &info); - if (info.type & FT_DIR) print("/"); - print(" \t"); - - if (info.type & FT_FILE) print("file "); - if (info.type & FT_DIR) print("dir "); - if (info.type & FT_SYMLINK) print("symlink "); - if (info.type & FT_DEV) print("dev "); - if (info.type & FT_TERMINAL) print("term "); - - if (info.type & FT_DIR) { - print(" \t"); - FILE ff = open_relative(f, buf, 0); - if (ff <= 0) { - printf("error: %i\n", ff); - } else { - printf("fd: %i\n", ff); - list_dir(ff, lv+1); - close(ff); - } - } else { - print("\n"); - } - i++; - } -} - -void list_root() { - FILE f = open("/", 0); - if (f <= 0) { - printf(" -> Could not open '/', error #%i\n", f); - } else { - printf("Now enumerating '/' (fd %i) :\n", f); - list_dir(f, 1); - close(f); - } -} - int main(char** args) { char**a; if (args != 0) { @@ -103,10 +52,7 @@ int main(char** args) { thread_sleep(100); if (threads == 0) break; } - printk("\n"); - - term = open("/.ui/klog", 0); - list_root(); + printk("\n -> Test process exiting. Press the super key to go to the home terminal.\n"); return 0; } diff --git a/src/user/yosh/main.c b/src/user/yosh/main.c index 7586ab0..d334d1e 100644 --- a/src/user/yosh/main.c +++ b/src/user/yosh/main.c @@ -2,17 +2,18 @@ #include #include #include +#include FILE cwd_f; char *cwd; void about() { - print("Trivial/Computing Environment v0.1.0 - yosh 2.\n"); + print("Trivial/Computing Environment v0.1.0 - yosh 3.\n"); } void help(char *args[]) { if (args[1] == 0) { - print("Available commands: about, help, exit, ls, cd, switch.\n"); + print("Available commands: about, help, exit, ls, cd, goto.\n"); } else if (strcmp(args[1], "about") == 0) { print("Usage:\tabout\nShows some info about yosh. Very usefull.\n"); } else if (strcmp(args[1], "help") == 0) { @@ -25,8 +26,8 @@ void help(char *args[]) { print("Usage:\tcd \nGoes to the location specified.\n"); } else if (strcmp(args[1], "ls") == 0) { print("Usage:\tls\n\tls ...\nShows the content of the current/specified directory.\n"); - } else if (strcmp(args[1], "switch") == 0) { - print("Usage:\tswitch \nSwitchs focus to specified virtual terminal.\n"); + } else if (strcmp(args[1], "goto") == 0) { + print("Usage:\tgoto \nSwitchs focus to specified virtual terminal.\n"); print("Type `ls /.ui` to see available terminals.\n"); } else { printf("No such command: %s\n", args[1]); @@ -82,7 +83,7 @@ void simplify_path(char* p) { } } -char* path_cat (char* a, char* b) { +char* path_cat (char* a, char* b, int trailing_slash) { char* ret; if (b[0] == '/') { int lb = strlen(b); @@ -111,6 +112,10 @@ char* path_cat (char* a, char* b) { ret[la + lb] = 0; } simplify_path(ret); + if (!trailing_slash) { + int l = strlen(ret); + if (ret[l-1] == '/') ret[l-1] = 0; + } return ret; } @@ -120,7 +125,7 @@ void cd(char **args) { } if (strcmp(args[1], ".") == 0) return; - char* newcwd = path_cat(cwd, args[1]); + char* newcwd = path_cat(cwd, args[1], 1); file_info info; int i = stat(newcwd, &info); @@ -135,7 +140,7 @@ void cd(char **args) { free(newcwd); } else { FILE nf = open(newcwd, 0); - if (nf <= 0) { + if (nf < 0) { printf("Error opening: %i\n", nf); free(newcwd); } else { @@ -186,16 +191,18 @@ void ls(char **args) { int i; for (i = 1; args[i] != 0; i++) { printf("Contents of %s :\n", args[i]); - char* d = path_cat(cwd, args[i]); + char* d = path_cat(cwd, args[i], 1); file_info info; int e = stat(d, &info); if (e == E_NOT_FOUND) { print(" No such file or directory\n"); } else if (e < 0) { printf(" Error stating: %i\n", e); + } else if ((info.type & FT_DIR) == 0) { + printf(" Not a directory.\n"); } else { FILE ff = open(d, 0); - if (ff <= 0) { + if (ff < 0) { printf(" Error opening: %i\n", ff); } else { ls_dir(ff); @@ -207,12 +214,35 @@ void ls(char **args) { } } -void t_switch(char** args) { +void cat(char **args) { + int i; + for (i = 1; args[i] != 0; i++) { + char *d = path_cat(cwd, args[i], 0); + file_info info; + int e = stat(d, &info); + if (e == E_NOT_FOUND) { + printf("No such file: %s\n", d); + } else if (e < 0) { + printf("Error stating %s : %i\n", d, e); + } else if ((info.type & FT_FILE) == 0) { + printf("Not a file: %s\n", d); + } else { + FILE ff = open(d, 0); + char* buff = (char*)malloc(info.size); + read(ff, 0, info.size, buff); + close(ff); + write(term, 0, info.size, buff); + free(buff); + } + } +} + +void t_goto(char** args) { if (args[1] == 0) { - print("Usage: switch \n"); + print("Usage: goto \n"); return; } - char* p = path_cat("/.ui/", args[1]); + char* p = path_cat("/.ui/", args[1], 0); int i; if ((i = link(p, "/.dev/vgatxt", LM_OUTPUT_TO)) == 0) { link("/.dev/ps2kbd", p, LM_OUTPUT_TO); @@ -222,78 +252,116 @@ void t_switch(char** args) { } int main(char **sh_args) { - term = open("/.ui/home", 0); - if (term <= 0) { - return -1; - } - about(); cwd = strdup("/"); cwd_f = open(cwd, 0); - char *path = path_cat(sh_args[0], ".."); - + char *path = path_cat(sh_args[0], "..", 1); + + int bg_pr[128], bg_pr_c = 0; + + readline_history h; h.str = 0; h.max = 4; + while (1) { - printf(" %s ", cwd); + printf("\x1b[33m %s \x1b[1m", cwd); - char *s = readln(); + char *s = readline(term, &h); + printf("\x1b[0m"); if (s == 0) return -1; - int l = strlen(s); - if (s[l-1] == '\n') { - s[l-1] = 0; l--; - - char *c_args[16] = {0}, *cmd; - c_args[0] = s; - int argc = 1; - for (cmd = s; *cmd != 0; cmd++) { - if (*cmd == ' ') { - *cmd = 0; - if (cmd[1] != ' ' && cmd[1] != 0) { - c_args[argc] = cmd + 1; - argc++; - if (argc == 15) break; - } + if (*s == 0) continue; + + char *c_args[16] = {0}, *cmd; + c_args[0] = s; + int argc = 1; + for (cmd = s; *cmd != 0; cmd++) { + if (*cmd == ' ') { + *cmd = 0; + if (cmd[1] != ' ' && cmd[1] != 0) { + c_args[argc] = cmd + 1; + argc++; + if (argc == 15) break; + } + } + } + + if (strcmp(c_args[0], "about") == 0) { + about(); + } else if (strcmp(c_args[0], "help") == 0) { + help(c_args); + } else if (strcmp(c_args[0], "exit") == 0) { + print("Exiting the shell. See you later!\n"); + break; + } else if (strcmp(c_args[0], "cd") == 0) { + cd(c_args); + } else if (strcmp(c_args[0], "ls") == 0) { + ls(c_args); + } else if (strcmp(c_args[0], "goto") == 0) { + t_goto(c_args); + } else if (strcmp(c_args[0], "cat") == 0) { + cat(c_args); + } else { + FILE vt = term; + char *t = 0; + if (strcmp(c_args[0], "on") == 0) { + if (c_args[1] == 0 || c_args[2] == 0) { + printf("Usage:\ton \n"); + continue; + } + t = path_cat("/.ui/", c_args[1], 0); + vt = open(t, 0); + if (vt < 0 || vt == term) { + printf("Error: cannot open terminal %s (%i)\n", t, vt); + free(t); + continue; + } + int i = 0; + while (1) { + c_args[i] = c_args[i+2]; + if (c_args[i] == 0) break; + i++; } } - if (strcmp(c_args[0], "about") == 0) { - about(); - } else if (strcmp(c_args[0], "help") == 0) { - help(c_args); - } else if (strcmp(c_args[0], "exit") == 0) { - print("Exiting the shell. See you later!\n"); - break; - } else if (strcmp(c_args[0], "cd") == 0) { - cd(c_args); - } else if (strcmp(c_args[0], "ls") == 0) { - ls(c_args); - } else if (strcmp(c_args[0], "switch") == 0) { - t_switch(c_args); + char *c; + if (strchr(c_args[0], '/')) { + c = path_cat(cwd, c_args[0], 0); } else { - char *c; - if (strchr(c_args[0], '/')) { - c = path_cat(cwd, c_args[0]); + c = path_cat(path, c_args[0], 0); + } + int pid = run(c, c_args + 1, vt); + if (pid <= 0) { + if (pid == E_NOT_FOUND) { + printf("Error: no such file %s\n", c); } else { - c = path_cat(path, c_args[0]); + printf("Error %i\n", pid); } - int pid = run(c, c_args + 1); - if (pid <= 0) { - if (pid == E_NOT_FOUND) { - printf("Error: no such file %s\n", c); - } else { - printf("Error %i\n", pid); - } - } else { - int ret = waitpid(pid); + } else { + if (vt == term) { + int ret = waitpid(pid, 1); printf(" -> child (pid %i) exited with status %i\n", pid, ret); + } else { + printf(" -> running on terminal %s, pid:%i\n", t, pid); + bg_pr[bg_pr_c++] = pid; + free(t); } - free(c); } - } else { - print("[freadln fail, sorry.]\n"); + free(c); + } + + for (; s < cmd; s++) if (*s == 0) *s = ' '; + + int i = 0; + while (i < bg_pr_c) { + int ret = waitpid(bg_pr[i], 0); + if (ret != E_NOT_FINISHED) { + printf(" -> child (pid %i) exited with status %i\n", bg_pr[i], ret); + bg_pr_c--; + bg_pr[i] = bg_pr[bg_pr_c]; + } else { + i++; + } } - free(s); } return 0; -- cgit v1.2.3