280 lines
4.9 KiB
NASM
280 lines
4.9 KiB
NASM
; 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
|