libasm/src/ft_atoibase.asm
2026-06-18 16:13:35 +02:00

230 lines
2.9 KiB
NASM

global ft_atoibase
extern ft_bzero
extern ft_isspace
extern __errno_location
section .text
;int has_dup(const char *s) {
; uint32_t bits[8] = {0}; // 8*32 = 256 bits
; for (const unsigned char *p = (const unsigned char*)s; *p; ++p) {
; unsigned int v = *p;
; unsigned int idx = v >> 5; // division par 32
; unsigned int bit = v & 31; // v % 32
; uint32_t mask = 1u << bit;
; if (bits[idx] & mask) return -1;
; bits[idx] |= mask;
; }
; return 0;
;}
; return base_len and check for "-+" or duplicate char
; rdi: base
check_base:
; uint32_t buffer[8]
push rbp
mov rbp, rsp
sub rsp, 40
mov qword [rsp + 32], rdi
; bzero buffer, 32
mov rdi, rsp
mov rsi, 32
call ft_bzero wrt ..plt
mov rax, qword [rsp + 32]
.loop:
mov dl, byte [rax]
test dl, dl
je .done
; if (*p == '-' || *p == '+') return -1
cmp dl, 45
je .error
cmp dl, 43
je .error
; r10(idx) = *p / 32
; rdx(bit) = *p % 32
mov r10, [rax]
shr r10, 5
mov rdx, [rax]
and rdx, 31
; mask = 1 << rdx(bit)
mov r11, 1
mov cl, dl
shl r11, cl
; if (bits[idx] & mask) return -1
mov r9, [rsp + rdx]
and r9, r11
test r9, r9
jne .error
; bits[idx] |= mask
or [rsp + rdx], r11
; ++p
inc rax
jmp .loop
.done:
sub rax, qword [rsp + 32]
.return:
add rsp, 40
pop rbp
ret
.error:
mov rax, -1
jmp .return
; skip whitespace and sign
; rdi: str
; return:
; rax str + x + is_signed
; dl is_signed
find_start:
push r12
mov r12, rdi
.loop:
mov dil, byte [r12]
call ft_isspace wrt ..plt
test rax, rax
je .done
test dil, dil
je .done
inc r12
jmp .loop
.done:
mov rax, r12
xor dl, dl
pop r12
cmp byte [rax], '-'
je .is_signed
ret
.is_signed:
inc dl
inc rax
ret
; rdi: base
; rsi: char
; rdx: baselen
; int i = 0
; while i < baselen
; if (c == base[i])
; return base[i]
; inc i
; return -1
get_num_from_base:
xor rax, rax
.loop:
cmp rax, rdx
jge .not_found
mov cl, byte [rdi + rax]
cmp cl, sil
je .found
inc rax
jmp .loop
.found:
ret
.not_found:
mov rax, -1
ret
; r12: str
; r13: base
ft_atoibase:
push r12
push r13
push r14
push r15
mov r12, rdi
mov r13, rsi
; if (check_base(base) <= 0 ) return 0;
mov rdi, r13
call check_base
test rax, rax
jle .invalid_base
; r14 = base_len
mov r14, rax
; str += start + is_signed
; rb9 = is_signed
mov rdi, r12
call find_start
mov r12, rax
mov r15b, dl
xor r11, r11
.loop:
cmp byte [r12], 0
je .end_loop
mov rdi, r13
movzx rsi, byte [r12]
mov rdx, r14
push r11
call get_num_from_base
pop r11
test rax, rax
jl .end_loop
imul r11d, r14d
jo .overflow
add r11, rax
jc .overflow
inc r12
jmp .loop
.end_loop:
mov rax, r11
.done:
test r15b, r15b
je .cleanup
neg rax
.cleanup:
pop r12
pop r13
pop r14
pop r15
ret
.invalid_base:
; errno = EINVAL
call __errno_location wrt ..plt
mov dword [rax], 22
xor rax, rax
jmp .done
.overflow:
call __errno_location wrt ..plt
mov dword [rax], 34
xor rax, rax
jmp .cleanup