kvisc/ka/crt/fmt/strtol.k

171 lines
2.5 KiB
Plaintext

; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; int strtol(const char *str, int base)
;
; rax = integer extracted from str
; rdx = pointer to first invalid byte
;
strtol:
mov ax2, 1
jmp strtoq
;
; int strtoul(const char *str, int base)
;
; rax = integer extracted from str
; rdx = pointer to first invalid byte
;
strtoul:
sub ax2, ax2
jmp strtoq
;
; int strtoq(const char *str, int base, bool signed)
;
; guesses base when 'base'=0
;
strtoq:
xor rax, rax
mov rdx, ax0
; make sure base is in [2, 32]
cmp ax1, 1
j.z .bad
cmp ax1, 36
j.a .bad
; empty string?
cmp b[rdx], 0
jmp.z .done
.skip_spc:
cmp b[rdx], ' '
inc.z rdx
jmp.z .skip_spc
; skip +
cmp b[rdx], '+'
inc.z rdx
; signed?
test ax2, ax2
sub.z lx1, lx1
jmp.z .unsigned
; parse '-'
cmp b[rdx], '-'
inc.z rdx
mov.z lx1, 1
sub.nz lx1, lx1
.unsigned:
; base 0
test ax1, ax1
jmp.z .base_0
; base prefix?
cmp b[rdx], '0'
jmp.nz .main_loop
inc rdx
; string is "0"
cmp b[rdx], 0
jmp.z .done
; "0x" prefix
cmp b[rdx], 'x'
jmp.z .parsed_0x
; "0b" prefix
cmp b[rdx], 'b'
jmp.z .parsed_0b
; may be octal, but we don't care
; we accept "0110101010" (binary) for instance
jmp .main_loop
.parsed_0x:
; are we in base 16?
; if not, leave rax = 0 and *rdx = 'x'
cmp ax1, 16
jmp.nz .done
; else
inc rdx
jmp .main_loop
.parsed_0b:
; are we in base 2?
; if not, leave rax = 0 and *rdx = 'b'
cmp ax1, 2
jmp.nz .done
; else
inc rdx
jmp .main_loop
.base_0:
; guess base
cmp b[rdx], '0'
mov.nz ax1, 10
jmp.nz .main_loop
inc rdx
cmp b[rdx], 'x'
inc.z rdx
mov.z ax1, 16
jmp.z .main_loop
cmp b[rdx], 'b'
inc.z rdx
mov.z ax1, 2
jmp.z .main_loop
mov ax1, 8
.main_loop:
mov lx0, b[rdx]
inc rdx
cmp lx0, '0'
jmp.b .done
cmp.ae lx0, '9'
sub.be lx0, '0'
jmp.be .next
cmp lx0, 'A'
cmp.ae lx0, 'Z'
sub.be lx0, 55 ; 'A' - 10
jmp.be .next
cmp lx0, 'a'
jmp.b .next
cmp.ae lx0, 'z'
sub.be lx0, 87 ; 'a' - 10
jmp.be .next
.next:
; too large for base?
cmp lx0, ax1
jmp.ae .done
mul rax, ax1
add rax, lx0
jmp .main_loop
.done:
; negative?
test lx1, lx1
ret.z
; yes
neg rax
ret
.bad:
mov q[errno], EINVAL
ret