Files
crawos/source/kernel/features/strings.asm
2025-12-30 22:52:30 +00:00

190 lines
4.1 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
; 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
os_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 os_upper_case
call os_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
os_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