Implement strtoll and strtoull (aka strtoimax and strtoumax).
This is a fairly straightforward adaptation of the strtol/strtoul code. The multiplication routine is modified to return the next 16 bits in X so that strtoull can detect overflows.
This commit is contained in:
parent
6635346ae8
commit
506f9fa965
|
@ -23,6 +23,7 @@ Int64 start dummy segment
|
|||
*
|
||||
* Outputs:
|
||||
* NUM2 - result
|
||||
* X - next 16 bits of true result (bits 64-79)
|
||||
*
|
||||
****************************************************************
|
||||
*
|
||||
|
@ -83,6 +84,7 @@ ML2 ROR ANS+14 shift the interim result
|
|||
move4 ANS,NUM2 move return value and address
|
||||
move4 ANS+4,NUM2+4
|
||||
move4 RETURN-1,NUM1+4
|
||||
LDX ANS+8 set X to next 16 bits of result
|
||||
PLD fix stack, DP
|
||||
TSC
|
||||
CLC
|
||||
|
|
365
stdlib.asm
365
stdlib.asm
|
@ -1161,6 +1161,371 @@ rt3 lda rtl fix the stack
|
|||
rtl
|
||||
end
|
||||
|
||||
****************************************************************
|
||||
*
|
||||
* strtoll - convert a string to a long long
|
||||
*
|
||||
* Inputs:
|
||||
* str - pointer to the string
|
||||
* ptr - pointer to a pointer; a pointer to the first
|
||||
* char past the number is placed here. If ptr is
|
||||
* nil, no pointer is returned
|
||||
* base - base of the number
|
||||
*
|
||||
* Outputs:
|
||||
* converted number
|
||||
*
|
||||
****************************************************************
|
||||
*
|
||||
strtoll start
|
||||
strtoimax entry
|
||||
base equ 26 base
|
||||
ptr equ 22 *return pointer
|
||||
str equ 18 string pointer
|
||||
rtl equ 15 return address
|
||||
|
||||
retptr equ 11 pointer to location for return value
|
||||
val equ 3 value
|
||||
negative equ 1 is the number negative?
|
||||
|
||||
pea 0 make room for & initialize retptr
|
||||
phx
|
||||
pea 0 make room for & initialize val
|
||||
pea 0
|
||||
pea 0
|
||||
pea 0
|
||||
pea 0 make room for & initialize negative
|
||||
tsc set up direct page addressing
|
||||
phd
|
||||
tcd
|
||||
;
|
||||
; Skip any leading whitespace
|
||||
;
|
||||
lda ptr if ptr in non-null then
|
||||
ora ptr+2
|
||||
beq sw1
|
||||
lda str initialize it to str
|
||||
sta [ptr]
|
||||
ldy #2
|
||||
lda str+2
|
||||
sta [ptr],Y
|
||||
|
||||
sw1 lda [str] skip the white space
|
||||
and #$00FF
|
||||
tax
|
||||
lda >__ctype+1,X
|
||||
and #_space
|
||||
beq cn0
|
||||
inc4 str
|
||||
bra sw1
|
||||
;
|
||||
; Convert the number
|
||||
;
|
||||
cn0 lda [str] if the next char is '-' then
|
||||
and #$00FF
|
||||
cmp #'-'
|
||||
bne cn1
|
||||
inc negative negative := true
|
||||
bra cn2 ++str
|
||||
cn1 cmp #'+' else if the char is '+' then
|
||||
bne cn3
|
||||
cn2 inc4 str ++str
|
||||
|
||||
cn3 ph4 str save the starting string
|
||||
ph2 base convert the unsigned number
|
||||
ph4 ptr
|
||||
ph4 str
|
||||
tdc
|
||||
clc
|
||||
adc #val
|
||||
tax
|
||||
jsl ~strtoull
|
||||
lda val+6
|
||||
bpl rt1 see if we have an overflow
|
||||
ldy negative allow LLONG_MIN as legal value
|
||||
beq ov0
|
||||
cmp #$8000
|
||||
bne ov0
|
||||
lda val
|
||||
ora val+2
|
||||
ora val+4
|
||||
beq rt1
|
||||
;
|
||||
; Overflow - flag the error
|
||||
;
|
||||
ov0 lda #ERANGE errno = ERANGE
|
||||
sta >errno
|
||||
ldx #$7FFF return value = LLONG_MAX
|
||||
ldy #$FFFF
|
||||
lda negative if negative then
|
||||
beq ov1
|
||||
inx return value = LLONG_MIN
|
||||
iny
|
||||
ov1 sty val
|
||||
sty val+2
|
||||
sty val+4
|
||||
stx val+6
|
||||
;
|
||||
; return the results
|
||||
;
|
||||
rt1 pla remove the original value of str from
|
||||
pla the stack
|
||||
lda negative if negative then
|
||||
beq rt2
|
||||
sub8 #0,val,val val = -val
|
||||
|
||||
rt2 lda val get the value
|
||||
sta [retptr]
|
||||
ldy #2
|
||||
lda val+2
|
||||
sta [retptr],y
|
||||
iny
|
||||
iny
|
||||
lda val+4
|
||||
sta [retptr],y
|
||||
iny
|
||||
iny
|
||||
lda val+6
|
||||
sta [retptr],y
|
||||
lda rtl fix the stack
|
||||
sta base-1
|
||||
lda rtl+1
|
||||
sta base
|
||||
pld
|
||||
tsc
|
||||
clc
|
||||
adc #24
|
||||
tcs
|
||||
tya return
|
||||
rtl
|
||||
end
|
||||
|
||||
****************************************************************
|
||||
*
|
||||
* strtoull - convert a string to an unsigned long long
|
||||
* ~strtoull - alt entry point that does not parse leading
|
||||
* white space and sign
|
||||
*
|
||||
* Inputs:
|
||||
* str - pointer to the string
|
||||
* ptr - pointer to a pointer; a pointer to the first
|
||||
* char past the number is placed here. If ptr is
|
||||
* nil, no pointer is returned
|
||||
* base - base of the number
|
||||
*
|
||||
* Outputs:
|
||||
* converted number
|
||||
*
|
||||
****************************************************************
|
||||
*
|
||||
strtoull start
|
||||
strtoumax entry
|
||||
base equ 30 base
|
||||
ptr equ 26 *return pointer
|
||||
str equ 22 string pointer
|
||||
rtl equ 19 return address
|
||||
|
||||
retptr equ 15 pointer to location for return value
|
||||
rangeOK equ 13 was the number within range?
|
||||
negative equ 11 was there a minus sign?
|
||||
val equ 3 value
|
||||
foundOne equ 1 have we found a number?
|
||||
|
||||
ldy #0
|
||||
bra init
|
||||
|
||||
~strtoull entry alt entry point called from strtoll
|
||||
ldy #1
|
||||
|
||||
init pea 0 make room for & initialize retptr
|
||||
phx
|
||||
pea 1 make room for & initialize rangeOK
|
||||
pea 0 make room for & initialize negative
|
||||
pea 0 make room for & initialize val
|
||||
pea 0
|
||||
pea 0
|
||||
pea 0
|
||||
pea 0 make room for & initialize foundOne
|
||||
tsc set up direct page addressing
|
||||
phd
|
||||
tcd
|
||||
;
|
||||
; Skip any leading whitespace
|
||||
;
|
||||
tya just process number if called from strtol
|
||||
bne db1c
|
||||
|
||||
lda ptr if ptr in non-null then
|
||||
ora ptr+2
|
||||
beq sw1
|
||||
lda str initialize it to str
|
||||
sta [ptr]
|
||||
ldy #2
|
||||
lda str+2
|
||||
sta [ptr],Y
|
||||
|
||||
sw1 lda [str] skip the white space
|
||||
and #$00FF
|
||||
tax
|
||||
lda >__ctype+1,X
|
||||
and #_space
|
||||
beq db1
|
||||
inc4 str
|
||||
bra sw1
|
||||
;
|
||||
; Deduce the base
|
||||
;
|
||||
db1 lda [str] if the next char is '-' then
|
||||
and #$00FF
|
||||
cmp #'-'
|
||||
bne db1a
|
||||
inc negative negative := true
|
||||
bra db1b
|
||||
db1a cmp #'+' skip any leading '+'
|
||||
bne db1c
|
||||
db1b inc4 str
|
||||
db1c lda base if the base is zero then
|
||||
bne db2
|
||||
lda #10 assume base 10
|
||||
sta base
|
||||
lda [str] if the first char is 0 then
|
||||
and #$00FF
|
||||
cmp #'0'
|
||||
bne cn1
|
||||
lda #8 assume base 8
|
||||
sta base
|
||||
ldy #1 if the second char is 'X' or 'x' then
|
||||
lda [str],Y
|
||||
and #$00DF
|
||||
cmp #'X'
|
||||
bne cn1
|
||||
asl base base 16
|
||||
bra db3
|
||||
db2 cmp #16 if the base is 16 then
|
||||
bne db4
|
||||
lda [str] if the first two chars are 0x or 0X then
|
||||
and #$DFFF
|
||||
cmp #'X0'
|
||||
bne cn1
|
||||
db3 add4 str,#2 skip them
|
||||
bra cn1
|
||||
db4 cmp #37 check for invalid base value
|
||||
jge cn6
|
||||
dec a
|
||||
jeq cn6
|
||||
;
|
||||
; Convert the number
|
||||
;
|
||||
cn1 lda [str] get a (possible) digit
|
||||
and #$00FF
|
||||
cmp #'0' branch if it is not a digit
|
||||
blt cn5
|
||||
cmp #'9'+1 branch if it is a numeric digit
|
||||
blt cn2
|
||||
and #$00DF convert lowercase to uppercase
|
||||
cmp #'A' branch if it is not a digit
|
||||
blt cn5
|
||||
cmp #'Z'+1 branch if it is not a digit
|
||||
bge cn5
|
||||
sbc #'A'-11 convert "alpha" digit to value
|
||||
bra cn3 go test the digit
|
||||
|
||||
cn2 and #$000F convert digit to value
|
||||
cn3 cmp base branch if the digit is too big
|
||||
bge cn5
|
||||
|
||||
ldx #1 note that we have found a number
|
||||
stx foundOne
|
||||
pha save the digit
|
||||
ph8 val val = val*base
|
||||
pea 0
|
||||
pea 0
|
||||
pea 0
|
||||
ph2 base
|
||||
jsl ~UMUL8
|
||||
pl8 val
|
||||
pla get the saved digit
|
||||
txy branch if there was an error
|
||||
beq cn3a
|
||||
stz rangeOK
|
||||
cn3a clc add in the new digit
|
||||
adc val
|
||||
sta val
|
||||
lda val+2
|
||||
adc #0
|
||||
sta val+2
|
||||
lda val+4
|
||||
adc #0
|
||||
sta val+4
|
||||
lda val+6
|
||||
adc #0
|
||||
sta val+6
|
||||
bcc cn4
|
||||
stz rangeOK
|
||||
cn4 inc4 str next char
|
||||
bra cn1
|
||||
|
||||
cn5 lda foundOne if no digits were found, flag the error
|
||||
bne rt1
|
||||
cn6 lda #EINVAL
|
||||
sta >errno
|
||||
bra rt2a
|
||||
;
|
||||
; return the results
|
||||
;
|
||||
rt1 lda ptr if ptr is non-null then
|
||||
ora ptr+2
|
||||
beq rt1a
|
||||
lda str set it to str
|
||||
sta [ptr]
|
||||
ldy #2
|
||||
lda str+2
|
||||
sta [ptr],Y
|
||||
|
||||
rt1a lda rangeOK check if number was out of range
|
||||
bne rt2
|
||||
lda #ERANGE errno = ERANGE
|
||||
sta >errno
|
||||
lda #$FFFF return value = ULLONG_MAX
|
||||
sta [retptr]
|
||||
ldy #2
|
||||
sta [retptr],y
|
||||
iny
|
||||
iny
|
||||
sta [retptr],y
|
||||
iny
|
||||
iny
|
||||
sta [retptr],y
|
||||
bra rt3
|
||||
rt2 lda negative if negative then
|
||||
beq rt2a
|
||||
sub8 #0,val,val val = -val
|
||||
rt2a lda val get the value
|
||||
sta [retptr]
|
||||
ldy #2
|
||||
lda val+2
|
||||
sta [retptr],y
|
||||
iny
|
||||
iny
|
||||
lda val+4
|
||||
sta [retptr],y
|
||||
iny
|
||||
iny
|
||||
lda val+6
|
||||
sta [retptr],y
|
||||
rt3 lda rtl fix the stack
|
||||
sta base-1
|
||||
lda rtl+1
|
||||
sta base
|
||||
pld
|
||||
tsc
|
||||
clc
|
||||
adc #28
|
||||
tcs
|
||||
tya return
|
||||
rtl
|
||||
end
|
||||
|
||||
****************************************************************
|
||||
*
|
||||
* int system(command)
|
||||
|
|
|
@ -689,3 +689,27 @@
|
|||
.f
|
||||
mnote "Missing closing '}'",16
|
||||
mend
|
||||
macro
|
||||
&l sub8 &n1,&n2,&n3
|
||||
&l ~setm
|
||||
ph8 &n1
|
||||
ph8 &n2
|
||||
jsl ~SUB8
|
||||
aif c:&n3,.a
|
||||
pl8 &n1
|
||||
ago .b
|
||||
.a
|
||||
pl8 &n3
|
||||
.b
|
||||
~restm
|
||||
mend
|
||||
macro
|
||||
&l jge &bp
|
||||
&l blt *+5
|
||||
brl &bp
|
||||
mend
|
||||
macro
|
||||
&l jeq &bp
|
||||
&l bne *+5
|
||||
brl &bp
|
||||
mend
|
||||
|
|
Loading…
Reference in New Issue