Files
libasm/srcs/bonus/ft_atoi_base.s

225 lines
3.4 KiB
ArmAsm

global ft_atoi_base
global check_duplicate_char
extern ft_strlen
section .data
invalid_chars: db "+- ", 0x0c, 0x0a, 0x0d, 0x09, 0x0b, 0
whitespaces: db " ", 0x0c, 0x0a, 0x0d, 0x09, 0x0b, 0
section .text
; get index of char in string or returns -1 if not found
; char in dil
; str in rsi
get_char_index:
xor rax, rax
push rsi ; keep start index in stack
test dil, dil
je .error
.get_char_index_loop:
cmp dil, [rsi] ;is char invalid
jz .get_char_index_found
mov al, [rsi] ; is end of string
test al, al
lea rsi, [rsi + 1]
jne .get_char_index_loop
.error:
mov rax, -1 ;not found and at the end
pop rsi
ret
.get_char_index_found:
pop rax ;return index of the found char (compare to top of stack)
sub rsi, rax
mov rax, rsi
ret
;function that ... it's in the name why are you looking here
; parameters : the string in rdi
; returns 1 if there is a duplicate char
check_duplicate_char:
mov al ,[rdi] ; test if \0
test al, al
jz .no_duplicate
push rdi
mov rsi, rdi
lea rsi, [rsi + 1]
mov dil, [rdi]
call get_char_index
pop rdi
cmp rax, -1 ;is char found
lea rdi, [rdi + 1]
jz check_duplicate_char
mov rax, 1
ret
.no_duplicate:
xor rax, rax
ret
;function that checks if the base is valid
;a valid base does not have any of these char : "+-" or any space defined by isspace(3) and does not have any duplicate char or does not have any char
; returns 0 if base is not valid
check_base:
xor rax, rax
mov al, [rdi] ; check if it's an empty string
test al, al
jne .chk_bs_duplicate
xor rax, rax
ret
.chk_bs_duplicate:
push rdi
call check_duplicate_char
pop rdi
test rax, rax
jz .chk_bs_char
xor rax, rax
ret
.chk_bs_char:
mov al, [rdi] ; if rdi is \0, return 0
test al, al
jz .base_ok
push rdi ; if current char is in invalid_chars
mov dil, [rdi];
lea rsi, [rel invalid_chars]
call get_char_index
pop rdi
cmp rax, -1 ; if not -1, error
lea rdi, [rdi + 1]
jz .chk_bs_char
xor rax, rax; return 0
ret
.base_ok:
mov rax,1
ret
; prototype : int ft_atoi_base(char *str, char *base)
; rdi str
; rsi base
ft_atoi_base:
xor rax, rax ;check if there is a null pointer in rdi or rsi
test rdi, rdi
jz .return
test rsi, rsi
jz .return
push rdi ; is base valid
push rsi
mov rdi, rsi
sub rsp, 8
call check_base
add rsp, 8
pop rsi
pop rdi
test rax, rax
jne .whitespace_skip ; if 0 , base is not valid
ret
.whitespace_skip_inc:
lea rdi, [rdi + 1]
.whitespace_skip:
push rdi
push rsi
mov dil, [rdi]
lea rsi, [rel whitespaces]
sub rsp, 8
call get_char_index
add rsp, 8
pop rsi
pop rdi
cmp rax, 0
jge .whitespace_skip_inc
xor rdx, rdx
jmp .plus_minus
.plus_minus_invert:
xor rdx, 1
.plus_minus_inc:
lea rdi, [rdi + 1]
.plus_minus:
mov al, [rdi]
cmp al, '-'
jz .plus_minus_invert
cmp al, '+'
jz .plus_minus_inc
push rdx ; keep invert sign setting in stack
push rdi
push rsi
mov rdi, rsi
call ft_strlen
pop rsi
pop rdi
mov rbx, rax ; keep the length of the base in rbx
xor rax, rax
.number_loop:
mov dl, [rdi]
test dl, dl
jz .final_number
push rax
push rdi
push rsi
mov dil, dl
sub rsp, 8
call get_char_index
add rsp, 8
pop rsi
pop rdi
mov rdx, rax ; save return value in rdx
pop rax
cmp rdx, -1 ; if the char is not in the base, return the number
jz .final_number
push rdx ; imul sets rdx to 0
imul rbx
pop rdx
add rax, rdx
lea rdi, [rdi + 1]
jmp .number_loop
.final_number:
pop rdx
test rdx, rdx
jne .neg_final_number
ret
.neg_final_number:
neg rax
.return:
ret