Commit f464cdae authored by Kevin Bracey's avatar Kevin Bracey
Browse files

Added the following C99 features:

  * snprintf(), vsnprintf(), vfscanf(), vscanf(), vsscanf()
  * hh, j, z and t printf length modifiers (indicating char, intmax_t, size_t
    and ptrdiff_t respectively)
  * Hexadecimal floating-point printing and scanning (%a/%A)
  * %F printf() specifier (upper-case form of %F)
  * Input/output of NaNs and Infinities
  * imaxdiv_t, imaxdiv(), strtoimax(), strtoumax() (simulated through macros)
  * <fenv.h>: feclearexcept(), fegetexceptflag(), feraiseexcept(),
              fesetexceptflag(), fetestexcept(), fegetround(), fesetround(),
              fegetenv(), feholdexcept(), fesetenv(), feupdateenv()
  * FLT_EVAL_METHOD, DECIMAL_DIG
  * hypot(), hypotf(), fabsf(), fdim(), fdimf(), fmax(), fmaxf(), fmin(),
    fminf()
  * INFINITY, NAN, fpclassify(), isfinite(), isinf(), isnan(), isnormal(),
    signbit(), copysign(), copysignf(), nan(), nanf(), nextafter(),
    nextafterf() isgreater(), isgreaterequal(), isless(), islessequal(),
    islessgreater(), isunordered()

This involves adding 36 new entries to the stubs. Current versions of the C
library will not fault client programs with such larger stubs, but will fill
in the extra entries with junk. Programs requiring the new functions will have
to RMEnsure this version of the Shared C Library.

This version of the C library has been fixed so that in future, any extra
unknown stubs entries will be filled in with a branch to zero, rather than
corrupted.

Requires cc 5.41 or later, both to build, and to make use of some of the extra
facilities.


Version 5.37. Tagged as 'RISC_OSLib-5_37'
parent 17f31184
......@@ -277,7 +277,7 @@ EXPORTS = ${MODWRAP} \
ANSI_OBJS =\
o.alloc o.armprof o.armsys o.clib o.ctype o.error o.fpprintf \
o.kernel o.locale o.math o.memcpset o.overmgr o.printf o.scanf \
o.signal o.sort o.stdio o.stdlib o.string o.swiv o.time
o.signal o.sort o.stdio o.stdlib o.string o.swiv o.time o.fenv
RM_OBJS =\
rm_o.k_modbody \
......@@ -299,6 +299,7 @@ RM_OBJS =\
rm_o.stdlib \
rm_o.string \
rm_o.time \
rm_o.fenv \
rm_o.swiv \
rm_o.cl_spare
......@@ -605,6 +606,7 @@ CLIB:h.swis: derived.swis
CLIB:h.assert: clib.h.assert ; ${CP} clib.h.assert $@ ${CPFLAGS}
CLIB:h.ctype: clib.h.ctype; ${CP} clib.h.ctype $@ ${CPFLAGS}
CLIB:h.errno: clib.h.errno; ${CP} clib.h.errno $@ ${CPFLAGS}
CLIB:h.fenv: clib.h.fenv; ${CP} clib.h.fenv $@ ${CPFLAGS}
CLIB:h.float: clib.h.float; ${CP} clib.h.float $@ ${CPFLAGS}
CLIB:h.inttypes: clib.h.inttypes; ${CP} clib.h.inttypes $@ ${CPFLAGS}
CLIB:h.iso646: clib.h.iso646; ${CP} clib.h.iso646 $@ ${CPFLAGS}
......
......@@ -12,14 +12,14 @@
GBLS Module_HelpVersion
GBLS Module_ComponentName
GBLS Module_ComponentPath
Module_MajorVersion SETS "5.36"
Module_Version SETA 536
Module_MajorVersion SETS "5.37"
Module_Version SETA 537
Module_MinorVersion SETS ""
Module_Date SETS "22 Feb 2002"
Module_ApplicationDate2 SETS "22-Feb-02"
Module_ApplicationDate4 SETS "22-Feb-2002"
Module_Date SETS "21 Mar 2002"
Module_ApplicationDate2 SETS "21-Mar-02"
Module_ApplicationDate4 SETS "21-Mar-2002"
Module_ComponentName SETS "RISC_OSLib"
Module_ComponentPath SETS "RiscOS/Sources/Lib/RISC_OSLib"
Module_FullVersion SETS "5.36"
Module_HelpVersion SETS "5.36 (22 Feb 2002)"
Module_FullVersion SETS "5.37"
Module_HelpVersion SETS "5.37 (21 Mar 2002)"
END
/* (5.36)
/* (5.37)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.62.
*
*/
#define Module_MajorVersion_CMHG 5.36
#define Module_MajorVersion_CMHG 5.37
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 22 Feb 2002
#define Module_Date_CMHG 21 Mar 2002
#define Module_MajorVersion "5.36"
#define Module_Version 536
#define Module_MajorVersion "5.37"
#define Module_Version 537
#define Module_MinorVersion ""
#define Module_Date "22 Feb 2002"
#define Module_Date "21 Mar 2002"
#define Module_ApplicationDate2 "22-Feb-02"
#define Module_ApplicationDate4 "22-Feb-2002"
#define Module_ApplicationDate2 "21-Mar-02"
#define Module_ApplicationDate4 "21-Mar-2002"
#define Module_ComponentName "RISC_OSLib"
#define Module_ComponentPath "RiscOS/Sources/Lib/RISC_OSLib"
#define Module_FullVersion "5.36"
#define Module_HelpVersion "5.36 (22 Feb 2002)"
#define Module_LibraryVersionInfo "5:36"
#define Module_FullVersion "5.37"
#define Module_HelpVersion "5.37 (21 Mar 2002)"
#define Module_LibraryVersionInfo "5:37"
......@@ -53,6 +53,7 @@ extern int __vfprintf(FILE *fp, const char *fmt,
#define _SHORTSPEC 0100
#define _PADZERO 0200 /* *** DEPRECATED FEATURE *** */
#define _FPCONV 0400
#define _CHARSPEC 01000
#ifndef NO_FLOATING_POINT
......@@ -284,24 +285,24 @@ static int fp_digits(char *buff, double d)
#endif /* HOST_HAS_BCD_FLT */
static int fp_addexp(char *buff, int len, int dx, int ch)
{ int dxDiv10;
static int fp_addexp(char *buff, int len, int dx, int ch, int min)
{
char tmp[10];
int n=0;
buff[len++] = ch;
if (dx<0) { dx = -dx; buff[len++] = '-'; }
else buff[len++] = '+';
if (dx >= 1000)
{ int dxDiv1000 = _kernel_sdiv(1000, dx);
buff[len++] = '0' + dxDiv1000;
dx = dx - dxDiv1000 * 1000;
}
if (dx >= 100)
{ int dxDiv100 = _kernel_sdiv(100, dx);
buff[len++] = '0' + dxDiv100;
dx = dx - dxDiv100 * 100;
while (dx > 0 || n < min)
{
tmp[n++] = '0' + dx % 10;
dx /= 10;
}
dxDiv10 = _kernel_sdiv10(dx);
buff[len++] = '0' + dxDiv10;
buff[len++] = '0' + dx - dxDiv10 * 10;
while (n)
buff[len++] = tmp[--n];
return len;
}
......@@ -315,18 +316,42 @@ static int fp_display(int ch, double *lvd, char buff[], int flags,
int *lvafter_dot)
{ int len = 0;
double d = *lvd;
switch (ch)
{
/* The following code places characters in the buffer buff[] */
/* to print the floating point number given as d. */
/* It is given flags that indicate what format is required and how */
/* many digits precision are needed. */
if (!isfinite(d))
{ int upper = ch < 'a';
if (signbit(d)) *lvprefix = "-";
else
*lvprefix = (flags&_SIGNED) ? "+" :
(flags&_BLANKER) ? " " : "";
if (isinf(d))
{ if (upper)
buff[0] = 'I', buff[1] = 'N', buff[2] = 'F';
else
buff[0] = 'i', buff[1] = 'n', buff[2] = 'f';
}
else
{ if (upper)
buff[0] = 'N', buff[1] = 'A', buff[2] = 'N';
else
buff[0] = 'n', buff[1] = 'a', buff[2] = 'n';
}
*lvbefore_dot = -1;
*lvafter_dot = -1;
return 3;
}
switch (ch)
{
/* Floating point values are ALWAYS converted into 18 decimal digits */
/* (the largest number possible reasonable) to start with, and rounding */
/* is then performed on this character representation. This is intended */
/* to avoid all possibility of boundary effects when numbers like .9999 */
/* are being displayed. */
case 'f':
case 'F':
{ int dx = fp_digits(buff, d);
if (dx & 1) *lvprefix = "-";
else
......@@ -467,7 +492,7 @@ static int fp_display(int ch, double *lvd, char buff[], int flags,
}
if (ch!='f') /* sets 'f' if it prints in f format */
/* and 'e' or 'E' if in e format. */
len = fp_addexp(buff, len, dx, ch + ('e'-'g'));
len = fp_addexp(buff, len, dx, ch + ('e'-'g'), 2);
}
break;
case 'e':
......@@ -489,7 +514,67 @@ static int fp_display(int ch, double *lvd, char buff[], int flags,
else buff[1] = *decimal_point;
/* Deal with trailing zeros for excessive precision requests */
if (*lvafter_dot>0) buff[len++] = '>';
len = fp_addexp(buff, len, dx, ch);
len = fp_addexp(buff, len, dx, ch, 2);
}
break;
/* Hexadecimal printing - this is pretty easy. Output is in the form */
/* [-]0xh.hhhhp<+|->d, where there is one hexadecimal digit (non-zero if */
/* normalised) before the '.', and precision digits after the '.' */
case 'a':
case 'A':
{ unsigned whi, wlo, bx, i;
const char *hextab;
hextab = ch=='a' ? "0123456789abcdef" : "0123456789ABCDEF";
whi = ((unsigned *)lvd)[0];
wlo = ((unsigned *)lvd)[1];
/* take 3 off exponent because putting 4 bits before . */
bx = ((whi >> 20) & 0x7FF) - 0x3FF;
if (whi & 0x80000000) *lvprefix = (ch=='a'?"-0x":"-0X");
else
*lvprefix = (flags&_SIGNED) ? (ch=='a'?"+0x":"+0X") :
(flags&_BLANKER) ? (ch=='a'?" 0x":" 0X") :
(ch=='a'?"0x":"0X");
if ((whi&0x7FFFFFFF)|wlo)
{ if (bx == -0x3FF)
bx = -0x3FE;
else
whi |= 0x00100000;
}
else
bx = 0;
whi &= 0x001FFFFF;
buff[0] = '0';
for (i=1; i<=6; i++)
buff[i] = hextab[(whi >> (24-i*4)) & 0xf];
for (i=7; i<=14; i++)
buff[i] = hextab[(wlo >> (56-i*4)) & 0xf];
if (!(flags&_PRECGIVEN))
{ *lvprecision = 0;
for (i=13; i>=1; i--)
if (buff[i+1] != '0')
{ *lvprecision = i;
break;
}
}
else if (*lvprecision>13)
{ *lvafter_dot = *lvprecision - 13;
*lvprecision = 13;
}
len = *lvprecision + 2;
buff[0] = buff[1];
if ((*lvprecision==0) && !(flags&_VARIANT)) len = 1;
else buff[1] = *decimal_point;
/* Deal with trailing zeros for excessive precision requests */
if (*lvafter_dot>0) buff[len++] = '>';
len = fp_addexp(buff, len, bx, ch + ('p'-'a'), 1);
}
break;
}
......@@ -547,6 +632,25 @@ int sprintf(char *buff, const char *fmt, ...)
return(length);
}
int snprintf(char *buff, size_t n, const char *fmt, ...)
{
FILE hack;
va_list a;
/*************************************************************************/
/* Note that this code interacts in a dubious way with the putc macro. */
/*************************************************************************/
int length;
va_start(a, fmt);
memclr(&hack, sizeof(FILE));
hack.__flag = _IOSTRG+_IOWRITE;
hack.__ptr = (unsigned char *)buff;
hack.__ocnt = n == 0 ? 0 : n-1;
length = __vfprintf(&hack, fmt, a, fp_display, 0);
if (n != 0) *hack.__ptr = 0;
va_end(a);
return(length);
}
int vfprintf(FILE *p, const char *fmt, va_list args)
{
return __vfprintf(p, fmt, args, fp_display, 0);
......@@ -573,5 +677,22 @@ int vsprintf(char *buff, const char *fmt, va_list a)
return(length);
}
int vsnprintf(char *buff, size_t n, const char *fmt, va_list a)
{
FILE hack;
/*************************************************************************/
/* Note that this code interacts in a dubious way with the putc macro. */
/*************************************************************************/
int length;
memclr(&hack, sizeof(FILE));
hack.__flag = _IOSTRG+_IOWRITE;
hack.__ptr = (unsigned char *)buff;
hack.__ocnt = n == 0 ? 0 : n-1;
length = __vfprintf(&hack, fmt, a, fp_display, 0);
if (n != 0) *hack.__ptr = 0;
return(length);
}
/* End of fpprintf.c */
......@@ -46,94 +46,10 @@
#include <math.h> /* for forward references */
#ifdef IBMFLOAT
const double __huge_val = 7.2370055773322621e+75;
#else
/* On the ARM, this has moved into the library's static data area */
/* so that it still works with the Shared C Library module. */
/* const double __huge_val = 1.79769313486231571e+308; */
#endif
#ifdef IBMFLOAT
double frexp(d, lvn)
double d; int *lvn;
{
fp_number d1;
int n;
if (d==0.0)
/* I worry a little about signed zeros here. I hope that -0.0 == 0.0 */
{ *lvn = 0;
return 0.0;
}
d1.d = d;
n = 4*(d1.i.x - 0x40); /* excess 64 exponent */
d1.i.x = 0x40;
d = d1.d;
/* Note that the following code works for unnormalised numbers, but */
/* can then take 55 cycles to converge instead of usual 3 max. */
while ((d>=0 ? d : -d) < 0.5) d = d+d, n--;
/* Now d is most definitely normalised. */
*lvn = n;
return d;
}
double ldexp(d, n)
double d; int n;
{
fp_number d1;
int nx;
if (d==0.0) return 0.0; /* special case */
d1.d = d;
nx = d1.i.x + (n & ~3)/4;
n &= 3;
#ifndef DO_NOT_SUPPORT_UNNORMALIZED_NUMBERS
/* The following code gets the msd/expt right for unnormalised nos. */
d1.i.x = 0x40;
d1.d += 0.0; /* i.e. normalise */
nx += d1.i.x - 0x40;
#endif
{ int mhi = d1.i.mhi;
int nx1 = (mhi & 0x00c00000)==0 ?
((mhi & 0x00200000)==0 ? n - 3 : n - 2) :
((mhi & 0x00800000)==0 ? n - 1 : n);
if (nx1 > 0) nx++, n -= 4;
/* That just dealt with the fact that in IBM format the exponent is for */
/* base 16 and so scaling by a power of two can involve a real multiply. */
/* I now know what the true exponent (nx) in the result will be. */
}
if (nx > 0x7f) /* Overflow (maybe do a raise() ?) */
{ d1.i.x = 0x7f;
d1.i.mhi = 0xffffff;
d1.i.mlo = 0xffffffff;
return d1.d;
}
if (nx < 0) /* Deal with underflow/unnormalised */
{ if (nx <= -14) return 0.0;
d1.i.x = 0;
while (nx < 0) d1.d /= 16, nx++; /* de-normalise gracefully */
}
d1.i.x = nx;
{ double d2;
switch (n)
{
case -3:d2 = 0.125; break;
case -2:d2 = 0.25; break;
case -1:d2 = 0.5; break;
default: /* avoid dataflow whinge */
case 0: d2 = 1.0; break;
case 1: d2 = 2.0; break;
case 2: d2 = 4.0; break;
case 3: d2 = 8.0; break;
}
d1.d *= d2;
}
return d1.d;
}
#else /* Here is the IEEE format stuff */
#ifndef DO_NOT_SUPPORT_UNNORMALIZED_NUMBERS
......@@ -210,14 +126,9 @@ double d; int n;
return (d1.d);
}
#endif
#ifdef IBMFLOAT
#define _exp_arg_limit 174.673089501106208
#else
#define _exp_arg_limit 709.78271289338397
#endif
/* machine independent code - but beware the 1e-20's */
......@@ -291,14 +202,10 @@ double cos(double x)
else return _sincos(x, _pi_2 + x, 1, 1);
}
#ifdef IBMFLOAT
#define _exp_negative_arg_limit -180.218266945585778
#else
/* NB: the following value is a proper limit provided denormalised */
/* values are not being supported. It would need to be changed if they */
/* were to start existing. */
#define _exp_negative_arg_limit -708.39641853226408
#endif
double exp(double x)
{
......@@ -313,14 +220,7 @@ double exp(double x)
/* In C the cast (int)x truncates towards zero. Here I want to round. */
n = (int)((x >= 0 ? 0.5 : -0.5) + 1.44266950408889634074 * x);
xn = (double)n;
#ifdef IBMFLOAT
{ double x1 = (double)(int)x;
double x2 = x - x1;
g = ((x1 - xn * 0.693359375) + x2) - xn * (-2.1219444005469058277e-4);
}
#else
g = (x - xn * 0.693359375) - xn * (-2.1219444005469058277e-4);
#endif
z = g * g;
#define _exp_p0 0.249999999999999993
#define _exp_p1 0.694360001511792852e-2
......@@ -387,34 +287,17 @@ double sqrt(double x)
return -HUGE_VAL;
}
f.d = x;
#ifdef IBMFLOAT
n = f.i.x - 0x40;
f.i.x = 0x40;
#else
n = f.i.x - 0x3fe;
f.i.x = 0x3fe;
#endif
{ double fd = f.d;
#ifdef IBMFLOAT
y0 = 0.223607 + 0.894427 * fd;
#else
y0 = 0.41731 + 0.59016 * fd;
#endif
y0 = 0.5 * (y0 + fd/y0);
y0 = 0.5 * (y0 + fd/y0);
y0 = 0.5 * (y0 + fd/y0);
#ifdef IBMFLOAT
#define __EPS 2.2204460492503131e-16
y0 = y0 + (0.5 * (fd/y0 - y0) + __EPS/32.0);
#endif
}
if (n & 1)
{
#ifdef IBMFLOAT
y0 = (y0 + __EPS/8.0) * 0.25;
#else
y0 *= _sqrt_half;
#endif
n += 1;
}
n /= 2;
......@@ -435,14 +318,7 @@ double _tancot(double x, int iflag)
n = (int) ((2.0 * y + _pi_2) / _pi_);
if (x < 0) n = - n;
xn = (double) n;
#ifdef IBMFLOAT
{ double x1 = (double)(int)x;
double x2 = x - x1;
f = ((x1 - xn*1.57080078125) + x2) + xn*4.454455103380768678308e-6;
}
#else
f = (x - xn*1.57080078125) + xn*4.454455103380768678308e-6;
#endif
if (fabs(f) > 1.e-10)
{ g = f * f;
#define _tan_p1 -0.13338350006421960681
......@@ -591,39 +467,6 @@ double pow(double x, double y)
/* The table a1[] contains properly rounded values for 2**(i/16), and */
/* a2[] contains differences between the true values of 2**(i/16) and */
/* the a1[] values for odd i. */
#ifdef IBMFLOAT
const static double a1[17] = {
/* It is painfully important that the following 17 floating point */
/* numbers are read in to yield the quantities shown on the right. */
1.000000000000000000, /* 41100000:00000000 */
0.957603280698573644, /* 40f5257d:152486cc */
0.917004043204671229, /* 40eac0c6:e7dd2439 */
0.878126080186649740, /* 40e0ccde:ec2a94e1 */
0.840896415253714543, /* 40d744fc:cad69d6b */
0.805245165974627155, /* 40ce248c:151f8481 */
0.771105412703970413, /* 40c5672a:115506db */
0.738413072969749659, /* 40bd08a3:9f580c37 */
0.707106781186547531, /* 40b504f3:33f9de65 */
0.677127773468446367, /* 40ad583e:ea42a14b */
0.648419777325504834, /* 40a5fed6:a9b15139 */
0.620928906036742028, /* 409ef532:6091a112 */
0.594603557501360527, /* 409837f0:518db8a9 */
0.569394317378345823, /* 4091c3d3:73ab11c3 */
0.545253866332628830, /* 408b95c1:e3ea8bd7 */
0.522136891213706919, /* 4085aac3:67cc487b */
0.500000000000000000 /* 40800000:00000000 */
};
const static double a2[8] = {
2.4114209503420287e-18,
9.2291566937243078e-19,
-1.5241915231122319e-18,
-3.5421849765286817e-18,
-3.1286215245415074e-18,
-4.4654376565694489e-18,
2.9305146686217562e-18,
1.1260851040933474e-18
};
#else /* IEEE format */
const static double a1[17] = {
/* It is painfully important that the following 17 floating point */
/* numbers are read in to yield the quantities shown on the right. */
......@@ -655,7 +498,6 @@ double pow(double x, double y)
4.4563878092065126e-17,
4.2759448527536718e-17
};
#endif
if (y == 1.0) return x;
if (x <= 0.0)
{ int ny;
......@@ -709,11 +551,7 @@ double pow(double x, double y)
w2 = w2 - w;
/* The following values have been determined experimentally, buth their */
/* values are not very critical. */
#ifdef IBMFLOAT
# define _negative_pow_limit -4160
#else
# define _negative_pow_limit -16352
#endif
if (iw1 < _negative_pow_limit)
{ errno = ERANGE; /* Underflow certain */
return 0.0;
......@@ -738,17 +576,6 @@ double pow(double x, double y)
z = a1[pdash] + a1[pdash]*z;
z = frexp(z, &m);
mdash += m;
#ifdef IBMFLOAT
if (mdash > 0x3f*4)
{ errno = ERANGE;
if (sign) r = -HUGE_VAL;
else r = HUGE_VAL;
}
else if (mdash <= -0x41*4)
{ errno = ERANGE;
r = 0.0;
}
#else
if (mdash >= 0x7ff-0x3fe)
{ errno = ERANGE;
if (sign) r = -HUGE_VAL;
......@@ -758,7 +585,6 @@ double pow(double x, double y)
{ errno = ERANGE;
r = 0.0;
}
#endif
else
{ r = ldexp(z, mdash);
if (sign) r = -r;
......@@ -789,14 +615,74 @@ double atan2(double y, double x)
return y;
}
#undef fabs
double hypot(double x, double y)
{
double p, q, r, s;
/* Use the Moler-Morrison algorithm */
p = fabs(x);
q = fabs(y);
/* Ensure p <= q (putting NaNs in p and Infs in q). p!=p is a
* simple NaN check without the function call overhead of isnan()
* [it has the nicety of not trapping signalling NaNs, which we don't
* need]. If we can avoid calling any functions, we save a lot of
* overhead.
*/
if (isgreater(p,q) || isunordered(p,q) && p!=p)
{
r = p; p = q; q = r;
}
if (p == 0.0 || q == INFINITY) return q;
if (p != p) return p;
for (;;)
{
r = q / p;
r = r * r;
s = r + 4.0;
/* The compiler is capable of optimising multiple comparisons */
if (s == 4.0 || isunordered(s, 4.0)) return p;
r = r / s;
p = p + 2.0 * r * p;
q = q * r;
}
}
double fabs(double x)
/* All over again, in floats */
float hypotf(float x, float y)
{
if (x<0.0) return -x;
else return x;
float p, q, r, s;
p = fabsf(x);
q = fabsf(y);
if (isgreater(p,q) || isunordered(p,q) && p!=p)
{
r = p; p = q; q = r;
}