kvisc/ka/crt/fmt/strtol.k

168 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:
nul ax2
jmp strtoq
;
; int strtoq(const char *str, int base, bool signed)
;
; guesses base when 'base'=0
;
strtoq:
nul rax, rsi
mov rdx, ax0
; make sure base is in [2, 32]
beq ax1, 1, .bad
bltu 36, ax1, .bad
; empty string?
bzr b[rdx], .done
.skip_spc:
bne b[rdx], ' ', .no_spc
inc rdx, 1
jmp .skip_spc
.no_spc:
; skip +
bne b[rdx], '+', .no_plus
inc rdx, 1
.no_plus:
; unsigned?
bzr ax2, .unsigned
; parse '-'
bne b[rdx], '-', .unsigned
inc rdx, 1
mov rsi, 1
.unsigned:
; base 0
bzr ax1, .base_0
; base prefix?
bne b[rdx], '0', .main_loop
inc rdx, 1
movzx rcx, b[rdx]
; "0x"/"0b" prefix
jrcxz .done ; "0"
beq rcx, 'x', .parsed_0x
beq rcx, 'b', .parsed_0b
; may be octal, but we don't care
; we accept "0110101010" (despite base=2) for instance
jmp .main_loop
.parsed_0x:
; are we in base 16?
; if not, leave rax = 0 and *rdx = 'x'
bne ax1, 16, .done
; else
inc rdx, 1
jmp .main_loop
.parsed_0b:
; are we in base 2?
; if not, leave rax = 0 and *rdx = 'b'
bne ax1, 2, .done
; else
inc rdx, 1
jmp .main_loop
.base_0:
; guess base
beq b[rdx], '0', .b0_not10
; must be base 10
mov ax1, 10
jmp .main_loop
.b0_not10:
inc rdx, 1
bne b[rdx], 'x', .b0_not16
inc rdx, 1
mov ax1, 16
jmp .main_loop
.b0_not16:
bne b[rdx], 'b', .b0_not2
inc rdx, 1
mov ax1, 2
jmp .main_loop
.b0_not2:
; take octal by default
mov ax1, 8
.main_loop:
movzx rcx, b[rdx]
inc rdx, 1
; between 0 and 9?
bltu rcx, '0', .done
bltu '9', rcx, .not_digit10
; yes
dec rcx, '0'
jmp .next
.not_digit10:
bltu rcx, 'A', .done
bltu 'Z', rcx, .not_digitAZ
dec rcx, 55 ; 'A' - 10
jmp .next
.not_digitAZ:
bltu rcx, 'a', .done
bltu 'z', rcx, .done
dec rcx, 87 ; 'a' - 10
jmp .next
.next:
; too large for base?
blteu ax1, rcx, .done
mul rax, ax1
inc rax, rcx
jmp .main_loop
.done:
; negative?
bzr rsi, .r
; yes
neg rax
.r:
ret
.bad:
ret