mirror of
https://github.com/byteworksinc/ORCALib.git
synced 2024-11-19 08:31:26 +00:00
1675 lines
45 KiB
NASM
1675 lines
45 KiB
NASM
keep obj/stdlib
|
|
mcopy stdlib.macros
|
|
case on
|
|
|
|
****************************************************************
|
|
*
|
|
* StdLib - Standard Library Utility Functions
|
|
*
|
|
* This code implements the tables and subroutines needed to
|
|
* support the standard C library STDLIB.
|
|
*
|
|
* December 1988
|
|
* Mike Westerfield
|
|
*
|
|
* Copyright 1988
|
|
* Byte Works, Inc.
|
|
*
|
|
* Note: Portions of this library appear in SysFloat
|
|
*
|
|
****************************************************************
|
|
*
|
|
StdLib start dummy segment
|
|
copy equates.asm
|
|
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* void abort()
|
|
*
|
|
* Stop the program.
|
|
*
|
|
****************************************************************
|
|
*
|
|
abort start
|
|
|
|
ph2 #SIGABRT
|
|
jsl raise
|
|
lda #-1
|
|
jmp ~C_QUIT
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* int abs(int i)
|
|
*
|
|
* Return the absolute value of i.
|
|
*
|
|
* Inputs:
|
|
* i - argument
|
|
*
|
|
* Outputs:
|
|
* Returns abs(i).
|
|
*
|
|
****************************************************************
|
|
*
|
|
abs start
|
|
i equ 4 position of argument on stack
|
|
|
|
lda i,S A := i
|
|
bpl lb1 if A < 0 then
|
|
eor #$FFFF A := -A
|
|
inc A
|
|
lb1 tay return A
|
|
lda 2,S
|
|
sta 4,S
|
|
pla
|
|
sta 1,S
|
|
tya
|
|
rtl
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* void *aligned_alloc(size_t alignment, size_t size)
|
|
*
|
|
* Allocate memory with specified alignment.
|
|
*
|
|
* Inputs:
|
|
* alignment - alignment to use (only value allowed is 1)
|
|
* size - bytes of memory to allocate
|
|
*
|
|
* Outputs:
|
|
* Returns pointer to allocated memory, or NULL on error.
|
|
*
|
|
****************************************************************
|
|
*
|
|
aligned_alloc start
|
|
csubroutine (4:alignment,4:size),0
|
|
|
|
lda alignment check that alignment==1
|
|
dec a
|
|
ora alignment+2
|
|
beq good
|
|
stz size return NULL on error
|
|
stz size+2
|
|
lda #EINVAL
|
|
sta >errno
|
|
bra ret
|
|
|
|
good ph4 <size call malloc
|
|
jsl malloc
|
|
sta size
|
|
stx size+2
|
|
|
|
ret creturn 4:size
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* int atexit(func)
|
|
* void (*func)();
|
|
*
|
|
* This function is used to build a list of functions that will
|
|
* be called as part of the exit processing.
|
|
*
|
|
* Inputs:
|
|
* func - address of the function to call on exit
|
|
*
|
|
* Outputs:
|
|
* Returns 0 if successful, -1 if not.
|
|
*
|
|
****************************************************************
|
|
*
|
|
atexit start
|
|
ptr equ 1 work pointer
|
|
rval equ 5 return value
|
|
|
|
csubroutine (4:func),6
|
|
|
|
lda #-1 assume we will fail
|
|
sta rval assume we will fail
|
|
dec4 func we need the addr-1, not the addr
|
|
ph4 #8 get space for the record
|
|
jsl malloc
|
|
stx ptr+2
|
|
sta ptr
|
|
ora ptr+2 quit now if we failed
|
|
beq lb1
|
|
ldy #2 place the record in the exit list
|
|
lda >~EXITLIST
|
|
sta [ptr]
|
|
lda >~EXITLIST+2
|
|
sta [ptr],Y
|
|
lda ptr
|
|
sta >~EXITLIST
|
|
lda ptr+2
|
|
sta >~EXITLIST+2
|
|
iny place the function address in the record
|
|
iny
|
|
lda func
|
|
sta [ptr],Y
|
|
iny
|
|
iny
|
|
lda func+2
|
|
sta [ptr],Y
|
|
inc rval success...
|
|
|
|
lb1 creturn 2:rval
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* int at_quick_exit(func)
|
|
* void (*func)();
|
|
*
|
|
* This function is used to build a list of functions that will
|
|
* be called as part of the quick exit processing.
|
|
*
|
|
* Inputs:
|
|
* func - address of the function to call on quick exit
|
|
*
|
|
* Outputs:
|
|
* Returns 0 if successful, -1 if not.
|
|
*
|
|
****************************************************************
|
|
*
|
|
at_quick_exit start
|
|
ptr equ 1 work pointer
|
|
rval equ 5 return value
|
|
|
|
csubroutine (4:func),6
|
|
|
|
lda #-1 assume we will fail
|
|
sta rval assume we will fail
|
|
dec4 func we need the addr-1, not the addr
|
|
ph4 #8 get space for the record
|
|
jsl malloc
|
|
stx ptr+2
|
|
sta ptr
|
|
ora ptr+2 quit now if we failed
|
|
beq lb1
|
|
ldy #2 place the record in the exit list
|
|
lda >~QUICKEXITLIST
|
|
sta [ptr]
|
|
lda >~QUICKEXITLIST+2
|
|
sta [ptr],Y
|
|
lda ptr
|
|
sta >~QUICKEXITLIST
|
|
lda ptr+2
|
|
sta >~QUICKEXITLIST+2
|
|
iny place the function address in the record
|
|
iny
|
|
lda func
|
|
sta [ptr],Y
|
|
iny
|
|
iny
|
|
lda func+2
|
|
sta [ptr],Y
|
|
inc rval success...
|
|
|
|
lb1 creturn 2:rval
|
|
end
|
|
|
|
|
|
****************************************************************
|
|
*
|
|
* atof - convert a string to a float
|
|
*
|
|
* Inputs:
|
|
* str - pointer to the string
|
|
*
|
|
* Outputs:
|
|
* X-A - pointer to converted number
|
|
*
|
|
****************************************************************
|
|
*
|
|
atof start
|
|
|
|
ph4 #0 no pointer returned
|
|
lda 10,S pass the string addr on
|
|
pha
|
|
lda 10,S
|
|
pha
|
|
jsl strtod convert the string
|
|
tay fix the stack
|
|
lda 2,S
|
|
sta 6,S
|
|
pla
|
|
sta 3,S
|
|
pla
|
|
tya
|
|
rtl
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* atoi - convert a string to an int
|
|
* atol - convert a string to a long
|
|
*
|
|
* Inputs:
|
|
* str - pointer to the string
|
|
*
|
|
* Outputs:
|
|
* X-A - converted number
|
|
*
|
|
****************************************************************
|
|
*
|
|
atoi start
|
|
atol entry
|
|
|
|
ph2 #10 base 10
|
|
ph4 #0 no pointer returned
|
|
lda 12,S pass the string addr on
|
|
pha
|
|
lda 12,S
|
|
pha
|
|
jsl strtol convert the string
|
|
tay fix the stack
|
|
lda 2,S
|
|
sta 6,S
|
|
pla
|
|
sta 3,S
|
|
pla
|
|
tya
|
|
rtl
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* atoll - convert a string to a long long
|
|
*
|
|
* Inputs:
|
|
* str - pointer to the string
|
|
*
|
|
* Outputs:
|
|
* converted number
|
|
*
|
|
****************************************************************
|
|
*
|
|
atoll start
|
|
|
|
ph2 #10 base 10
|
|
ph4 #0 no pointer returned
|
|
lda 12,S pass the string addr on
|
|
pha
|
|
lda 12,S
|
|
pha note: x reg is unchanged
|
|
jsl strtoll convert the string
|
|
lda 2,S fix the stack
|
|
sta 6,S
|
|
pla
|
|
sta 3,S
|
|
pla
|
|
rtl
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* char *bsearch(key, base, count, size, compar)
|
|
* void *key, *base;
|
|
* size_t count, size;
|
|
* int (*compar)(const void *, const void *)
|
|
*
|
|
* Inputs:
|
|
* key - pointer to element to search for
|
|
* base - start address of the array to search
|
|
* count - # elements in the array
|
|
* size - size of each array element
|
|
* compar - function that compares array elements
|
|
*
|
|
* Outputs:
|
|
* Returns a pointer to the array element found; NULL if
|
|
* no match was found.
|
|
*
|
|
****************************************************************
|
|
*
|
|
bsearch start
|
|
left equ 1 left index
|
|
right equ 5 right index
|
|
test equ 9 test index
|
|
addr equ 13 address of array element of index test
|
|
|
|
csubroutine (4:key,4:base,4:count,4:size,4:compar),16
|
|
|
|
lda compar patch the call address
|
|
sta >jsl+1
|
|
lda compar+1
|
|
sta >jsl+2
|
|
stz left left = 0
|
|
stz left+2
|
|
sub4 count,#1,right right = count-1
|
|
lb1 clc test = (left+right)/2
|
|
lda left
|
|
adc right
|
|
sta test
|
|
lda left+2
|
|
adc right+2
|
|
lsr A
|
|
sta test+2
|
|
ror test
|
|
mul4 test,size,addr addr = test*size + base
|
|
add4 addr,base
|
|
ph4 addr compare the array elements
|
|
ph4 key
|
|
jsl jsl jsl
|
|
tax quit if *addr = *key
|
|
beq lb6
|
|
bmi lb2 if *key > *addr then
|
|
add4 test,#1,left left = test+1
|
|
bra lb3 else
|
|
lb2 sub4 test,#1,right right = test-1
|
|
lb3 lda right+2 loop if right >= left
|
|
bmi lb5
|
|
cmp left+2
|
|
bne lb4
|
|
lda right
|
|
cmp left
|
|
lb4 bge lb1
|
|
|
|
lb5 stz addr no match - return null
|
|
stz addr+2
|
|
|
|
lb6 creturn 4:addr
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* div_t div(n,d)
|
|
* int n,d;
|
|
*
|
|
* Inputs:
|
|
* n - numerator
|
|
* d - denominator
|
|
*
|
|
* Outputs:
|
|
* div_t - contains result & remainder
|
|
*
|
|
****************************************************************
|
|
*
|
|
div start
|
|
addr equ 1
|
|
|
|
csubroutine (2:n,2:d),4
|
|
|
|
phb use local data
|
|
phk
|
|
plb
|
|
lda n do the divide
|
|
ldx d
|
|
jsl ~DIV2
|
|
sta div_t save the results
|
|
stx div_t+2
|
|
lda n if the numerator is negative then
|
|
bpl lb1
|
|
sub2 #0,div_t+2,div_t+2 make the remainder negative
|
|
lb1 lla addr,div_t return the address
|
|
plb
|
|
|
|
creturn 4:addr
|
|
|
|
div_t ds 4
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* void exit(int status);
|
|
*
|
|
* void _exit(int status);
|
|
*
|
|
* void _Exit(int status);
|
|
*
|
|
* void quick_exit(int status);
|
|
*
|
|
* Stop the program. Exit cleans up, _exit does not. Status
|
|
* is the status returned to the shell.
|
|
*
|
|
* Inputs:
|
|
* status - exit code
|
|
*
|
|
****************************************************************
|
|
*
|
|
exit start
|
|
|
|
jsr ~EXIT
|
|
_exit entry
|
|
_Exit entry
|
|
lda 4,S
|
|
jmp ~C_QUIT
|
|
end
|
|
|
|
quick_exit start
|
|
|
|
jsr ~QUICKEXIT
|
|
lda 4,S
|
|
jmp ~C_QUIT
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* char *getenv(const char *name)
|
|
*
|
|
* Returns a pointer to a shell variable. If the shell variable
|
|
* has no value, a null is returned.
|
|
*
|
|
* Inputs:
|
|
* namePtr - pointer to the name of the shell variable
|
|
*
|
|
* Outputs:
|
|
* Returns a pointer to the shell variable
|
|
*
|
|
****************************************************************
|
|
*
|
|
getenv start
|
|
ptr equ 1 pointer to the shell variable
|
|
|
|
csubroutine (4:namePtr),4
|
|
|
|
phb use local addressing
|
|
phk
|
|
plb
|
|
lla ptr,0 initialize the pointer to null
|
|
short I,M copy the variable name to the buffer
|
|
ldy #0
|
|
lb1 lda [namePtr],Y
|
|
beq lb2
|
|
iny
|
|
sta name,Y
|
|
bne lb1
|
|
dey
|
|
lb2 sty name
|
|
long I,M
|
|
Read_Variable rdRec read the shell variable
|
|
bcs lb3 if there was no error then
|
|
lda var if the variable was set then
|
|
and #$00FF
|
|
beq lb3
|
|
short I,M set the null terminator
|
|
ldx var
|
|
stz var+1,X
|
|
long I,M
|
|
lla ptr,var+1 set the pointer to return
|
|
|
|
lb3 plb restore B
|
|
creturn 4:ptr
|
|
|
|
rdRec dc a4'name,var' read variable record
|
|
|
|
name ds 256 shell variable name
|
|
var ds 257 shell variable value
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* long labs(long i)
|
|
*
|
|
* Return the absolute value of i.
|
|
*
|
|
* Inputs:
|
|
* i - argument
|
|
*
|
|
* Outputs:
|
|
* Returns abs(i).
|
|
*
|
|
****************************************************************
|
|
*
|
|
labs start
|
|
|
|
csubroutine (4:i),0
|
|
|
|
lda i+2
|
|
bpl lb1
|
|
sub4 #0,i,i
|
|
|
|
lb1 creturn 4:i
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* long long llabs(long long i)
|
|
*
|
|
* Return the absolute value of i.
|
|
*
|
|
* Inputs:
|
|
* i - argument
|
|
*
|
|
* Outputs:
|
|
* Returns abs(i).
|
|
*
|
|
****************************************************************
|
|
*
|
|
llabs start
|
|
imaxabs entry
|
|
retptr equ 1
|
|
|
|
csubroutine (8:i),4
|
|
stx retptr
|
|
stz retptr+2
|
|
|
|
ph8 <i
|
|
jsl ~ABS8
|
|
pla
|
|
sta [retptr]
|
|
ldy #2
|
|
pla
|
|
sta [retptr],y
|
|
iny
|
|
iny
|
|
pla
|
|
sta [retptr],y
|
|
iny
|
|
iny
|
|
pla
|
|
sta [retptr],y
|
|
|
|
creturn
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* ldiv_t ldiv(n,d)
|
|
* long n,d;
|
|
*
|
|
* Inputs:
|
|
* n - numerator
|
|
* d - denominator
|
|
*
|
|
* Outputs:
|
|
* ldiv_t - contains result & remainder
|
|
*
|
|
****************************************************************
|
|
*
|
|
ldiv start
|
|
addr equ 1
|
|
|
|
csubroutine (4:n,4:d),4
|
|
|
|
phb use local addressing
|
|
phk
|
|
plb
|
|
ph4 n do the divide
|
|
ph4 d
|
|
jsl ~DIV4
|
|
pl4 div_t
|
|
pl4 div_t+4
|
|
lda n+2 if the numerator is negative then
|
|
bpl lb1
|
|
sub4 #0,div_t+4,div_t+4 make the remainder negative
|
|
lb1 lla addr,div_t return the result
|
|
plb
|
|
|
|
creturn 4:addr
|
|
|
|
div_t ds 8
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* lldiv_t lldiv(long long n, long long d)
|
|
*
|
|
* Inputs:
|
|
* n - numerator
|
|
* d - denominator
|
|
*
|
|
* Outputs:
|
|
* lldiv_t - contains result & remainder
|
|
*
|
|
****************************************************************
|
|
*
|
|
lldiv start
|
|
imaxdiv entry
|
|
addr equ 1
|
|
|
|
csubroutine (8:n,8:d),4
|
|
phb use local addressing
|
|
phk
|
|
plb
|
|
ph8 <n do the divide
|
|
ph8 <d
|
|
jsl ~CDIV8
|
|
pl8 lldiv_t
|
|
pl8 lldiv_t+8
|
|
lla addr,lldiv_t return the result
|
|
plb
|
|
|
|
creturn 4:addr
|
|
|
|
lldiv_t ds 16
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* void qsort(base, count, size, compar)
|
|
* void *base;
|
|
* size_t count, size;
|
|
* int (*compar)(const void *, const void *)
|
|
*
|
|
* Inputs:
|
|
* base - start address of the array to sort
|
|
* count - # elements in the array
|
|
* size - size of each array element
|
|
* compar - function that compares array elements
|
|
*
|
|
* Outputs:
|
|
* The array is sorted on exit.
|
|
*
|
|
****************************************************************
|
|
*
|
|
qsort start
|
|
|
|
csubroutine (4:base,4:count,4:size,4:compar),0
|
|
phb
|
|
phk
|
|
plb
|
|
|
|
lda count nothing to do if count is 0
|
|
ora count+2
|
|
beq done
|
|
dec4 count set count to the addr of the last entry
|
|
mul4 count,size
|
|
add4 count,base
|
|
move4 size,lsize save size in a global var
|
|
lda compar set the jsl addresses
|
|
sta jsl1+1
|
|
sta jsl2+1
|
|
lda compar+1
|
|
sta jsl1+2
|
|
sta jsl2+2
|
|
ph4 count do the sort
|
|
ph4 base
|
|
jsl rsort
|
|
|
|
done plb
|
|
creturn
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* rand - get a random number
|
|
*
|
|
* Outputs:
|
|
* A - random number
|
|
*
|
|
****************************************************************
|
|
*
|
|
rand start
|
|
|
|
lda >~srand if no initialization then
|
|
bne lb1
|
|
ph2 #1 initialize with a value of 1
|
|
jsl srand
|
|
lb1 jsl ~RANX find the random number
|
|
lda >~SEED
|
|
and #$7FFF
|
|
rtl
|
|
|
|
~srand entry
|
|
dc i'0'
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* rsort - recursive sort for qsort
|
|
*
|
|
* Inputs:
|
|
* first - first array element to sort
|
|
* last - last array element to sort
|
|
*
|
|
****************************************************************
|
|
*
|
|
rsort private
|
|
left equ 1 left address
|
|
right equ 5 right address
|
|
|
|
csubroutine (4:first,4:last),8
|
|
|
|
phb
|
|
phk
|
|
plb
|
|
sr0 lda last+2 if last <= first then quit
|
|
cmp first+2
|
|
bne sr1
|
|
lda last
|
|
cmp first
|
|
sr1 bgt sr1a
|
|
plb
|
|
creturn
|
|
|
|
sr1a move4 last,right right = last
|
|
move4 first,left left = first
|
|
bra sr3
|
|
sr2 add4 left,lsize inc left until *left >= *last
|
|
sr3 ph4 last
|
|
ph4 left
|
|
jsl1 entry
|
|
jsl jsl1
|
|
tax
|
|
bmi sr2
|
|
sr4 lda right quit if right = first
|
|
cmp first
|
|
bne sr4a
|
|
lda right+2
|
|
cmp first+2
|
|
beq sr4b
|
|
sr4a sub4 right,lsize dec right until *right <= *last
|
|
ph4 last
|
|
ph4 right
|
|
jsl2 entry
|
|
jsl jsl2
|
|
dec A
|
|
bpl sr4
|
|
sr4b ph4 left swap left/right entries
|
|
ph4 right
|
|
jsr swap
|
|
lda left+2 loop if left < right
|
|
cmp right+2
|
|
bne sr5
|
|
lda left
|
|
cmp right
|
|
sr5 blt sr2
|
|
ph4 right swap left/right entries
|
|
ph4 left
|
|
jsr swap
|
|
ph4 left swap left/last entries
|
|
ph4 last
|
|
jsr swap
|
|
sub4 left,lsize,right sort left part of array
|
|
ph4 right
|
|
ph4 first
|
|
jsl rsort
|
|
add4 left,lsize,first sort right part of array
|
|
brl sr0
|
|
;
|
|
; swap - swap two entries
|
|
;
|
|
l equ 3 left entry
|
|
r equ 7 right entry
|
|
|
|
swap tsc set up addressing
|
|
phd
|
|
tcd
|
|
ldx lsize+2 move 64K chunks
|
|
beq sw2
|
|
ldy #0
|
|
sw1 lda [l],Y
|
|
tax
|
|
lda [r],Y
|
|
sta [l],Y
|
|
txa
|
|
sta [r],Y
|
|
dey
|
|
dey
|
|
bne sw1
|
|
inc l+2
|
|
inc r+2
|
|
dex
|
|
bne sw1
|
|
sw2 lda lsize if there are an odd number of bytes then
|
|
lsr A
|
|
bcc sw3
|
|
short M move one byte
|
|
lda [l]
|
|
tax
|
|
lda [r]
|
|
sta [l]
|
|
txa
|
|
sta [r]
|
|
long M
|
|
inc4 l
|
|
inc4 r
|
|
lda lsize
|
|
lsr A
|
|
sw3 asl A quit if there are no more bytes
|
|
beq sw6
|
|
tay
|
|
bra sw5
|
|
sw4 lda [l],Y move the bytes
|
|
tax
|
|
lda [r],Y
|
|
sta [l],Y
|
|
txa
|
|
sta [r],Y
|
|
sw5 dey
|
|
dey
|
|
bne sw4
|
|
lda [l]
|
|
tax
|
|
lda [r]
|
|
sta [l]
|
|
txa
|
|
sta [r]
|
|
sw6 pld
|
|
plx
|
|
tsc
|
|
clc
|
|
adc #8
|
|
tcs
|
|
phx
|
|
rts
|
|
;
|
|
; local data
|
|
;
|
|
lsize entry
|
|
ds 4 local copy of size
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* srand - seed the random number generator
|
|
*
|
|
* Inputs:
|
|
* 4,S - random number seed
|
|
*
|
|
****************************************************************
|
|
*
|
|
srand start
|
|
|
|
lda #1
|
|
sta >~srand
|
|
phb
|
|
plx
|
|
ply
|
|
pla
|
|
phy
|
|
phx
|
|
plb
|
|
brl ~RANX2
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* strtol - convert a string to a 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:
|
|
* X-A - converted number
|
|
*
|
|
****************************************************************
|
|
*
|
|
strtol start
|
|
base equ 18 base
|
|
ptr equ 14 *return pointer
|
|
str equ 10 string pointer
|
|
rtl equ 7 return address
|
|
|
|
val equ 3 value
|
|
negative equ 1 is the number negative?
|
|
|
|
pea 0 make room for & initialize val
|
|
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
|
|
jsl ~strtoul
|
|
stx val+2
|
|
sta val
|
|
txy see if we have an overflow
|
|
bpl rt1
|
|
ldy negative allow -2147483648 as legal value
|
|
beq ov0
|
|
cpx #$8000
|
|
bne ov0
|
|
tay
|
|
beq rt1
|
|
;
|
|
; Overflow - flag the error
|
|
;
|
|
ov0 lda #ERANGE errno = ERANGE
|
|
sta >errno
|
|
ldx #$7FFF return value = LONG_MAX
|
|
ldy #$FFFF
|
|
lda negative if negative then
|
|
beq ov1
|
|
inx return value = LONG_MIN
|
|
iny
|
|
ov1 sty val
|
|
stx val+2
|
|
;
|
|
; return the results
|
|
;
|
|
rt1 pla remove the original value of str from
|
|
pla the stack
|
|
lda negative if negative then
|
|
beq rt2
|
|
sub4 #0,val,val val = -val
|
|
|
|
rt2 ldx val+2 get the value
|
|
ldy val
|
|
lda rtl fix the stack
|
|
sta base-1
|
|
lda rtl+1
|
|
sta base
|
|
pld
|
|
tsc
|
|
clc
|
|
adc #16
|
|
tcs
|
|
tya return
|
|
rtl
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* strtoul - convert a string to an unsigned long
|
|
* ~strtoul - 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:
|
|
* X-A - converted number
|
|
*
|
|
****************************************************************
|
|
*
|
|
strtoul start
|
|
base equ 22 base
|
|
ptr equ 18 *return pointer
|
|
str equ 14 string pointer
|
|
rtl equ 11 return address
|
|
|
|
rangeOK equ 9 was the number within range?
|
|
negative equ 7 was there a minus sign?
|
|
val equ 3 value
|
|
foundOne equ 1 have we found a number?
|
|
|
|
ldx #0
|
|
bra init
|
|
|
|
~strtoul entry alt entry point called from strtol
|
|
ldx #1
|
|
|
|
init 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 make room for & initialize foundOne
|
|
tsc set up direct page addressing
|
|
phd
|
|
tcd
|
|
;
|
|
; Skip any leading whitespace
|
|
;
|
|
txa 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
|
|
bge cn6
|
|
dec a
|
|
beq 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
|
|
pha val = val*base
|
|
pha
|
|
pha
|
|
pha
|
|
ph4 val
|
|
pea 0
|
|
ph2 base
|
|
_LongMul
|
|
pl4 val
|
|
pla branch if there was an error
|
|
ora 1,S
|
|
plx
|
|
ply
|
|
tax
|
|
beq cn3a
|
|
stz rangeOK
|
|
cn3a clc add in the new digit
|
|
tya
|
|
adc val
|
|
sta val
|
|
bcc cn4
|
|
inc val+2
|
|
bne 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
|
|
ldx #$FFFF return value = ULONG_MAX
|
|
txy
|
|
bra rt3
|
|
rt2 lda negative if negative then
|
|
beq rt2a
|
|
sub4 #0,val,val val = -val
|
|
rt2a ldx val+2 get the value
|
|
ldy val
|
|
rt3 lda rtl fix the stack
|
|
sta base-1
|
|
lda rtl+1
|
|
sta base
|
|
pld
|
|
tsc
|
|
clc
|
|
adc #20
|
|
tcs
|
|
tya return
|
|
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
|
|
negate8 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
|
|
negate8 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)
|
|
* char *command;
|
|
*
|
|
* Executes the command steam as an exec file.
|
|
*
|
|
* Inputs:
|
|
* command - command string
|
|
*
|
|
* Outputs:
|
|
* Returns the status of the command
|
|
*
|
|
****************************************************************
|
|
*
|
|
system start
|
|
|
|
phb get the addr of the string from the
|
|
phk stack
|
|
plb
|
|
plx
|
|
ply
|
|
pla
|
|
sta exComm
|
|
pla
|
|
sta exComm+2
|
|
ora exComm
|
|
sta empty
|
|
bne lb1 if calling system(NULL)
|
|
lda #empty use empty command string
|
|
sta exComm
|
|
lda #^empty
|
|
sta exComm+2
|
|
lb1 phy execute the command
|
|
phx
|
|
Execute ex
|
|
ldy empty
|
|
bne ret if doing system(NULL)
|
|
tya
|
|
bcs ret error => no command processor
|
|
inc a (& vice versa)
|
|
ret plb
|
|
rtl
|
|
|
|
ex dc i'$8000'
|
|
exComm ds 4
|
|
|
|
empty ds 2
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* void __va_end(list)
|
|
* va_list list;
|
|
*
|
|
* Remove variable length arguments from the stack.
|
|
*
|
|
* Inputs:
|
|
* list - Pointer to an array. The second element is a
|
|
* pointer to the first variable argument, while
|
|
* the first is a pointer to the first byte past
|
|
* the argument list.
|
|
*
|
|
* Notes:
|
|
* 1. The number of bytes to remove must be even.
|
|
* 2. D is incremented by the # of bytes removed.
|
|
*
|
|
****************************************************************
|
|
*
|
|
__va_end start
|
|
list equ 7 pointer to the array
|
|
D equ 1 caller's DP
|
|
|
|
phb save the caller's data bank
|
|
phd save the caller's D reg
|
|
tsc set up our stack frame
|
|
tcd
|
|
sec calculate the # of bytes to be removed
|
|
ldy #4
|
|
lda [list]
|
|
sbc [list],Y
|
|
sta >toRemove
|
|
clc update the caller's DP
|
|
adc D
|
|
sta D
|
|
|
|
lda [list],Y set the source address
|
|
tax
|
|
dex
|
|
lda [list] set the destination address
|
|
tay
|
|
dey
|
|
sec set the # of bytes to move - 1
|
|
tsc
|
|
sbc [list]
|
|
eor #$FFFF
|
|
mvp 0,0 move the bytes
|
|
|
|
clc update out stack ptr
|
|
tsc
|
|
adc >toRemove
|
|
tcs
|
|
pld restore the caller's DP
|
|
plx remove the parameter from the stack
|
|
ply
|
|
pla
|
|
pla
|
|
phy
|
|
phx
|
|
plb restore the caller's data bank
|
|
rtl
|
|
|
|
toRemove ds 2 # bytes to remove
|
|
end
|