; 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