diff --git a/lib/libc/stdlib/Makefile b/lib/libc/stdlib/Makefile index 0734cd5..479fea4 100644 --- a/lib/libc/stdlib/Makefile +++ b/lib/libc/stdlib/Makefile @@ -1,11 +1,18 @@ # -# $Id: Makefile,v 1.1 1997/02/28 05:12:49 gdr Exp $ +# gno/lib/libc/stdlib/Makefile +# +# Devin Reade, 1997 +# +# $Id: Makefile,v 1.2 1997/09/05 06:31:58 gdr Exp $ # +.INCLUDE: ../../../paths.mk .INCLUDE: ../../const.mk -OBJS = environ.o getopt.o getsubopt.o +OBJS = cvt.o environ.o fpspecnum.o getopt.o getsubopt.o default: $(OBJS) .INCLUDE: ../rules.mk + +fpspecnum.o:: fpspecnum.mac diff --git a/lib/libc/stdlib/cvt.c b/lib/libc/stdlib/cvt.c new file mode 100644 index 0000000..3fb8a64 --- /dev/null +++ b/lib/libc/stdlib/cvt.c @@ -0,0 +1,136 @@ +/* + * Floating point conversion routines. + * Devin Reade, 1997. + * + * $Id: cvt.c,v 1.1 1997/09/05 06:31:59 gdr Exp $ + * + * This file is formatted with tab stops every 8 columns. + */ + +#include +#include +#include +#include + +char * +ecvt (double number, size_t ndigits, int *decpt, int *sign) +{ + static DecForm convert; + static Decimal d; + + convert.style = FLOATDECIMAL; + if (ndigits > SIGDIGLEN) { + ndigits = SIGDIGLEN; + } + convert.digits = ndigits; + s_num2dec(&convert, number, &d); + *decpt = (int)d.sig.length + d.exp; + *sign = d.sgn; + *(d.sig.text + (int)d.sig.length) = '\0'; /* depends on d.sig.unused */ + return d.sig.text; +} + +char * +fcvt (double number, size_t ndigits, int *decpt, int *sign) +{ + static DecForm convert; + static Decimal d; + + convert.style = FIXEDDECIMAL; + if (ndigits > SIGDIGLEN) { + ndigits = SIGDIGLEN; + } + convert.digits = ndigits; + s_num2dec(&convert, number, &d); + *decpt = (int)d.sig.length + d.exp; + *sign = d.sgn; + *(d.sig.text + (int)d.sig.length) = '\0'; /* depends on d.sig.unused */ + return d.sig.text; +} + + /* __dtoa: These are the comments from the BSD implementation of + this routine. Whether or not we have achieved compatibility + remains to be seen. + + Arguments ndigits, decpt, sign are similar to those + of ecvt and fcvt; trailing zeros are suppressed from + the returned string. If not null, *rve is set to point + to the end of the return value. If d is +-Infinity or NaN, + then *decpt is set to 9999. + + mode: + 0 ==> shortest string that yields d when read in + and rounded to nearest. + 1 ==> like 0, but with Steele & White stopping rule; + e.g. with IEEE P754 arithmetic , mode 0 gives + 1e23 whereas mode 1 gives 9.999999999999999e22. + 2 ==> max(1,ndigits) significant digits. This gives a + return value similar to that of ecvt, except + that trailing zeros are suppressed. + 3 ==> through ndigits past the decimal point. This + gives a return value similar to that from fcvt, + except that trailing zeros are suppressed, and + ndigits can be negative. + 4-9 should give the same return values as 2-3, i.e., + 4 <= mode <= 9 ==> same return as mode + 2 + (mode & 1). These modes are mainly for + debugging; often they run slower but sometimes + faster than modes 2-3. + 4,5,8,9 ==> left-to-right digit generation. + 6-9 ==> don't try fast floating-point estimate + (if applicable). + + Values of mode other than 0-9 are treated as mode 0. + + Sufficient space is allocated to the return value + to hold the suppressed trailing zeros. + */ + +#undef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +char * +__dtoa (double number, int mode, int ndigits, int *decpt, int *sign, + char **rve) +{ + char *result, *p; + + switch(mode) { + case 2: + case 4: + case 6: + case 8: +mode0: /* this label doesn't belong here */ + result = ecvt(number, MAX(1, ndigits), decpt, sign); + break; + case 3: + case 5: + case 7: + case 9: + result = fcvt(number, ndigits, decpt, sign); + break; + + case 0: + case 1: + default: + goto mode0; /* TEMP KLUDGE */ + } + + /* truncate trailing zeros */ + p = result; + while (*p) p++; + p--; + while ((p > result) && (*p == '0')) { + *p-- = '\0'; + } + if (rve != NULL) { + *rve = p + 1; + } + + /* set decimal point for NaNs and Infinities */ + if (isnan(number) || isinf(number)) { + *decpt = 9999; + } + + return result; +} diff --git a/lib/libc/stdlib/fpspecnum.asm b/lib/libc/stdlib/fpspecnum.asm new file mode 100644 index 0000000..3774a81 --- /dev/null +++ b/lib/libc/stdlib/fpspecnum.asm @@ -0,0 +1,107 @@ +* +* Test an extended to see whether it is NaN or INF +* +* $Id: fpspecnum.asm,v 1.1 1997/09/05 06:31:59 gdr Exp $ +* +* Soenke Behrens, August 1997 +* + case on + mcopy fpspecnum.mac + +* +* Dummy function to take care of fpspecnum.root, which +* can then be discarded. +* + +dummy start + copy :lib:ainclude:e16.sane ; Apple-supplied SANE EQUs + end + +**************************************************************** +* +* int _isnan (extended x); +* +* Check whether x is NaN, if so, return 1, otherwise, return 0. +* +**************************************************************** +* + +_isnan start libc_stdlib +result equ 1 +space equ result+2 + + csub (10:x),space + + short m clear the specific NaN code + stz x+6 + long m + + lda x and do the compare + cmp nan_x + bne diff + lda x+2 + cmp nan_x+2 + bne diff + lda x+4 + cmp nan_x+4 + bne diff + lda x+6 + cmp nan_x+6 + bne diff + lda x+8 + cmp nan_x+8 + bne diff + lda #1 + sta result + bra bye +diff stz result + +bye ret (2:result) + +nan_x dc h'0000000000000040FF7F' ; Hex encoding of a NaN + end + +**************************************************************** +* +* int _isinf (extended x); +* +* Check whether x is INF, if so, return 1, otherwise, return 0. +* +**************************************************************** +* + +_isinf start libc_stdlib +result equ 1 +space equ result+2 + + csub (10:x),space + short m + lda x+9 get rid of sign bit + and #%01111111 + sta x+9 + long m + + lda x and do the compare + cmp inf_x + bne diff + lda x+2 + cmp inf_x+2 + bne diff + lda x+4 + cmp inf_x+4 + bne diff + lda x+6 + cmp inf_x+6 + bne diff + lda x+8 + cmp inf_x+8 + bne diff + lda #1 + sta result + bra bye +diff stz result + +bye ret (2:result) + +inf_x dc h'0000000000000000FF7F' ; Hex encoding of +INF + end diff --git a/lib/libc/stdlib/fpspecnum.mac b/lib/libc/stdlib/fpspecnum.mac new file mode 100644 index 0000000..8cfcb38 --- /dev/null +++ b/lib/libc/stdlib/fpspecnum.mac @@ -0,0 +1,133 @@ + macro +&l csub &parms,&work +&l anop + aif c:&work,.a + lclc &work +&work setc 0 +.a + gbla &totallen + gbla &worklen +&worklen seta &work +&totallen seta 0 + aif c:&parms=0,.e + lclc &len + lclc &p + lcla &i +&i seta 1 +.b +&p setc &parms(&i) +&len amid &p,2,1 + aif "&len"=":",.c +&len amid &p,1,2 +&p amid &p,4,l:&p-3 + ago .d +.c +&len amid &p,1,1 +&p amid &p,3,l:&p-2 +.d +&p equ &totallen+4+&work +&totallen seta &totallen+&len +&i seta &i+1 + aif &i<=c:&parms,^b +.e + tsc + aif &work=0,.f + sec + sbc #&work + tcs +.f + phd + tcd + mend + macro +&l ret &r +&l anop + lclc &len + aif c:&r,.a + lclc &r +&r setc 0 +&len setc 0 + ago .h +.a +&len amid &r,2,1 + aif "&len"=":",.b +&len amid &r,1,2 +&r amid &r,4,l:&r-3 + ago .c +.b +&len amid &r,1,1 +&r amid &r,3,l:&r-2 +.c + aif &len<>2,.d + ldy &r + ago .h +.d + aif &len<>4,.e + ldx &r+2 + ldy &r + ago .h +.e + aif &len<>10,.g + ldy #&r + ldx #^&r + ago .h +.g + mnote 'Not a valid return length',16 + mexit +.h + aif &totallen=0,.i + lda &worklen+2 + sta &worklen+&totallen+2 + lda &worklen+1 + sta &worklen+&totallen+1 +.i + pld + tsc + clc + adc #&worklen+&totallen + tcs + aif &len=0,.j + tya +.j + rtl + mend + macro +&l long &a,&b + lclb &i + lclb &m +&a amid &a,1,1 +&m setb ("&a"="M").or.("&a"="m") +&i setb ("&a"="I").or.("&a"="i") + aif c:&b=0,.a +&b amid &b,1,1 +&m setb ("&b"="M").or.("&b"="m").or.&m +&i setb ("&b"="I").or.("&b"="i").or.&i +.a +&l rep #&m*32+&i*16 + aif .not.&m,.b + longa on +.b + aif .not.&i,.c + longi on +.c + mend + macro +&l short &a,&b + lclb &i + lclb &m +&a amid &a,1,1 +&m setb ("&a"="M").or.("&a"="m") +&i setb ("&a"="I").or.("&a"="i") + aif c:&b=0,.a +&b amid &b,1,1 +&m setb ("&b"="M").or.("&b"="m").or.&m +&i setb ("&b"="I").or.("&b"="i").or.&i +.a +&l sep #&m*32+&i*16 + aif .not.&m,.b + longa off +.b + aif .not.&i,.c + longi off +.c + mend