Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
245cfa57f3 | ||
|
|
88716c0b64 | ||
|
|
7a9b82d57c |
7
Makefile
7
Makefile
@@ -15,7 +15,7 @@ $(BUILD_DIR)/crawos.iso: floppy_image
|
||||
# Floppy image
|
||||
# Fat12
|
||||
floppy_image: $(BUILD_DIR)/crawos.img
|
||||
$(BUILD_DIR)/crawos.img: bootloader kernel
|
||||
$(BUILD_DIR)/crawos.img: bootloader kernel check-fat83
|
||||
mkdir -p disk_images
|
||||
dd if=/dev/zero of=$(BUILD_DIR)/crawos.img bs=512 count=2880 # Use dd to make a disk image
|
||||
mkfs.fat -F 12 -n "CRAWOS" $(BUILD_DIR)/crawos.img # Format the disk image with fat12
|
||||
@@ -36,6 +36,11 @@ $(BUILD_DIR)/kernel.bin:
|
||||
mkdir -p disk_images
|
||||
$(ASM) $(SRC_DIR)/kernel/kernel.asm -f bin -o $ $(BUILD_DIR)/kernel.bin
|
||||
|
||||
check-fat83:
|
||||
@echo "Checking filenames for FAT 8.3 compliance..."
|
||||
@find ./data -type f | awk -F/ '{print $$NF}' | \
|
||||
awk -F. 'length($$1)>8 || length($$2)>3 || NF>2 {print "Invalid FAT 8.3 filename:", $$0; bad=1} END{exit bad}'
|
||||
|
||||
# Clean
|
||||
clean:
|
||||
rm -f disk_images/*
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
Kernel written in Assmebly
|
||||
I'm using a modified JazzOS Bootloader
|
||||
# What is this?
|
||||
This is a simple implementation of a computer kernel
|
||||
written in pure x86 assembly with features including
|
||||
- Read/Write disk operations
|
||||
- The ability to boot from the BIOS using the JazzOS Bootloader
|
||||
- A modified MikeOS BASIC interpreter
|
||||
- A functional POSIX inspired CLI
|
||||
|
||||
Commands:
|
||||
CAT
|
||||
HELP
|
||||
CLEAR
|
||||
REBOOT
|
||||
PONG
|
||||
# Commands
|
||||
- CAT <filename>: outputs the contents of the file.
|
||||
- LS: outputs a list of files on the system .
|
||||
- CLEAR: clears the screen.
|
||||
- REBOOT: or esc reboots the system
|
||||
- BAS <filename>: runs a basic script.
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
PORT OUT 80 5
|
||||
PRINT "Hello, what is your name?"
|
||||
INPUT $1
|
||||
PRINT "Hello " ;
|
||||
PRINT $1
|
||||
END
|
||||
|
||||
2
data/test.asm
Normal file
2
data/test.asm
Normal file
@@ -0,0 +1,2 @@
|
||||
X = 100
|
||||
PRINT X
|
||||
@@ -1 +0,0 @@
|
||||
x = 5
|
||||
@@ -26,7 +26,7 @@ ebr_system_id: db 'FAT12 ' ; must be 8 bytes
|
||||
fat12_file_name: db ' ' ; 11 free bytes to store a filename in
|
||||
boot_message: db 'OK] Kernel successfully loaded!\n"HELP" to see a list of available commands\n', 0
|
||||
user_input: times 20 db 0
|
||||
prompt_length: db 20
|
||||
prompt_length: dw 20
|
||||
prompt: db 'sh > ', 0
|
||||
help_string: db 'HELP', 0
|
||||
clear_string: db 'CLEAR', 0
|
||||
@@ -34,7 +34,8 @@ reboot_string: db 'REBOOT', 0
|
||||
basic_string: db 'BAS', 0
|
||||
cat_string: db 'CAT', 0
|
||||
ls_string: db 'LS', 0
|
||||
help_text: db 'This is for Cowards:\n"LS" to list the directory,\n"CAT" to output the contents of a file,\n"BAS" to run a basic script,\n"HELP" for this helpful text,\n"CLEAR" to clear the screen,\n"REBOOT" or esc to reboot\n', 0
|
||||
ed_string: db 'ED', 0
|
||||
help_text: db 'This is for Cowards:\n"LS" to list the directory,\n"CAT <filename>" to output the contents of a file,\n"BAS <filename>" to run a basic script,\n"HELP" for this helpful text,\n"CLEAR" to clear the screen,\n"REBOOT" or esc to reboot\n', 0
|
||||
basic_text: db 'BASIC PROGRAM BEGUN:\n', 0
|
||||
command_result_text: db 'You typed: ', 0
|
||||
unknown_command: db 'Error: Unkown Command..\n ', 0
|
||||
@@ -47,12 +48,6 @@ file_not_found: db 'File not found\n', 0
|
||||
too_long_filename: db 'Filename too long for Fat12\n', 0
|
||||
file_found: db 'File found\n', 0
|
||||
loading_root: db 'Loading root diretory\n', 0
|
||||
read_only: db 'Read Only', 0 ; 1
|
||||
hidden: db ' Hidden ', 0 ; 2
|
||||
system: db ' System ', 0 ; 4
|
||||
volume: db ' Volume ', 0 ; 8
|
||||
directory: db 'Directory', 0 ; 10
|
||||
archive: db ' Archive ', 0 ; 20
|
||||
file_name_length: db 0
|
||||
file_cluster: dw 0
|
||||
file_length: dd 0
|
||||
|
||||
@@ -842,14 +842,14 @@ do_break:
|
||||
do_call:
|
||||
call get_token
|
||||
cmp ax, NUMBER
|
||||
je .is_number
|
||||
je .check_is_number
|
||||
|
||||
mov ax, 0
|
||||
mov byte al, [token]
|
||||
call get_var
|
||||
jmp .execute_call
|
||||
|
||||
.is_number:
|
||||
.check_is_number:
|
||||
mov si, token
|
||||
call string_cast_to_int
|
||||
|
||||
@@ -1325,7 +1325,7 @@ do_for:
|
||||
cmp ax, NUMBER
|
||||
jne .error
|
||||
|
||||
.second_is_number:
|
||||
.second_check_is_number:
|
||||
mov si, token ; Get target number
|
||||
call string_cast_to_int
|
||||
jmp .continue2
|
||||
@@ -1625,7 +1625,7 @@ do_if:
|
||||
je .equals_char
|
||||
|
||||
mov byte al, [token]
|
||||
call is_letter
|
||||
call check_is_letter
|
||||
jc .equals_var
|
||||
|
||||
mov si, token ; Otherwise it's, eg 'X = 1' (a number)
|
||||
@@ -1711,7 +1711,7 @@ do_if:
|
||||
.greater:
|
||||
call get_token ; Greater than a variable or number?
|
||||
mov byte al, [token]
|
||||
call is_letter
|
||||
call check_is_letter
|
||||
jc .greater_var
|
||||
|
||||
mov si, token ; Must be a number here...
|
||||
@@ -1736,7 +1736,7 @@ do_if:
|
||||
.less:
|
||||
call get_token
|
||||
mov byte al, [token]
|
||||
call is_letter
|
||||
call check_is_letter
|
||||
jc .less_var
|
||||
|
||||
mov si, token
|
||||
@@ -1950,8 +1950,9 @@ do_input:
|
||||
|
||||
.number_var:
|
||||
mov ax, .tmpstring ; Get input from the user
|
||||
mov bx, 6
|
||||
mov bx, 20
|
||||
call keyboard_display_input
|
||||
jc .end
|
||||
|
||||
mov ax, .tmpstring
|
||||
call string_length
|
||||
@@ -1973,8 +1974,6 @@ do_input:
|
||||
call os_print_newline
|
||||
|
||||
jmp mainloop
|
||||
|
||||
|
||||
.string_var:
|
||||
mov ax, 128
|
||||
mul bx
|
||||
@@ -1987,8 +1986,9 @@ do_input:
|
||||
|
||||
jmp mainloop
|
||||
|
||||
|
||||
.tmpstring times 6 db 0
|
||||
.tmpstring times 20 db 0
|
||||
.end
|
||||
ret
|
||||
|
||||
|
||||
; -----------------------------------------------------------
|
||||
@@ -2636,7 +2636,7 @@ do_peekint:
|
||||
cmp ax, NUMBER
|
||||
jne .error
|
||||
|
||||
.address_is_number:
|
||||
.address_check_is_number:
|
||||
mov si, token
|
||||
call string_cast_to_int
|
||||
jmp .load_data
|
||||
@@ -3770,14 +3770,14 @@ do_string:
|
||||
call get_token ; Now there should be a number
|
||||
|
||||
cmp ax, NUMBER
|
||||
je .third_is_number
|
||||
je .third_check_is_number
|
||||
|
||||
cmp ax, VARIABLE
|
||||
je .third_is_variable
|
||||
|
||||
jmp .error
|
||||
|
||||
.third_is_number:
|
||||
.third_check_is_number:
|
||||
mov si, token
|
||||
call string_cast_to_int
|
||||
jmp .got_number
|
||||
@@ -3984,7 +3984,7 @@ get_token:
|
||||
cmp al, ' '
|
||||
je .newline
|
||||
|
||||
call is_number
|
||||
call check_is_number
|
||||
jc get_number_token
|
||||
|
||||
cmp al, '"'
|
||||
@@ -4030,7 +4030,7 @@ get_number_token:
|
||||
je .done
|
||||
cmp al, ' '
|
||||
je .done
|
||||
call is_number
|
||||
call check_is_number
|
||||
jc .fine
|
||||
|
||||
mov si, err_char_in_num
|
||||
@@ -4153,7 +4153,7 @@ get_string_token:
|
||||
|
||||
.is_not_string:
|
||||
mov byte al, [token]
|
||||
call is_letter
|
||||
call check_is_letter
|
||||
jc .is_var
|
||||
|
||||
mov ax, UNKNOWN
|
||||
@@ -4164,37 +4164,6 @@ get_string_token:
|
||||
ret
|
||||
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; Set carry flag if AL contains ASCII number
|
||||
|
||||
is_number:
|
||||
cmp al, 48
|
||||
jl .not_number
|
||||
cmp al, 57
|
||||
jg .not_number
|
||||
stc
|
||||
ret
|
||||
.not_number:
|
||||
clc
|
||||
ret
|
||||
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; Set carry flag if AL contains ASCII letter
|
||||
|
||||
is_letter:
|
||||
cmp al, 65
|
||||
jl .not_letter
|
||||
cmp al, 90
|
||||
jg .not_letter
|
||||
stc
|
||||
ret
|
||||
|
||||
.not_letter:
|
||||
clc
|
||||
ret
|
||||
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; Print error message and quit out
|
||||
|
||||
|
||||
29
source/kernel/features/check.asm
Normal file
29
source/kernel/features/check.asm
Normal file
@@ -0,0 +1,29 @@
|
||||
check_is_number:
|
||||
cmp al, 48
|
||||
jl .not_number
|
||||
cmp al, 57
|
||||
jg .not_number
|
||||
stc
|
||||
ret
|
||||
.not_number:
|
||||
clc
|
||||
ret
|
||||
|
||||
check_is_letter:
|
||||
cmp al, 65
|
||||
jl .not_letter
|
||||
cmp al, 122
|
||||
jg .not_letter
|
||||
cmp al, 90
|
||||
jg .maybe_not_letter
|
||||
stc
|
||||
ret
|
||||
.maybe_not_letter:
|
||||
cmp al, 97
|
||||
jl .not_letter
|
||||
stc
|
||||
ret
|
||||
.not_letter:
|
||||
clc
|
||||
ret
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
os_start_cli:
|
||||
pusha
|
||||
|
||||
|
||||
call os_print_newline
|
||||
|
||||
mov si, prompt
|
||||
@@ -11,6 +12,7 @@ os_start_cli:
|
||||
mov ax, user_input
|
||||
|
||||
call keyboard_display_input
|
||||
jc power_reboot
|
||||
jmp os_read_cli
|
||||
|
||||
|
||||
@@ -30,14 +32,14 @@ os_read_cli:
|
||||
mov di, help_string
|
||||
call os_compare_strings
|
||||
cmp cl, 1
|
||||
je help
|
||||
je .help
|
||||
|
||||
; Clear screen
|
||||
mov si, user_input
|
||||
mov di, clear_string
|
||||
call os_compare_strings
|
||||
cmp cl, 1
|
||||
je clear
|
||||
je .clear
|
||||
|
||||
; Reboot
|
||||
mov si, user_input
|
||||
@@ -51,21 +53,28 @@ os_read_cli:
|
||||
mov di, basic_string
|
||||
call os_compare_strings
|
||||
cmp cl, 1
|
||||
je basic
|
||||
je .basic
|
||||
|
||||
; Cat
|
||||
mov si, user_input
|
||||
mov di, cat_string
|
||||
call os_compare_strings
|
||||
cmp cl, 1
|
||||
je cat
|
||||
je .cat
|
||||
|
||||
; LS
|
||||
mov si, user_input
|
||||
mov di, ls_string
|
||||
call os_compare_strings
|
||||
cmp cl, 1
|
||||
je ls
|
||||
je .ls
|
||||
|
||||
;ED
|
||||
mov si, user_input
|
||||
mov di, ed_string
|
||||
call os_compare_strings
|
||||
cmp cl, 1
|
||||
je .ed
|
||||
|
||||
jmp .unkown
|
||||
|
||||
@@ -77,24 +86,33 @@ os_read_cli:
|
||||
jmp .finish
|
||||
|
||||
.finish:
|
||||
; Clear the user input
|
||||
mov al, 0
|
||||
mov cx, 20
|
||||
mov di,user_input
|
||||
repe stosb
|
||||
popa
|
||||
call os_start_cli
|
||||
|
||||
clear:
|
||||
.clear:
|
||||
call os_set_text_mode
|
||||
call os_read_cli.finish
|
||||
|
||||
help:
|
||||
.help:
|
||||
mov si, help_text
|
||||
call os_print_string
|
||||
call os_read_cli.finish
|
||||
|
||||
basic:
|
||||
.basic:
|
||||
call util_basic
|
||||
call os_read_cli.finish
|
||||
cat:
|
||||
.cat:
|
||||
call util_cat
|
||||
call os_read_cli.finish
|
||||
ls:
|
||||
.ls:
|
||||
call util_ls
|
||||
call os_read_cli.finish
|
||||
.ed:
|
||||
call util_ed
|
||||
call os_read_cli.finish
|
||||
|
||||
|
||||
@@ -171,6 +171,7 @@ disk_clear_output_buffer:
|
||||
; OUT
|
||||
; data_buffer: file contents
|
||||
; TODO use predefined data for calculations
|
||||
; CX = 0 if failed to load
|
||||
disk_load_file:
|
||||
pusha
|
||||
call string_length ; cl = string length
|
||||
@@ -227,13 +228,18 @@ disk_load_file:
|
||||
.file_not_found:
|
||||
mov si, file_not_found
|
||||
call os_print_string
|
||||
jmp .done
|
||||
jmp .done_fail
|
||||
.filename_too_long:
|
||||
mov si, too_long_filename
|
||||
call os_print_string
|
||||
jmp .done
|
||||
jmp .done_fail
|
||||
.done_fail:
|
||||
popa
|
||||
mov bx, 1
|
||||
ret
|
||||
.done:
|
||||
popa
|
||||
xor bx,bx
|
||||
ret
|
||||
|
||||
; Write data to file
|
||||
|
||||
@@ -15,6 +15,7 @@ os_read_input:
|
||||
|
||||
; AX = key pressed
|
||||
; Returns straight away
|
||||
; carry flag is set when escape is pressed and data is returned straight away
|
||||
keyboard_check_key:
|
||||
xor ax,ax
|
||||
mov ah, 11h ; BIOS call to check for key
|
||||
@@ -27,12 +28,13 @@ keyboard_check_key:
|
||||
; IN:
|
||||
; AX = output address
|
||||
; BX = max length
|
||||
|
||||
; OUT:
|
||||
; BX = 1 if escape is pressed
|
||||
keyboard_display_input:
|
||||
pusha
|
||||
mov di, ax
|
||||
mov ax, bx
|
||||
mov bx,20
|
||||
xor ax,ax
|
||||
mov [prompt_length], bx
|
||||
|
||||
.check_key_pressed:
|
||||
call os_read_input
|
||||
@@ -55,16 +57,19 @@ keyboard_display_input:
|
||||
jmp .check_key_pressed
|
||||
|
||||
.esc_key:
|
||||
call power_reboot
|
||||
popa
|
||||
mov bx, 1
|
||||
ret
|
||||
|
||||
.enter_key:
|
||||
mov al, 0
|
||||
stosb
|
||||
popa
|
||||
xor bx,bx
|
||||
ret ; Return to the parent function (whatever that may be)
|
||||
|
||||
.backspace:
|
||||
cmp bx, 20 ; Cannot backspace if the cursor is at the start
|
||||
cmp bx, [prompt_length] ; Cannot backspace if the cursor is at the start
|
||||
jb .move_cursor_back ; then .move_cursor_back
|
||||
jmp .check_key_pressed ; Else check the next key
|
||||
|
||||
@@ -87,6 +92,7 @@ keyboard_display_input:
|
||||
mov ah, 0Eh
|
||||
int 10h
|
||||
jmp .check_key_pressed
|
||||
.input_length db 0
|
||||
|
||||
keyboard_get_cursor_pos:
|
||||
ret
|
||||
|
||||
@@ -106,35 +106,42 @@ string_join:
|
||||
ret
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; TODO
|
||||
; Converts a null terminated string to an integer
|
||||
; Converts a string to an integer
|
||||
; IN: SI = string location (max 5 chars, up to '65536')
|
||||
; OUT: AX = number
|
||||
; OUT: AX = number, DX = length of int string
|
||||
string_cast_to_int:
|
||||
pusha
|
||||
push cx
|
||||
push bx
|
||||
push dx
|
||||
xor cx,cx
|
||||
.loop:
|
||||
xor ax,ax
|
||||
lodsb
|
||||
cmp al, 0
|
||||
je .finish
|
||||
sub al, 30h
|
||||
|
||||
; Exit if the character is not a number
|
||||
cmp al,'0'
|
||||
jl .finish
|
||||
cmp al,'9'
|
||||
jg .finish
|
||||
|
||||
sub al, '0'
|
||||
mov bx, ax
|
||||
|
||||
mov ax, 10
|
||||
mul cx ; Multiple the current value by 10
|
||||
add ax, bx ; Then add the new digit
|
||||
mov cx, ax
|
||||
jmp .loop
|
||||
.finish:
|
||||
mov [int_tmp], cx
|
||||
popa
|
||||
mov ax, [int_tmp]
|
||||
mov ax,cx
|
||||
pop dx
|
||||
pop bx
|
||||
pop cx
|
||||
ret
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; IN: AX = integer (unsigned)
|
||||
; OUT: AX -> null-terminated string
|
||||
|
||||
string_cast_from_int:
|
||||
pusha
|
||||
cld ; Write backwards
|
||||
|
||||
@@ -55,10 +55,16 @@ text_print_raw:
|
||||
je .space
|
||||
cmp al, 0Ah ; When there's an NL or CR, do both, linux encodes files only with NL
|
||||
je .new_line
|
||||
cmp al, 09h ; TAB
|
||||
je .tab
|
||||
cmp al, 0Dh
|
||||
je .repeat
|
||||
int 10h
|
||||
jmp .repeat
|
||||
.tab:
|
||||
mov al, ' '
|
||||
int 10h
|
||||
jmp .repeat
|
||||
.space:
|
||||
mov al, 20h
|
||||
int 10h
|
||||
@@ -130,6 +136,15 @@ os_set_text_mode:
|
||||
mov dl, 0
|
||||
int 10h
|
||||
|
||||
text_newline:
|
||||
pusha
|
||||
mov ax,0E0Ah
|
||||
int 10h
|
||||
mov al,0Dh
|
||||
int 10h
|
||||
popa
|
||||
ret
|
||||
|
||||
popa
|
||||
ret
|
||||
|
||||
|
||||
@@ -1,30 +1,33 @@
|
||||
util_cat:
|
||||
pusha
|
||||
pusha
|
||||
|
||||
call disk_clear_file_buffer
|
||||
mov si, user_input
|
||||
; TODO make this more consistent to account for double spaces
|
||||
add si, 4 ; Move si to after 'CAT'
|
||||
call disk_clear_file_buffer
|
||||
mov si, user_input
|
||||
; TODO make this more consistent to account for double spaces
|
||||
add si, 4 ; Move si to after 'CAT'
|
||||
|
||||
call disk_load_file
|
||||
mov si, file_buffer
|
||||
mov cx, [file_length]
|
||||
call text_print_raw
|
||||
call disk_load_file
|
||||
cmp bx, 1
|
||||
je .done
|
||||
|
||||
popa
|
||||
ret
|
||||
mov si, file_buffer
|
||||
mov cx, [file_length]
|
||||
call text_print_raw
|
||||
.done
|
||||
popa
|
||||
ret
|
||||
|
||||
util_ls:
|
||||
pusha
|
||||
pusha
|
||||
|
||||
call disk_list_contents
|
||||
call disk_list_contents
|
||||
|
||||
mov si, output_buffer
|
||||
call os_print_string
|
||||
call disk_clear_output_buffer
|
||||
mov si, output_buffer
|
||||
call os_print_string
|
||||
call disk_clear_output_buffer
|
||||
|
||||
popa
|
||||
ret
|
||||
popa
|
||||
ret
|
||||
|
||||
util_basic:
|
||||
pusha
|
||||
@@ -34,6 +37,8 @@ util_basic:
|
||||
; TODO make this more consistent to account for double spaces
|
||||
;add si, 3 ; Move si to after 'BAS'
|
||||
call disk_load_file
|
||||
cmp bx, 1
|
||||
je .done
|
||||
|
||||
mov si, file_buffer
|
||||
|
||||
@@ -41,5 +46,16 @@ util_basic:
|
||||
mov si, 0
|
||||
call basic_run_basic
|
||||
|
||||
.done
|
||||
popa
|
||||
ret
|
||||
|
||||
util_ed:
|
||||
pusha
|
||||
call disk_load_root
|
||||
call disk_load_file
|
||||
|
||||
call ed
|
||||
|
||||
popa
|
||||
ret
|
||||
|
||||
@@ -33,13 +33,19 @@ halt:
|
||||
%INCLUDE "source/kernel/features/sound.asm"
|
||||
%INCLUDE "source/kernel/features/disk.asm"
|
||||
%INCLUDE "source/kernel/features/math.asm"
|
||||
%INCLUDE "source/kernel/features/check.asm"
|
||||
%INCLUDE "source/kernel/features/time.asm"
|
||||
%INCLUDE "source/kernel/features/utils.asm"
|
||||
%INCLUDE "source/kernel/features/cli.asm"
|
||||
%INCLUDE "source/kernel/features/misc.asm"
|
||||
%INCLUDE "source/kernel/features/basic.asm"
|
||||
|
||||
; PROGRAMS
|
||||
%INCLUDE "source/kernel/programs/ed.asm"
|
||||
|
||||
; DATA/VARIABLES
|
||||
%INCLUDE "source/kernel/data.asm"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
; Planned commands:
|
||||
; [ ] i insert
|
||||
; [ ] a append
|
||||
; [-] d delete
|
||||
; [x] l prints lines
|
||||
; [ ] w save to disk
|
||||
; [x] q quit
|
||||
ed:
|
||||
pusha
|
||||
call determine_line_count
|
||||
.main_loop:
|
||||
; CLEAR VARIABLES
|
||||
mov [ed_start_int], 0
|
||||
mov [ed_end_int], 0
|
||||
mov [ed_operation_from], 0
|
||||
mov [ed_operation_by], 0
|
||||
|
||||
; Setup prompt
|
||||
mov ax, ed_prompt
|
||||
mov bx, 40
|
||||
call keyboard_display_input ; AX = string location, BX = max prompt length
|
||||
cmp bx, 1 ; I user pressed escape
|
||||
je .quit
|
||||
mov si, ed_prompt
|
||||
mov bx, 0 ; Keeps track of whether comma has passed
|
||||
jmp .get_token
|
||||
|
||||
.error:
|
||||
call ed_error
|
||||
jmp .main_loop
|
||||
|
||||
; Types of tokens:
|
||||
; Number: eg 123
|
||||
; Doller (refers to the last line) $
|
||||
; Comma ,
|
||||
; Command: eg i
|
||||
; eg 123,127i
|
||||
.get_token:
|
||||
lodsb
|
||||
|
||||
; COMMA
|
||||
cmp al, ','
|
||||
je .comma
|
||||
|
||||
; DOLLAR SIGN
|
||||
cmp al, '$'
|
||||
je .dollar
|
||||
|
||||
; NUMBER
|
||||
call check_is_number
|
||||
jc .get_number_token
|
||||
|
||||
; COMMAND
|
||||
call check_is_letter
|
||||
jc .get_letter_token
|
||||
jmp .error
|
||||
|
||||
; Assign a number to either the start or end int (start,end)
|
||||
.dollar:
|
||||
mov ax, [ed_line_count]
|
||||
inc si ; Cancel out the last dec si
|
||||
jmp .after_int_cast
|
||||
.get_number_token:
|
||||
dec si
|
||||
call string_cast_to_int ; AX = integer, DX = length of int string
|
||||
.after_int_cast:
|
||||
cmp bx, 0
|
||||
je .assign_start_int
|
||||
jg .assign_end_int
|
||||
.assign_start_int:
|
||||
mov [ed_start_int], ax
|
||||
jmp .after_int_assign
|
||||
.assign_end_int:
|
||||
mov [ed_end_int], ax
|
||||
|
||||
; Check it's not after the end of the file
|
||||
cmp ax, [ed_line_count]
|
||||
jg .error
|
||||
; Check it's not less than the start int
|
||||
cmp ax, [ed_start_int]
|
||||
jl .error
|
||||
.after_int_assign:
|
||||
dec si
|
||||
jmp .get_token
|
||||
|
||||
|
||||
; Determines a command
|
||||
.get_letter_token:
|
||||
; If ed int
|
||||
cmp [ed_end_int], 0
|
||||
je .set_end_int
|
||||
.after_end_int_check:
|
||||
cmp al, 'l'
|
||||
je .list
|
||||
cmp al, 'd'
|
||||
je .delete
|
||||
cmp al, 'q'
|
||||
je .quit
|
||||
call ed_error
|
||||
jmp .main_loop
|
||||
; If no end int is assigned, set it to the start int
|
||||
.set_end_int:
|
||||
cmp bx,0
|
||||
push ax
|
||||
jne .end_int_to_end ; If , has been passed
|
||||
.end_int_to_start_int:
|
||||
mov ax, [ed_start_int]
|
||||
mov [ed_end_int], ax
|
||||
pop ax
|
||||
jmp .after_end_int_check
|
||||
.end_int_to_end:
|
||||
mov ax, [ed_line_count]
|
||||
mov [ed_end_int], ax
|
||||
pop ax
|
||||
jmp .after_end_int_check
|
||||
|
||||
|
||||
; Changes the value from start int to end int
|
||||
.comma:
|
||||
mov bx, 1
|
||||
jmp .get_token
|
||||
|
||||
|
||||
; COMMANDS
|
||||
; DELETE ;
|
||||
.delete:
|
||||
; Adjust the ed line count
|
||||
mov ax,[ed_end_int]
|
||||
sub ax,[ed_start_int] ; difference in the lines
|
||||
inc ax
|
||||
sub [ed_line_count], ax
|
||||
|
||||
; set up registers to shift data left
|
||||
; Get the byte of where the left shift will start
|
||||
mov bx, [ed_end_int]
|
||||
inc bx
|
||||
call get_byte_of_line ; CX = byte of start of new line (relative to file buffer)
|
||||
mov [ed_operation_from], cx
|
||||
|
||||
; Get the number of bytes to shift left by
|
||||
mov bx, [ed_start_int]
|
||||
call get_byte_of_line
|
||||
mov ax, [ed_operation_from]
|
||||
sub ax, cx
|
||||
mov [ed_operation_by], ax
|
||||
|
||||
; Perform the shift
|
||||
call shift_data_left
|
||||
|
||||
; Adjust the file metadata byte count
|
||||
mov ax, [file_length]
|
||||
sub ax, [ed_operation_by]
|
||||
mov [file_length], ax
|
||||
|
||||
; Exit
|
||||
call text_newline
|
||||
jmp .main_loop
|
||||
|
||||
|
||||
; LIST ;
|
||||
.list:
|
||||
; set up registers to print the data
|
||||
; Get the byte of where the printing will start
|
||||
mov bx, [ed_start_int]
|
||||
call get_byte_of_line ; CX = byte of start of new line (relative to file buffer)
|
||||
mov si, cx
|
||||
|
||||
; Get the number of bytes to print
|
||||
mov bx,[ed_end_int]
|
||||
inc bx
|
||||
call get_byte_of_line
|
||||
sub cx,si
|
||||
|
||||
call text_newline
|
||||
add si, file_buffer
|
||||
call text_print_raw
|
||||
jmp .main_loop
|
||||
|
||||
.quit:
|
||||
popa
|
||||
jmp os_start_cli
|
||||
|
||||
; This could probably go in disk_?
|
||||
shift_data_left:
|
||||
; Calculate source pointer
|
||||
mov si, [ed_operation_by]
|
||||
add si, file_buffer
|
||||
|
||||
; Calculate destination pointer
|
||||
mov di, si
|
||||
sub di, [ed_operation_by]
|
||||
|
||||
; Loop count
|
||||
mov cx, file_length ; STORES THE LENGTH OF THE FILE IN BYTES
|
||||
sub cx, ed_operation_by
|
||||
|
||||
; Perform the actual left shift
|
||||
rep movsb
|
||||
|
||||
; Override the rest with zeroes
|
||||
mov cx, [ed_operation_by]
|
||||
mov al, 0
|
||||
rep stosb
|
||||
|
||||
ret
|
||||
|
||||
ed_error:
|
||||
pusha
|
||||
|
||||
call text_newline
|
||||
mov ah, 0Eh
|
||||
mov al, '?'
|
||||
int 10h
|
||||
call text_newline
|
||||
|
||||
popa
|
||||
ret
|
||||
|
||||
; IN: BX = target line
|
||||
; OUT: CX = relative byte
|
||||
; TODO fix
|
||||
get_byte_of_line:
|
||||
push dx
|
||||
push si
|
||||
push ax
|
||||
|
||||
mov si, file_buffer
|
||||
|
||||
xor dx,dx
|
||||
xor cx,cx
|
||||
|
||||
jmp .increment_line_count
|
||||
.line_loop:
|
||||
xor ax,ax
|
||||
lodsb
|
||||
inc cx
|
||||
|
||||
cmp al, 0Ah
|
||||
je .increment_line_count
|
||||
|
||||
jmp .line_loop
|
||||
.increment_line_count:
|
||||
inc dx
|
||||
cmp dx, bx
|
||||
jl .line_loop
|
||||
jmp .exit
|
||||
.exit:
|
||||
pop ax
|
||||
pop si
|
||||
pop dx
|
||||
ret
|
||||
|
||||
determine_line_count:
|
||||
mov si, file_buffer
|
||||
mov dx, file_length ; STORES THE LENGTH OF THE FILE IN BYTES
|
||||
xor cx,cx
|
||||
.line_count_loop:
|
||||
lodsb
|
||||
cmp al, 0Ah
|
||||
je .increment_line_count
|
||||
dec dx
|
||||
cmp dx, 0
|
||||
jg .line_count_loop
|
||||
mov [ed_line_count], cx
|
||||
ret
|
||||
.increment_line_count:
|
||||
inc cx
|
||||
jmp .line_count_loop
|
||||
|
||||
ed_data_start: db "ED IS COOL"
|
||||
ed_prompt: times 40 db 0
|
||||
ed_start_int: dw 1
|
||||
ed_end_int: dw 0
|
||||
|
||||
ed_line_count: dw 0
|
||||
|
||||
ed_operation_from: dw 0
|
||||
ed_operation_by: dw 0
|
||||
ed_tmp: dd 0
|
||||
|
||||
Reference in New Issue
Block a user