339 lines
7.2 KiB
NASM
Executable File
339 lines
7.2 KiB
NASM
Executable File
; How string comparison works
|
|
; DI => scasb compares value stored in DI which is 's' with 's' stored in AX register
|
|
; and then increments DI if DF is 0
|
|
; v
|
|
; memory address 1: |s|n|a|t|0|
|
|
; memory address 2: |s|n|a|k|e|0|
|
|
; ^
|
|
; SI => lodsb loads value stored at SI to AX and then increments SI if DF is 0
|
|
; Additionaly, if the di string ends and the relevant character in si contains a space, it will still return
|
|
; the strings as being equal, this is to allow for command line arquments
|
|
os_compare_strings:
|
|
cld
|
|
|
|
.compare:
|
|
mov al, 0
|
|
scasb
|
|
je .di_ended
|
|
dec di
|
|
lodsb
|
|
scasb ; Compare di to si
|
|
jne .unequal ; If they are not equal, jump to .unequal
|
|
jmp .compare ; Finally, repeat
|
|
|
|
.unequal:
|
|
mov cl, 0 ; Change to 0 if unquality is proven
|
|
ret
|
|
.di_ended:
|
|
lodsb
|
|
cmp al, 20h ; 20h = space
|
|
je .equal
|
|
cmp al, 0
|
|
je .equal
|
|
jmp .unequal
|
|
.equal:
|
|
mov cl, 1
|
|
ret
|
|
|
|
; ------------------------------------------------------------------
|
|
; os_string_compare -- See if two strings match
|
|
; IN: SI = string one, DI = string two
|
|
; OUT: carry set if same, clear if different
|
|
; from MikeOS kernel
|
|
|
|
string_direct_compare:
|
|
pusha
|
|
.more:
|
|
mov al, [si] ; Retrieve string contents
|
|
mov bl, [di]
|
|
cmp al, bl ; Compare characters at current location
|
|
jne .not_same
|
|
cmp al, 0 ; End of first string? Must also be end of second
|
|
je .end
|
|
inc si
|
|
inc di
|
|
jmp .more
|
|
.not_same: ; If unequal lengths with same beginning, the byte
|
|
popa ; comparison fails at shortest string terminator
|
|
clc ; Clear carry flag
|
|
ret
|
|
.end: ; Both strings terminated at the same position
|
|
popa
|
|
stc ; Set carry flag
|
|
ret
|
|
|
|
|
|
; --------------------------------------------------------------------
|
|
; Copies a string from si to di
|
|
; IN:
|
|
; si: points to first character of source string
|
|
; OUT:
|
|
; di: points to first character of destination string
|
|
string_copy:
|
|
pusha
|
|
.loop:
|
|
; TODO could this cause issue when a character is > 1 byte?
|
|
lodsb ; Load si character into ax and increment si by 1
|
|
stosb ; Store ax in di location and increment di by 1
|
|
cmp ax, 0 ; if ax is a 0, quit
|
|
jne .loop
|
|
.done:
|
|
popa
|
|
ret
|
|
|
|
; --------------------------------------------------------------------
|
|
; Joins two strings together into a new string
|
|
; IN/OUT:
|
|
; ax: string1
|
|
; bx: string2
|
|
; cx: result string
|
|
|
|
string_join:
|
|
pusha
|
|
.copy_string1:
|
|
mov si, ax
|
|
mov di, cx
|
|
call string_copy
|
|
mov ax, cx ; TODO check this bit
|
|
call string_length
|
|
add cx, ax
|
|
.copy_string2:
|
|
mov si, bx
|
|
mov di, dx
|
|
call string_copy
|
|
.done:
|
|
popa
|
|
ret
|
|
|
|
; ------------------------------------------------------------------------
|
|
; TODO
|
|
string_cast_to_int:
|
|
ret
|
|
|
|
; ------------------------------------------------------------------------
|
|
|
|
; IN: AX = int
|
|
; OUT: AX = string location (output buffer)
|
|
string_cast_from_int: ; TODO I think this algorithm could be optimised
|
|
pusha
|
|
; Initialise base to decimal (base 10)
|
|
mov bx, 10
|
|
; clear the strigified int location
|
|
mov cx, 6
|
|
push ax
|
|
xor ax,ax
|
|
.clear_loop:
|
|
stosb
|
|
dec cx
|
|
cmp cx, 0
|
|
ja .clear_loop
|
|
; setup
|
|
pop ax
|
|
push ax
|
|
mov cx, -1
|
|
; loop over number to get the value of count (cx)
|
|
.count_loop:
|
|
xor dx,dx
|
|
div bx ; ax = ax // bx
|
|
inc cx
|
|
cmp ax, 0
|
|
ja .count_loop ; Jump if greater
|
|
pop ax
|
|
; loop over count downwards until count is 0
|
|
mov di, stringified_int
|
|
.stringify_loop:
|
|
mov cx,1 ;DEL
|
|
push cx
|
|
push bx
|
|
push ax
|
|
; Generate power of 10
|
|
mov ax, 1
|
|
mov cx,0 ;DEL
|
|
cmp cx, 1
|
|
jl .after_power_loop
|
|
.power_loop:
|
|
mul bx
|
|
dec cx
|
|
cmp cx, 0
|
|
ja .power_loop
|
|
.after_power_loop:
|
|
mov bx,ax
|
|
pop ax
|
|
pop cx
|
|
; ax = ax DIV bx
|
|
; dx = ax MOD bx
|
|
xor dx,dx
|
|
div bx
|
|
pop bx
|
|
add ax, 30h
|
|
stosb
|
|
mov ax, dx
|
|
dec cx
|
|
cmp cx, 0
|
|
ja .stringify_loop
|
|
.finish:
|
|
popa
|
|
;mov ax, stringified_int
|
|
ret
|
|
|
|
; Get the length of a string
|
|
; 'hello world', 0 is 11 characters long (excluding the terminator)
|
|
; input: si points to the string to be counted
|
|
; output: cl holds the length
|
|
string_length:
|
|
push si
|
|
xor cl,cl ; Clear the al register
|
|
.loop:
|
|
lodsb
|
|
cmp al, 0
|
|
je .finish
|
|
inc cl
|
|
jmp .loop
|
|
.finish:
|
|
pop si
|
|
ret
|
|
|
|
|
|
|
|
; convert a string to fat's filename format
|
|
; It will be capitalised and 11 characters long,
|
|
; 8 for the filename, 3 for the extension
|
|
; eg: 'file.txt' -> 'FILE TXT'
|
|
; input: si points to filename, di points to a free 11 bytes in memory
|
|
; output: di points to the fat formatted filename
|
|
os_format_fat_filename:
|
|
pusha
|
|
call string_upper_case
|
|
call string_length ; Stores the length of the string in cl
|
|
xor ch,ch ; Clear ch to reset it to 0
|
|
.character_loop:
|
|
lodsb
|
|
cmp al, 0
|
|
je .finish
|
|
cmp al, 2Eh ; 2Eh
|
|
je .add_spaces ; This will end up back at .character_loop
|
|
stosb
|
|
inc ch
|
|
jmp .character_loop
|
|
|
|
.add_spaces: ; Add the number of spaces as bl holds
|
|
mov al, ' ' ; 20h = space
|
|
|
|
; Work out the number of spaces in between
|
|
; the name and extension.
|
|
; 8 - name_length(ch)
|
|
xor bl, bl
|
|
sub bl, ch
|
|
add bl, 7
|
|
.spaces_loop:
|
|
stosb
|
|
cmp bl, 0
|
|
je .character_loop
|
|
dec bl
|
|
jmp .spaces_loop
|
|
.finish:
|
|
popa
|
|
ret
|
|
|
|
; Does the inverse of the previous
|
|
; Converts a fat filename back to human readable
|
|
; eg. 'KERNEL BIN' -> 'KERNEL.BIN'
|
|
; input: si points to fat filename (11 bytes)
|
|
; output:
|
|
; di points to the unformatted filename
|
|
; [file_name_length] stores the length of the filename
|
|
string_unformat_fat_filename:
|
|
pusha
|
|
|
|
xor ax,ax
|
|
xor dx,dx
|
|
mov cx, 11 ; Counter
|
|
.name_loop:
|
|
lodsb
|
|
stosb
|
|
dec cx
|
|
inc dx
|
|
cmp cx, 3
|
|
jne .name_loop
|
|
push si
|
|
mov si, di
|
|
.space_loop:
|
|
dec si
|
|
lodsb
|
|
dec si
|
|
dec dx
|
|
cmp al, 20h ; Space
|
|
je .space_loop
|
|
jmp .insert_stop
|
|
.insert_stop:
|
|
mov di, si
|
|
inc di
|
|
inc dx
|
|
pop si
|
|
mov al, 2Eh
|
|
stosb
|
|
mov cx, 3
|
|
.extension_loop:
|
|
lodsb
|
|
stosb
|
|
dec cx
|
|
inc dx
|
|
cmp cx, 0
|
|
jne .extension_loop
|
|
|
|
.finish:
|
|
inc dx
|
|
mov [file_name_length], dx
|
|
popa
|
|
ret
|
|
|
|
; Convert a string to all upper/lower case
|
|
; INPUT: si pointing to a string
|
|
; OUPUT: the same string in memory will now be capitalised/decapitalised
|
|
string_upper_case: ; to upper case
|
|
pusha
|
|
mov di, si
|
|
.loop:
|
|
lodsb ; Load the character into al
|
|
inc di
|
|
cmp al, 0
|
|
je .finish ; If it's null then the string is finished
|
|
cmp al, 7Ah ; 7Ah = 'z'
|
|
jns .loop ; Ignore if it's more than 'z'
|
|
cmp al, 61h ; 61h = 'a'
|
|
js .loop ; Ignore if it's less than 'a'
|
|
sub al, 20h ; Otherwise subtract 20h to capitalise it
|
|
dec di
|
|
stosb ; Store the new value
|
|
jmp .loop ; Next character
|
|
.finish:
|
|
popa
|
|
ret
|
|
|
|
os_lower_case: ; to lower case
|
|
pusha
|
|
mov di, si
|
|
.loop:
|
|
lodsb ; Load the character into al
|
|
inc di
|
|
cmp al, 0
|
|
je .finish ; If it's null then the string is finished
|
|
cmp al, 5Ah ; 5Ah = 'Z'
|
|
jns .loop ; Ignore if it's more than 'Z'
|
|
cmp al, 41h ; 41h = 'A'
|
|
js .loop ; Ignore if it's less than 'A'
|
|
add al, 20h ; Otherwise subtract 20h to capitalise it
|
|
dec di
|
|
stosb ; Store the new value
|
|
jmp .loop ; Next character
|
|
.finish:
|
|
popa
|
|
ret
|
|
|
|
string_lower_case:
|
|
ret
|
|
string_input:
|
|
ret
|
|
string_print_2hex:
|
|
ret
|