summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex AUVOLAT <alexis211@gmail.com>2012-05-19 09:23:48 +0200
committerAlex AUVOLAT <alexis211@gmail.com>2012-05-19 09:23:48 +0200
commit7b466345af0d3a7dc5622617ce443a90c64e34a4 (patch)
treef276b6bf391ccfe8ec3a2cb62a7f70964249621f
parentac10c1a29c44b0cb29960cd0f792c7361bc430ce (diff)
downloadTCE-7b466345af0d3a7dc5622617ce443a90c64e34a4.tar.gz
TCE-7b466345af0d3a7dc5622617ce443a90c64e34a4.zip
Added ANSI support, minimal readline-like library.
-rw-r--r--doc/syscalls.txt2
-rw-r--r--doc/terminal.txt14
-rw-r--r--src/include/tce/syscalls.h1
-rw-r--r--src/kernel/config.h4
-rw-r--r--src/kernel/core/kmain.cpp5
-rw-r--r--src/kernel/dev/display.h2
-rw-r--r--src/kernel/dev/vgatxt.cpp22
-rw-r--r--src/kernel/task/syscall.cpp4
-rw-r--r--src/kernel/task/task.cpp15
-rw-r--r--src/kernel/task/task.h5
-rw-r--r--src/kernel/ui/vt.cpp211
-rw-r--r--src/kernel/ui/vt.h5
-rw-r--r--src/kernel/vfs/node.cpp1
-rw-r--r--src/user/init/main.c8
-rw-r--r--src/user/lib/Makefile2
-rw-r--r--src/user/lib/include/readline.h16
-rw-r--r--src/user/lib/include/stdio.h4
-rw-r--r--src/user/lib/include/tce/syscall.h4
-rw-r--r--src/user/lib/std/readline.c139
-rw-r--r--src/user/lib/std/stdio.c124
-rw-r--r--src/user/lib/tce/syscall.c8
-rw-r--r--src/user/test/main.c56
-rw-r--r--src/user/yosh/main.c200
23 files changed, 606 insertions, 246 deletions
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 <lib/earray.h>
+#include <tce/vfs.h>
#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 <stdio.h>
+
+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 <stdarg.h>
+#include <tce/syscall.h>
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 <readline.h>
+#include <stdlib.h>
+
+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 <tce/vfs.h>
#include <stdlib.h>
#include <stdio.h>
+#include <readline.h>
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 <location>\nGoes to the location specified.\n");
} else if (strcmp(args[1], "ls") == 0) {
print("Usage:\tls\n\tls <location>...\nShows the content of the current/specified directory.\n");
- } else if (strcmp(args[1], "switch") == 0) {
- print("Usage:\tswitch <vt name>\nSwitchs focus to specified virtual terminal.\n");
+ } else if (strcmp(args[1], "goto") == 0) {
+ print("Usage:\tgoto <vt name>\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 <vt_name>\n");
+ print("Usage: goto <vt_name>\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 <vt> <command>\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;