keep obj/stdlib mcopy stdlib.macros case on **************************************************************** * * StdDef - Standard Definitions * * This code implements the tables and subroutines needed to * support the standard C library STDDEF. * * December 1988 * Mike Westerfield * * Copyright 1988 * Byte Works, Inc. * * Note: Portions of this library appear in SysFloat * **************************************************************** * StdDef start dummy segment copy equates.asm end **************************************************************** * * void abort() * * Stop the program. * **************************************************************** * abort start ph2 #SIGABRT jsl raise lda #-1 jmp ~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 **************************************************************** * * 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 **************************************************************** * * 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 **************************************************************** * * 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 tay if the result 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(status) * int status; * * void _exit(status) * 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 lda 4,S jmp ~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 **************************************************************** * * 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 div_t+2 if the result 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 **************************************************************** * * 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 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 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 sqap 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 negative pea 0 make room for & initialize val pea 0 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 ; ; Overflow - flag the error ; lda #ERANGE errno = ERANGE sta >errno lda ptr if ptr <> NULL then ora ptr+2 bne rt1 lda 1,S *ptr = original str sta [ptr] ldy #2 lda 3,S sta [ptr],Y ; ; 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 * * 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 18 base ptr equ 14 *return pointer str equ 10 string pointer rtl equ 7 return address val equ 3 value foundOne equ 1 have we found a number? pea 0 make room for & initialize foundOne pea 0 make room for & initialize val pea 0 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 db1 inc4 str bra sw1 ; ; Deduce the base ; db1 lda [str] skip any leading '+' and #$00FF cmp #'+' bne db1a inc4 str db1a 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 db2 lda #8 assume base 8 sta base ldy #1 if the second char is 'X' or 'x' then lda [str],Y and #$005F cmp #'X' bne db2 asl base base 16 db2 lda [str] if the first two chars are 0x or 0X then and #$5F7F cmp #'X0' bne cn1 add4 str,#2 skip them lda base make sure the base is 16 cmp #16 bne returnERANGE ; ; 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 #$005F 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 bne returnERANGE clc add in the new digit tya adc val sta val bcc cn4 inc val+2 beq returnERANGE cn4 inc4 str next char bra cn1 cn5 lda foundOne if no digits were found, flag the error bne rt1 ; ; flag an error ; returnERANGE anop lda #ERANGE errno = ERANGE sta >errno bra rt2 skip setting ptr ; ; return the results ; rt1 lda ptr if ptr is non-null then ora ptr+2 beq rt2 lda str set it to str sta [ptr] ldy #2 lda str+2 sta [ptr],Y 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 **************************************************************** * * 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 phy execute the command phx plb Execute ex rtl ex dc i'$8000' exComm ds 4 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 resore 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