; Internal convention: ; r1 - Partially parsed output integer ; r2 - Parsing position ; r3 - Character being parsed ; r4 - Set to -1 if the input is negative ; Convert string to integer ; Arguments: ; r1 - Pointer to string ; Result: ; r1 - Parsed integer ; r2 - Pointer to first rejected input byte ; Clobbers: ; flags ; r3 - last character read ; Note: Unless the input is "0", tail-calls into a base-specific specialization. pub atoi: mov r2, r1 mov r1, 0 mov r4, 0 load_8 r3, [r2] cmp r3, 0x2D ; '-' jne atoi_positive sub r4, zr, 1 ; Set r4 to -1 add r2, r2, 1 load_8 r3, [r2] atoi_positive: cmp r3, 0x30 ; '0' jne atoi_dec_loop ; No prefix, parse decimal add r2, r2, 1 load_8 r3, [r2] ; From "boxBOX", or an octal digit cmp r3, 0x30 ; '0' jl atoi_done cmp r3, 0x37 ; '7' jle atoi_oct_loop ; Octal with just '0' prefix add r2, r2, 1 ; 2-byte prefix and r3, r3, 0x5F ; to uppercase cmp r3, 0x42 ; 'B' je atoi_bin_loop cmp r3, 0x4F ; 'O' je atoi_oct_loop cmp r3, 0x58 ; 'X' je atoi_hex_loop ; FALLTHROUGH: not a valid prefix, but we did see a zero atoi_done: add r1, r1, r4 ; If r4 is -1, negate r1. Else it's 0 and no effect. xor r1, r1, r4 mov flags, 0 ; No error jmp r13 ; Convert decimal string to integer ; Arguments: ; r1 - Pointer to string ; Result: ; r1 - Parsed integer ; r2 - Pointer to first rejected input byte ; Clobbers: ; flags ; r3 - last character read pub atoi_dec: mov r2, r1 mov r1, 0 mov r4, 0 load_8 r3, [r2] cmp r3, 0x2D ; '-' jne atoi_dec_positive sub r4, zr, 1 ; Set r4 to -1 add r2, r2, 1 atoi_dec_loop: load_8 r3, [r2] atoi_dec_positive: cmp r3, 0x30 ; '0' jl atoi_done cmp r3, 0x39 ; '9' jg atoi_done add r2, r2, 1 sub r3, r3, 0x30 ; '0' lsl flags, r1, 2 add r1, r1, flags lsl r1, r1, 1 add r1, r1, r3 jmp atoi_dec_loop ; Convert binary string to integer ; Arguments: ; r1 - Pointer to string ; Result: ; r1 - Parsed integer ; r2 - Pointer to first rejected input byte ; Clobbers: ; flags ; r3 - last character read pub atoi_bin: mov r2, r1 mov r1, 0 mov r4, 0 load_8 r3, [r2] cmp r3, 0x2D ; '-' jne atoi_bin_positive sub r4, zr, 1 ; Set r4 to -1 add r2, r2, 1 atoi_bin_positive: load_16 r3, [r2] ; check for prefix and r3, r3, 0xFF5F ; to uppercase cmp r3, 0x3042 ; "0B" jne atoi_bin_loop add r2, r2, 2 atoi_bin_loop: load_8 r3, [r2] cmp r3, 0x30 ; '0' jl atoi_done cmp r3, 0x31 ; '1' jg atoi_done add r2, r2, 1 sub r3, r3, 0x30 ; '0' lsl r1, r1, 1 add r1, r1, r3 jmp atoi_bin_loop ; Convert octal string to integer ; Arguments: ; r1 - Pointer to string ; Result: ; r1 - Parsed integer ; r2 - Pointer to first rejected input byte ; Clobbers: ; flags ; r3 - last character read pub atoi_oct: mov r2, r1 mov r1, 0 mov r4, 0 load_8 r3, [r2] cmp r3, 0x2D ; '-' jne atoi_oct_positive sub r4, zr, 1 ; Set r4 to -1 add r2, r2, 1 atoi_oct_positive: load_16 r3, [r2] ; check for prefix and r3, r3, 0xFF5F ; to uppercase cmp r3, 0x304F ; "0O" jne atoi_oct_loop add r2, r2, 2 atoi_oct_loop: load_8 r3, [r2] cmp r3, 0x30 ; '0' jl atoi_done cmp r3, 0x37 ; '7' jg atoi_done add r2, r2, 1 sub r3, r3, 0x30 ; '0' lsl r1, r1, 3 add r1, r1, r3 jmp atoi_oct_loop ; Convert hexadecimal string to integer ; Arguments: ; r1 - Pointer to string ; Result: ; r1 - Parsed integer ; r2 - Pointer to first rejected input byte ; Clobbers: ; flags ; r3 - last character read pub atoi_hex: mov r2, r1 mov r1, 0 mov r4, 0 load_8 r3, [r2] cmp r3, 0x2D ; '-' jne atoi_hex_positive sub r4, zr, 1 ; Set r4 to -1 add r2, r2, 1 atoi_hex_positive: load_16 r3, [r2] ; check for prefix and r3, r3, 0xFF5F ; to uppercase cmp r3, 0x3058 ; "0X" jne atoi_oct_loop add r2, r2, 2 atoi_hex_loop: load_8 r3, [r2] cmp r3, 0x30 ; '0' jl atoi_done cmp r3, 0x39 ; '9' jg atoi_hex_letter add r2, r2, 1 sub r3, r3, 0x30 ; '0' lsl r1, r1, 4 add r1, r1, r3 jmp atoi_hex_loop atoi_hex_letter: and r3, r3, 0x5F ; to uppercase cmp r3, 0x41 ; 'A' jl atoi_done cmp r3, 0x46 ; 'F' jg atoi_done add r2, r2, 1 sub r3, r3, 0x37 ; 'A' - 10 lsl r1, r1, 4 add r1, r1, r3 jmp atoi_hex_loop