diff --git a/Makefile b/Makefile index a21b21c..131e10d 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,8 @@ CFLAGS = -g -std=gnu11 -m32 -mgeneral-regs-only -nostdlib -fno-builtin -fno-exce CXXFLAGS = -g -m32 -fno-use-cxa-atexit -mgeneral-regs-only -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore -fpermissive -fno-pie -fno-stack-protector -I. LDFLAGS = -DISK_IMG_FILES = build/kernel/kernel.bin build/world/world.bin hello.txt alpha.txt +DISK_IMG_FILES = build/kernel/kernel.bin build/world/world.bin hello.txt alpha.txt \ + build/hello/hello.bin KERNEL_CPP_SRCS = $(wildcard src/kernel/*.cpp) $(wildcard src/kernel/*/*.cpp) KERNEL_ASM_SRCS = $(wildcard src/kernel/*.asm) @@ -44,6 +45,7 @@ disk.img: clean prepare build/boot/boot.bin build/boot_stage2/boot.bin $(DISK_IM dd obs=512 seek=1 if=build/boot_stage2/boot.bin of=disk.img conv=notrunc mount disk.img img.d cp $(DISK_IMG_FILES) img.d/ + sleep 0.1 umount img.d chmod 777 disk.img diff --git a/src/common/common.c b/src/common/common.c index 7b2f732..fae785c 100644 --- a/src/common/common.c +++ b/src/common/common.c @@ -28,6 +28,18 @@ int write(uint32_t count, void* filehanlder, uint8_t* buffer) { asm volatile ("mov $11, %%eax; mov %0, %%ebx; mov %1, %%esi; mov %2, %%edi; int $0x7f" : : "m" (count), "m" (filehanlder), "m" (buffer): "ebx", "esi", "edi"); } +uint32_t fork(char* filename) { + asm volatile("mov $7, %%eax; mov %0, %%esi; int $0x7f" : : "m" (filename) : "esi"); +} + +uint32_t bindStdout(uint32_t PID) { + asm volatile("mov $13, %%eax; mov %0, %%esi; int $0x7f" : : "m" (PID) : "esi"); +} + +uint32_t bindStdin(uint32_t PID) { + asm volatile("mov $14, %%eax; mov %0, %%esi; int $0x7f" : : "m" (PID) : "esi"); +} + void bindToKeyboard() { asm volatile ("mov $12, %%eax; int $0x7f" : : :); } diff --git a/src/common/common.h b/src/common/common.h index 168d576..bf52277 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -9,6 +9,10 @@ void* localalloc(uint32_t size); void localdelete(void* ptr); uint32_t filesize(char* filename); +uint32_t fork(char* filename); +uint32_t bindStdout(uint32_t PID); +uint32_t bindStdin(uint32_t PID); + uint32_t getPID(); int read(uint32_t count, void* filehandler, uint8_t* buffer); diff --git a/src/hello/hello.c b/src/hello/hello.c index 717a8aa..b80c00f 100644 --- a/src/hello/hello.c +++ b/src/hello/hello.c @@ -1,16 +1,40 @@ #include "../common/common.h" -int main() { - uint32_t counter = 0; - uint32_t PID = getPID(); - char intbuffer[32]; - uint32_t index = int_to_decimal(PID, intbuffer); - while (1) { - counter++; - if (counter == 312500) { - print(intbuffer+index); - print(" "); - counter = 0; +void readline(int count, char* buffer) { + int index = 0; + char c; + while (index < count) { + if (read(1, 1, &c)) { + if (c == '\n') + break; + if (c == '\b') { + if (index == 0) + continue; + else { + index--; + buffer[index] = 0; + write(1, 0, &c); + continue; + } + } + + buffer[index++] = c; + write(1, 0, &c); } } + print("\n"); +} + +int main() { + print("Hello, World!\n"); + char buffer[32]; + while (1) { + for (int i=0; i<32; i++) + buffer[i] = 0; + print(">>> "); + readline(32, buffer); + print("You said: "); + print(buffer); + print("\n\n"); + } } \ No newline at end of file diff --git a/src/kernel/global.cpp b/src/kernel/global.cpp index 96f76cf..63689a0 100644 --- a/src/kernel/global.cpp +++ b/src/kernel/global.cpp @@ -5,7 +5,7 @@ namespace Global { Kernel* kernel = 0; Process* currentProc = 0; tss_struct* tss = 0; - bool currentProcValid = true; + bool currentProcValid = false; } void* operator new (uint32_t size) { diff --git a/src/kernel/idt.cpp b/src/kernel/idt.cpp index c2755ff..d7c8251 100644 --- a/src/kernel/idt.cpp +++ b/src/kernel/idt.cpp @@ -21,18 +21,36 @@ void set_entry(uint8_t interrupt_number, uint16_t code_segment, void(*handler)() }; } -void page_fault(frame_struct* frame) { - // Clear interrupts, we don't want to perform a context switch during a page fault. +void handle_fault(frame_struct* frame) { + // Clear interrupts, we don't want to perform a context switch whilst handling a fault. asm ("cli"); uint32_t problem_address; - asm("mov %%cr2, %0" : "=a" (problem_address) :); - Global::kernel->terminal->printf("(CS %x EIP %x): Page Fault at %x Error Code: %x Gate: %d\n", frame->cs, frame->eip, problem_address, frame->errcode, frame->gate); + asm ("mov %%cr2, %0" : "=a" (problem_address):); + Global::kernel->terminal->printf("(CS %x EIP %x): ", frame->cs, frame->eip); + switch (frame->gate) { + case 0: // Divide by zero + Global::kernel->terminal->printf("Divide by Zero"); + break; + case 6: // Invalid Opcode + Global::kernel->terminal->printf("Invalid Opcode"); + break; + case 13: // GPF + Global::kernel->terminal->printf("General Protection Fault!"); + break; + case 14: // Page Fault + Global::kernel->terminal->printf("Page Fault at %x", problem_address); + break; + default: + Global::kernel->terminal->printf("Unkown Fault!"); + break; + } + Global::kernel->terminal->printf(" Error Code: %x\n", frame->errcode); if (!(frame->cs & 3)) { - Global::kernel->terminal->printf("[FATAL] Kernel Page Fault!!!\n"); + Global::kernel->terminal->printf("[FATAL] Kernel Fault!!!\n"); while (1) asm("hlt"); } else { // Print an error message. - Global::kernel->terminal->printf("PID %d Terminated due to page fault!\n", Global::currentProc->PID); + Global::kernel->terminal->printf("PID %d Terminated due to fault!\n", Global::currentProc->PID); asm volatile ("mov %0, %%esp" ::"m"(Global::kernel->globalISRStack)); Global::kernel->PD->select(); @@ -49,11 +67,6 @@ void page_fault(frame_struct* frame) { void ignore_interrupt(frame_struct* frame) {} -void gpf(frame_struct* frame) { - printf("(EIP %x) General Protection Fault %x\n", frame->eip, frame->errcode); - while (1) asm("hlt"); -} - void context_switch(frame_struct* frame) { // When any interrupt occurs (including context_switch), SS:ESP is set to // the values of SS0:ESP0 in Global::tss @@ -70,77 +83,65 @@ void context_switch(frame_struct* frame) { asm ("cli"); // Disable interrupts whilst handling the context switch. - // Restore eax - asm ("mov %0, %%eax"::"r"(frame->eax)); + xnoe::linkedlist* processes = &Global::kernel->processes; - Process* currentProc = 0; - Process* nextProc = 0; - - if (Global::currentProcValid) { - currentProc = Global::currentProc; - // Write current esp to currentProc->kernelStackPtr - asm ("mov %%esp, %0" : "=a" (currentProc->kernelStackPtr):); + if (!processes->start) { + Global::kernel->terminal->printf("[FATAL] No more processes! Halting!\n"); + while (1) asm ("hlt"); } - if (currentProc || !Global::currentProcValid) { - xnoe::linkedlist* processes = &Global::kernel->processes; - - // This cursed bit of code first determines if the processes list is longer than 1 and if it is - // - Determines if it has 2 or more elements - // - If it has two, swap the first and last, update prev and next of each to be null or the other item - // - If it has more than two, add the start to the end then set start to the second element - if (processes->start) { - if (processes->start->next != 0) { - if (processes->end->prev == processes->start) { - xnoe::linkedlistelem* tmp = processes->start; - processes->start = processes->end; - processes->end = tmp; + if (Global::currentProcValid) + asm ("mov %%esp, %0" : "=a" (Global::currentProc->kernelStackPtr):); + + // This cursed bit of code first determines if the processes list is longer than 1 and if it is + // - Determines if it has 2 or more elements + // - If it has two, swap the first and last, update prev and next of each to be null or the other item + // - If it has more than two, add the start to the end then set start to the second element + if (Global::currentProc) { + if (processes->start->next != 0) { + if (processes->end->prev == processes->start) { + xnoe::linkedlistelem* tmp = processes->start; + processes->start = processes->end; + processes->end = tmp; - processes->start->prev = 0; - processes->end->next = 0; - processes->end->prev = processes->start; - processes->start->next = processes->end; - } else { - processes->end->next = processes->start; - processes->start = processes->start->next; - processes->start->prev = 0; - xnoe::linkedlistelem* tmp = processes->end; - processes->end = processes->end->next; - processes->end->next = 0; - processes->end->prev = tmp; - } + processes->start->prev = 0; + processes->end->next = 0; + processes->end->prev = processes->start; + processes->start->next = processes->end; + } else { + processes->end->next = processes->start; + processes->start = processes->start->next; + processes->start->prev = 0; + xnoe::linkedlistelem* tmp = processes->end; + processes->end = processes->end->next; + processes->end->next = 0; + processes->end->prev = tmp; } } + } - // Get the next process. - if (processes->start) - nextProc = processes->start->elem; + Global::currentProc = processes->start->elem; - if (nextProc == 0) { - Global::kernel->terminal->printf("[FATAL] No more processes! Halting!\n"); - while (1) asm ("hlt"); - } + // Select the next processes page directory + asm volatile ("mov %0, %%cr3" : : "r" (Global::currentProc->PD->phys_addr)); + // Restore kernelStackPtr of the new process. + asm volatile ("mov %0, %%esp" : : "m" (Global::currentProc->kernelStackPtr)); - Global::currentProc = nextProc; + // At this point interrupts are disabled till iret so we can safely set + // Global::tss->esp0 to the new Process's kernelStackPtrDefault - // Select the next processes page directory - asm volatile ("mov %0, %%cr3" : : "r" (nextProc->PD->phys_addr)); - // Restore kernelStackPtr of the new process. - asm volatile ("mov %0, %%esp" : : "m" (Global::kernel->processes.start->elem->kernelStackPtr)); + Global::tss->esp0 = Global::currentProc->kernelStackPtrDefault; - // At this point interrupts are disabled till iret so we can safely set - // Global::tss->esp0 to the new Process's kernelStackPtrDefault + // Set the current proc to valid + Global::currentProcValid = true; - Global::tss->esp0 = Global::kernel->processes.start->elem->kernelStackPtrDefault; - - // Set the current proc to valid - Global::currentProcValid = true; - - if (Global::currentProc->firstRun) { - Global::currentProc->firstRun = false; - asm("add $4, %esp"); - asm("ret"); - } + if (Global::currentProc->firstRun) { + Global::currentProc->firstRun = false; + asm("add $4, %esp"); + asm("ret"); + } else { + asm("add $28, %esp"); + asm("ret"); } } @@ -153,12 +154,15 @@ void syscall(frame_struct* frame) { // 4: localalloc: LocalAlloc: Allocate under current process (in esi: size; out eax void* ptr) // 5: localdelete: LocalDelete: Deallocate under current process (in esi: pointer) // 6: X - // 7: X + // 7: fork :: char* filename esi -> int PID // Spawns a process and returns its PID. // 8: getPID: returns the current process's PID (out eax: uint32_t) // 9: getFileHandler :: char* path esi -> void* eax // Returns a file handlers for a specific file // 10: read :: uint32_t count ebx -> void* filehandler esi -> uint8_t* outputbuffer edi -> int read // Reads from a file handler in to a buffer, returns successful read // 11: write :: uint32_t count ebx -> void* filehandler esi -> uint8_t* inputbuffer edi -> int written // Reads from a buffer in to a file, returns successful written // 12: bindToKeyboard :: void -> void // Binds the current process's stdout to the keyboard. + + // 13: bindStdout :: int PID esi -> int filehandler // Returns a filehandler for a CircularRWBuffer binding stdout of another process. + // 14: bindStdin :: int PID esi -> int filehandler // Returns a filehandler for a CircularRWBuffer binding stdin of another process. // File handlers: // 0: Stdout @@ -190,8 +194,16 @@ void syscall(frame_struct* frame) { break; case 6: break; - case 7: + case 7: { + asm("cli"); + char filename[12]; + for (int i=0; i<12; i++) + filename[i] = ((char*)(frame->esi))[i]; + Process* p = Global::kernel->createProcess(filename); + rval = p->PID; + asm("sti"); break; + } case 8: rval = currentProc->PID; break; @@ -208,8 +220,10 @@ void syscall(frame_struct* frame) { rval = stdin->read(frame->ebx, edi); } else { xnoe::Maybe fh = Global::kernel->FH->get(esi); - if (!fh.is_ok()) + if (!fh.is_ok()) { + rval = 0; break; + } ReadWriter* rw = fh.get(); rval = rw->read(frame->ebx, edi); @@ -226,8 +240,10 @@ void syscall(frame_struct* frame) { rval = stdout->write(frame->ebx, edi); } else { xnoe::Maybe fh = Global::kernel->FH->get(esi); - if (!fh.is_ok()) + if (!fh.is_ok()) { + rval = 0; break; + } ReadWriter* rw = fh.get(); rval = rw->write(frame->ebx, edi); @@ -241,6 +257,33 @@ void syscall(frame_struct* frame) { currentProc->stdin = new CircularRWBuffer(currentProc->PID, 0); Global::kernel->KBListeners.append(currentProc); + break; + + case 13: { + xnoe::Maybe pm = Global::kernel->pid_map->get(esi); + if (!pm.is_ok()) + break; + Process* p = pm.get(); + if (!p->stdout) { + ReadWriter* buffer = new CircularRWBuffer(currentProc->PID, esi); + p->stdout = buffer; + rval = Global::kernel->mapFH(buffer); + } + break; + } + + case 14: { + xnoe::Maybe pm = Global::kernel->pid_map->get(esi); + if (!pm.is_ok()) + break; + Process* p = pm.get(); + if (!p->stdin) { + ReadWriter* buffer = new CircularRWBuffer(esi, currentProc->PID); + p->stdin = buffer; + rval = Global::kernel->mapFH(buffer); + } + break; + } default: break; @@ -259,12 +302,28 @@ void init_idt() { for (int i=0; i<256; i++) gates[i] = &ignore_interrupt; - gates[0x20] = &context_switch; - gates[0xd] = &gpf; - gates[0xe] = &page_fault; - gates[0x7f] = &syscall; + gates[32] = &context_switch; + gates[0] = &handle_fault; + gates[5] = &handle_fault; + gates[6] = &handle_fault; + gates[7] = &handle_fault; + gates[9] = &handle_fault; + gates[10] = &handle_fault; + gates[11] = &handle_fault; + gates[12] = &handle_fault; + gates[13] = &handle_fault; + gates[14] = &handle_fault; + gates[16] = &handle_fault; + gates[17] = &handle_fault; + gates[19] = &handle_fault; + gates[20] = &handle_fault; + gates[21] = &handle_fault; + gates[29] = &handle_fault; + gates[30] = &handle_fault; + gates[31] = &handle_fault; + gates[127] = &syscall; - idt[0x7f].privilege = 3; + idt[127].privilege = 3; outb(0x20, 0x11); outb(0xA0, 0x11); diff --git a/src/kernel/kernel.cpp b/src/kernel/kernel.cpp index 49f23b0..40d4f14 100644 --- a/src/kernel/kernel.cpp +++ b/src/kernel/kernel.cpp @@ -11,11 +11,14 @@ Kernel::Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint this->stack = stack; + this->lastFH = 8; + //this->processes.append(this); } void Kernel::init_kernel() { this->pid_map = new xnoe::hashtable(); + this->FH = new xnoe::hashtable(); this->globalISRStack = (new uint8_t[0x8000]) + 0x8000; } @@ -41,6 +44,11 @@ void Kernel::destroyProcess(Process* p) { delete p; } +int Kernel::mapFH(ReadWriter* fh) { + this->FH->set(this->lastFH++, fh); + return this->lastFH - 1; +} + //void Kernel::loadPrimaryStack() { // asm volatile("mov %0, %%esp"::"m"(this->stack - 64)); //} \ No newline at end of file diff --git a/src/kernel/kernel.h b/src/kernel/kernel.h index d808f68..4687575 100644 --- a/src/kernel/kernel.h +++ b/src/kernel/kernel.h @@ -7,6 +7,8 @@ #include "terminal.h" class Kernel : public Process { +private: + int lastFH; public: uint32_t currentPID; uint32_t stack; @@ -26,6 +28,8 @@ public: Process* createProcess(char* filename); Process* createProcess(char* filename, ReadWriter* stdout); void destroyProcess(Process* p); + + int mapFH(ReadWriter* fh); //void loadPrimaryStack(); }; diff --git a/src/kernel/keyboard.cpp b/src/kernel/keyboard.cpp index 134cfbb..36c9225 100644 --- a/src/kernel/keyboard.cpp +++ b/src/kernel/keyboard.cpp @@ -36,12 +36,15 @@ bool shift_on = false; void keyboard_interrupt(frame_struct* frame) { uint8_t decoded = 0; uint8_t current_scancode = inb(0x60); - outb(0x20, 0x21); - if ((current_scancode&0x7f) == 0x2a) + if ((current_scancode&0x7f) == 0x2a) { shift_on = !(current_scancode&0x80); + return; + } - if (current_scancode == 0x3a) + if (current_scancode == 0x3a) { caps_on ^= 1; + return; + } if (shift_on) decoded = key_to_char_shift[current_scancode&0x7f]; diff --git a/src/kernel/kmain.cpp b/src/kernel/kmain.cpp index 1a73d97..3d9ce72 100644 --- a/src/kernel/kmain.cpp +++ b/src/kernel/kmain.cpp @@ -44,10 +44,7 @@ int main() { term->printf("KERNEL OK!\n"); - Global::currentProc = &kernel; - Process* p1 = kernel.createProcess("WORLD BIN", term); - //kernel.createProcess("HELLO BIN"); init_keyboard(); diff --git a/src/kernel/memory.cpp b/src/kernel/memory.cpp index 2c3e860..feca1d5 100644 --- a/src/kernel/memory.cpp +++ b/src/kernel/memory.cpp @@ -244,6 +244,9 @@ void* Allocator::allocate(uint32_t size) { this->PD->map(phys_addr, virt_addr + 4096 * i, this->privilege); } + for (int i=0; i<4096; i++) + ((uint8_t*)virt_addr)[i] = 0; + return virt_addr; } diff --git a/src/kernel/process.cpp b/src/kernel/process.cpp index 845d117..5ddbc45 100644 --- a/src/kernel/process.cpp +++ b/src/kernel/process.cpp @@ -59,44 +59,26 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, cha // We also need to initialise ESP and the stack uint32_t* stack32 = ((uint32_t)this->kernelStackPtr); - stack32--; - *stack32 = 0x23; // SS - stack32--; - *stack32 = ((uint32_t)this->stack + 0x8000); // ESP - stack32--; - *stack32 = 0x200; // EFLAGS - stack32--; - *stack32 = 27; // CS 0x08 - stack32--; - *stack32 = (uint32_t)program_data; // EIP - - stack32--; - *stack32 = ((uint32_t)this->stack + 0x8000); // EBP + *(--stack32) = 0x23; // SS + *(--stack32) = ((uint32_t)this->stack + 0x8000); // ESP + *(--stack32) = 0x200; // EFLAGS + *(--stack32) = 27; // CS + *(--stack32) = (uint32_t)program_data; // EIP + *(--stack32) = ((uint32_t)this->stack + 0x8000); // EBP uint32_t rEBP = stack32; + //stack32--; + *(--stack32) = 0; // EAX + *(--stack32) = 0; // ECX + *(--stack32) = 0; // EDX + *(--stack32) = 0; // EBX + *(--stack32) = 0; // ESP + *(--stack32) = rEBP; // EBP + *(--stack32) = 0; // ESI + *(--stack32) = 0; // EDI stack32--; - *stack32 = 0; // EAX - stack32--; - *stack32 = 0; // ECX - stack32--; - *stack32 = 0; // EDX - stack32--; - *stack32 = 0; // EBX - stack32--; - *stack32 = 0; // ESP - stack32--; - *stack32 = rEBP; // EBP - stack32--; - *stack32 = 0; // ESI - stack32--; - *stack32 = 0; // EDI - - stack32--; - - stack32--; - *stack32 = &catchall_return; // cachall_return - + *(--stack32) = &catchall_return; // cachall_return stack32--; this->kernelStackPtr = stack32; diff --git a/src/kernel/terminal.cpp b/src/kernel/terminal.cpp index 04b0551..c9f30c5 100644 --- a/src/kernel/terminal.cpp +++ b/src/kernel/terminal.cpp @@ -46,6 +46,23 @@ Terminal::Terminal(uint32_t width, uint32_t height, uint32_t pages) this->active = false; } +int strToInt(char* str) { + int r=0; + while (*str >= 0x30 && *str <= 0x39) { + r *= 10; + r += *(str++) - 0x30; + } + return r; +} + +int clamp(int a, int b, int c) { + if (a < b) + return b; + if (a > c) + return c; + return a; +} + void Terminal::printf(const char* string, ...) { va_list ptr; va_start(ptr, string); @@ -59,10 +76,50 @@ void Terminal::printf(const char* string, ...) { this->cur_y++; } + if (current == 0x1b && string[index] == '[') { + index++; + char* parameterStart = (string+index); + while (string[index] >= 0x30 && string[index] <= 0x3F) + index++; + char* parameterEnd = (string+index); + + char* intermediateStart = (string+index); + while (string[index] >= 0x20 && string[index] <= 0x2F) + index++; + + char final = *(string+(index++)); + + switch (final) { + case 'A': + this->cur_y -= clamp(strToInt(parameterStart), 0, this->cur_y); + break; + case 'B': + this->cur_y += clamp(strToInt(parameterStart), 0, this->height - this->cur_y); + break; + case 'C': + this->cur_x += clamp(strToInt(parameterStart), 0, this->width - this->cur_x); + break; + case 'D': + this->cur_x -= clamp(strToInt(parameterStart), 0, this->cur_x); + break; + case 'H': { + char* s=parameterStart; + while (*s != ';' && s < parameterEnd) + s++; + s++; + this->cur_y = clamp(strToInt(parameterStart), 1, this->height) - 1; + this->cur_x = clamp(strToInt(s), 1, this->width) - 1; + break; + } + } + + continue; + } + if (current == '\b') { if (this->cur_x > 0) { this->cur_x--; - } else { + } else if (this->cur_y > 0) { this->cur_y--; this->cur_x = this->width-1; } @@ -125,14 +182,94 @@ void Terminal::printf(const char* string, ...) { va_end(ptr); } -int Terminal::write(uint32_t count, uint8_t* buffer) { - char* buf = new char[count+1]; +int Terminal::write(uint32_t count, uint8_t* string) { + /*char* buf = new char[count+1]; for (int i=0;icur_x = 0; + this->cur_y++; + } + + if (current == 0x1b && string[index] == '[') { + index++; + char* parameterStart = (string+index); + while (string[index] >= 0x30 && string[index] <= 0x3F) + index++; + char* parameterEnd = (string+index); + + char* intermediateStart = (string+index); + while (string[index] >= 0x20 && string[index] <= 0x2F) + index++; + + char final = *(string+(index++)); + + switch (final) { + case 'A': + this->cur_y -= clamp(strToInt(parameterStart), 0, this->cur_y); + break; + case 'B': + this->cur_y += clamp(strToInt(parameterStart), 0, this->height - this->cur_y); + break; + case 'C': + this->cur_x += clamp(strToInt(parameterStart), 0, this->width - this->cur_x); + break; + case 'D': + this->cur_x -= clamp(strToInt(parameterStart), 0, this->cur_x); + break; + case 'H': { + char* s=parameterStart; + while (*s != ';' && s < parameterEnd) + s++; + s++; + this->cur_y = clamp(strToInt(parameterStart), 1, this->height) - 1; + this->cur_x = clamp(strToInt(s), 1, this->width) - 1; + break; + } + } + + continue; + } + + if (current == '\b') { + if (this->cur_x > 0) { + this->cur_x--; + } else if (this->cur_y > 0) { + this->cur_y--; + this->cur_x = this->width-1; + } + + int mem_pos = this->cur_y * this->width + this->cur_x; + + this->putchar(mem_pos, ' '); + continue; + } + + if (this->cur_x == this->width) { + this->cur_x = 0; + this->cur_y++; + } + + if (this->cur_y == this->height) + this->scroll_up(); + + if (current != '\n') { + int mem_pos = this->cur_y * this->width + this->cur_x++; + + this->putchar(mem_pos, current); + } + } + + this->set_curpos(this->cur_x, this->cur_y); } int Terminal::read(uint32_t count, uint8_t* buffer) {} diff --git a/src/world/world.c b/src/world/world.c index fa8b79d..b167a50 100644 --- a/src/world/world.c +++ b/src/world/world.c @@ -1,14 +1,137 @@ #include "../common/common.h" #include +void scrollBuffer(char* buf) { + for (int y=0; y<21; y++) + for (int x=0; x<38; x++) + if (y != 20) + buf[y*38+x] = buf[(y+1)*38+x]; + else + buf[y*38+x] = ' '; +} + +void writeToBuf(char c, char* buf, int* cx, int* cy) { + switch (c) { + case '\n': + *cx = 0; + (*cy)++; + break; + + case '\b': + if (*cx > 0) + (*cx)--; + else if (*cy > 0) { + *cx = 37; + (*cy)--; + } + buf[(*cy)*38+(*cx)] = ' '; + break; + + default: + buf[(*cy)*38+(*cx)++] = c; + } + if (*cx == 38) { + *cx = 0; + (*cy)++; + } + if (*cy == 21) { + (*cy)--; + scrollBuffer(buf); + } +} + +void writeStrToBuf(char* c, char* buf, int* cx, int* cy) { + char* s = c; + while(*s) + writeToBuf(*(s++), buf, cx, cy); +} + +void displayBuf(char* buf, int dx, int dy) { + char pset[9] = "\x1b[00;00H"; + for (int i=0; i