diff --git a/README.md b/README.md index e2947db..6053ac2 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,9 @@ **TBA** \ Repository ini akan digunakan sebagai duplikat public dari repository private yang terdapat pada GitHub Classroom informatika19 \ -Log : 3 April 2021, Upload v2.0.0 -Log : 23 April 2021, Penambahan README.md milestone 3 +Log : 3 April 2021, Upload v2.0.0 \ +Log : 23 April 2021, Penambahan README.md milestone 3 \ +Log : 27 April 2021, Penambahan milestone 3 dan branch baru ## Anggota: Nama | NIM diff --git a/makefile b/makefile index 21a54b5..62668eb 100644 --- a/makefile +++ b/makefile @@ -1,20 +1,190 @@ # 13519214 - Makefile -all: diskimage bootloader kernel createfilesystem insertfilesystem +all: basekernel shellpackage extrapackage createrecursiontest logoinsert + +basekernel: diskimage bootloader kernel createfilesystem insertfilesystem clean: # -- Cleaning output files -- - @rm out/fs/*; + @rm out/fs/* @rm out/* + @rm out/asm/* + @rm out/shell/* test: kernelgcc cleantest: cleangcc +shellpackage: basekernel fileloader mash insertls insertcd insertmkdir \ + insertcat insertcp insertmv insertln insertrm + + +extrapackage: shellpackage insertfile insertwc insertstrings insertmim \ + insertwhereis insertsnok insertprintf + +mash: + if [ ! -d "out/shell" ]; then mkdir out/shell; fi + @bcc -ansi -c -o out/shell/mash.o src/mash.c + @bcc -ansi -c -o out/shell/std_stringio.o src/std_stringio.c + @bcc -ansi -c -o out/shell/std_fileio.o src/std_fileio.c + @bcc -ansi -c -o out/shell/shell_common.o src/shell_common.c + @bcc -ansi -c -o out/shell/std_opr.o src/std_opr.c + if [ ! -d "out/shell/asm" ]; then mkdir out/shell/asm; fi + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/mash -d out/shell/*.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img mash 0 + +insertls: + if [ ! -d "out/shell/ls" ]; then mkdir out/shell/ls; fi + @bcc -ansi -c -o out/shell/ls/ls.o src/ls.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/ls -d out/shell/ls/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img ls 0 + +insertcd: + if [ ! -d "out/shell/cd" ]; then mkdir out/shell/cd; fi + @bcc -ansi -c -o out/shell/cd/cd.o src/cd.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/cd -d out/shell/cd/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img cd 0 + +insertmkdir: + if [ ! -d "out/shell/mkdir" ]; then mkdir out/shell/mkdir; fi + @bcc -ansi -c -o out/shell/mkdir/mkdir.o src/mkdir.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/mkdir -d out/shell/mkdir/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img mkdir 0 + +insertcat: + if [ ! -d "out/shell/cat" ]; then mkdir out/shell/cat; fi + @bcc -ansi -c -o out/shell/cat/cat.o src/cat.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/cat -d out/shell/cat/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img cat 0 + +insertcp: + if [ ! -d "out/shell/cp" ]; then mkdir out/shell/cp; fi + @bcc -ansi -c -o out/shell/cp/cp.o src/cp.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/cp -d out/shell/cp/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img cp 0 + +insertmv: + if [ ! -d "out/shell/mv" ]; then mkdir out/shell/mv; fi + @bcc -ansi -c -o out/shell/mv/mv.o src/mv.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/mv -d out/shell/mv/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img mv 0 + +insertln: + if [ ! -d "out/shell/ln" ]; then mkdir out/shell/ln; fi + @bcc -ansi -c -o out/shell/ln/ln.o src/ln.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/ln -d out/shell/ln/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img ln 0 + +insertrm: + if [ ! -d "out/shell/rm" ]; then mkdir out/shell/rm; fi + @bcc -ansi -c -o out/shell/rm/rm.o src/rm.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/rm -d out/shell/rm/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img rm 0 + +insertfile: + if [ ! -d "out/shell/file" ]; then mkdir out/shell/file; fi + @bcc -ansi -c -o out/shell/file/file.o src/file.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/file -d out/shell/file/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img file 0 + +insertwc: + if [ ! -d "out/shell/wc" ]; then mkdir out/shell/wc; fi + @bcc -ansi -c -o out/shell/wc/wc.o src/wc.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/wc -d out/shell/wc/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img wc 0 + +insertstrings: + if [ ! -d "out/shell/strings" ]; then mkdir out/shell/strings; fi + @bcc -ansi -c -o out/shell/strings/strings.o src/strings.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/strings -d out/shell/strings/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img strings 0 + +insertmim: + if [ ! -d "out/shell/mim" ]; then mkdir out/shell/mim; fi + @bcc -ansi -c -o out/shell/mim/mim.o src/mim.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/mim -d out/shell/mim/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img mim 0 + +insertsnok: + if [ ! -d "out/shell/snok" ]; then mkdir out/shell/snok; fi + @bcc -ansi -c -o out/shell/snok/snok.o src/snok.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/snok -d out/shell/snok/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img snok 0 + +insertwhereis: + if [ ! -d "out/shell/whereis" ]; then mkdir out/shell/whereis; fi + @bcc -ansi -c -o out/shell/whereis/whereis.o src/whereis.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/whereis -d out/shell/whereis/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img whereis 0 + +insertprintf: + if [ ! -d "out/shell/printf" ]; then mkdir out/shell/printf; fi + @bcc -ansi -c -o out/shell/printf/printf.o src/printf.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/printf -d out/shell/printf/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img printf 0 + +createrecursiontest: + if [ ! -d "out/shell/recursion_test" ]; then mkdir out/shell/recursion_test; fi + @bcc -ansi -c -o out/shell/recursion_test/recursion_test.o src/recursion_test.c + @nasm -f as86 src/asm/interrupt.asm -o out/shell/asm/interrupt.o + @ld86 -o out/recursion_test -d out/shell/recursion_test/*.o out/shell/std_fileio.o \ + out/shell/std_stringio.o out/shell/shell_common.o \ + out/shell/std_opr.o out/shell/asm/interrupt.o + @cd out; ./loadFile mangga.img recursion_test 0 +logoinsert: + @cp other/logo.hoho out/logo.hoho + @cd out; ./loadFile mangga.img logo.hoho 255 # Main recipes diskimage: # -- Initial mangga.img -- + if [ ! -d "out" ]; then mkdir out; fi @dd if=/dev/zero of=out/mangga.img bs=512 count=2880 status=noxfer bootloader: @@ -25,21 +195,23 @@ bootloader: kernel: # -- Source Compilation -- @bcc -ansi -c -o out/kernel.o src/kernel.c - @bcc -ansi -c -o out/std.o src/std.c + @bcc -ansi -c -o out/std_stringio.o src/std_stringio.c + @bcc -ansi -c -o out/std_fileio.o src/std_fileio.c @bcc -ansi -c -o out/screen.o src/screen.c - @bcc -ansi -c -o out/shell.o src/shell.c @bcc -ansi -c -o out/output.o src/output.c - @bcc -ansi -c -o out/opr.o src/opr.c + @bcc -ansi -c -o out/std_opr.o src/std_opr.c @nasm -f as86 src/asm/kernel.asm -o out/kernel_asm.o - @ld86 -o out/kernel -d out/*.o + if [ ! -d "out/asm" ]; then mkdir out/asm; fi + @nasm -f as86 src/asm/interrupt.asm -o out/asm/interrupt.o + ld86 -o out/kernel -d out/*.o out/asm/interrupt.o # ------------ Compiled kernel stat ------------ - # Max Kernel Size : 15872 bytes (31 sectors, 1 sector = 512 bytes) + # Max Kernel Size : 8192 bytes (16 sectors, 1 sector = 512 bytes) @stat --printf="Kernel Size : %s bytes\n" out/kernel # ---------------------------------------------- @dd if=out/kernel of=out/mangga.img bs=512 conv=notrunc seek=1 status=noxfer createfilesystem: - [ -d out/fs ] || mkdir out/fs; + if [ ! -d "out/fs" ]; then mkdir out/fs; fi @./other/fscreate out/fs/map.img out/fs/files.img out/fs/sectors.img insertfilesystem: @@ -49,10 +221,12 @@ insertfilesystem: @dd if=out/fs/sectors.img of=out/mangga.img bs=512 count=1 seek=259 conv=notrunc status=noxfer filesystemcreator: + if [ ! -d "other" ]; then mkdir other; fi @gcc -Wall -Wextra -O3 -o other/fscreate other/filesystem_create.c + chmod +x other/fscreate fileloader: - @gcc -Wall -Wextra -O3 -o other/loadFile other/fileloader.c + @gcc -Wall -Wextra -O3 -o out/loadFile other/fileloader.c # Test recipes diff --git a/src/asm/bootloader.asm b/src/asm/bootloader.asm index fe941c4..63d7950 100644 --- a/src/asm/bootloader.asm +++ b/src/asm/bootloader.asm @@ -6,7 +6,7 @@ bits 16 KSEG equ 0x1000 ;Lokasi kernel = 0x10000 -KSIZE equ 31 ;Ukuran kernel = 31 sektor +KSIZE equ 16 ;Ukuran kernel = 16 sektor KSTART equ 1 ;Lokasi kernel = sektor 1 ;boot loader starts at 0 in segment 0x7c00 diff --git a/src/asm/interrupt.asm b/src/asm/interrupt.asm new file mode 100644 index 0000000..55fc6ef --- /dev/null +++ b/src/asm/interrupt.asm @@ -0,0 +1,23 @@ +global _interrupt + +;int interrupt (int number, int AX, int BX, int CX, int DX) +_interrupt: + push bp + mov bp,sp + mov ax,[bp+4] ;get the interrupt number in AL + push ds ;use self-modifying code to call the right interrupt + mov bx,cs + mov ds,bx + mov si,intr + mov [si+1],al ;change the 00 below to the contents of AL + pop ds + mov ax,[bp+6] ;get the other parameters AX, BX, CX, and DX + mov bx,[bp+8] + mov cx,[bp+10] + mov dx,[bp+12] + +intr: int 0x00 ;call the interrupt (00 will be changed above) + + mov ah,0 ;we only want AL returned + pop bp + ret diff --git a/src/asm/kernel.asm b/src/asm/kernel.asm index d668d21..0e3fcee 100644 --- a/src/asm/kernel.asm +++ b/src/asm/kernel.asm @@ -5,12 +5,32 @@ ;kernel.asm contains assembly functions that you can use in your kernel global _putInMemory -global _interrupt +; global _interrupt global _makeInterrupt21 global _getRawCursorPos global _getFullKeyPress +global _launchProgram extern _handleInterrupt21 + +; void launchProgram(int segment) +_launchProgram: + mov bp,sp + mov bx,[bp+2] + mov ax,cs + mov ds,ax + mov si,jump + mov [si+3],bx + mov ds,bx + mov ss,bx + mov es,bx + mov sp,0xfff0 + mov bp,0xfff0 + +jump: jmp 0x0000:0x0000 +; TODO : Extra, forkexec, currently no memory left for kernel modification +; outline : save address, put on stack, do jump again + ;void putInMemory (int segment, int address, char character) _putInMemory: push bp @@ -26,26 +46,26 @@ _putInMemory: ret ;int interrupt (int number, int AX, int BX, int CX, int DX) -_interrupt: - push bp - mov bp,sp - mov ax,[bp+4] ;get the interrupt number in AL - push ds ;use self-modifying code to call the right interrupt - mov bx,cs - mov ds,bx - mov si,intr - mov [si+1],al ;change the 00 below to the contents of AL - pop ds - mov ax,[bp+6] ;get the other parameters AX, BX, CX, and DX - mov bx,[bp+8] - mov cx,[bp+10] - mov dx,[bp+12] - -intr: int 0x00 ;call the interrupt (00 will be changed above) - - mov ah,0 ;we only want AL returned - pop bp - ret +; _interrupt: +; push bp +; mov bp,sp +; mov ax,[bp+4] ;get the interrupt number in AL +; push ds ;use self-modifying code to call the right interrupt +; mov bx,cs +; mov ds,bx +; mov si,intr +; mov [si+1],al ;change the 00 below to the contents of AL +; pop ds +; mov ax,[bp+6] ;get the other parameters AX, BX, CX, and DX +; mov bx,[bp+8] +; mov cx,[bp+10] +; mov dx,[bp+12] +; +; intr: int 0x00 ;call the interrupt (00 will be changed above) +; +; mov ah,0 ;we only want AL returned +; pop bp +; ret ;void makeInterrupt21() ;this sets up the interrupt 0x21 vector diff --git a/src/basic-header/std_opr.h b/src/basic-header/std_opr.h new file mode 100644 index 0000000..8d0c789 --- /dev/null +++ b/src/basic-header/std_opr.h @@ -0,0 +1,5 @@ +// 13519214 - Basic operation + +int div(int a, int b); + +int mod(int a, int n); diff --git a/src/cat.c b/src/cat.c new file mode 100644 index 0000000..6e0d575 --- /dev/null +++ b/src/cat.c @@ -0,0 +1,158 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" +#include "std-header/boolean.h" + +void cat(char *dirtable, char *filename, char target_dir); + +int main() { + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char dirstr[BUFFER_SIZE]; + char argc = 0; + int returncode = 0; + char current_dir_index; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(dirstr, BUFFER_SIZE); + memcpy(dirstr, shell_cache+ARGV_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + current_dir_index = shell_cache[CURRENT_DIR_CACHE_OFFSET]; + + + // Argument count + if (argc == 2) + if (!strcmp("--help", dirstr)) { + print("Utility to view file\n", BIOS_WHITE); + print("Possible Usage:\n", BIOS_LIGHT_BLUE); + print("cat [file_name]\n", BIOS_LIGHT_CYAN); + } + else { + cat(directory_table, dirstr, current_dir_index); + } + else + print("Usage : cat \n", BIOS_WHITE); + shellReturn(); +} + + +void cat(char *dirtable, char *filename, char target_dir) { + char filename_buffer[16]; + char source_directory_name[16]; + char file_read[FILE_SIZE_MAXIMUM]; + char directory_name[ARGC_MAX][ARG_LENGTH]; + char evaluator_temp[ARGC_MAX*ARG_LENGTH]; + char eval_dir = target_dir; + char target_entry_byte = 0; + char target_parent_byte = 0; + char source_dir_idx; + char link_status = -1; + bool is_found_parent = false; + int returncode_src = 0; + int returncode = -1, eval_returncode = -1; + int dirnamecount; + int i, j, k; + + + // Another splitter stealing + clear(directory_name, ARGC_MAX*ARG_LENGTH); + clear(evaluator_temp, ARGC_MAX*ARG_LENGTH); + i = 0; + j = 0; + k = 0; + while (filename[i] != CHAR_NULL) { + // If found slash in commands and not within double quote mark, make new + if (filename[i] == CHAR_SLASH && j < ARGC_MAX) { + k = 0; + j++; + } + else { + // Only copy if char is not double quote + // and space outside double quote + directory_name[j][k] = filename[i]; + k++; + } + i++; + } + dirnamecount = j + 1; // Due j is between counting space between 2 args + + i = 0; + // Note : Entry directory_name[dirnamecount - 1] is a FILENAME, not folder + while (i < dirnamecount - 1) { + strapp(evaluator_temp, directory_name[i]); + strapp(evaluator_temp, "/"); + i++; + } + + strcpybounded(source_directory_name, directory_name[dirnamecount - 1], 14); // TODO : Test + + if (dirnamecount > 1) { + eval_dir = directoryEvaluator(dirtable, evaluator_temp, &eval_returncode, target_dir); + } + source_dir_idx = eval_dir; + + clear(file_read, FILE_SIZE_MAXIMUM); + // Take last argv, use it as filename + read(file_read, directory_name[dirnamecount-1], &returncode, eval_dir); + if (returncode == -1) { + print("cat: ", BIOS_GRAY); + print(directory_name[dirnamecount-1], BIOS_GRAY); + print(": file not found", BIOS_GRAY); + } + else { + i = 0; + while (i < FILES_ENTRY_COUNT && !is_found_parent) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, 14); + if (dirtable[i*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET] == source_dir_idx && + !strcmp(source_directory_name, filename_buffer)) { + is_found_parent = true; + target_entry_byte = dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET]; + link_status = dirtable[i*FILES_ENTRY_SIZE+LINK_BYTE_OFFSET]; + } + i++; + } + + if (link_status == SOFTLINK_ENTRY) { + i = 0; + // TODO : Extra, currently only single softlink depth supported + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+target_entry_byte*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + target_parent_byte = dirtable[target_entry_byte*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET]; + target_entry_byte = dirtable[target_entry_byte*FILES_ENTRY_SIZE + ENTRY_BYTE_OFFSET]; + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, filename_buffer, &returncode_src, target_parent_byte); + // Needed to compare due _mash_cache always filling empty space + // Implying softlink to _mash_cache is not available + if (!strcmp(filename_buffer, "_mash_cache")) + target_entry_byte = EMPTY_FILES_ENTRY; + } + + if (returncode_src == 0 && target_entry_byte != EMPTY_FILES_ENTRY) { + if (file_read[0] == NULL) { + print("cat: ", BIOS_WHITE); + print(directory_name[dirnamecount-1], BIOS_WHITE); + print(" is a folder", BIOS_WHITE); + } + else { + i = 0; + while (i < FILE_SIZE_MAXIMUM && file_read[i] != CHAR_NULL) { + if (file_read[i] == CHAR_CARRIAGE_RETURN) + file_read[i] = CHAR_SPACE; + i++; + } + print(file_read, BIOS_GRAY); + } + } + else { + print("cat: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print(" softlink broken\n", BIOS_WHITE); + } + } + print("\n\n", BIOS_GRAY); +} diff --git a/src/cd.c b/src/cd.c new file mode 100644 index 0000000..424e5ca --- /dev/null +++ b/src/cd.c @@ -0,0 +1,153 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "std-header/boolean.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" + +char cd(char *dirtable, char *dirstr, char current_dir); + +int main() { + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char dirstr[BUFFER_SIZE]; + char new_index; + int argc; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(dirstr, BUFFER_SIZE); + memcpy(dirstr, shell_cache+ARGV_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + + if (argc == 2) { + if (!strcmp("--help", dirstr)) { + print("Utility to change working directory\n", BIOS_WHITE); + print("Possible Usage:\n", BIOS_LIGHT_BLUE); + print("cd [directory_name]\n", BIOS_LIGHT_CYAN); + print("cd ..\n", BIOS_LIGHT_CYAN); + } + else { + new_index = cd(directory_table, dirstr, shell_cache[CURRENT_DIR_CACHE_OFFSET]); + shell_cache[CURRENT_DIR_CACHE_OFFSET] = new_index; + } + } + else if (argc == 1) + shell_cache[CURRENT_DIR_CACHE_OFFSET] = ROOT_PARENT_FOLDER; + else + print("Usage : cd \n", BIOS_WHITE); + + setShellCache(shell_cache); + shellReturn(); +} + +char cd(char *dirtable, char *dirstr, char current_dir) { + int returncode = 0; + char new_dir_idx = directoryEvaluator(dirtable, dirstr, &returncode, current_dir); + // Copied from other code + int i = 0; + bool is_found_parent = false; + char filename_buffer[16]; + char source_dir_idx; + char source_directory_name[16]; + int returncode_src; + char file_read[FILE_SIZE_MAXIMUM]; + char target_parent_byte; + char target_entry_byte; + char link_status = -1; + char original_softlink_entry_byte; + int last_slash_index; + + // If success return new dir index + if (returncode == 0) { + return new_dir_idx; + } + else if (returncode == 1) { + // Else, entry is not folder + // Find whether file is softlink or not + + // The super smelly code + // Relative pathing + clear(source_directory_name, 16); + // Split target / source + last_slash_index = getLastMatchedCharIdx(CHAR_SLASH, dirstr); + // FIXME : Extra, unsafe getlast + if (last_slash_index != -1) { + // Split argument to path and filename + // Get path + strcpybounded(source_directory_name, dirstr, last_slash_index); + source_dir_idx = directoryEvaluator(dirtable, source_directory_name, &returncode_src, current_dir); + + // Get filename + strcpybounded(source_directory_name, dirstr+last_slash_index+1, ARG_LENGTH-last_slash_index-1); + } + else { + // Cut slash + strcpybounded(source_directory_name, dirstr, ARG_LENGTH); + + source_dir_idx = current_dir; + returncode_src = 0; + } + + + + if (returncode_src == 0) { + // Find entry in files + i = 0; + while (i < FILES_ENTRY_COUNT && !is_found_parent) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, 14); + if (dirtable[i*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET] == source_dir_idx && + !strcmp(source_directory_name, filename_buffer)) { + is_found_parent = true; + target_entry_byte = dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET]; + link_status = dirtable[i*FILES_ENTRY_SIZE+LINK_BYTE_OFFSET]; + } + i++; + } + + if (link_status == SOFTLINK_ENTRY) { + // Get linked strings / folder with recursion depth limit 16 + i = 0; + // TODO : Extra, currently only single softlink depth supported + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+target_entry_byte*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + target_parent_byte = dirtable[target_entry_byte*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET]; + original_softlink_entry_byte = target_entry_byte; + target_entry_byte = dirtable[target_entry_byte*FILES_ENTRY_SIZE + ENTRY_BYTE_OFFSET]; + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, filename_buffer, &returncode_src, target_parent_byte); + // Needed to compare due _mash_cache always filling empty space + // Implying softlink to _mash_cache is not available + if (!strcmp(filename_buffer, "_mash_cache")) + target_entry_byte = EMPTY_FILES_ENTRY; + } + + if (target_entry_byte == FOLDER_ENTRY) + returncode = 0; + } + else { + print("cd: path ", BIOS_WHITE); + print(dirstr, BIOS_WHITE); + print(" evaluation failed\n", BIOS_WHITE); + returncode = -1; + } + + if (returncode != 0) { + print("cd: target type is a file\n", BIOS_WHITE); + return current_dir; + } + else { + print("cd: softlink to ", BIOS_WHITE); + print(filename_buffer, BIOS_LIGHT_CYAN); + print("\n", BIOS_WHITE); + return original_softlink_entry_byte; + } + } + else { + // Else, return original dir + print("cd: path not found\n", BIOS_WHITE); + return current_dir; + } +} diff --git a/src/cp.c b/src/cp.c new file mode 100644 index 0000000..1226e7a --- /dev/null +++ b/src/cp.c @@ -0,0 +1,373 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" +#include "std-header/boolean.h" + +void cp(char *dirtable, char current_dir_index, char flags, char *target, char *linkname); + +int main() { + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char arg_vector[ARGC_MAX][ARG_LENGTH]; + char file_read[FILE_SIZE_MAXIMUM]; + char argc = 0; + int current_dir_index; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(arg_vector, ARGC_MAX*ARG_LENGTH); + memcpy(arg_vector[0], shell_cache+ARGV_OFFSET, ARG_LENGTH); + memcpy(arg_vector[1], shell_cache+ARGV_2_OFFSET, ARG_LENGTH); + memcpy(arg_vector[2], shell_cache+ARGV_3_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + current_dir_index = shell_cache[CURRENT_DIR_CACHE_OFFSET]; + + // Argument count + if (argc == 2 && !strcmp("--help", arg_vector[0])) { + print("Utility to copy file\n", BIOS_WHITE); + print("Possible Usage:\n", BIOS_LIGHT_BLUE); + print("cp [source_directory] [target_directory]\n", BIOS_LIGHT_CYAN); + print("cp -r [source_directory] [target_directory]\n", BIOS_LIGHT_CYAN); + } + else if (argc >= 3) { + if (!strcmp("-r", arg_vector[0])) + cp(file_read, directory_table, current_dir_index, 1, arg_vector[1], arg_vector[2]); + else + cp(file_read, directory_table, current_dir_index, 0, arg_vector[0], arg_vector[1]); + } + else + print("Usage : cp [-r] \n", BIOS_WHITE); + + setShellCache(shell_cache); + shellReturn(); +} + +void file_copy(char *file_read, char *source_directory_name, char *returncode_src, char source_dir_idx, + char *copied_directory_name, char *returncode_cpy, char copied_dir_idx, char *dirtable) { + char filename_buffer[16]; + + char target_entry_byte; + char link_status = -1; + char target_parent_byte; + char original_softlink_index; + + int i = 0; + bool empty_entry_found = false; + bool is_found_parent = false; + + if (getKeyboardCursor(true) > 20) + scrollScreen(); + + // Find entry in files + i = 0; + while (i < FILES_ENTRY_COUNT && !is_found_parent) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, 14); + if (dirtable[i*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET] == source_dir_idx && + !strcmp(source_directory_name, filename_buffer)) { + is_found_parent = true; + target_entry_byte = dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET]; + target_parent_byte = dirtable[i*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET]; + link_status = dirtable[i*FILES_ENTRY_SIZE+LINK_BYTE_OFFSET]; + memcpy(filename_buffer, dirtable+i*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + original_softlink_index = i; + } + i++; + } + + if (link_status == SOFTLINK_ENTRY || link_status == HARDLINK_ENTRY) { + // Will copy softlink + getDirectoryTable(dirtable); + + // Find empty entry + i = 0; + while (i < FILES_ENTRY_COUNT && !empty_entry_found) { + if (dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET] == EMPTY_FILES_ENTRY) { + empty_entry_found = true; + dirtable[i*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET] = target_parent_byte; + dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET] = target_entry_byte; + clear(filename_buffer, 16); + strcpybounded(filename_buffer, copied_directory_name, 14); + memcpy(dirtable+i*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, filename_buffer, 14); + dirtable[i*FILES_ENTRY_SIZE+LINK_BYTE_OFFSET] = link_status; + } + i++; + } + + directSectorWrite(dirtable, FILES_SECTOR); + directSectorWrite(dirtable+SECTOR_SIZE, FILES_SECTOR+1); + *returncode_cpy = -1; + *returncode_src = 0; + } + else { + if (target_entry_byte != EMPTY_FILES_ENTRY) { + read(file_read, source_directory_name, returncode_src, source_dir_idx); + if (file_read[0] != NULL) { + print("cp: ", BIOS_WHITE); + print(source_directory_name, BIOS_LIGHT_GREEN); + print(" copied\n", BIOS_WHITE); + write(file_read, copied_directory_name, returncode_cpy, copied_dir_idx); + *returncode_cpy = -1; + *returncode_src = 0; + } + else { + print("cp: internal error: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print(" is a folder\n", BIOS_WHITE); + } + } + else { + print("cp: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print(" softlink broken\n", BIOS_WHITE); + } + } + +} + +void cp(char *file_read, char *dirtable, char current_dir_index, char flags, char *target, char *linkname) { + // Technically just "copy" of previous implementation of ln + // char as string / char + char filename_buffer[16]; + char source_directory_name[16]; + char copied_directory_name[16]; + char evaluator_buffer[16]; + + // char as 1 byte integer + char target_entry_byte = 0; + char target_parent_byte = 0; + char link_status = -1; + int stack_source[256]; // <3 stack, but not bcc :( + int stack_copied[256]; // actually pseudo-stack but whatever + int copied_parent_dir[256]; + char stack_top_pointer_src; + char stack_top_pointer_cpy; + char source_dir_idx; + char copied_dir_idx; + char current_recursion_parent_index_src; + char current_recursion_parent_index_cpy; + int top_cpy; + int returncode_src = 0; + int returncode_cpy = 0; + bool is_write_success = false, valid_filename = true; + bool f_target_found = false, empty_entry_found = false; + bool recursion_loop_pass_success = false; + bool is_found_parent = false; + bool is_first_rec = true; + int i = 0, j = 0; + int f_entry_idx = 0; + int f_entry_sector_idx = 0; + int last_slash_index; + + + // Relative pathing + clear(source_directory_name, 16); + clear(copied_directory_name, 16); + // Split target / source + last_slash_index = getLastMatchedCharIdx(CHAR_SLASH, target); + // FIXME : Extra, unsafe getlast + if (last_slash_index != -1) { + // Split argument to path and filename + // Get path + strcpybounded(source_directory_name, target, last_slash_index); + source_dir_idx = directoryEvaluator(dirtable, source_directory_name, &returncode_src, current_dir_index); + + // Get filename + strcpybounded(source_directory_name, target+last_slash_index+1, ARG_LENGTH-last_slash_index-1); + } + else { + // Cut slash + strcpybounded(source_directory_name, target, ARG_LENGTH); + + read(file_read, source_directory_name, &returncode_src, current_dir_index); + if (file_read[0] == FOLDER && flags == 1) { + clear(evaluator_buffer, 16); + strcpy(evaluator_buffer, source_directory_name); + strapp(evaluator_buffer, "/"); + source_dir_idx = directoryEvaluator(dirtable, evaluator_buffer, &returncode_src, current_dir_index); + } + else + source_dir_idx = current_dir_index; + + returncode_src = 0; + } + + // Split destination / copied + last_slash_index = getLastMatchedCharIdx(CHAR_SLASH, linkname); + // FIXME : Extra, unsafe getlast + if (last_slash_index != -1) { + // Split argument to path and filename + // Get path + strcpybounded(copied_directory_name, linkname, last_slash_index); + copied_dir_idx = directoryEvaluator(dirtable, copied_directory_name, &returncode_cpy, current_dir_index); + + // Get filename + strcpybounded(copied_directory_name, linkname+last_slash_index+1, ARG_LENGTH-last_slash_index-1); + } + else { + // Cut slash + strcpybounded(copied_directory_name, linkname, ARG_LENGTH); + + read(file_read, copied_directory_name, &returncode_cpy, current_dir_index); + if (file_read[0] == FOLDER && flags == 1) { + clear(evaluator_buffer, 16); + strcpy(evaluator_buffer, copied_directory_name); + strapp(evaluator_buffer, "/"); + copied_dir_idx = directoryEvaluator(dirtable, evaluator_buffer, &returncode_cpy, current_dir_index); + } + else + copied_dir_idx = current_dir_index; + + returncode_cpy = 0; + } + + + // Copying file if path evaluation success + if (returncode_src == -1) { + print("cp: ", BIOS_GRAY); + print(target, BIOS_GRAY); + print(": target not found\n", BIOS_GRAY); + } + else if (returncode_cpy == -1) { + print("cp: ", BIOS_GRAY); + print(copied_directory_name, BIOS_GRAY); + print(": path not found\n", BIOS_GRAY); + } + else { + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, copied_directory_name, &returncode_cpy, copied_dir_idx); + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, source_directory_name, &returncode_src, source_dir_idx); + if ((returncode_src == 0 && returncode_cpy == -1) || flags == 1) { + if (flags == 0) { + // Simple copy, refuse folder + if (file_read[0] != NULL) { + file_copy(file_read, source_directory_name, &returncode_src, source_dir_idx, + copied_directory_name, &returncode_cpy, copied_dir_idx, dirtable); + returncode_cpy = -1; + returncode_src = 0; + } + else { + print("cp: error: ", BIOS_WHITE); + print(target, BIOS_WHITE); + print(" is a folder\n", BIOS_WHITE); + returncode_src = -1; + } + } + else { + // Stolen from rm + // Will deleting file normally on -r + if (file_read[0] != NULL) { + file_copy(file_read, source_directory_name, &returncode_src, source_dir_idx, + copied_directory_name, &returncode_cpy, copied_dir_idx, dirtable); + } + else { + i = 0; + while (i < 256) { + copied_parent_dir[i] = 0; + stack_source[i] = 0; + stack_copied[i] = 0; + i++; + } + stack_top_pointer_src = 0; + stack_top_pointer_cpy = 0; + stack_source[0] = source_dir_idx; + stack_copied[0] = copied_dir_idx; + copied_parent_dir[0] = 0; + + while (!recursion_loop_pass_success) { + // FIXME : Extra, Extra, actually cannot copy 2 directory in 1 parent + i = 0; + recursion_loop_pass_success = true; + + if (is_first_rec) { + // Use original copied directory name on first recursion + is_first_rec = false; + } + else { + clear(copied_directory_name, 16); + top_cpy = (stack_source[stack_top_pointer_src])*FILES_ENTRY_SIZE; + strcpybounded(copied_directory_name, dirtable+top_cpy+PATHNAME_BYTE_OFFSET, 14); + } + print("cp: ", BIOS_WHITE); + print(copied_directory_name, BIOS_LIGHT_BLUE); + print(" created\n", BIOS_WHITE); + write(FOLDER, copied_directory_name, &returncode_cpy, stack_copied[stack_top_pointer_cpy]); + getDirectoryTable(dirtable); + current_recursion_parent_index_src = stack_source[stack_top_pointer_src]; + copied_parent_dir[stack_top_pointer_src] = 0; + // Get new file index + while (i < FILES_ENTRY_COUNT) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+i*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + if (!strcmp(filename_buffer, copied_directory_name) && dirtable[i*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET] == stack_copied[stack_top_pointer_cpy]) { + stack_top_pointer_cpy++; + stack_copied[stack_top_pointer_cpy] = i; + } + i++; + } + current_recursion_parent_index_cpy = stack_copied[stack_top_pointer_cpy]; + + i = 0; + while (i < FILES_ENTRY_COUNT) { + if (current_recursion_parent_index_src == dirtable[i*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET]) { + // If still file, pass is still success + if (dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET] != FOLDER_ENTRY + && dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET] != EMPTY_FILES_ENTRY) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+i*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + file_copy(file_read, filename_buffer, &returncode_src, current_recursion_parent_index_src, + filename_buffer, &returncode_cpy, current_recursion_parent_index_cpy, dirtable); + } + // If folder, pass failed + else { + stack_top_pointer_src++; + stack_source[stack_top_pointer_src] = (char) i; + copied_parent_dir[stack_top_pointer_src] = current_recursion_parent_index_src; + recursion_loop_pass_success = false; + } + } + i++; + } + + if (recursion_loop_pass_success) { + i = stack_top_pointer_src; + while (i > 0) { + if (copied_parent_dir[i] != 0) { + // Stack unwinding + stack_top_pointer_src = i; + stack_top_pointer_cpy = i; + recursion_loop_pass_success = false; + break; + } + i--; + } + } + } + + + returncode_cpy = -1; + returncode_src = 0; + print("cp: recursion done\n", BIOS_WHITE); + } + } + + } + else { + print("cp: error: ", BIOS_WHITE); + print(target, BIOS_WHITE); + print(" not found\n", BIOS_WHITE); + returncode_src = -1; + } + + if (returncode_src == 0 && returncode_cpy == -1) { + print(linkname, BIOS_GRAY); + print(": copy created\n", BIOS_GRAY); + } + else + print("cp: file writing error\n", BIOS_GRAY); + } +} diff --git a/src/file.c b/src/file.c new file mode 100644 index 0000000..d93248e --- /dev/null +++ b/src/file.c @@ -0,0 +1,212 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" +#include "std-header/boolean.h" + +void file(char *dirtable, char current_dir_index, char *target); + +int main() { + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char arg_vector[ARGC_MAX][ARG_LENGTH]; + char argc = 0; + int current_dir_index; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(arg_vector, ARGC_MAX*ARG_LENGTH); + memcpy(arg_vector[0], shell_cache+ARGV_OFFSET, ARG_LENGTH); + memcpy(arg_vector[1], shell_cache+ARGV_2_OFFSET, ARG_LENGTH); + memcpy(arg_vector[2], shell_cache+ARGV_3_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + current_dir_index = shell_cache[CURRENT_DIR_CACHE_OFFSET]; + + // Argument count + if (argc == 2) + if (!strcmp("--help", arg_vector[0])) { + print("Utility to determine file type\n", BIOS_WHITE); + print("Possible Usage:\n", BIOS_LIGHT_BLUE); + print("file [file_name]\n", BIOS_LIGHT_CYAN); + } + else { + file(directory_table, current_dir_index, arg_vector[0]); + } + else + print("Usage : file \n", BIOS_WHITE); + + setShellCache(shell_cache); + shellReturn(); +} + +bool isTextCharOnly(char *buffer) { + int i = 0; + int null_count = 0; + bool isCharOnly = true; + while (i < FILE_SIZE_MAXIMUM && null_count < 5 && isCharOnly) { + if (buffer[i] == '\0') + null_count++; + else + null_count = 0; + + if (!(CHAR_SPACE <= buffer[i] && buffer[i] <= CHAR_TILDE + || buffer[i] == CHAR_NULL || buffer[i] == CHAR_CARRIAGE_RETURN + || buffer[i] == CHAR_LINEFEED) ) + isCharOnly = false; + + i++; + } + return isCharOnly; +} + +void file(char *dirtable, char current_dir_index, char *target) { + // char as string / char + char filename_buffer[16]; + char source_directory_name[16]; + char string_byte_count[32]; + char string_disk_byte_count[32]; + // char as 1 byte integer + char file_read[FILE_SIZE_MAXIMUM]; + char sectors_buf[SECTOR_SIZE]; + char target_entry_byte = 0; + char target_parent_byte = 0; + char source_dir_idx; + char link_status = -1; + int returncode_src = 0; + bool is_write_success = false, valid_filename = true; + bool f_target_found = false, empty_entry_found = false; + bool is_found_parent = false; + int i = 0, j = 0; + int f_entry_idx = 0; + int f_entry_sector_idx = 0; + int last_slash_index; + int sectors_byte_count; + + // Relative pathing + clear(source_directory_name, 16); + // Split target / source + last_slash_index = getLastMatchedCharIdx(CHAR_SLASH, target); + // FIXME : Extra, unsafe getlast + if (last_slash_index != -1) { + // Split argument to path and filename + // Get path + strcpybounded(source_directory_name, target, last_slash_index); + source_dir_idx = directoryEvaluator(dirtable, source_directory_name, &returncode_src, current_dir_index); + + // Get filename + strcpybounded(source_directory_name, target+last_slash_index+1, ARG_LENGTH-last_slash_index-1); + } + else { + // Cut slash + strcpybounded(source_directory_name, target, ARG_LENGTH); + + source_dir_idx = current_dir_index; + returncode_src = 0; + } + + + + // Copying file if path evaluation success + if (returncode_src == -1) { + print("file: ", BIOS_GRAY); + print(target, BIOS_GRAY); + print(": target not found\n", BIOS_GRAY); + } + else { + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, source_directory_name, &returncode_src, source_dir_idx); + if (returncode_src == 0) { + + // Find entry in files + i = 0; + while (i < FILES_ENTRY_COUNT && !is_found_parent) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, 14); + if (dirtable[i*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET] == source_dir_idx && + !strcmp(source_directory_name, filename_buffer)) { + is_found_parent = true; + target_entry_byte = dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET]; + link_status = dirtable[i*FILES_ENTRY_SIZE+LINK_BYTE_OFFSET]; + } + i++; + } + + print("file: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print("\n", BIOS_WHITE); + + if (link_status == HARDLINK_ENTRY) { + print("type : ", BIOS_WHITE); + print("hardlink\n", BIOS_LIGHT_RED); + } + else if (link_status == SOFTLINK_ENTRY) { + print("type : ", BIOS_WHITE); + print("softlink\n", BIOS_LIGHT_CYAN); + // Get linked file / folder with recursion depth limit 16 + i = 0; + // TODO : Extra, currently only single softlink depth supported + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+target_entry_byte*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + target_parent_byte = dirtable[target_entry_byte*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET]; + target_entry_byte = dirtable[target_entry_byte*FILES_ENTRY_SIZE + ENTRY_BYTE_OFFSET]; + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, filename_buffer, &returncode_src, target_parent_byte); + // Needed to compare due _mash_cache always filling empty space + // Implying softlink to _mash_cache is not available + if (!strcmp(filename_buffer, "_mash_cache")) + target_entry_byte = EMPTY_FILES_ENTRY; + } + + if (returncode_src == 0 && target_entry_byte != EMPTY_FILES_ENTRY) { + if (target_entry_byte != FOLDER_ENTRY) { + if (isBinaryFileMagicNumber(file_read)) { + print("type : ", BIOS_WHITE); + print("binary executable\n", BIOS_LIGHT_GREEN); + } + else if (isTextCharOnly(file_read)) + print("type : text\n", BIOS_WHITE); + else + print("type : file\n", BIOS_WHITE); + + clear(string_byte_count, 32); + clear(string_disk_byte_count, 32); + inttostr(string_byte_count, strlenbin(file_read) - 5); + print("file size : ", BIOS_WHITE); + print(string_byte_count, BIOS_WHITE); + + directSectorRead(sectors_buf, SECTORS_SECTOR); + i = 0; + sectors_byte_count = 0; + while (i < SECTORS_ENTRY_SIZE) { + if (sectors_buf[target_entry_byte*SECTORS_ENTRY_SIZE+i] != FILLED_EMPTY_SECTORS_BYTE) + sectors_byte_count++; + i++; + } + + print(" bytes\ndisk size : ", BIOS_WHITE); + inttostr(string_disk_byte_count, sectors_byte_count*SECTOR_SIZE); + print(string_disk_byte_count, BIOS_WHITE); + print(" bytes\n", BIOS_WHITE); + } + else { + print("type : folder\n", BIOS_WHITE); + } + } + else { + print("file: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print(" softlink broken\n", BIOS_WHITE); + } + + } + else { + print("file: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print(" not found\n", BIOS_WHITE); + } + + + } +} diff --git a/src/kernel-header/config.h b/src/kernel-header/config.h index c4f52ab..f394016 100644 --- a/src/kernel-header/config.h +++ b/src/kernel-header/config.h @@ -14,6 +14,7 @@ #define CHAR_DOUBLE_QUOTE 0x22 #define CHAR_SINGLE_QUOTE 0x27 #define CHAR_SLASH 0x2F +#define CHAR_TILDE 0x7E // BIOS Scancodes #define SCANCODE_RIGHT_ARROW 0x4D @@ -56,8 +57,11 @@ // Kernel Maximum Size, if changed ensure dd commands in makefile, // bootloader.asm, and fscreator set properly -#define KERNEL_SECTOR_SIZE 31 +#define KERNEL_SECTOR_SIZE 16 +// Logo filename, put file on ROOT_PARENT_FOLDER +#define LOGO_FILENAME "logo.hoho" +#define EMPTY_CACHE "_NULL" // Macro for filesystem syscalls // Filesytem location @@ -81,11 +85,18 @@ #define FILLED_MAP_ENTRY 0xFF // If sector are filled // Flags in files filesystem +// Structure, +// P | S | Filename | L (optional) +// 1 | 1 | 14 or 13 | 0 or 1 #define ROOT_PARENT_FOLDER 0xFF // Flag for "P" byte +#define BIN_PARENT_FOLDER 0x00 // Flag for "P" byte #define EMPTY_FILES_ENTRY 0xFE // Flag for "S" byte #define FOLDER_ENTRY 0xFF // Flag for "S" byte +#define SOFTLINK_ENTRY 0xFD // Flag for "L" byte +#define HARDLINK_ENTRY 0xFC // Flag for "L" byte #define PARENT_BYTE_OFFSET 0x0 // "P" byte, parent folder index #define ENTRY_BYTE_OFFSET 0x1 // "S" byte, entry index at sectors filesystem +#define LINK_BYTE_OFFSET 0xF // "L" byte, link type #define PATHNAME_BYTE_OFFSET 0x2 // 14 bytes, filled with pathnames // Predefined values in sectors filesystem diff --git a/src/kernel-header/kernel.h b/src/kernel-header/kernel.h index 06ef502..0c62603 100644 --- a/src/kernel-header/kernel.h +++ b/src/kernel-header/kernel.h @@ -13,6 +13,7 @@ extern void putInMemory(int segment, int address, char character); extern void makeInterrupt21(); extern int interrupt(int number, int AX, int BX, int CX, int DX); +extern void launchProgram(int segment); // External procedure call extern void shell(); @@ -46,6 +47,7 @@ void readFile(char *buffer, char *path, int *result, char parentIndex); void writeFile(char *buffer, char *path, int *sectors, char parentIndex); // Writing file with relative path // WARNING : writeFile() will treat buffer as stream of binary +// WARNING : writeFile() will stop if and only if writeFile() found 5 consecutive null terminator // -- Error code list -- // 0 - Exit successfully // -1 - File exists @@ -58,3 +60,17 @@ void writeFile(char *buffer, char *path, int *sectors, char parentIndex); // sectors will be used as error code container // parentIndex used as "P" byte value / parent index at files filesystem entry // If buffer == NULL, creating folder instead file + +void deleteFile(char *path, int *returncode, char parentIndex); +// Delete file with relative path +// -- Error code list -- +// 1 - Exit successfully, deleted object is folder +// 0 - Exit successfully, deleted object is file +// -1 - File not found +// -- deleteFile() services -- +// path is filename, only maximum 14 char +// parentIndex used as "P" byte value / parent index at files filesystem entry +// Will delete both file and folder + +void executeProgram(char *filename, int segment, int *success, char parentIndex); +// Executing program from file diff --git a/src/kernel.c b/src/kernel.c index eb5bc5a..eb48e54 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -9,21 +9,23 @@ #include "kernel-header/kernel.h" #include "kernel-header/output.h" #include "kernel-header/screen.h" -#include "basic-header/opr.h" +#include "basic-header/std_opr.h" #include "std-header/boolean.h" -#include "std-header/std.h" +#include "std-header/std_fileio.h" +#include "std-header/std_stringio.h" int main() { // Setup // DEBUG - // char buf[SECTOR_SIZE]; - // int t; + int ret_code; + char buf[SECTOR_SIZE*SECTORS_ENTRY_SIZE]; + clear(buf, SECTOR_SIZE*SECTORS_ENTRY_SIZE); makeInterrupt21(); // Initial screen clearScreen(); // DEBUG - drawBootLogo(); // Note : drawBootLogo() does not revert video mode + drawBootLogo(buf); // Note : drawBootLogo() does not revert video mode // Change video mode and spawn shell interrupt(0x10, 0x0003, 0, 0, 0); @@ -38,11 +40,11 @@ int main() { // |--> not_a_file // this_is_file // folder 2 - // writeFile(FOLDER, "folder 1", &t, ROOT_PARENT_FOLDER); - // writeFile(FOLDER, "folder 2", &t, ROOT_PARENT_FOLDER); - // writeFile(FOLDER, "inside f1", &t, 0); - // writeFile(FOLDER, "another f1", &t, 0); - // writeFile(FOLDER, "in in f1", &t, 2); + // writeFile(FOLDER, "folder 1", &ret_code, ROOT_PARENT_FOLDER); + // writeFile(FOLDER, "folder 2", &ret_code, ROOT_PARENT_FOLDER); + // writeFile(FOLDER, "inside f1", &ret_code, 0); + // writeFile(FOLDER, "another f1", &ret_code, 0); + // writeFile(FOLDER, "in in f1", &ret_code, 2); // // strtobytes(buf, "ezhd or hddt", SECTOR_SIZE); // writeFile(buf, "this_is_file", &t, ROOT_PARENT_FOLDER); @@ -50,7 +52,25 @@ int main() { // writeFile(buf, "not_a_file", &t, 0); // writeFile(FOLDER, "ok", &t, 0); - shell(); + // Check if /bin exists or not, if not create new + readFile(buf, "bin", &ret_code, ROOT_PARENT_FOLDER); + if (ret_code == -1) + writeFile(CHAR_NULL, "bin", &ret_code, ROOT_PARENT_FOLDER); + + // Check if _mash_cache exist, if exists delete old record + readFile(buf, "_mash_cache\0\0\0", &ret_code, ROOT_PARENT_FOLDER); + if (ret_code == 0) + deleteFile("_mash_cache\0\0\0", &ret_code, ROOT_PARENT_FOLDER); + + clear(buf, SECTOR_SIZE*SECTORS_ENTRY_SIZE); + strcpybounded(buf, EMPTY_CACHE, 32); + writeFile(buf, "_mash_cache", &ret_code, ROOT_PARENT_FOLDER); + + // Shell executing + executeProgram("mash", 0x2000, &ret_code, BIN_PARENT_FOLDER); + if (ret_code == -1) + print("mash shell not found in bin/", BIOS_LIGHT_RED); + while (true); } @@ -69,6 +89,9 @@ void handleInterrupt21(int AX, int BX, int CX, int DX) { case 0x2: scrollScreenSingleRow(); break; + case 0x3: + clearScreen(); + break; } break; case 0x1: @@ -105,6 +128,12 @@ void handleInterrupt21(int AX, int BX, int CX, int DX) { case 0x5: writeFile(BX, CX, DX, AH); break; + case 0x6: + executeProgram(BX, CX, DX, AH); + break; + case 0x7: + deleteFile(BX, CX, DX); + break; default: printString("Invalid interrupt\n"); } @@ -222,11 +251,11 @@ void readFile(char *buffer, char *path, int *result, char parentIndex) { if (files_buf[i][j+PARENT_BYTE_OFFSET] == parentIndex) { // Needed buffer because entry may ignoring null terminator clear(filename_buffer, 16); - strcpybounded(filename_buffer, files_buf[i]+j+PATHNAME_BYTE_OFFSET, 14); + memcpy(filename_buffer, files_buf[i]+j+PATHNAME_BYTE_OFFSET, 14); if (!strcmp(path, filename_buffer)) { is_filename_match_found = true; sectors_entry_idx = files_buf[i][j+ENTRY_BYTE_OFFSET]; - if (files_buf[i][j*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET] == FOLDER_ENTRY) + if (files_buf[i][j+ENTRY_BYTE_OFFSET] == FOLDER_ENTRY) // FIXME : Check again is_type_is_file = false; } } @@ -244,8 +273,8 @@ void readFile(char *buffer, char *path, int *result, char parentIndex) { while (i < SECTORS_ENTRY_SIZE && sector_read_target != FILLED_EMPTY_SECTORS_BYTE) { clear(file_segment_buffer, SECTOR_SIZE); readSector(file_segment_buffer, sector_read_target); - strcpybounded((buffer+i*SECTOR_SIZE), file_segment_buffer, SECTOR_SIZE); - // memcpy((buffer+i*SECTOR_SIZE), file_segment_buffer, SECTOR_SIZE); // FIXME : Extra, if fixing read binary file use memcpy + // strcpybounded((buffer+i*SECTOR_SIZE), file_segment_buffer, SECTOR_SIZE); + memcpy((buffer+i*SECTOR_SIZE), file_segment_buffer, SECTOR_SIZE); // FIXME : Extra, if fixing read binary file use memcpy i++; sector_read_target = sectors_buf[sectors_entry_idx*SECTORS_ENTRY_SIZE + i]; } @@ -308,7 +337,7 @@ void writeFile(char *buffer, char *path, int *sectors, char parentIndex) { if (files_buf[i][j+PARENT_BYTE_OFFSET] == parentIndex) { // Needed buffer because entry may ignoring null terminator clear(filename_buffer, 16); - strcpybounded(filename_buffer, files_buf[i]+j+PATHNAME_BYTE_OFFSET, 14); + memcpy(filename_buffer, files_buf[i]+j+PATHNAME_BYTE_OFFSET, 14); if (!strcmp(path, filename_buffer)) valid_filename = false; } @@ -338,7 +367,7 @@ void writeFile(char *buffer, char *path, int *sectors, char parentIndex) { if (is_empty_dir_exist && valid_parent_folder && valid_filename) { // Updating files filesystem buffer files_buf[f_entry_sector_idx][f_entry_idx+PARENT_BYTE_OFFSET] = parentIndex; - rawstrcpy((files_buf[f_entry_sector_idx]+f_entry_idx+PATHNAME_BYTE_OFFSET), path); + memcpy((files_buf[f_entry_sector_idx]+f_entry_idx+PATHNAME_BYTE_OFFSET), path, 14); // ----------- Folder Writing Branch----------- // Folder writing does not need to readSector() sectors and map @@ -354,8 +383,8 @@ void writeFile(char *buffer, char *path, int *sectors, char parentIndex) { if (buffer_type_is_file) { readSector(map_buf, MAP_SECTOR); i = 0; - buffer_size = strlen(buffer); // In bytes, - // FIXME : Extra, due to strlen() stop at null byte, it cannot write in pure binary mode + buffer_size = strlenbin(buffer); // In bytes, + // WARNING : strlenbin only stop if found n-consecutive null terminator, may cause some problem while (i < (SECTOR_SIZE >> 1) && !is_enough_sector) { // Finding empty sector in map if (map_buf[i] == EMPTY_MAP_ENTRY) @@ -460,4 +489,113 @@ void writeFile(char *buffer, char *path, int *sectors, char parentIndex) { (*sectors) = 0; } +void deleteFile(char *path, int *returncode, char parentIndex) { + // TODO : Extra, Extra, Extra, use multidimensional array damnit + char files_buf[2][SECTOR_SIZE], map_buf[SECTOR_SIZE], sectors_buf[SECTOR_SIZE]; // Filesystem buffer + char file_segment_buffer[SECTOR_SIZE]; + char filename_buffer[16]; + int i = 0, j = 0; + int sectors_entry_idx = 0, sector_read_target = 0, files_entry_idx = 0; + int files_entry_sector_idx = 0; + bool valid_parent_folder = true, is_filename_match_found = false, valid_filename_length = true; + bool is_type_is_file = true; + + readSector(files_buf[0], FILES_SECTOR); + readSector(files_buf[1], FILES_SECTOR + 1); + + // Filename length check + if (strlen(path) > 14) + valid_filename_length = false; + + // Find matching filename + if (valid_filename_length) { + while (i < 2 && !is_filename_match_found) { + j = 0; + while (j < SECTOR_SIZE && !is_filename_match_found) { + // Checking existing filename in same parent folder + if (files_buf[i][j+PARENT_BYTE_OFFSET] == parentIndex) { + // Needed buffer because entry may ignoring null terminator + clear(filename_buffer, 16); + strcpybounded(filename_buffer, files_buf[i]+j+PATHNAME_BYTE_OFFSET, 14); + if (!strcmp(path, filename_buffer)) { + is_filename_match_found = true; + sectors_entry_idx = files_buf[i][j+ENTRY_BYTE_OFFSET]; + files_entry_sector_idx = i; + files_entry_idx = j; + if (files_buf[i][j*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET] == FOLDER_ENTRY) + is_type_is_file = false; + } + } + j += FILES_ENTRY_SIZE; + } + i++; + } + } + + if (is_filename_match_found) { + if (is_type_is_file) { + i = 0; + // Deleting entry on files filesystem + files_buf[files_entry_sector_idx][files_entry_idx + ENTRY_BYTE_OFFSET] = EMPTY_FILES_ENTRY; + files_buf[files_entry_sector_idx][files_entry_idx + PARENT_BYTE_OFFSET] = ROOT_PARENT_FOLDER; + while (i < 14) { + files_buf[files_entry_sector_idx][files_entry_idx + PATHNAME_BYTE_OFFSET + i] = '\0'; + i++; + } + + readSector(sectors_buf, SECTORS_SECTOR); + readSector(map_buf, MAP_SECTOR); + + i = 0; + sector_read_target = sectors_buf[sectors_entry_idx*SECTORS_ENTRY_SIZE + i]; + // Deleting entry on sectors and map filesystem + while (i < SECTORS_ENTRY_SIZE) { + if (sector_read_target > KERNEL_SECTOR_SIZE) + map_buf[sector_read_target] = EMPTY_MAP_ENTRY; + sectors_buf[sectors_entry_idx*SECTORS_ENTRY_SIZE + i] = EMPTY_SECTORS_ENTRY; + i++; + sector_read_target = sectors_buf[sectors_entry_idx*SECTORS_ENTRY_SIZE + i]; + } + } + + // Filesystem records update + writeSector(files_buf[0], FILES_SECTOR); + writeSector(files_buf[1], FILES_SECTOR + 1); + if (is_type_is_file) { + writeSector(map_buf, MAP_SECTOR); + writeSector(sectors_buf, SECTORS_SECTOR); + } + } + + + + + // Error code writing + if (!is_filename_match_found) + (*returncode) = -1; + else if (is_type_is_file) + (*returncode) = 0; + else + (*returncode) = 1; +} + +void executeProgram(char *filename, int segment, int *success, char parentIndex) { + // Buat buffer + int return_code; + int i = 0; + char fileBuffer[SECTOR_SIZE*SECTORS_ENTRY_SIZE]; + // Buka file dengan readFile + clear(fileBuffer, SECTOR_SIZE*SECTORS_ENTRY_SIZE); + readFile(&fileBuffer, filename, &return_code, parentIndex); + // If success, salin dengan putInMemory + if (return_code == 0) { + // launchProgram + for (i = 0; i < SECTOR_SIZE*SECTORS_ENTRY_SIZE; i++) + putInMemory(segment, i, fileBuffer[i]); + launchProgram(segment); + } + else + *success = -1; +} + // FIXME : Extra, softlink ln can cause many weird behavior with commands other than readFile and cat diff --git a/src/ln.c b/src/ln.c new file mode 100644 index 0000000..ef4e224 --- /dev/null +++ b/src/ln.c @@ -0,0 +1,229 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" +#include "std-header/boolean.h" + +// Available parameter +// -s , create softlink, currently cd not supporting softlink + +void ln(char *dirtable, char current_dir_index, char flags, char *target, char *linkname); + +int main() { + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char arg_vector[ARGC_MAX][ARG_LENGTH]; + char argc = 0; + int current_dir_index; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(arg_vector, ARGC_MAX*ARG_LENGTH); + memcpy(arg_vector[0], shell_cache+ARGV_OFFSET, ARG_LENGTH); + memcpy(arg_vector[1], shell_cache+ARGV_2_OFFSET, ARG_LENGTH); + memcpy(arg_vector[2], shell_cache+ARGV_3_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + current_dir_index = shell_cache[CURRENT_DIR_CACHE_OFFSET]; + + // Argument count + if (argc == 2 && !strcmp("--help", arg_vector[0])) { + print("Utility to create a hard link or a symbolic link (symlink)\n to an existing file or directory\n", BIOS_WHITE); + print("Possible Usage:\n", BIOS_LIGHT_BLUE); + print("ln [source_directory] [destination_directory]\n", BIOS_LIGHT_CYAN); + print("ln -s [source_directory] [destination_directory]\n", BIOS_LIGHT_CYAN); + } + else if (argc >= 3) { + if (!strcmp("-s", arg_vector[0])) { + print("ln: softlink mode\n", BIOS_WHITE); + ln(directory_table, current_dir_index, 1, arg_vector[1], arg_vector[2]); + } + else + ln(directory_table, current_dir_index, 0, arg_vector[0], arg_vector[1]); + } + else + print("Usage : ln [-s] \n", BIOS_WHITE); + + setShellCache(shell_cache); + shellReturn(); +} + +void ln(char *dirtable, char current_dir_index, char flags, char *target, char *linkname) { + // Technically just "copy" of previous implementation of ln + // char as string / char + char filename_buffer[16]; + char source_directory_name[16]; + char copied_directory_name[16]; + // char as 1 byte integer + char file_read[FILE_SIZE_MAXIMUM]; + char target_entry_byte = 0; + char source_dir_idx; + char copied_dir_idx; + char link_status; + char parent_entry_byte; + char parent_files_index; + int returncode_src = 0; + int returncode_cpy = 0; + bool is_write_success = false, valid_filename = true; + bool f_target_found = false, empty_entry_found = false; + bool is_found_parent = false; + bool is_found_empty = false; + bool is_hardlink_file = true; + int i = 0, j = 0; + int f_entry_idx = 0; + int f_entry_sector_idx = 0; + int last_slash_index; + + + // Relative pathing + clear(source_directory_name, 16); + clear(copied_directory_name, 16); + // Split target / source + last_slash_index = getLastMatchedCharIdx(CHAR_SLASH, target); + // FIXME : Extra, unsafe getlast + if (last_slash_index != -1) { + // Split argument to path and filename + // Get path + strcpybounded(source_directory_name, target, last_slash_index); + source_dir_idx = directoryEvaluator(dirtable, source_directory_name, &returncode_src, current_dir_index); + + // Get filename + strcpybounded(source_directory_name, target+last_slash_index+1, ARG_LENGTH-last_slash_index-1); + } + else { + // Cut slash + strcpybounded(source_directory_name, target, ARG_LENGTH); + + source_dir_idx = current_dir_index; + returncode_src = 0; + } + + // Split destination / copied + last_slash_index = getLastMatchedCharIdx(CHAR_SLASH, linkname); + // FIXME : Extra, unsafe getlast + if (last_slash_index != -1) { + // Split argument to path and filename + // Get path + strcpybounded(copied_directory_name, linkname, last_slash_index); + copied_dir_idx = directoryEvaluator(dirtable, copied_directory_name, &returncode_cpy, current_dir_index); + + // Get filename + strcpybounded(copied_directory_name, linkname+last_slash_index+1, ARG_LENGTH-last_slash_index-1); + } + else { + // Cut slash + strcpybounded(copied_directory_name, linkname, ARG_LENGTH); + + copied_dir_idx = current_dir_index; + returncode_src = 0; + } + + + // Copying file if path evaluation success + if (returncode_src == -1) { + print("ln: ", BIOS_GRAY); + print(target, BIOS_GRAY); + print(": target not found\n", BIOS_GRAY); + } + else if (returncode_cpy == -1) { + print("ln: ", BIOS_GRAY); + print(copied_directory_name, BIOS_GRAY); + print(": path not found\n", BIOS_GRAY); + } + else { + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, copied_directory_name, &returncode_cpy, copied_dir_idx); + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, source_directory_name, &returncode_src, source_dir_idx); + if (returncode_src == 0 && returncode_cpy == -1) { + if (flags == 1) + link_status = SOFTLINK_ENTRY; + else { + if (file_read[0] == NULL) { + print("ln: ", BIOS_GRAY); + print(source_directory_name, BIOS_GRAY); + print(": cannot hardlink folder\n", BIOS_GRAY); + is_hardlink_file = false; + returncode_src = -1; + } + else + link_status = HARDLINK_ENTRY; + } + + // Find parent S byte + i = 0; + while (i < FILES_ENTRY_COUNT && !is_found_parent) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, 14); + if (dirtable[i*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET] == source_dir_idx && + !strcmp(source_directory_name, filename_buffer)) { + is_found_parent = true; + parent_entry_byte = dirtable[i*FILES_ENTRY_SIZE + ENTRY_BYTE_OFFSET]; + parent_files_index = i; + } + i++; + } + + // Find empty files entry + i = 0; + while (i < FILES_ENTRY_COUNT && !is_found_empty && is_found_parent) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, 14); + if (dirtable[i*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET] == ROOT_PARENT_FOLDER && + dirtable[i*FILES_ENTRY_SIZE + ENTRY_BYTE_OFFSET] == EMPTY_FILES_ENTRY) { + is_found_empty = true; + // Put P and filename + dirtable[i*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET] = copied_dir_idx; + memcpy(dirtable+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, copied_directory_name, 14); + dirtable[i*FILES_ENTRY_SIZE+LINK_BYTE_OFFSET] = link_status; + // Put S byte + if (flags == 0) + dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET] = parent_entry_byte; + else + dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET] = parent_files_index; + } + i++; + } + + + if (!is_found_parent) { + print("ln: searching parent ", BIOS_WHITE); + print(target, BIOS_WHITE); + print(" error\n", BIOS_WHITE); + returncode_cpy = -1; + } + else if (!is_found_empty) { + print("ln: searching empty space for ", BIOS_WHITE); + print(linkname, BIOS_WHITE); + print(" error\n", BIOS_WHITE); + returncode_cpy = -1; + } + else if (is_hardlink_file) { + // Updating directory table + directSectorWrite(dirtable, FILES_SECTOR); + directSectorWrite(dirtable+SECTOR_SIZE, FILES_SECTOR+1); + } + + } + else if (returncode_src == -1) { + print("ln: error: ", BIOS_WHITE); + print(target, BIOS_WHITE); + print(" not found\n", BIOS_WHITE); + returncode_src = -1; + } + else if (returncode_cpy == 0) { + print("ln: error: ", BIOS_WHITE); + print(linkname, BIOS_WHITE); + print(" exist\n", BIOS_WHITE); + returncode_cpy = 0; + } + + if (returncode_src == 0 && returncode_cpy == -1) { + print(linkname, BIOS_GRAY); + print(": link created\n", BIOS_GRAY); + } + else + print("ln: file writing error\n", BIOS_GRAY); + } +} diff --git a/src/ls.c b/src/ls.c new file mode 100644 index 0000000..05f3abe --- /dev/null +++ b/src/ls.c @@ -0,0 +1,100 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" + +void ls(char *dirtable, char target_dir); + +int main() { + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char temp; + int returncode = -1, target_directory; + char dirstr[BUFFER_SIZE]; + char argc = 0; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(dirstr, BUFFER_SIZE); + memcpy(dirstr, shell_cache+ARGV_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + + if (argc == 1 || argc == 2) { + if (argc == 2) { + if (!strcmp("--help", dirstr)) { + print("ls:\n", BIOS_WHITE); + print("blue ", BIOS_LIGHT_BLUE); + print(": folder\n", BIOS_WHITE); + print("green ", BIOS_LIGHT_GREEN); + print(": file\n", BIOS_WHITE); + print("red ", BIOS_LIGHT_RED); + print(": hardlink\n", BIOS_WHITE); + print("cyan ", BIOS_LIGHT_CYAN); + print(": softlink\n", BIOS_WHITE); + returncode = 2; + } + else + target_directory = directoryEvaluator(directory_table, dirstr, &returncode, shell_cache[CURRENT_DIR_CACHE_OFFSET]); + } + else { + target_directory = shell_cache[CURRENT_DIR_CACHE_OFFSET]; + returncode = 0; + } + + if (returncode == 0) + ls(directory_table, target_directory); + else if (returncode == 1) + print("ls: target is file\n", BIOS_WHITE); + else if (returncode != 2) + print("ls: path not found\n", BIOS_WHITE); + } + else + print("Usage : ls [--help, directory]\n", BIOS_WHITE); + + setShellCache(shell_cache); + shellReturn(); +} + +void ls(char *dirtable, char target_dir) { + int i = 0; + // char as string / char + char filename_buffer[16]; + // Use char as 1 byte integer + char parent_byte_entry, entry_byte_entry; + char print_color; + char link_byte_entry; + while (i < FILES_ENTRY_COUNT) { + if (getKeyboardCursor(0) > 50) + print("\n", BIOS_WHITE); + + parent_byte_entry = dirtable[FILES_ENTRY_SIZE*i+PARENT_BYTE_OFFSET]; + entry_byte_entry = dirtable[FILES_ENTRY_SIZE*i+ENTRY_BYTE_OFFSET]; + link_byte_entry = dirtable[FILES_ENTRY_SIZE*i+LINK_BYTE_OFFSET]; + if (parent_byte_entry == target_dir && entry_byte_entry != EMPTY_FILES_ENTRY) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, 14); + + if (entry_byte_entry == FOLDER_ENTRY) + print_color = BIOS_LIGHT_BLUE; + else if (link_byte_entry == SOFTLINK_ENTRY) + print_color = BIOS_LIGHT_CYAN; + else if (link_byte_entry == HARDLINK_ENTRY) + print_color = BIOS_LIGHT_RED; + else + print_color = BIOS_LIGHT_GREEN; + + if (isCharInString(CHAR_SPACE, filename_buffer)) { + print("\"", BIOS_GRAY); + print(filename_buffer, print_color); + print("\"", BIOS_GRAY); + } + else + print(filename_buffer, print_color); + print(" ", BIOS_WHITE); + } + i++; + } + print("\n", BIOS_WHITE); +} diff --git a/src/mash.c b/src/mash.c new file mode 100644 index 0000000..0922e31 --- /dev/null +++ b/src/mash.c @@ -0,0 +1,535 @@ +#include "std-header/std_fileio.h" +#include "std-header/std_stringio.h" +#include "basic-header/std_opr.h" +#include "kernel-header/config.h" +#include "std-header/boolean.h" +#include "shell-header/shell_common.h" + +void shell(); + +// Shell convention +// cache 0-0xF reserved for argv passing and shell state +// cache[0xF] used as current working directory +// cache 1-0xF will filled with evaluated argv +// cache 0x10-0x4F, 0x50-0x8F, 0x90-0xCF, 0xD0-0x10F, 0x110-0x14F +// used as shell history +// rest of cache used as argv + +// BIOS_LIGHT_BLUE indicate folder +// BIOS_LIGHT_GREEN indicate file +// BIOS_LIGHT_CYAN indicate softlink +// BIOS_LIGHT_RED indicate hardlink + +// CTRL + F / find Activate autocompletion for adding directory +// autocomplete for arbitrary commands + +int main() { + char cache_buffer[SECTOR_SIZE]; + int returncode; + // Cache reading + clear(cache_buffer, SECTOR_SIZE); + getShellCache(cache_buffer); + showKeyboardCursor(); + + // Empty cache case + if (!forcestrcmp(EMPTY_CACHE, cache_buffer)) { + clear(cache_buffer, SECTOR_SIZE); + cache_buffer[CURRENT_DIR_CACHE_OFFSET] = ROOT_PARENT_FOLDER; + cache_buffer[CACHE_SIGNATURE_OFFSET] = CACHE_SIGNATURE; + } + + setShellCache(cache_buffer); + shell(cache_buffer); + while (1); +} + +void directoryStringBuilder(char *string, char *dirtable, char current_dir) { + // Use as string / char + char filename_buffer[16]; + // Use as 1 bytes integer + char current_parent = 0, parent[FILES_ENTRY_COUNT]; + // parent will contain indices in reversed order + int i = 0, parent_length = 0; + if (current_dir == ROOT_PARENT_FOLDER) + string[0] = '/'; + else { + clear(parent, FILES_ENTRY_COUNT); + // Traversing folder until reaching root + current_parent = dirtable[current_dir*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET]; + while (current_parent != ROOT_PARENT_FOLDER) { + parent[parent_length] = current_parent; + parent_length++; + current_parent = dirtable[current_parent*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET]; + } + + // Adding lower parent + i = parent_length - 1; + while (i >= 0) { + strapp(string, "/"); + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+(parent[i]*FILES_ENTRY_SIZE)+PATHNAME_BYTE_OFFSET, 14); + strapp(string, filename_buffer); + + i--; + } + + // Adding topmost parent + strapp(string, "/"); + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+current_dir*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + strapp(string, filename_buffer); + } +} + +void shellInput(char *commands_history, char *dirtable, char current_dir) { + // char as string + char string[BUFFER_SIZE]; + char move_string_buffer_1[BUFFER_SIZE]; + char move_string_buffer_2[BUFFER_SIZE]; + char arg_vector[ARGC_MAX][ARG_LENGTH]; + char temp_eval[ARGC_MAX*ARG_LENGTH]; + char to_be_completed[ARGC_MAX*ARG_LENGTH]; + char filename_buffer[16]; + // char as 1 byte integer + char c, scancode; + int i = 0, j = 0, max_i = 0, rawKey, dbg = 0; + int split_i, split_j, split_k; + int selected_his_idx = 0, current_eval_idx = 0; + int savedCursorRow = getKeyboardCursor(1); + int savedCursorCol = getKeyboardCursor(0); + bool is_modified = false, is_autocomplete_available = false; + bool is_between_quote_mark = false, autocomplete_found = false; + int argc = 0, returncode = 0, matched_idx = 0; + int target_copy_arg_idx; + showKeyboardCursor(); + + // Move history up + strcpybounded(move_string_buffer_1, commands_history, BUFFER_SIZE - 1); + while (i < MAX_HISTORY - 1) { + strcpybounded(move_string_buffer_2, commands_history+BUFFER_SIZE*(i+1), BUFFER_SIZE - 1); + strcpybounded(commands_history+BUFFER_SIZE*(i+1), move_string_buffer_1, BUFFER_SIZE - 1); + strcpybounded(move_string_buffer_1, move_string_buffer_2, BUFFER_SIZE - 1); + i++; + } + clear(commands_history, BUFFER_SIZE); // Delete first entry + + i = 0; + selected_his_idx = 0; + do { + rawKey = getFullKey(); + c = rawKey & 0xFF; // AL Value + scancode = rawKey >> 8; // AH Value + // WARNING : Prioritizing ASCII before scancode + switch (c) { + case CHAR_INPUT_NEWLINE: + break; + case CHAR_BACKSPACE: + is_modified = true; + // If i is not at starting input pos, decrement + if (i > 0) + i--; + + // Shift copy from deleted index + j = i; + while (j < max_i) { + string[j] = string[j + 1]; + j++; + } + + // If buffer not empty, decrement size by 1 + if (max_i > 0) + max_i--; + + string[max_i] = CHAR_SPACE; // For deleting last char + string[max_i+1] = CHAR_NULL; + setKeyboardCursor(savedCursorRow, savedCursorCol); + print(string, BIOS_GRAY); + + setKeyboardCursor(savedCursorRow, savedCursorCol + i); + break; + default: + // If char (AL) is not ASCII Control codes, check scancode (AH) + switch (scancode) { + case SCANCODE_TAB: + // Note : Currently autocomplete not available for inside quote + // Part 1: command identification + // TODO : Extra, need strsplit so badly :( + // TODO : Extra, Extra, sometimes print failed (?) + // Arguments splitting + // Temporary cut string + string[max_i] = CHAR_NULL; + argc = 0; + clear(arg_vector, ARGC_MAX*ARG_LENGTH); + is_between_quote_mark = false; + split_i = 0; + split_j = 0; + split_k = 0; + + while (string[split_i] != CHAR_NULL) { + // TODO : Extra, Extra, mixing double and single quote + // If found space in commands and not within double quote mark, make new + if (string[split_i] == CHAR_SPACE && split_j < ARGC_MAX && !is_between_quote_mark) { + split_k = 0; + split_j++; + } + else if (string[split_i] == CHAR_DOUBLE_QUOTE) { + // Toggling is_between_quote_mark + is_between_quote_mark = !is_between_quote_mark; + } + else { + // Only copy if char is not double quote + // and space outside double quote + arg_vector[split_j][split_k] = string[split_i]; + split_k++; + } + + split_i++; + } + argc = split_j + 1; // Due split_j is between counting space between 2 args + + is_autocomplete_available = false; + // ------ Activate autocompletion feature here ------ + if (argc == 4 && + ( isLastSubstring(arg_vector[0], "cp") || isLastSubstring(arg_vector[0], "mv") + || isLastSubstring(arg_vector[0], "ln")) + ) { + // Fourth arg autocomplete + target_copy_arg_idx = 3; + is_autocomplete_available = true; + } + else if (argc == 3 && + ( isLastSubstring(arg_vector[0], "cp") || isLastSubstring(arg_vector[0], "mv") + || isLastSubstring(arg_vector[0], "ln") || isLastSubstring(arg_vector[0], "rm")) + ) { + // Third arg autocomplete + target_copy_arg_idx = 2; + is_autocomplete_available = true; + } + else if (isLastSubstring(arg_vector[0], "ls") || isLastSubstring(arg_vector[0], "cat") + || isLastSubstring(arg_vector[0], "cd") || isLastSubstring(arg_vector[0], "cp") + || isLastSubstring(arg_vector[0], "mv") || isLastSubstring(arg_vector[0], "ln") + || isLastSubstring(arg_vector[0], "rm") || isLastSubstring(arg_vector[0], "file") + || isLastSubstring(arg_vector[0], "wc")) { + // Second arg autocomplete + target_copy_arg_idx = 1; + is_autocomplete_available = true; + } + else if (!forcestrcmp("./", arg_vector[0]) && argc == 1) { + // First arg autocomplete + target_copy_arg_idx = 0; + is_autocomplete_available = true; + } + + if (!is_between_quote_mark && is_autocomplete_available) { + // Part 2: current index evaluation + current_eval_idx = current_dir; + matched_idx = getLastMatchedCharIdx(CHAR_SLASH, arg_vector[target_copy_arg_idx]); + // If argv[1] is only single name, use original dir + if (matched_idx != -1) { + clear(temp_eval,ARGC_MAX*ARG_LENGTH); + strcpybounded(temp_eval, arg_vector[target_copy_arg_idx], matched_idx); + current_eval_idx = directoryEvaluator(dirtable, temp_eval, &returncode, current_dir); + } + + + // Part 3: command autocompletion + // "To be completed" command (ex. cat mnt/abc/pqr -> pqr) + clear(to_be_completed, ARGC_MAX*ARG_LENGTH); + strcpy(to_be_completed, arg_vector[target_copy_arg_idx]+matched_idx+1); + // Searching from directory table + autocomplete_found = false; + split_i = 0; + while (split_i < FILES_ENTRY_COUNT && !autocomplete_found) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+FILES_ENTRY_SIZE*split_i+PATHNAME_BYTE_OFFSET, 14); + if (current_eval_idx == dirtable[FILES_ENTRY_SIZE*split_i+PARENT_BYTE_OFFSET]) { + // Partial string comparation + split_j = 0; + autocomplete_found = true; + // Set autocomplete_found as found, if string comparation below failed + // cancel searching status to not found + while (to_be_completed[split_j] != CHAR_NULL && autocomplete_found) { + if (to_be_completed[split_j] != filename_buffer[split_j]) + autocomplete_found = false; + split_j++; + } + } + split_i++; + } + + if (autocomplete_found) { + if (matched_idx != -1) { + // If using relative pathing, then find last slash location and insert completion + strcpy(string+getLastMatchedCharIdx(CHAR_SLASH, string)+1, filename_buffer); + } + else { + // Autocomplete for n-arg + // If not using relative pathing, use space as insertion location + strcpy(string+getLastMatchedCharIdx(CHAR_SPACE, string)+1, filename_buffer); + } + } + + // Autocomplete printing + setKeyboardCursor(savedCursorRow, savedCursorCol); + print(" ", BIOS_GRAY); + setKeyboardCursor(savedCursorRow, savedCursorCol); + + // Change proper i and max_i values + i = strlen(string); + max_i = i; + + print(string, BIOS_GRAY); + } + break; + case SCANCODE_DOWN_ARROW: + case SCANCODE_UP_ARROW: + if (scancode == SCANCODE_DOWN_ARROW && selected_his_idx > 0) + selected_his_idx--; + else if (scancode == SCANCODE_UP_ARROW && selected_his_idx < MAX_HISTORY - 1) + selected_his_idx++; + + setKeyboardCursor(savedCursorRow, savedCursorCol); + print(" ", BIOS_GRAY); + setKeyboardCursor(savedCursorRow, savedCursorCol); + // Move current buffer to history first location, only if string is modified + if (is_modified) { + string[max_i] = CHAR_NULL; + strcpybounded(commands_history, string, BUFFER_SIZE - 1); + } + + // Load command from history + strcpybounded(string, commands_history+(selected_his_idx*BUFFER_SIZE), BUFFER_SIZE - 1); + // Change proper i and max_i values + i = strlen(string); + max_i = i; + + print(commands_history+(selected_his_idx*BUFFER_SIZE), BIOS_GRAY); + is_modified = false; + break; + case SCANCODE_LEFT_ARROW: + if (i > 0) + i--; + break; + case SCANCODE_RIGHT_ARROW: + if (i < max_i) + i++; + break; + default: + is_modified = true; + putchar(c); + string[i] = c; + if (i == max_i) + max_i++; + i++; + } + setKeyboardCursor(savedCursorRow, savedCursorCol + i); + } + } while (c != CHAR_INPUT_NEWLINE); + string[max_i] = CHAR_NULL; // Terminating string + hideKeyboardCursor(); + setKeyboardCursor(savedCursorRow + 1, 0); // TODO : Extra, for multi-line input, maybe can be adjusted + + strcpybounded(commands_history, string, BUFFER_SIZE - 1); +} + +void shell(char *cache) { + // char as string / char + char filename_buffer[16]; + char source_directory_name[16]; + char commands_history[MAX_HISTORY][BUFFER_SIZE]; // "FIFO" data type for commands + char directory_string[BUFFER_SIZE]; + char arg_vector[ARGC_MAX][ARG_LENGTH]; + char directory_table[2][SECTOR_SIZE]; + char arg_execute[ARG_LENGTH]; + // char as 1 byte integer + char target_entry_byte = 0; + char target_parent_byte = 0; + char source_dir_idx; + char link_status = -1; + char io_buffer[SECTOR_SIZE]; + char temp_file[FILE_SIZE_MAXIMUM]; + char current_dir_index = cache[CURRENT_DIR_CACHE_OFFSET]; + char is_between_quote_mark = false; + bool is_found_parent = false; + int returncode_src; + int temp, returncode; + char evaluated_dir_idx = current_dir_index; + int last_execute_slash_index = 0; + int i = 0, j = 0, k = 0, argc = 0; + + getDirectoryTable(directory_table); + + clear(commands_history, BUFFER_SIZE*MAX_HISTORY); + memcpy(commands_history, cache+HISTORY_CACHE_OFFSET, BUFFER_SIZE*MAX_HISTORY); + + while (true) { + clear(arg_vector, ARGC_MAX*ARG_LENGTH); + clear(directory_string, BUFFER_SIZE); + print("mangga", BIOS_GREEN); + print(":", BIOS_GRAY); + directoryStringBuilder(directory_string, directory_table, current_dir_index); + print(directory_string, BIOS_LIGHT_BLUE); + print("$ ", BIOS_GRAY); + shellInput(commands_history, directory_table, current_dir_index); + memcpy(cache+HISTORY_CACHE_OFFSET, commands_history, BUFFER_SIZE*MAX_HISTORY); + + // Scroll up if cursor at lower screen + while (getKeyboardCursor(1) > 20) { + scrollScreen(); + setKeyboardCursor(getKeyboardCursor(1)-1, 0); + showKeyboardCursor(); + } + + // Arguments splitting + i = 0; + j = 0; + k = 0; + while (commands_history[0][i] != CHAR_NULL) { + // TODO : Extra, Extra, mixing double and single quote + // If found space in commands and not within double quote mark, make new + if (commands_history[0][i] == CHAR_SPACE && j < ARGC_MAX && !is_between_quote_mark) { + k = 0; + j++; + } + else if (commands_history[0][i] == CHAR_DOUBLE_QUOTE) { + // Toggling is_between_quote_mark + is_between_quote_mark = !is_between_quote_mark; + } + else { + // Only copy if char is not double quote + // and space outside double quote + arg_vector[j][k] = commands_history[0][i]; + k++; + } + + i++; + } + argc = j + 1; // Due j is between counting space between 2 args + + clear(cache+ARGV_OFFSET, ARG_LENGTH); + memcpy(cache+ARGV_OFFSET, arg_vector[1], ARG_LENGTH); + memcpy(cache+ARGV_2_OFFSET, arg_vector[2], ARG_LENGTH); + memcpy(cache+ARGV_3_OFFSET, arg_vector[3], ARG_LENGTH); + cache[ARGC_OFFSET] = argc; + setShellCache(cache); + clear(temp_file, FILE_SIZE_MAXIMUM); + // Command evaluation, TODO : Move to program itself + if (!forcestrcmp("./", arg_vector[0])) { + // Do relative pathing if more than 1 + last_execute_slash_index = getLastMatchedCharIdx(CHAR_SLASH, arg_vector[0]); + // FIXME : Extra, unsafe getlast + clear(arg_execute, ARG_LENGTH); + if (last_execute_slash_index != 1) { + // Split argument to path and filename + // Get path + strcpybounded(arg_execute, arg_vector[0], last_execute_slash_index); + evaluated_dir_idx = directoryEvaluator(directory_table, arg_execute, &returncode, current_dir_index); + + // Get filename + strcpybounded(arg_execute, arg_vector[0]+last_execute_slash_index+1, ARG_LENGTH-last_execute_slash_index-1); + } + else { + // Cut slash + strcpybounded(arg_execute, arg_vector[0]+2, ARG_LENGTH-2); + + evaluated_dir_idx = current_dir_index; + returncode = 0; + } + + // Link check + // Find entry in files + i = 0; + is_found_parent = false; + while (i < FILES_ENTRY_COUNT && !is_found_parent) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, directory_table[0]+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, 14); + if (directory_table[0][i*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET] == evaluated_dir_idx && + !forcestrcmp(filename_buffer, arg_execute)) { + is_found_parent = true; + target_entry_byte = directory_table[0][i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET]; + link_status = directory_table[0][i*FILES_ENTRY_SIZE+LINK_BYTE_OFFSET]; + + } + i++; + } + + if (link_status == SOFTLINK_ENTRY) { + // TODO : Extra, currently only single softlink depth supported + clear(filename_buffer, 16); + strcpybounded(filename_buffer, directory_table[0]+target_entry_byte*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + strcpybounded(arg_execute, filename_buffer, 14); + target_parent_byte = directory_table[0][target_entry_byte*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET]; + evaluated_dir_idx = target_parent_byte; + target_entry_byte = directory_table[0][target_entry_byte*FILES_ENTRY_SIZE + ENTRY_BYTE_OFFSET]; + clear(temp_file, FILE_SIZE_MAXIMUM); + read(temp_file, filename_buffer, &returncode_src, target_parent_byte); + // Needed to compare due _mash_cache always filling empty space + // Implying softlink to _mash_cache is not available + print("mash: executing softlink to ", BIOS_WHITE); + print(arg_execute, BIOS_LIGHT_CYAN); + print("\n", BIOS_WHITE); + + if (!strcmp(filename_buffer, "_mash_cache")) + target_entry_byte = EMPTY_FILES_ENTRY; + } + + + // Preventing to loading empty arg_execute + if (target_entry_byte != EMPTY_FILES_ENTRY) { + // Empty arg_execute will cause load kernel / restarting OS + read(temp_file, arg_execute, &returncode, evaluated_dir_idx); + if (!strcmp("./", arg_vector[0])) + print("unknown command", BIOS_LIGHT_RED); + else if (returncode == 0 && isBinaryFileMagicNumber(temp_file)) + exec(arg_execute, 0x3000, evaluated_dir_idx); + // If executed, this code wont run + print(arg_execute, BIOS_WHITE); + print(": binary signature not found\n", BIOS_WHITE); + } + else { + print("mash: ", BIOS_WHITE); + print(arg_execute, BIOS_WHITE); + print(" softlink broken", BIOS_WHITE); + } + } + else if (!strcmp("echo", arg_vector[0])) { + // Because shell structure is simple, just handle echo here + if (argc <= 2) + print(arg_vector[1], BIOS_WHITE); + else if (!strcmp(">", arg_vector[2])) { // Sad redirection + clear(io_buffer, SECTOR_SIZE); + strcpybounded(io_buffer, arg_vector[1], SECTOR_SIZE); + write(io_buffer, arg_vector[3], &returncode, current_dir_index); + if (returncode == -1) { + print("echo: ", BIOS_WHITE); + print(arg_vector[3], BIOS_WHITE); + print(" exist ", BIOS_WHITE); + } + else { + // If success writing to file, load new updated dirtable + getDirectoryTable(directory_table); + } + } + } + else if (!strcmp("clear", arg_vector[0])) { + clearEntireScreen(); + setKeyboardCursor(0, 0); + } + else if (!strcmp("", arg_vector[0])) { + // WARNING : Multiple space in single block will count as multiple argument due to argsplit above + // FIXME : Extra, ^ fix this argsplitter + // Empty string -> doing nothing + } + else { + // WARNING : Softlink in bin/ will executing arbitrary pointed sectors as program + // / Shell will ignore softlink flag and execute S byte as sectors entry index + read(temp_file, arg_vector[0], &returncode, BIN_PARENT_FOLDER); + if (returncode == 0 && isBinaryFileMagicNumber(temp_file)) + exec(arg_vector[0], 0x3000, BIN_PARENT_FOLDER); + // If executed, this code wont run + print(arg_vector[0], BIOS_WHITE); + print(": command not found\n", BIOS_WHITE); + } + } + +} diff --git a/src/mim.c b/src/mim.c new file mode 100644 index 0000000..589b6dc --- /dev/null +++ b/src/mim.c @@ -0,0 +1,256 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" +#include "std-header/boolean.h" + +#define CTRL_C_SCANCODE_LOW 0x03 +#define CTRL_C_SCANCODE_HIGH 0x2E + +void mim_editor(char *target_filename, char current_dir_index, char *dirtable); + +int main() { + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char arg_vector[ARGC_MAX][ARG_LENGTH]; + char argc = 0; + int current_dir_index; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(arg_vector, ARGC_MAX*ARG_LENGTH); + memcpy(arg_vector[0], shell_cache+ARGV_OFFSET, ARG_LENGTH); + memcpy(arg_vector[1], shell_cache+ARGV_2_OFFSET, ARG_LENGTH); + memcpy(arg_vector[2], shell_cache+ARGV_3_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + current_dir_index = shell_cache[CURRENT_DIR_CACHE_OFFSET]; + + // Argument count + if (argc == 2) + if (!strcmp("--help", arg_vector[0])) { + print("Utility to create/edit file in mim text editor\n", BIOS_WHITE); + print("Possible Usage:\n", BIOS_LIGHT_BLUE); + print("mim [file_name]\n", BIOS_LIGHT_CYAN); + } + else { + mim_editor(arg_vector[0], current_dir_index, directory_table); + } + else + print("Usage : mim \n", BIOS_WHITE); + + setShellCache(shell_cache); + shellReturn(); +} + +void print_title(char *title) { + int saved_r = getKeyboardCursor(true); + int saved_c = getKeyboardCursor(false); + setKeyboardCursor(0, 0); + print(title, BIOS_YELLOW); + setKeyboardCursor(saved_r, saved_c); +} + +void editor(char *file_buffer, char *title) { + // char as 1 byte integer + char c, scancode; + int i = 0, j = 0, max_i = 0, rawKey; + int savedCursorRow = getKeyboardCursor(true); + int savedCursorCol = getKeyboardCursor(false); + + clearEntireScreen(); + print_title(title); + setKeyboardCursor(1, 0); + showKeyboardCursor(); + + print(file_buffer, BIOS_GRAY); + savedCursorRow = getKeyboardCursor(true); + savedCursorCol = getKeyboardCursor(false); + i = strlenbin(file_buffer) - 5; + max_i = i; + do { + if (getKeyboardCursor(true) > 20) + scrollScreen(); + rawKey = getFullKey(); + c = rawKey & 0xFF; // AL Value + scancode = rawKey >> 8; // AH Value + // WARNING : Prioritizing ASCII before scancode + if (!(scancode == CTRL_C_SCANCODE_HIGH && c == CTRL_C_SCANCODE_LOW)) { + switch (c) { + case CHAR_INPUT_NEWLINE: + file_buffer[i] = CHAR_LINEFEED; + i++; + savedCursorRow = getKeyboardCursor(true); + savedCursorCol = getKeyboardCursor(false); + setKeyboardCursor(savedCursorRow + 1, 0); + break; + case CHAR_BACKSPACE: + // If i is not at starting input pos, decrement + if (i == max_i) { + if (i > 0) + // TODO : Extra, Extra, Extra, Extra, printing on edge screen sucks + i--; + + if (max_i > 0) + max_i--; + + savedCursorRow = getKeyboardCursor(true); + savedCursorCol = getKeyboardCursor(false); + file_buffer[max_i] = CHAR_SPACE; // For deleting last char + file_buffer[max_i+1] = CHAR_NULL; + setKeyboardCursor(1, 0); + print(file_buffer, BIOS_GRAY); + + setKeyboardCursor(savedCursorRow, savedCursorCol-1); + } + break; + default: + // If char (AL) is not ASCII Control codes, check scancode (AH) + switch (scancode) { + // case SCANCODE_TAB: + // // Deleted auto complete + // break; + // case SCANCODE_DOWN_ARROW: + // case SCANCODE_UP_ARROW: + // // Deleted auto complete + // break; + case SCANCODE_LEFT_ARROW: + if (i > 0) + i--; + break; + case SCANCODE_RIGHT_ARROW: + if (i < max_i) + i++; + break; + default: + putchar(c); + file_buffer[i] = c; + if (i == max_i) + max_i++; + i++; + } + // savedCursorRow = getKeyboardCursor(true); + // savedCursorCol = getKeyboardCursor(false); + // setKeyboardCursor(savedCursorRow, savedCursorCol + 1); + } + + } + } while (!(scancode == CTRL_C_SCANCODE_HIGH && c == CTRL_C_SCANCODE_LOW)); + + clearEntireScreen(); + setKeyboardCursor(0, 0); + print("mim: ", BIOS_WHITE); + print(title, BIOS_LIGHT_GREEN); + print(" saved\n", BIOS_WHITE); +} + + +void mim_editor(char *target_filename, char current_dir_index, char *dirtable) { + // char as string / char + char filename_buffer[16]; + char source_directory_name[16]; + char string_word_count[32]; + // char as 1 byte integer + char file_read[FILE_SIZE_MAXIMUM]; + char target_entry_byte = 0; + char target_parent_byte = 0; + char source_dir_idx; + char link_status = -1; + int returncode_editor = -1; + int returncode_src = 0; + bool is_write_success = false, valid_filename = true; + bool f_target_found = false, empty_entry_found = false; + bool is_found_parent = false; + int i = 0, j = 0; + int f_entry_idx = 0; + int f_entry_sector_idx = 0; + int last_slash_index; + int word_count; + int null_count; + + // Relative pathing + clear(source_directory_name, 16); + // Split target / source + last_slash_index = getLastMatchedCharIdx(CHAR_SLASH, target_filename); + // FIXME : Extra, unsafe getlast + if (last_slash_index != -1) { + // Split argument to path and filename + // Get path + strcpybounded(source_directory_name, target_filename, last_slash_index); + source_dir_idx = directoryEvaluator(dirtable, source_directory_name, &returncode_src, current_dir_index); + + // Get filename + strcpybounded(source_directory_name, target_filename+last_slash_index+1, ARG_LENGTH-last_slash_index-1); + } + else { + // Cut slash + strcpybounded(source_directory_name, target_filename, ARG_LENGTH); + + source_dir_idx = current_dir_index; + returncode_src = 0; + } + + // Copying strings if path evaluation success + if (returncode_src == -1) { + print("mim: ", BIOS_GRAY); + print(target_filename, BIOS_GRAY); + print(": target path not found\n", BIOS_GRAY); + } + else { + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, source_directory_name, &returncode_src, source_dir_idx); + if (returncode_src == 0) { + // Find entry in files + i = 0; + while (i < FILES_ENTRY_COUNT && !is_found_parent) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, 14); + if (dirtable[i*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET] == source_dir_idx && + !strcmp(source_directory_name, filename_buffer)) { + is_found_parent = true; + target_entry_byte = dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET]; + link_status = dirtable[i*FILES_ENTRY_SIZE+LINK_BYTE_OFFSET]; + } + i++; + } + + if (link_status == SOFTLINK_ENTRY) { + // Get linked strings / folder with recursion depth limit 16 + i = 0; + // TODO : Extra, currently only single softlink depth supported + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+target_entry_byte*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + target_parent_byte = dirtable[target_entry_byte*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET]; + target_entry_byte = dirtable[target_entry_byte*FILES_ENTRY_SIZE + ENTRY_BYTE_OFFSET]; + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, filename_buffer, &returncode_src, target_parent_byte); + // Needed to compare due _mash_cache always filling empty space + // Implying softlink to _mash_cache is not available + if (!strcmp(filename_buffer, "_mash_cache")) + target_entry_byte = EMPTY_FILES_ENTRY; + } + + if (returncode_src == 0 && target_entry_byte != EMPTY_FILES_ENTRY && target_entry_byte != FOLDER_ENTRY) { + // Editing existing file + editor(file_read, source_directory_name); + remove(source_directory_name, &returncode_editor, source_dir_idx); + write(file_read, source_directory_name, &returncode_editor, source_dir_idx); + } + else { + print("mim: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print(" softlink broken\n", BIOS_WHITE); + } + + } + else { + // Creating new + clear(file_read, FILE_SIZE_MAXIMUM); + editor(file_read, source_directory_name); + write(file_read, source_directory_name, &returncode_editor, source_dir_idx); + } + + + } +} diff --git a/src/mkdir.c b/src/mkdir.c new file mode 100644 index 0000000..cb9e594 --- /dev/null +++ b/src/mkdir.c @@ -0,0 +1,59 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" + +void mkdir(char *foldername, char current_dir_index); + +int main() { + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char dirstr[BUFFER_SIZE]; + char argc = 0; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(dirstr, BUFFER_SIZE); + memcpy(dirstr, shell_cache+ARGV_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + + // Argument count + if (argc == 2) { + if (!strcmp("--help", dirstr)) { + print("Utility to create a new folder/directory\n", BIOS_WHITE); + print("Possible Usage:\n", BIOS_LIGHT_BLUE); + print("mkdir [folder_name]\n", BIOS_LIGHT_CYAN); + } + else { + mkdir(dirstr, shell_cache[CURRENT_DIR_CACHE_OFFSET]); + setShellCache(shell_cache); + } + } + else + print("Usage : mkdir \n", BIOS_WHITE); + shellReturn(); +} + +void mkdir(char *foldername, char current_dir_index) { + int returncode; + // Slash checking + if (getLastMatchedCharIdx(CHAR_SLASH, foldername) == -1) { + write(FOLDER, foldername, &returncode, current_dir_index); + switch (returncode) { + case 0: + // Do nothing + break; + case -1: + print("mkdir: ", BIOS_WHITE); + print(foldername, BIOS_WHITE); + print(" exist\n", BIOS_WHITE); + break; + default: + print("Usage : mkdir \n"); + } + } + else + print("mkdir: invalid directory name\n", BIOS_WHITE); +} diff --git a/src/mv.c b/src/mv.c new file mode 100644 index 0000000..205cc2f --- /dev/null +++ b/src/mv.c @@ -0,0 +1,177 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" +#include "std-header/boolean.h" + +void mv(char *dirtable, char current_dir_index, char *target, char *linkname); + +int main() { + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char arg_vector[ARGC_MAX][ARG_LENGTH]; + char argc = 0; + int current_dir_index; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(arg_vector, ARGC_MAX*ARG_LENGTH); + memcpy(arg_vector[0], shell_cache+ARGV_OFFSET, ARG_LENGTH); + memcpy(arg_vector[1], shell_cache+ARGV_2_OFFSET, ARG_LENGTH); + memcpy(arg_vector[2], shell_cache+ARGV_3_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + current_dir_index = shell_cache[CURRENT_DIR_CACHE_OFFSET]; + + // Argument count + if (argc == 2 && !strcmp("--help", arg_vector[0])) { + print("Utility to move file to a certain directory\n", BIOS_WHITE); + print("Possible Usage:\n", BIOS_LIGHT_BLUE); + print("mv [file_name] [target_directory]\n", BIOS_LIGHT_CYAN); + print("mv [folder_name] [target_directory]\n", BIOS_LIGHT_CYAN); + } + else if (argc >= 3) { + mv(directory_table, current_dir_index, arg_vector[0], arg_vector[1]); + } + else + print("Usage : mv \n", BIOS_WHITE); + + setShellCache(shell_cache); + shellReturn(); +} + +// TODO : Autocomplete & relative pathing +void mv(char *dirtable, char current_dir_index, char *target, char *linkname) { + // Technically just "copy" of previous implementation of ln + // char as string / char + char filename_buffer[16]; + char source_directory_name[16]; + char copied_directory_name[16]; + // char as 1 byte integer + char file_read[FILE_SIZE_MAXIMUM]; + char target_entry_byte = 0; + char source_dir_idx; + char copied_dir_idx; + char link_status; + int returncode_src = 0; + int returncode_cpy = 0; + bool is_write_success = false, valid_filename = true; + bool f_target_found = false, empty_entry_found = false; + bool is_found = false; + int i = 0, j = 0; + int f_entry_idx = 0; + int f_entry_sector_idx = 0; + int last_slash_index; + + + // Relative pathing + clear(source_directory_name, 16); + clear(copied_directory_name, 16); + // Split target / source + last_slash_index = getLastMatchedCharIdx(CHAR_SLASH, target); + // FIXME : Extra, unsafe getlast + if (last_slash_index != -1) { + // Split argument to path and filename + // Get path + strcpybounded(source_directory_name, target, last_slash_index); + source_dir_idx = directoryEvaluator(dirtable, source_directory_name, &returncode_src, current_dir_index); + + // Get filename + strcpybounded(source_directory_name, target+last_slash_index+1, ARG_LENGTH-last_slash_index-1); + } + else { + // Cut slash + strcpybounded(source_directory_name, target, ARG_LENGTH); + + source_dir_idx = current_dir_index; + returncode_src = 0; + } + + // Split destination / copied + last_slash_index = getLastMatchedCharIdx(CHAR_SLASH, linkname); + // FIXME : Extra, unsafe getlast + if (last_slash_index != -1) { + // Split argument to path and filename + // Get path + strcpybounded(copied_directory_name, linkname, last_slash_index); + copied_dir_idx = directoryEvaluator(dirtable, copied_directory_name, &returncode_cpy, current_dir_index); + + // Get filename + strcpybounded(copied_directory_name, linkname+last_slash_index+1, ARG_LENGTH-last_slash_index-1); + } + else { + // Cut slash + strcpybounded(copied_directory_name, linkname, ARG_LENGTH); + + copied_dir_idx = current_dir_index; + returncode_src = 0; + } + + + // Copying file if path evaluation success + if (returncode_src == -1) { + print("mv: ", BIOS_GRAY); + print(target, BIOS_GRAY); + print(": target not found\n", BIOS_GRAY); + } + else if (returncode_cpy == -1) { + print("mv: ", BIOS_GRAY); + print(copied_directory_name, BIOS_GRAY); + print(": path not found\n", BIOS_GRAY); + } + else { + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, source_directory_name, &returncode_src, source_dir_idx); + read(file_read, copied_directory_name, &returncode_cpy, copied_dir_idx); + if (returncode_src == 0 && returncode_cpy == -1) { + i = 0; + j = 0; + while (i < FILES_ENTRY_COUNT && !is_found) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, 14); + if (dirtable[i*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET] == source_dir_idx && + !strcmp(source_directory_name, filename_buffer)) { + is_found = true; + dirtable[i*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET] = copied_dir_idx; + link_status = dirtable[i*FILES_ENTRY_SIZE + LINK_BYTE_OFFSET]; + memcpy(dirtable+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, copied_directory_name, 14); + dirtable[i*FILES_ENTRY_SIZE+LINK_BYTE_OFFSET] = link_status; + } + i++; + } + + if (!is_found) { + print("mv: searching: ", BIOS_WHITE); + print(target, BIOS_WHITE); + print(" error\n", BIOS_WHITE); + returncode_src = -1; + } + else { + // Updating directory table + directSectorWrite(dirtable, FILES_SECTOR); + directSectorWrite(dirtable+SECTOR_SIZE, FILES_SECTOR+1); + } + + } + else if (returncode_src == -1) { + print("mv: error: ", BIOS_WHITE); + print(target, BIOS_WHITE); + print(" not found\n", BIOS_WHITE); + returncode_src = -1; + } + else { + print("mv: error: ", BIOS_WHITE); + print(linkname, BIOS_WHITE); + print(" exists\n", BIOS_WHITE); + returncode_src = -1; + } + + if (returncode_src == 0 && returncode_cpy == -1) { + print(linkname, BIOS_GRAY); + print(": moved\n", BIOS_GRAY); + } + else + print("mv: file writing error\n", BIOS_GRAY); + } +} diff --git a/src/printf.c b/src/printf.c new file mode 100644 index 0000000..b44691b --- /dev/null +++ b/src/printf.c @@ -0,0 +1,89 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" +#include "std-header/boolean.h" + +#define PRINTF_BUFFER 1024 + +bool isNumber(char *buffer); + +int main() { + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char arg_vector[ARGC_MAX][ARG_LENGTH]; + char buffer[PRINTF_BUFFER]; + char move_buffer[PRINTF_BUFFER]; + char number_buffer[32]; + char argc = 0; + bool is_error = false; + int current_dir_index; + int i = 0; + int current_variadic_arg = 1; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(arg_vector, ARGC_MAX*ARG_LENGTH); + memcpy(arg_vector[0], shell_cache+ARGV_OFFSET, ARG_LENGTH); + memcpy(arg_vector[1], shell_cache+ARGV_2_OFFSET, ARG_LENGTH); + memcpy(arg_vector[2], shell_cache+ARGV_3_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + current_dir_index = shell_cache[CURRENT_DIR_CACHE_OFFSET]; + + // Argument count + if (argc >= 3) { + clear(buffer, PRINTF_BUFFER); + strcpy(buffer, arg_vector[0]); + + while (i < PRINTF_BUFFER-1 && buffer[i] != CHAR_NULL) { + if (buffer[i] == '%' && buffer[i+1] == 's') { + clear(move_buffer, PRINTF_BUFFER); + strcpy(move_buffer, buffer+i+2); + buffer[i] = CHAR_NULL; + strapp(buffer, arg_vector[current_variadic_arg]); + strapp(buffer, move_buffer); + current_variadic_arg++; + } + else if (buffer[i] == '%' && buffer[i+1] == 'd') { + if (isNumber(arg_vector[current_variadic_arg])) { + clear(move_buffer, PRINTF_BUFFER); + strcpy(move_buffer, buffer+i+2); + buffer[i] = CHAR_NULL; + strapp(buffer, arg_vector[current_variadic_arg]); + strapp(buffer, move_buffer); + current_variadic_arg++; + } + else { + print("printf: error ", BIOS_WHITE); + print(arg_vector[current_variadic_arg], BIOS_WHITE); + print(" not a number\n", BIOS_WHITE); + is_error = true; + } + } + i++; + } + + if (!is_error) { + print(buffer, BIOS_WHITE); + print("\n", BIOS_WHITE); + } + } + else + print("Usage : printf \n", BIOS_WHITE); + + setShellCache(shell_cache); + shellReturn(); +} + +bool isNumber(char *buffer) { + int i = 0; + + while (buffer[i] != '\0') { + if (!('0' <= buffer[i] && buffer[i] <= '9')) + return false; + i++; + } + return true; +} diff --git a/src/recursion_test.c b/src/recursion_test.c new file mode 100644 index 0000000..67f8309 --- /dev/null +++ b/src/recursion_test.c @@ -0,0 +1,40 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "std-header/std_fileio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" +#include "std-header/boolean.h" + +#define ENTRY_INDEX 0x14 // Set this + +int main() { + int debug_retcode; + char garbage[SECTOR_SIZE]; + + // Recursion test, don't forget to setting ENTRY_INDEX + clear(garbage, 512); + strcpy(garbage, "recursion test"); + write(FOLDER, "fold1\0\0\0\0\0\0\0\0\0", &debug_retcode, ROOT_PARENT_FOLDER); + write(FOLDER, "infold1\0\0\0\0\0\0\0", &debug_retcode, ENTRY_INDEX); + write(FOLDER, "infold2\0\0\0\0\0\0\0", &debug_retcode, ENTRY_INDEX); + write(FOLDER, "in2fold1\0\0\0\0\0\0", &debug_retcode, ENTRY_INDEX+1); + write(garbage, "in2-file1\0\0\0\0\0", &debug_retcode, ENTRY_INDEX+2); + write(garbage, "in-file1\0\0\0\0\0\0", &debug_retcode, ENTRY_INDEX); + write(garbage, "in-file2\0\0\0\0\0\0", &debug_retcode, ENTRY_INDEX); + write(garbage, "in-file3\0\0\0\0\0\0", &debug_retcode, ENTRY_INDEX); + + // Test structure + // fold1 + // | - in-file1 + // | - in-file2 + // | - in-file3 + // | - infold1 + // | - in2fold1 + // | - + // | - infold2 + // | - in2-file1 + + print("Created\n", BIOS_WHITE); + + shellReturn(); +} diff --git a/src/rm.c b/src/rm.c new file mode 100644 index 0000000..0955278 --- /dev/null +++ b/src/rm.c @@ -0,0 +1,304 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" +#include "std-header/boolean.h" + +void rm(char *dirtable, char current_dir_index, char flags, char *target); + +int main() { + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char arg_vector[ARGC_MAX][ARG_LENGTH]; + char argc = 0; + int current_dir_index; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(arg_vector, ARGC_MAX*ARG_LENGTH); + memcpy(arg_vector[0], shell_cache+ARGV_OFFSET, ARG_LENGTH); + memcpy(arg_vector[1], shell_cache+ARGV_2_OFFSET, ARG_LENGTH); + memcpy(arg_vector[2], shell_cache+ARGV_3_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + current_dir_index = shell_cache[CURRENT_DIR_CACHE_OFFSET]; + + // Argument count + if (argc == 2 || argc == 3) { + if (!strcmp("--help", arg_vector[0])) { + print("Utility to delete file\n", BIOS_WHITE); + print("Possible Usage:\n", BIOS_LIGHT_BLUE); + print("rm [file_name]\n", BIOS_LIGHT_CYAN); + print("rm -r [folder_name]\n", BIOS_LIGHT_CYAN); + } + else if (!strcmp("-r", arg_vector[0])) + rm(directory_table, current_dir_index, 1, arg_vector[1]); + else + rm(directory_table, current_dir_index, 0, arg_vector[0]); + } + else + print("Usage : rm [-r] \n", BIOS_WHITE); + + setShellCache(shell_cache); + shellReturn(); +} + +void file_delete(char *file_read, char *source_directory_name, char *returncode_src, char source_dir_idx, char *dirtable) { + // char as character + char filename_buffer[16]; + // char as 1 byte integer + char target_files_entry_index; + char target_entry_byte; + char target_parent_byte; + char link_status = -1; + bool is_found_parent = false; + int i = 0; + + if (getKeyboardCursor(true) > 20) + scrollScreen(); + + read(file_read, source_directory_name, returncode_src, source_dir_idx); + if (file_read[0] != NULL) { + + // Find entry in files + i = 0; + while (i < FILES_ENTRY_COUNT && !is_found_parent) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, 14); + if (dirtable[i*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET] == source_dir_idx && + !strcmp(source_directory_name, filename_buffer)) { + is_found_parent = true; + target_entry_byte = dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET]; + target_files_entry_index = i; + link_status = dirtable[i*FILES_ENTRY_SIZE+LINK_BYTE_OFFSET]; + } + i++; + } + + if (link_status == HARDLINK_ENTRY || link_status == SOFTLINK_ENTRY) { + dirtable[target_files_entry_index*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET] = EMPTY_FILES_ENTRY; + dirtable[target_files_entry_index*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET] = ROOT_PARENT_FOLDER; + clear(dirtable+target_files_entry_index*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + + if (!is_found_parent) { + print("rm: searching hardlink: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print(" error\n", BIOS_WHITE); + returncode_src = -1; + } + else if (link_status == HARDLINK_ENTRY) { + // Updating directory table + print("rm: hardlink: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print(" deleted\n", BIOS_WHITE); + + directSectorWrite(dirtable, FILES_SECTOR); + directSectorWrite(dirtable+SECTOR_SIZE, FILES_SECTOR+1); + } + else if (link_status == SOFTLINK_ENTRY) { + // Updating directory table + print("rm: softlink: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print(" deleted\n", BIOS_WHITE); + + directSectorWrite(dirtable, FILES_SECTOR); + directSectorWrite(dirtable+SECTOR_SIZE, FILES_SECTOR+1); + } + } + else { + remove(source_directory_name, &returncode_src, source_dir_idx); + if (returncode_src == -1) + print("rm: removal error\n", BIOS_LIGHT_RED); + else { + print("rm: ", BIOS_WHITE); + print(source_directory_name, BIOS_LIGHT_GREEN); + print(" deleted\n", BIOS_WHITE); + } + } + } + else { + print("rm: error: ", BIOS_WHITE); + print(source_directory_name, BIOS_LIGHT_BLUE); + print(" is a folder\n", BIOS_WHITE); + } +} + +void rm(char *dirtable, char current_dir_index, char flags, char *target) { + // FIXME : Extra, Extra, Currently deleting file that softlinked will have some consistency problem + // char as string / char + char filename_buffer[16]; + char source_directory_name[16]; + char evaluator_buffer[16]; + // char as 1 byte integer + char file_read[FILE_SIZE_MAXIMUM]; + char target_entry_byte = 0; + char stack_but_without_typedef_because_im_scared_with_bcc[256]; // <3 stack, but not bcc :( + char stack_top_pointer; + char deleted_dir_pointer; + char target_parent_dir[256]; + char deleted_dir_list[256]; + char source_dir_idx; + char current_recursion_parent_index; + char stack_folder_idx; + int returncode_src = 0; + bool is_write_success = false, valid_filename = true; + bool f_target_found = false, empty_entry_found = false; + bool recursion_ended = false, recursion_loop_pass_success = false; + int i = 0, j = 0; + int f_entry_idx = 0; + int f_entry_sector_idx = 0; + int last_slash_index; + + // Relative pathing + clear(source_directory_name, 16); + // Split target / source + last_slash_index = getLastMatchedCharIdx(CHAR_SLASH, target); + // FIXME : Extra, unsafe getlast + if (last_slash_index != -1) { + // Split argument to path and filename + // Get path + strcpybounded(source_directory_name, target, last_slash_index); + source_dir_idx = directoryEvaluator(dirtable, source_directory_name, &returncode_src, current_dir_index); + + // Get filename + strcpybounded(source_directory_name, target+last_slash_index+1, ARG_LENGTH-last_slash_index-1); + } + else { + // Cut slash + strcpybounded(source_directory_name, target, ARG_LENGTH); + + read(file_read, source_directory_name, &returncode_src, current_dir_index); + if (file_read[0] == FOLDER && flags == 1) { + clear(evaluator_buffer, 16); + strcpy(evaluator_buffer, source_directory_name); + strapp(evaluator_buffer, "/"); + source_dir_idx = directoryEvaluator(dirtable, evaluator_buffer, &returncode_src, current_dir_index); + } + else + source_dir_idx = current_dir_index; + returncode_src = 0; + } + + + + // Copying file if path evaluation success + if (returncode_src == -1) { + print("rm: ", BIOS_GRAY); + print(target, BIOS_GRAY); + print(": target not found\n", BIOS_GRAY); + } + else { + clear(file_read, FILE_SIZE_MAXIMUM); + if (flags == 1 && last_slash_index == -1) + read(file_read, source_directory_name, &returncode_src, current_dir_index); + else + read(file_read, source_directory_name, &returncode_src, source_dir_idx); + if (returncode_src == 0) { + if (flags == 0) { + // Simple delete, refuse folder + file_delete(file_read, source_directory_name, &returncode_src, source_dir_idx, dirtable); + } + else { + // Recursive + // Will deleting file normally on -r + if (file_read[0] != NULL) + file_delete(file_read, source_directory_name, &returncode_src, source_dir_idx, dirtable); + else { + i = 0; + while (i < 256) { + target_parent_dir[i] = 0; + deleted_dir_list[i] = 0; + i++; + } + clear(stack_but_without_typedef_because_im_scared_with_bcc, 256); + stack_top_pointer = 0; + deleted_dir_pointer = 0; + stack_but_without_typedef_because_im_scared_with_bcc[0] = source_dir_idx; + deleted_dir_list[0] = source_dir_idx; + + while (!recursion_loop_pass_success) { + i = 0; + recursion_loop_pass_success = true; + current_recursion_parent_index = stack_but_without_typedef_because_im_scared_with_bcc[stack_top_pointer]; + target_parent_dir[stack_top_pointer] = 0; + while (i < FILES_ENTRY_COUNT) { + if (current_recursion_parent_index == dirtable[i*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET]) { + // If still file, pass is still success + if (dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET] != FOLDER_ENTRY + && dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET] != EMPTY_FILES_ENTRY) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+i*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + file_delete(file_read, filename_buffer, &returncode_src, current_recursion_parent_index, dirtable); + } + // If folder, pass failed + else { + stack_top_pointer++; + deleted_dir_pointer++; + stack_but_without_typedef_because_im_scared_with_bcc[stack_top_pointer] = i; + target_parent_dir[stack_top_pointer] = current_recursion_parent_index; + deleted_dir_list[deleted_dir_pointer] = i; + recursion_loop_pass_success = false; + } + } + i++; + } + + + if (recursion_loop_pass_success) { + i = stack_top_pointer; + while (i > 0) { + if (target_parent_dir[i] != 0) { + // Stack unwinding + stack_top_pointer = i; + recursion_loop_pass_success = false; + break; + } + i--; + } + } + + } + + // Folder stack deletion + // Updating to current updated files filesystem + getDirectoryTable(dirtable); + // Find entry in files + i = 0; + while (i <= deleted_dir_pointer) { + stack_folder_idx = deleted_dir_list[i]; + dirtable[stack_folder_idx*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET] = ROOT_PARENT_FOLDER; + dirtable[stack_folder_idx*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET] = EMPTY_FILES_ENTRY; + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+stack_folder_idx*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + + if (getKeyboardCursor(true) > 20) + scrollScreen(); + + print("rm: ", BIOS_WHITE); + print(filename_buffer, BIOS_LIGHT_BLUE); + print(" deleted\n", BIOS_WHITE); + clear(dirtable+stack_folder_idx*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + i++; + } + + // Updating files filesystem entry + directSectorWrite(dirtable, FILES_SECTOR); + directSectorWrite(dirtable+SECTOR_SIZE, FILES_SECTOR+1); + + print("rm: recursion done\n", BIOS_WHITE); + } + + } + } + else { + print("rm: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print(" not found\n", BIOS_WHITE); + } + + if (returncode_src != 0) + print("rm: error\n", BIOS_RED); + + } +} diff --git a/src/screen.c b/src/screen.c index 5f6e632..9cca614 100644 --- a/src/screen.c +++ b/src/screen.c @@ -2,7 +2,7 @@ #include "kernel-header/kernel.h" #include "kernel-header/screen.h" -#include "basic-header/opr.h" +#include "basic-header/std_opr.h" #include "std-header/boolean.h" void drawPixel(int x, int y, int color) { @@ -49,7 +49,7 @@ void clearScreen() { int i = 0; while (i < 4096) { charVideoMemoryWrite(2*i, ' '); - charVideoMemoryWrite(1 + 2*i, 0x0); + // charVideoMemoryWrite(1 + 2*i, 0x0); i++; } } @@ -149,14 +149,17 @@ void charVideoMemoryWrite(int offset, char character) { putInMemory(V_MEM, V_OFFSET + offset, character); } -void drawBootLogo() { - int i = 0, j = 0; - char *logo = LOGO_STRING; +void drawBootLogo(char *buf) { + // Bring your own buffer -someone + int i = 0, j = 0, ret_code; + + readFile(buf, LOGO_FILENAME, &ret_code, ROOT_PARENT_FOLDER); + interrupt(0x10, 0x0013, 0, 0, 0); // Change video mode to 0x13, Graphical 320x200 - bitDraw(LOGO_X_OFFSET + 10, LOGO_Y_OFFSET + 10, 0xE, logo); + bitDraw(LOGO_X_OFFSET + 10, LOGO_Y_OFFSET + 10, 0xE, buf); printString("\n\n\n\n\n mangga"); drawRectangle(LOGO_X_OFFSET + 4, LOGO_Y_OFFSET + 6, 54, 44); // Draw logo with offset and color preset diff --git a/src/shell-header/shell_common.h b/src/shell-header/shell_common.h new file mode 100644 index 0000000..193a67e --- /dev/null +++ b/src/shell-header/shell_common.h @@ -0,0 +1,45 @@ +// Commonly used function or procedures in shell +#define CURRENT_DIR_CACHE_OFFSET 0xF +#define HISTORY_CACHE_OFFSET 0x10 +#define CACHE_SIGNATURE_OFFSET 0x0 +#define ARGC_OFFSET 0xE +#define ARGV_OFFSET 0x150 +#define ARGV_2_OFFSET 0x170 +#define ARGV_3_OFFSET 0x190 + +// TODO : Cleanup +#define LS_TARGET_DIR_CACHE_OFFSET 1 +#define CD_TARGET_DIR_CACHE_OFFSET 1 + +#define CACHE_SIGNATURE 'm' + +#define ARG_LENGTH 32 +#define ARGC_MAX 8 +#define BUFFER_SIZE 64 +#define MAX_HISTORY 5 + +#define EXECUTABLE_SIGNATURE "\x55\x89\xE5\x57\x56\x81\xC4" + +void getDirectoryTable(char *buffer); +// WARNING : No bound checking +// Get all directory table, put in buffer + +void shellReturn(); +// Exec shell on segment 0x2000 + +void getShellCache(char *buffer); +// Get shell cache, used for message passing and state storage + +void setShellCache(char *buffer); +// Set shell cache, used for updating cache + +char isBinaryFileMagicNumber(char *buffer); +// Checking whether bytes in buffer is a supported executable binary file +// Header samples +// 55 89 E5 57 56 81 C4 BF F9 30 C0 88 86 BB F9 4C +// 55 89 E5 57 56 81 C4 BC F9 B8 00 02 50 8D 9E FC +// 55 89 E5 57 56 81 C4 FC F9 B8 FF FF 89 86 F8 F9 +// Taking 55 89 E5 57 56 81 C4 as magic number to compare + +char directoryEvaluator(char *dirtable, char *dirstr, int *returncode, char current_dir); +// Directory string evaluator, returning evaluated files filesystem entry index diff --git a/src/shell.c b/src/shell.c index d706812..0880a2a 100644 --- a/src/shell.c +++ b/src/shell.c @@ -18,10 +18,13 @@ void getDirectoryTable(char *buffer); // WARNING : No bound checking // Get all directory table, put in buffer +void shell(); - - +// int main() { +// shell(); +// return 0; +// } @@ -409,8 +412,15 @@ char cd(char *dirtable, char *dirstr, char current_dir) { int returncode = 0; char new_dir_idx = directoryEvaluator(dirtable, dirstr, &returncode, current_dir); // If success return new dir index - if (returncode == 0) - return new_dir_idx; + if (returncode == 0) { + if (dirtable[new_dir_idx*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET] == FOLDER_ENTRY) + return new_dir_idx; + else { + // Else, entry is not folder + print("cd: target type is a file\n", BIOS_WHITE); + return current_dir; + } + } else { // Else, return original dir print("cd: path not found\n", BIOS_WHITE); @@ -463,7 +473,7 @@ void cat(char *dirtable, char *filename, char target_dir) { clear(file_read, FILE_SIZE_MAXIMUM); // Take last argv, use it as filename - readFile(file_read, directory_name[dirnamecount-1], &returncode, eval_dir); + read(file_read, directory_name[dirnamecount-1], &returncode, eval_dir); if (returncode == -1) { print("cat: ", BIOS_GRAY); print(directory_name[dirnamecount-1], BIOS_GRAY); @@ -475,8 +485,15 @@ void cat(char *dirtable, char *filename, char target_dir) { print(directory_name[dirnamecount-1], BIOS_WHITE); print(" is a folder", BIOS_WHITE); } - else + else { + i = 0; + while (i < FILE_SIZE_MAXIMUM && file_read[i] != CHAR_NULL) { + if (file_read[i] == CHAR_CARRIAGE_RETURN) + file_read[i] = CHAR_SPACE; + i++; + } print(file_read, BIOS_GRAY); + } } print("\n", BIOS_GRAY); } @@ -499,7 +516,7 @@ void ln(char *dirtable, char target_dir, char flags, char *target, char *linknam // For simplicity, only 2 flags either hard / soft link available // For more fancy version, use bitmasking clear(file_read, FILE_SIZE_MAXIMUM); - readFile(file_read, target, &returncode, target_dir); + read(file_read, target, &returncode, target_dir); if (returncode == -1) { print("ln: ", BIOS_GRAY); print(target, BIOS_GRAY); @@ -633,9 +650,9 @@ void shell() { shellInput(commands_history, directory_table, current_dir_index); // Scroll up if cursor at lower screen - while (getCursorPos(1) > 20) { + while (getKeyboardCursor(1) > 20) { scrollScreen(); - setCursorPos(getCursorPos(1)-1, 0); + setKeyboardCursor(getKeyboardCursor(1)-1, 0); showKeyboardCursor(); } @@ -705,7 +722,7 @@ void shell() { else if (!strcmp("mkdir", arg_vector[0])) { if (argc == 2) { mkdir(arg_vector[1], current_dir_index); - getDirectoryTable(directory_table); // Reload + getDirectoryTable(directory_table); } else print("Usage : mkdir \n", BIOS_WHITE); @@ -723,7 +740,10 @@ void shell() { print(arg_vector[3], BIOS_WHITE); print(" exist ", BIOS_WHITE); } - getDirectoryTable(directory_table); + else { + // If success writing to file, load new updated dirtable + getDirectoryTable(directory_table); + } } } else if (!strcmp("", arg_vector[0])) { diff --git a/src/shell_common.c b/src/shell_common.c new file mode 100644 index 0000000..c3b255f --- /dev/null +++ b/src/shell_common.c @@ -0,0 +1,129 @@ +#include "kernel-header/config.h" +#include "std-header/std_fileio.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "std-header/boolean.h" + +extern int interrupt(int number, int AX, int BX, int CX, int DX); + +void getDirectoryTable(char *buffer) { + // WARNING : Naive implementation + directSectorRead(buffer, FILES_SECTOR); + directSectorRead(buffer + SECTOR_SIZE, FILES_SECTOR + 1); +} + +void shellReturn() { + int AX = BIN_PARENT_FOLDER << 8; + int ret_code; + AX |= 0x06; + interrupt(0x21, AX, "mash", 0x2000, &ret_code); +} + +void getShellCache(char *buffer) { + int returncode; + read(buffer, "_mash_cache\0\0\0", &returncode, ROOT_PARENT_FOLDER); +} + +void setShellCache(char *buffer) { + int returncode; + remove("_mash_cache", &returncode, ROOT_PARENT_FOLDER); + write(buffer, "_mash_cache\0\0\0", &returncode, ROOT_PARENT_FOLDER); +} + +bool isBinaryFileMagicNumber(char *buffer) { + return !forcestrcmp(EXECUTABLE_SIGNATURE, buffer); +} + + + +char directoryEvaluator(char *dirtable, char *dirstr, int *returncode, char current_dir) { + // FIXME : Extra, will have problem with file & folder with same name on same directory + // -- Evaluator return code -- + // -1 - Path not found + // 0 - Evaluator find folder + // 1 - Evaluator find file + char evaluated_dir = current_dir; + char parent_byte_buffer = -1; + char entry_byte_buffer = -1; + char directory_name[ARGC_MAX][ARG_LENGTH]; + char filename_buffer[16]; + int i, j, k, dirnamecount; + bool is_valid_args = true, is_folder_found = false; + bool is_type_is_folder = true; + clear(directory_name, ARGC_MAX*ARG_LENGTH); + + // TODO : Extra, maybe std -> strsplit() + // Arguments splitting -> From argv in shell(), with some modification + i = 0; + j = 0; + k = 0; + while (dirstr[i] != CHAR_NULL) { + // If found slash in commands and not within double quote mark, make new + if (dirstr[i] == CHAR_SLASH && j < ARGC_MAX) { + k = 0; + j++; + } + else { + // Only copy if char is not double quote + // and space outside double quote + directory_name[j][k] = dirstr[i]; + k++; + } + i++; + } + dirnamecount = j + 1; // Due j is between counting space between 2 args + + // Deleting last slash (ex. mnt/a/b/ -> argv entries = {mnt, a, b, ""} to argv = {mnt, a, b}) + if (!strcmp(directory_name[dirnamecount-1], "")) + dirnamecount--; + + + // Parsing priority : + // 1. If found "." -> change evaluated dir to current dir, will ignoring previous evaluation + // 2. If found ".." -> move to parent folder + // 3. If found foldername -> search foldername in evaluated dir + i = 0; + while (i < dirnamecount && is_valid_args) { + if (!strcmp(directory_name[i], ".")) { + evaluated_dir = current_dir; + } + else if (!strcmp(directory_name[i], "..")) { + // If evaluated dir is NOT in between files entry count and 0 (or valid files index), do nothing + // (Root flag by default is on 0xFF which is by default not in range) + // else, change evaluated dir to parent evaluated dir + if (0 <= evaluated_dir && evaluated_dir < FILES_ENTRY_COUNT) + evaluated_dir = dirtable[evaluated_dir*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET]; + } + else { + // If string matching not found, break loop return -1 as failed evaluation + j = 0; + is_folder_found = false; + while (j < FILES_ENTRY_COUNT && !is_folder_found) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+j*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + // If within same parent folder and pathname match, change evaluated_dir + parent_byte_buffer = dirtable[j*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET]; + entry_byte_buffer = dirtable[j*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET]; + if (!strcmp(directory_name[i], filename_buffer) && parent_byte_buffer == evaluated_dir) { + is_folder_found = true; + is_type_is_folder = (entry_byte_buffer == FOLDER_ENTRY); + evaluated_dir = j; // NOTE : j represent files entry index + } + j++; + } + + if (!is_folder_found) + is_valid_args = false; + } + i++; + } + + if (!is_valid_args) + *returncode = -1; + else if (is_type_is_folder) + *returncode = 0; + else + *returncode = 1; + + return evaluated_dir; +} diff --git a/src/snok.c b/src/snok.c new file mode 100644 index 0000000..d8e0ec3 --- /dev/null +++ b/src/snok.c @@ -0,0 +1,131 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" +#include "std-header/boolean.h" + +#define CTRL_C_SCANCODE_LOW 0x03 +#define CTRL_C_SCANCODE_HIGH 0x2E + +void snok(); + +int main() { + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char arg_vector[ARGC_MAX][ARG_LENGTH]; + char argc = 0; + int current_dir_index; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(arg_vector, ARGC_MAX*ARG_LENGTH); + memcpy(arg_vector[0], shell_cache+ARGV_OFFSET, ARG_LENGTH); + memcpy(arg_vector[1], shell_cache+ARGV_2_OFFSET, ARG_LENGTH); + memcpy(arg_vector[2], shell_cache+ARGV_3_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + current_dir_index = shell_cache[CURRENT_DIR_CACHE_OFFSET]; + + // Argument count + if (argc == 1) + snok(); + else + print("Usage : snok\n", BIOS_WHITE); + + setShellCache(shell_cache); + shellReturn(); +} + + +void snok() { + // char as 1 byte integer + char c, scancode; + int i = 0, rawKey; + int last_direction = SCANCODE_DOWN_ARROW; + int savedCursorRow = getKeyboardCursor(true); + int savedCursorCol = getKeyboardCursor(false); + int p_x, p_y; + int j = 0; + + // Sad that getFullKeyPress() is blocking :( and no kernel size left + clearEntireScreen(); + hideKeyboardCursor(); + setKeyboardCursor(10, 10); + putchar('o'); + setKeyboardCursor(10, 10); + savedCursorRow = getKeyboardCursor(true); + savedCursorCol = getKeyboardCursor(false); + p_x = savedCursorRow; + p_y = savedCursorCol; + i = 0; + do { + savedCursorRow = getKeyboardCursor(true); + savedCursorCol = getKeyboardCursor(false); + + switch (scancode) { + case SCANCODE_DOWN_ARROW: + if (p_x < 25) { + p_x++; + // putchar(' '); + setKeyboardCursor(savedCursorRow + 1, savedCursorCol); + putchar('o'); + setKeyboardCursor(savedCursorRow + 1, savedCursorCol); + } + break; + case SCANCODE_UP_ARROW: + if (p_x > 0) { + p_x--; + // putchar(' '); + setKeyboardCursor(savedCursorRow - 1, savedCursorCol); + putchar('o'); + setKeyboardCursor(savedCursorRow - 1, savedCursorCol); + } + break; + case SCANCODE_RIGHT_ARROW: + if (p_y < 80) { + p_y++; + // putchar(' '); + setKeyboardCursor(savedCursorRow, savedCursorCol + 1); + putchar('o'); + setKeyboardCursor(savedCursorRow, savedCursorCol + 1); + } + break; + case SCANCODE_LEFT_ARROW: + if (p_y > 0) { + p_y--; + // putchar(' '); + setKeyboardCursor(savedCursorRow, savedCursorCol - 1); + putchar('o'); + setKeyboardCursor(savedCursorRow, savedCursorCol - 1); + } + break; + } + savedCursorRow = getKeyboardCursor(true); + savedCursorCol = getKeyboardCursor(false); + + + + rawKey = getFullKey(); + c = rawKey & 0xFF; // AL Value + scancode = rawKey >> 8; // AH Value + // WARNING : Prioritizing ASCII before scancode + if (!(scancode == CTRL_C_SCANCODE_HIGH && c == CTRL_C_SCANCODE_LOW)) { + // If char (AL) is not ASCII Control codes, check scancode (AH) + switch (scancode) { + case SCANCODE_DOWN_ARROW: + case SCANCODE_RIGHT_ARROW: + case SCANCODE_UP_ARROW: + case SCANCODE_LEFT_ARROW: + last_direction = scancode; + break; + default: + break; + } + } + } while (!(scancode == CTRL_C_SCANCODE_HIGH && c == CTRL_C_SCANCODE_LOW)); + + clearEntireScreen(); + setKeyboardCursor(0, 0); + print("snok: exit\n", BIOS_WHITE); +} diff --git a/src/std-header/std.h b/src/std-header/std.h index 42487cd..d21a214 100644 --- a/src/std-header/std.h +++ b/src/std-header/std.h @@ -71,6 +71,12 @@ void showKeyboardCursor(); void hideKeyboardCursor(); // Disable keyboard cursor +void setKeyboardCursor(char r, char c); +// Set keyboard cursor position to row r and column c + +int getKeyboardCursor(bool isrow); +// Get current keyboard cursor position + void scrollScreen(); // Scroll entire screen upward 1 row diff --git a/src/std-header/std_fileio.h b/src/std-header/std_fileio.h new file mode 100644 index 0000000..231d6d0 --- /dev/null +++ b/src/std-header/std_fileio.h @@ -0,0 +1,29 @@ +// 13519214 - Standard function header + +// ---------------- Standard Macro ---------------- +#define NULL 0x00 + + + +extern int interrupt(int number, int AX, int BX, int CX, int DX); + + +// --- File I/O --- +void write(char *buffer, char *path, int *returncode, char parentIndex); +// Write "buffer" with name "path" at "parentIndex" folder + +void read(char *buffer, char *path, int *returncode, char parentIndex); +// Read file with name "path" at "parentIndex" folder and write to "buffer" + +void directSectorWrite(char *buffer, int sector); +// Direct writing to sector, no checking + +void directSectorRead(char *buffer, int sector); +// Direct reading to sector, no checking + +// --- Misc --- +void memcpy(char *dest, char *src, int bytes); +// Copying data from src to desc until bytes reached + +void remove(char *filename, int *returncode, char parentIndex); +// Deleting file or folder diff --git a/src/std-header/std_stringio.h b/src/std-header/std_stringio.h new file mode 100644 index 0000000..025b379 --- /dev/null +++ b/src/std-header/std_stringio.h @@ -0,0 +1,88 @@ +// 13519214 - Standard function header + +// ---------------- Standard Macro ---------------- +#define NULL 0x00 + + + +extern int interrupt(int number, int AX, int BX, int CX, int DX); + +// ---------------- Standard string operation ---------------- +int strlen(char *string); +// Standard string length + +void strcpy(char *dest, char *src); +// Standard strcpy without returning + +void strcpybounded(char *dest, char *src, int n); +// strcpy only first n characters + +void rawstrcpy(char *dest, char *src); +// strcpy without copying null terminator + +void rawstrcpybounded(char *dest, char *src, int n); +// strcpy only first n characters and without null terminator + +char strcmp(char *s1, char *s2); +// Standard strcmp function + +char forcestrcmp(char *s1, char *s2); +// strcmp function, but ignoring strlen until s1 terminated + +void strrev(char *string); +// Reversing string at pointed location + +void strapp(char *string1, char* string2); +// WARNING : No bound checking +// Append string 1 with string 2 + +void strtobytes(char *buffer, char *string, int bytecount); +// Converting string to bytes with size "bytecount" at "buffer" + +void inttostr(char *buffer, int n); +// WARNING : Naive implementation, no bound checking +// Converting integer n to string pointed at buffer + +char isCharInString(char c, char *string); +// Finding whether char c is in string + +int getLastMatchedCharIdx(char c, char *string); +// Get last index of matching char + +int getFirstMatchedCharIdx(char c, char *string); +// Get first index of matching char + +void clear(char *buffer, int length); +// Clearing string buffer + +char isLastSubstring(char *source_string, char *substring); +// Returning whether substring is substring of source_string +// located at last element + +// ---------------- Standard I/O ---------------- +void print(char *string, char color); +// Simple printing with color + +void gets(char *string); +// Simple keyboard input, ye olde gets() + +void putchar(char a); +// Standard 1 char output + +int getFullKey(); +// Getting 1 keypress, blocking, no echo + +void showKeyboardCursor(); +// Showing keyboard cursor to screen + +void hideKeyboardCursor(); +// Disable keyboard cursor + +void setKeyboardCursor(char r, char c); +// Set keyboard cursor position to row r and column c + +int getKeyboardCursor(bool isrow); +// Get current keyboard cursor position + +void scrollScreen(); +// Scroll entire screen upward 1 row diff --git a/src/std_fileio.c b/src/std_fileio.c new file mode 100644 index 0000000..84da852 --- /dev/null +++ b/src/std_fileio.c @@ -0,0 +1,50 @@ +// 13519214 - Standard function + +#include "std-header/std_fileio.h" +#include "std-header/boolean.h" +#include "kernel-header/config.h" + +// ---------------- File I/O ---------------- +void write(char *buffer, char *path, int *returncode, char parentIndex) { + int AX = parentIndex << 8; + AX |= 0x05; + interrupt(0x21, AX, buffer, path, returncode); +} + +void read(char *buffer, char *path, int *returncode, char parentIndex) { + int AX = parentIndex << 8; + AX |= 0x04; + interrupt(0x21, AX, buffer, path, returncode); +} + +void directSectorWrite(char *buffer, int sector) { + interrupt(0x21, 0x03, buffer, sector, 0); +} + +void directSectorRead(char *buffer, int sector) { + interrupt(0x21, 0x02, buffer, sector, 0); +} + +// ---------------- Misc ---------------- +void memcpy(char *dest, char *src, int bytes) { + int i = 0; + while (i < bytes) { + dest[i] = src[i]; + i++; + } +} + +void exec(char *filename, int segment, char parentIndex) { + int AX = parentIndex << 8; + int ret_code; + AX |= 0x06; + interrupt(0x21, AX, filename, segment, &ret_code); + if (ret_code == -1) { + print(filename, BIOS_LIGHT_RED); + print(" not found!\n", BIOS_LIGHT_RED); + } +} + +void remove(char *filename, int *returncode, char parentIndex) { + interrupt(0x21, 0x07, filename, returncode, parentIndex); +} diff --git a/src/std_opr.c b/src/std_opr.c new file mode 100644 index 0000000..102634d --- /dev/null +++ b/src/std_opr.c @@ -0,0 +1,9 @@ +// 13519214 - Basic operator + +int div(int a, int b) { + return a/b; +} + +int mod(int a, int n) { + return a - n*(a/n); +} diff --git a/src/std_stringio.c b/src/std_stringio.c new file mode 100644 index 0000000..bd1ae8e --- /dev/null +++ b/src/std_stringio.c @@ -0,0 +1,266 @@ +// 13519214 - Standard function + +#include "std-header/std_stringio.h" +#include "std-header/boolean.h" +#include "kernel-header/config.h" + +// ---------------- Standard string operation ---------------- +int strlen(char *string) { + int i = 0; + while (string[i] != '\0') + i++; + return i; +} + +int strlenbin(char *string) { + int i = 0; + int null_count = 0; + // Only stop if found 5 consecutive null terminator + while (null_count < 5) { + if (string[i] == '\0') + null_count++; + else + null_count = 0; + i++; + } + return i; +} + +void strcpy(char *dest, char *src) { + int i = 0; + while (src[i] != '\0') { + dest[i] = src[i]; + i++; + } + dest[i] = '\0'; +} + +void rawstrcpy(char *dest, char *src) { + int i = 0; + while (src[i] != '\0') { + dest[i] = src[i]; + i++; + } +} + +void strcpybounded(char *dest, char *src, int n) { + int i = 0; + while (src[i] != '\0' && i < n) { + dest[i] = src[i]; + i++; + } + dest[i] = '\0'; +} + +void rawstrcpybounded(char *dest, char *src, int n) { + int i = 0; + while (src[i] != '\0' && i < n) { + dest[i] = src[i]; + i++; + } +} + +char strcmp(char *s1, char *s2) { + int i = 0; + if (strlen(s1) == strlen(s2)) { + // If string length matches, check every char + while (s1[i] != '\0') { + if (s1[i] != s2[i]) + return 1; + i++; + } + + // If both string matches + return 0; + } + + return 1; +} + +char forcestrcmp(char *s1, char *s2) { + int i = 0; + // If string length matches, check every char + while (s1[i] != '\0') { + if (s1[i] != s2[i]) + return 1; + i++; + } + + // If both string matches + return 0; +} + +void strapp(char *string1, char *string2) { + int i = strlen(string1), j = 0; + while (string2[j] != CHAR_NULL) { + string1[i] = string2[j]; + i++; + j++; + } + string1[i] = CHAR_NULL; +} + +char isCharInString(char c, char *string) { + int i = 0; + while (string[i] != CHAR_NULL) { + if (string[i] == c) + return 1; + i++; + } + return 0; +} + +int getLastMatchedCharIdx(char c, char *string) { + int i = 0, tp = -1; + while (string[i] != CHAR_NULL) { + if (string[i] == c) + tp = i; + i++; + } + return tp; +} + +int getFirstMatchedCharIdx(char c, char *string) { + int i = 0, tp = -1; + while (string[i] != CHAR_NULL && tp == -1) { + if (string[i] == c) + tp = i; + i++; + } + return tp; +} + +void clear(char *string, int length) { + int i = 0; + while (i < length) { + string[i] = CHAR_NULL; + i++; + } +} + +void inttostr(char *buffer, int n) { + int i = 0; + bool is_negative = false; + if (n < 0) { + n *= -1; + is_negative = true; + } + while (n > 10) { + buffer[i] = CHAR_NUMBER_0 + mod(n, 10); + i++; + n /= 10; + } + buffer[i] = CHAR_NUMBER_0 + mod(n, 10); // First digit + i++; + if (is_negative) { + buffer[i] = '-'; + i++; + } + buffer[i] = '\0'; + strrev(buffer); +} + +void strrev(char *string) { + int i = 0, length = strlen(string); + char temp; + while (i < length/2) { + temp = string[i]; + string[i] = string[length - 1 - i]; + string[length - 1 - i] = temp; + i++; + } +} + +void strtobytes(char *buffer, char *string, int bytecount) { + int i = 0; + while (string[i] != CHAR_NULL && i < bytecount) { + buffer[i] = string[i]; + i++; + } + while (i < bytecount) { + buffer[i] = 0x00; + i++; + } +} + +bool isLastSubstring(char *source_string, char *substring) { + bool is_substring = true; + int i, j; + int source_count = strlen(source_string); + int substring_count = strlen(substring); + + if (source_count < substring_count) + is_substring = false; + else { + i = source_count - substring_count; + j = 0; + while (i < source_count && is_substring) { + if (source_string[i] != substring[j]) + is_substring = false; + j++; + i++; + } + } + + return is_substring; +} + +// ---------------- Standard I/O ---------------- +void print(char *string, char color) { + // TODO : Extra, Maybe not safe (?) + // TODO : Extra, Including black color + if (BIOS_BLACK < color && color <= BIOS_WHITE) + interrupt(0x21, 0x00, string, 0x00, color); + else + interrupt(0x21, 0x00, string, 0x00, BIOS_GRAY); +} + +void gets(char *string) { + interrupt(0x21, 0x01, string, 0x00, 0); +} + +void putchar(char a) { + int temp; + char tempstring[2]; + tempstring[0] = a; + tempstring[1] = '\0'; + if (a == CHAR_BACKSPACE) + interrupt(0x21, 0x00, 0, 0x01, 0); + else + interrupt(0x21, 0x00, tempstring, 0x00, BIOS_GRAY); + +} + +int getFullKey() { + int key; + interrupt(0x21, 0x01, &key, 0x01, 0); + return key; +} + +void showKeyboardCursor() { + interrupt(0x21, 0x0001, 0, 0x4, 0); +} + +void hideKeyboardCursor() { + interrupt(0x21, 0x0001, 0, 0x5, 0); +} + +void setKeyboardCursor(char r, char c) { + int BX = (r << 8); + BX |= c; + interrupt(0x21, 0x01, BX, 0x02, 0); +} + +int getKeyboardCursor(bool isrow) { + int pos; + interrupt(0x21, 0x01, &pos, 0x3, isrow); + return pos; +} + +void scrollScreen() { + interrupt(0x21, 0x00, 0, 0x02, 0); +} + +void clearEntireScreen() { + interrupt(0x21, 0x00, 0, 0x03, 0); +} diff --git a/src/strings.c b/src/strings.c new file mode 100644 index 0000000..5b4f9a8 --- /dev/null +++ b/src/strings.c @@ -0,0 +1,180 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" +#include "std-header/boolean.h" + +void strings(char *dirtable, char current_dir_index, char *target); + +int main() { + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char arg_vector[ARGC_MAX][ARG_LENGTH]; + char argc = 0; + int current_dir_index; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(arg_vector, ARGC_MAX*ARG_LENGTH); + memcpy(arg_vector[0], shell_cache+ARGV_OFFSET, ARG_LENGTH); + memcpy(arg_vector[1], shell_cache+ARGV_2_OFFSET, ARG_LENGTH); + memcpy(arg_vector[2], shell_cache+ARGV_3_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + current_dir_index = shell_cache[CURRENT_DIR_CACHE_OFFSET]; + + // Argument count + if (argc == 2) + if (!strcmp("--help", arg_vector[0])) { + print("Utility to print any printable character in file\n", BIOS_WHITE); + print("Possible Usage:\n", BIOS_LIGHT_BLUE); + print("strings [file_name]\n", BIOS_LIGHT_CYAN); + } + else { + strings(directory_table, current_dir_index, arg_vector[0]); + } + else + print("Usage : strings \n", BIOS_WHITE); + + setShellCache(shell_cache); + shellReturn(); +} + +void strings(char *dirtable, char current_dir_index, char *target) { + // char as string / char + char filename_buffer[16]; + char source_directory_name[16]; + char string_word_count[32]; + // char as 1 byte integer + char file_read[FILE_SIZE_MAXIMUM]; + char target_entry_byte = 0; + char target_parent_byte = 0; + char source_dir_idx; + char link_status = -1; + int returncode_src = 0; + bool is_write_success = false, valid_filename = true; + bool f_target_found = false, empty_entry_found = false; + bool is_found_parent = false; + int i = 0, j = 0; + int f_entry_idx = 0; + int f_entry_sector_idx = 0; + int last_slash_index; + int word_count; + int null_count; + + // Relative pathing + clear(source_directory_name, 16); + // Split target / source + last_slash_index = getLastMatchedCharIdx(CHAR_SLASH, target); + // FIXME : Extra, unsafe getlast + if (last_slash_index != -1) { + // Split argument to path and filename + // Get path + strcpybounded(source_directory_name, target, last_slash_index); + source_dir_idx = directoryEvaluator(dirtable, source_directory_name, &returncode_src, current_dir_index); + + // Get filename + strcpybounded(source_directory_name, target+last_slash_index+1, ARG_LENGTH-last_slash_index-1); + } + else { + // Cut slash + strcpybounded(source_directory_name, target, ARG_LENGTH); + + source_dir_idx = current_dir_index; + returncode_src = 0; + } + + + + // Copying strings if path evaluation success + if (returncode_src == -1) { + print("strings: ", BIOS_GRAY); + print(target, BIOS_GRAY); + print(": target not found\n", BIOS_GRAY); + } + else { + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, source_directory_name, &returncode_src, source_dir_idx); + if (returncode_src == 0) { + + // Find entry in files + i = 0; + while (i < FILES_ENTRY_COUNT && !is_found_parent) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, 14); + if (dirtable[i*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET] == source_dir_idx && + !strcmp(source_directory_name, filename_buffer)) { + is_found_parent = true; + target_entry_byte = dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET]; + link_status = dirtable[i*FILES_ENTRY_SIZE+LINK_BYTE_OFFSET]; + } + i++; + } + + print("strings: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print("\n", BIOS_WHITE); + + if (link_status == SOFTLINK_ENTRY) { + // Get linked strings / folder with recursion depth limit 16 + i = 0; + // TODO : Extra, currently only single softlink depth supported + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+target_entry_byte*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + target_parent_byte = dirtable[target_entry_byte*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET]; + target_entry_byte = dirtable[target_entry_byte*FILES_ENTRY_SIZE + ENTRY_BYTE_OFFSET]; + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, filename_buffer, &returncode_src, target_parent_byte); + // Needed to compare due _mash_cache always filling empty space + // Implying softlink to _mash_cache is not available + if (!strcmp(filename_buffer, "_mash_cache")) + target_entry_byte = EMPTY_FILES_ENTRY; + } + + if (returncode_src == 0 && target_entry_byte != EMPTY_FILES_ENTRY) { + if (target_entry_byte != FOLDER_ENTRY) { + clear(string_word_count, 32); + + i = 0; + word_count = 0; + null_count = 0; + while (i < FILE_SIZE_MAXIMUM && null_count < 5) { + if (file_read[i] == CHAR_NULL) + null_count++; + else + null_count = 0; + + if ((CHAR_SPACE <= file_read[i] && file_read[i] <= CHAR_TILDE + || file_read[i] == CHAR_NULL || file_read[i] == CHAR_CARRIAGE_RETURN + || file_read[i] == CHAR_LINEFEED)) + putchar(file_read[i]); + + if (getKeyboardCursor(true) > 20) { + scrollScreen(); + scrollScreen(); + } + i++; + } + + } + else { + print("strings: not a file\n", BIOS_WHITE); + } + } + else { + print("string: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print(" softlink broken\n", BIOS_WHITE); + } + + } + else { + print("strings: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print(" not found\n", BIOS_WHITE); + } + + + } +} diff --git a/src/wc.c b/src/wc.c new file mode 100644 index 0000000..a3897f1 --- /dev/null +++ b/src/wc.c @@ -0,0 +1,198 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" +#include "std-header/boolean.h" + +void wc(char *dirtable, char current_dir_index, char *target); + +int main() { + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char arg_vector[ARGC_MAX][ARG_LENGTH]; + char argc = 0; + int current_dir_index; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(arg_vector, ARGC_MAX*ARG_LENGTH); + memcpy(arg_vector[0], shell_cache+ARGV_OFFSET, ARG_LENGTH); + memcpy(arg_vector[1], shell_cache+ARGV_2_OFFSET, ARG_LENGTH); + memcpy(arg_vector[2], shell_cache+ARGV_3_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + current_dir_index = shell_cache[CURRENT_DIR_CACHE_OFFSET]; + + // Argument count + if (argc == 2) + if (!strcmp("--help", arg_vector[0])) { + print("Utility to view word count of a file\n", BIOS_WHITE); + print("Possible Usage:\n", BIOS_LIGHT_BLUE); + print("wc [file_name]\n", BIOS_LIGHT_CYAN); + } + else { + wc(directory_table, current_dir_index, arg_vector[0]); + } + else + print("Usage : wc \n", BIOS_WHITE); + + setShellCache(shell_cache); + shellReturn(); +} + +bool isTextCharOnly(char *buffer) { + int i = 0; + int null_count = 0; + bool isCharOnly = true; + while (i < FILE_SIZE_MAXIMUM && null_count < 5 && isCharOnly) { + if (buffer[i] == '\0') + null_count++; + else + null_count = 0; + + if (!(CHAR_SPACE <= buffer[i] && buffer[i] <= CHAR_TILDE + || buffer[i] == CHAR_NULL || buffer[i] == CHAR_CARRIAGE_RETURN + || buffer[i] == CHAR_LINEFEED) ) + isCharOnly = false; + + i++; + } + return isCharOnly; +} + +void wc(char *dirtable, char current_dir_index, char *target) { + // char as string / char + char filename_buffer[16]; + char source_directory_name[16]; + char string_word_count[32]; + // char as 1 byte integer + char file_read[FILE_SIZE_MAXIMUM]; + char target_entry_byte = 0; + char target_parent_byte = 0; + char source_dir_idx; + char link_status = -1; + int returncode_src = 0; + bool is_write_success = false, valid_filename = true; + bool f_target_found = false, empty_entry_found = false; + bool is_found_parent = false; + int i = 0, j = 0; + int f_entry_idx = 0; + int f_entry_sector_idx = 0; + int last_slash_index; + int word_count; + int null_count; + + // Relative pathing + clear(source_directory_name, 16); + // Split target / source + last_slash_index = getLastMatchedCharIdx(CHAR_SLASH, target); + // FIXME : Extra, unsafe getlast + if (last_slash_index != -1) { + // Split argument to path and filename + // Get path + strcpybounded(source_directory_name, target, last_slash_index); + source_dir_idx = directoryEvaluator(dirtable, source_directory_name, &returncode_src, current_dir_index); + + // Get filename + strcpybounded(source_directory_name, target+last_slash_index+1, ARG_LENGTH-last_slash_index-1); + } + else { + // Cut slash + strcpybounded(source_directory_name, target, ARG_LENGTH); + + source_dir_idx = current_dir_index; + returncode_src = 0; + } + + + + // Copying wc if path evaluation success + if (returncode_src == -1) { + print("wc: ", BIOS_GRAY); + print(target, BIOS_GRAY); + print(": target not found\n", BIOS_GRAY); + } + else { + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, source_directory_name, &returncode_src, source_dir_idx); + if (returncode_src == 0) { + + // Find entry in files + i = 0; + while (i < FILES_ENTRY_COUNT && !is_found_parent) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+FILES_ENTRY_SIZE*i+PATHNAME_BYTE_OFFSET, 14); + if (dirtable[i*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET] == source_dir_idx && + !strcmp(source_directory_name, filename_buffer)) { + is_found_parent = true; + target_entry_byte = dirtable[i*FILES_ENTRY_SIZE+ENTRY_BYTE_OFFSET]; + link_status = dirtable[i*FILES_ENTRY_SIZE+LINK_BYTE_OFFSET]; + } + i++; + } + + print("wc: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print("\n", BIOS_WHITE); + + if (link_status == SOFTLINK_ENTRY) { + // Get linked wc / folder with recursion depth limit 16 + i = 0; + // TODO : Extra, currently only single softlink depth supported + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+target_entry_byte*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + target_parent_byte = dirtable[target_entry_byte*FILES_ENTRY_SIZE + PARENT_BYTE_OFFSET]; + target_entry_byte = dirtable[target_entry_byte*FILES_ENTRY_SIZE + ENTRY_BYTE_OFFSET]; + clear(file_read, FILE_SIZE_MAXIMUM); + read(file_read, filename_buffer, &returncode_src, target_parent_byte); + // Needed to compare due _mash_cache always filling empty space + // Implying softlink to _mash_cache is not available + if (!strcmp(filename_buffer, "_mash_cache")) + target_entry_byte = EMPTY_FILES_ENTRY; + } + + if (returncode_src == 0 && target_entry_byte != EMPTY_FILES_ENTRY) { + if (target_entry_byte != FOLDER_ENTRY && isTextCharOnly(file_read)) { + + clear(string_word_count, 32); + + i = 0; + word_count = 0; + null_count = 0; + while (i < FILE_SIZE_MAXIMUM && null_count < 5) { + if (file_read[i] == CHAR_NULL) + null_count++; + else + null_count = 0; + + if (file_read[i] == CHAR_SPACE || file_read[i] == CHAR_LINEFEED) + word_count++; + i++; + } + + print("wc: ", BIOS_WHITE); + inttostr(string_word_count, word_count); + print(string_word_count, BIOS_WHITE); + print(" words\n", BIOS_WHITE); + } + else { + print("wc: not text file\n", BIOS_WHITE); + } + } + else { + print("wc: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print(" softlink broken\n", BIOS_WHITE); + } + + } + else { + print("wc: ", BIOS_WHITE); + print(source_directory_name, BIOS_WHITE); + print(" not found\n", BIOS_WHITE); + } + + + } +} diff --git a/src/whereis.c b/src/whereis.c new file mode 100644 index 0000000..e4d8f1b --- /dev/null +++ b/src/whereis.c @@ -0,0 +1,108 @@ +#include "kernel-header/config.h" +#include "std-header/std_stringio.h" +#include "shell-header/shell_common.h" +#include "basic-header/std_opr.h" +#include "std-header/boolean.h" + +void directoryStringBuilder(char *string, char *dirtable, char current_dir); + +int main() { + // char as character + char filename_buffer[16]; + char absolute_path[256]; + // char as 1 byte integer + char directory_table[FILES_SECTOR_SIZE*SECTOR_SIZE]; + char shell_cache[SECTOR_SIZE]; + char arg_vector[ARGC_MAX][ARG_LENGTH]; + char argc = 0; + int current_dir_index; + int i = 0; + bool any_match = false; + + clear(shell_cache, SECTOR_SIZE); + getDirectoryTable(directory_table); + getShellCache(shell_cache); + + clear(arg_vector, ARGC_MAX*ARG_LENGTH); + memcpy(arg_vector[0], shell_cache+ARGV_OFFSET, ARG_LENGTH); + memcpy(arg_vector[1], shell_cache+ARGV_2_OFFSET, ARG_LENGTH); + memcpy(arg_vector[2], shell_cache+ARGV_3_OFFSET, ARG_LENGTH); + argc = shell_cache[ARGC_OFFSET]; + current_dir_index = shell_cache[CURRENT_DIR_CACHE_OFFSET]; + + // Argument count + if (argc == 2) { + if (!strcmp("--help", arg_vector[0])) { + print("Utility to find the location of source/binary file of a command and manuals sections for a specified file\n", BIOS_WHITE); + print("Possible Usage:\n", BIOS_LIGHT_BLUE); + print("whereis [file_name]\n", BIOS_LIGHT_CYAN); + print("whereis [folder_name]\n", BIOS_LIGHT_CYAN); + } + else { + i = 0; + while (i < FILES_ENTRY_COUNT) { + clear(filename_buffer, 16); + strcpybounded(filename_buffer, directory_table+i*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + if (!strcmp(filename_buffer, arg_vector[0])) { + any_match = true; + clear(absolute_path, 256); + directoryStringBuilder(absolute_path, directory_table, directory_table[i*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET]); + strapp(absolute_path, "/"); + strapp(absolute_path, arg_vector[0]); + print(absolute_path, BIOS_LIGHT_BLUE); + print("\n", BIOS_WHITE); + } + i++; + } + + if (!any_match) { + print("whereis: ", BIOS_WHITE); + print(arg_vector[1], BIOS_WHITE); + print(" not found", BIOS_WHITE); + } + } + } + else + print("Usage : whereis \n", BIOS_WHITE); + + setShellCache(shell_cache); + shellReturn(); +} + +void directoryStringBuilder(char *string, char *dirtable, char current_dir) { + // Use as string / char + char filename_buffer[16]; + // Use as 1 bytes integer + char current_parent = 0, parent[FILES_ENTRY_COUNT]; + // parent will contain indices in reversed order + int i = 0, parent_length = 0; + if (current_dir == ROOT_PARENT_FOLDER) + string[0] = '/'; + else { + clear(parent, FILES_ENTRY_COUNT); + // Traversing folder until reaching root + current_parent = dirtable[current_dir*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET]; + while (current_parent != ROOT_PARENT_FOLDER) { + parent[parent_length] = current_parent; + parent_length++; + current_parent = dirtable[current_parent*FILES_ENTRY_SIZE+PARENT_BYTE_OFFSET]; + } + + // Adding lower parent + i = parent_length - 1; + while (i >= 0) { + strapp(string, "/"); + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+(parent[i]*FILES_ENTRY_SIZE)+PATHNAME_BYTE_OFFSET, 14); + strapp(string, filename_buffer); + + i--; + } + + // Adding topmost parent + strapp(string, "/"); + clear(filename_buffer, 16); + strcpybounded(filename_buffer, dirtable+current_dir*FILES_ENTRY_SIZE+PATHNAME_BYTE_OFFSET, 14); + strapp(string, filename_buffer); + } +}