From bd5969fc876a10b18613302db7087ef3c40f18e1 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 7 Mar 2024 17:28:00 -0500 Subject: lib: Add mlibc Signed-off-by: Ian Moffett --- lib/mlibc/options/ansi/generic/assert-stubs.cpp | 13 + lib/mlibc/options/ansi/generic/complex-stubs.c | 9 + lib/mlibc/options/ansi/generic/complex/cabs.c | 53 + lib/mlibc/options/ansi/generic/complex/cabsf.c | 19 + lib/mlibc/options/ansi/generic/complex/cacos.c | 99 ++ lib/mlibc/options/ansi/generic/complex/cacosf.c | 46 + lib/mlibc/options/ansi/generic/complex/cacosh.c | 93 + lib/mlibc/options/ansi/generic/complex/cacoshf.c | 48 + lib/mlibc/options/ansi/generic/complex/carg.c | 59 + lib/mlibc/options/ansi/generic/complex/cargf.c | 19 + lib/mlibc/options/ansi/generic/complex/casin.c | 165 ++ lib/mlibc/options/ansi/generic/complex/casinf.c | 122 ++ lib/mlibc/options/ansi/generic/complex/casinh.c | 97 ++ lib/mlibc/options/ansi/generic/complex/casinhf.c | 44 + lib/mlibc/options/ansi/generic/complex/catan.c | 130 ++ lib/mlibc/options/ansi/generic/complex/catanf.c | 79 + lib/mlibc/options/ansi/generic/complex/catanh.c | 90 + lib/mlibc/options/ansi/generic/complex/catanhf.c | 44 + lib/mlibc/options/ansi/generic/complex/ccos.c | 81 + lib/mlibc/options/ansi/generic/complex/ccosf.c | 48 + lib/mlibc/options/ansi/generic/complex/ccosh.c | 81 + lib/mlibc/options/ansi/generic/complex/ccoshf.c | 48 + .../options/ansi/generic/complex/cephes_subr.c | 126 ++ .../options/ansi/generic/complex/cephes_subr.h | 9 + .../options/ansi/generic/complex/cephes_subrf.c | 125 ++ .../options/ansi/generic/complex/cephes_subrf.h | 9 + lib/mlibc/options/ansi/generic/complex/cexp.c | 82 + lib/mlibc/options/ansi/generic/complex/cexpf.c | 49 + lib/mlibc/options/ansi/generic/complex/cimag.c | 54 + lib/mlibc/options/ansi/generic/complex/cimagf.c | 21 + lib/mlibc/options/ansi/generic/complex/clog.c | 91 + lib/mlibc/options/ansi/generic/complex/clogf.c | 49 + lib/mlibc/options/ansi/generic/complex/conj.c | 56 + lib/mlibc/options/ansi/generic/complex/conjf.c | 23 + lib/mlibc/options/ansi/generic/complex/cpow.c | 101 ++ lib/mlibc/options/ansi/generic/complex/cpowf.c | 59 + lib/mlibc/options/ansi/generic/complex/cproj.c | 105 ++ lib/mlibc/options/ansi/generic/complex/cprojf.c | 67 + lib/mlibc/options/ansi/generic/complex/creal.c | 54 + lib/mlibc/options/ansi/generic/complex/crealf.c | 21 + lib/mlibc/options/ansi/generic/complex/csin.c | 81 + lib/mlibc/options/ansi/generic/complex/csinf.c | 48 + lib/mlibc/options/ansi/generic/complex/csinh.c | 80 + lib/mlibc/options/ansi/generic/complex/csinhf.c | 48 + lib/mlibc/options/ansi/generic/complex/csqrt.c | 137 ++ lib/mlibc/options/ansi/generic/complex/csqrtf.c | 102 ++ lib/mlibc/options/ansi/generic/complex/ctan.c | 91 + lib/mlibc/options/ansi/generic/complex/ctanf.c | 58 + lib/mlibc/options/ansi/generic/complex/ctanh.c | 83 + lib/mlibc/options/ansi/generic/complex/ctanhf.c | 50 + lib/mlibc/options/ansi/generic/complex/fdlibm.h | 17 + lib/mlibc/options/ansi/generic/ctype-stubs.cpp | 326 ++++ lib/mlibc/options/ansi/generic/environment.cpp | 164 ++ lib/mlibc/options/ansi/generic/errno-stubs.cpp | 12 + lib/mlibc/options/ansi/generic/fenv-stubs.cpp | 43 + lib/mlibc/options/ansi/generic/file-io.cpp | 745 ++++++++ lib/mlibc/options/ansi/generic/inttypes-stubs.cpp | 100 ++ lib/mlibc/options/ansi/generic/locale-stubs.cpp | 195 +++ .../options/ansi/generic/math-stubs.ignored-cpp | 1831 ++++++++++++++++++++ lib/mlibc/options/ansi/generic/signal-stubs.cpp | 44 + lib/mlibc/options/ansi/generic/stdio-stubs.cpp | 1270 ++++++++++++++ lib/mlibc/options/ansi/generic/stdlib-stubs.cpp | 511 ++++++ lib/mlibc/options/ansi/generic/string-stubs.cpp | 542 ++++++ lib/mlibc/options/ansi/generic/threads.cpp | 97 ++ lib/mlibc/options/ansi/generic/time-stubs.cpp | 729 ++++++++ lib/mlibc/options/ansi/generic/uchar.cpp | 23 + lib/mlibc/options/ansi/generic/wchar-stubs.cpp | 783 +++++++++ lib/mlibc/options/ansi/generic/wctype.cpp | 9 + 68 files changed, 10807 insertions(+) create mode 100644 lib/mlibc/options/ansi/generic/assert-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/complex-stubs.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cabs.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cabsf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cacos.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cacosf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cacosh.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cacoshf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/carg.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cargf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/casin.c create mode 100644 lib/mlibc/options/ansi/generic/complex/casinf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/casinh.c create mode 100644 lib/mlibc/options/ansi/generic/complex/casinhf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/catan.c create mode 100644 lib/mlibc/options/ansi/generic/complex/catanf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/catanh.c create mode 100644 lib/mlibc/options/ansi/generic/complex/catanhf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ccos.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ccosf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ccosh.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ccoshf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cephes_subr.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cephes_subr.h create mode 100644 lib/mlibc/options/ansi/generic/complex/cephes_subrf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cephes_subrf.h create mode 100644 lib/mlibc/options/ansi/generic/complex/cexp.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cexpf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cimag.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cimagf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/clog.c create mode 100644 lib/mlibc/options/ansi/generic/complex/clogf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/conj.c create mode 100644 lib/mlibc/options/ansi/generic/complex/conjf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cpow.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cpowf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cproj.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cprojf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/creal.c create mode 100644 lib/mlibc/options/ansi/generic/complex/crealf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/csin.c create mode 100644 lib/mlibc/options/ansi/generic/complex/csinf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/csinh.c create mode 100644 lib/mlibc/options/ansi/generic/complex/csinhf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/csqrt.c create mode 100644 lib/mlibc/options/ansi/generic/complex/csqrtf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ctan.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ctanf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ctanh.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ctanhf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/fdlibm.h create mode 100644 lib/mlibc/options/ansi/generic/ctype-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/environment.cpp create mode 100644 lib/mlibc/options/ansi/generic/errno-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/fenv-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/file-io.cpp create mode 100644 lib/mlibc/options/ansi/generic/inttypes-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/locale-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/math-stubs.ignored-cpp create mode 100644 lib/mlibc/options/ansi/generic/signal-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/stdio-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/stdlib-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/string-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/threads.cpp create mode 100644 lib/mlibc/options/ansi/generic/time-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/uchar.cpp create mode 100644 lib/mlibc/options/ansi/generic/wchar-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/wctype.cpp (limited to 'lib/mlibc/options/ansi/generic') diff --git a/lib/mlibc/options/ansi/generic/assert-stubs.cpp b/lib/mlibc/options/ansi/generic/assert-stubs.cpp new file mode 100644 index 0000000..6ebb6ed --- /dev/null +++ b/lib/mlibc/options/ansi/generic/assert-stubs.cpp @@ -0,0 +1,13 @@ + +#include +#include +#include + +#include + +[[gnu::noreturn]] void __assert_fail(const char *assertion, const char *file, unsigned int line, + const char *function) { + fprintf(stderr, "In function %s, file %s:%d: Assertion '%s' failed!\n", + function, file, line, assertion); + abort(); +} diff --git a/lib/mlibc/options/ansi/generic/complex-stubs.c b/lib/mlibc/options/ansi/generic/complex-stubs.c new file mode 100644 index 0000000..069626b --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex-stubs.c @@ -0,0 +1,9 @@ +#include + +long double cimagl(long double complex z) { + return __imag__(z); +} + +long double creall(long double complex z) { + return __real__(z); +} diff --git a/lib/mlibc/options/ansi/generic/complex/cabs.c b/lib/mlibc/options/ansi/generic/complex/cabs.c new file mode 100644 index 0000000..2750fab --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cabs.c @@ -0,0 +1,53 @@ +/* $NetBSD: cabs.c,v 1.1 2007/08/20 16:01:30 drochner Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex absolute-value + +INDEX + cabs +INDEX + cabsf + +ANSI_SYNOPSIS + #include + double cabs(double complex <[z]>); + float cabsf(float complex <[z]>); + + +DESCRIPTION + These functions compute compute the complex absolute value + (also called norm, modulus, or magnitude) of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cabs functions return the complex absolute value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double +cabs(double complex z) +{ + + return hypot( creal(z), cimag(z) ); +} diff --git a/lib/mlibc/options/ansi/generic/complex/cabsf.c b/lib/mlibc/options/ansi/generic/complex/cabsf.c new file mode 100644 index 0000000..635e23e --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cabsf.c @@ -0,0 +1,19 @@ +/* $NetBSD: cabsf.c,v 1.1 2007/08/20 16:01:30 drochner Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float +cabsf(float complex z) +{ + + return hypotf( crealf(z), cimagf(z) ); +} diff --git a/lib/mlibc/options/ansi/generic/complex/cacos.c b/lib/mlibc/options/ansi/generic/complex/cacos.c new file mode 100644 index 0000000..86e1198 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cacos.c @@ -0,0 +1,99 @@ +/* $NetBSD: cacos.c,v 1.1 2007/08/20 16:01:30 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc cosine + +INDEX + cacos +INDEX + cacosf + +ANSI_SYNOPSIS + #include + double complex cacos(double complex <[z]>); + float complex cacosf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex arc cosine of <[z]>, + with branch cuts outside the interval [-1, +1] along the real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc cosine value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [0, pi] along the real axis. + @end ifnottex + @tex + These functions return the complex arc cosine value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [<<0>>, $\pi$] along the real axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include +#include + +double complex +cacos(double complex z) +{ + double complex w; + + /* FIXME: The original NetBSD code results in an ICE when trying to + build this function on ARM/Thumb using gcc 4.5.1. For now we use + a hopefully temporary workaround. */ +#if 0 + w = casin(z); + w = (M_PI_2 - creal(w)) - cimag(w) * I; +#else + double complex tmp0, tmp1; + + tmp0 = casin(z); + tmp1 = M_PI_2 - creal(tmp0); + w = tmp1 - (cimag(tmp0) * I); +#endif + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cacosf.c b/lib/mlibc/options/ansi/generic/complex/cacosf.c new file mode 100644 index 0000000..3874dd5 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cacosf.c @@ -0,0 +1,46 @@ +/* $NetBSD: cacosf.c,v 1.1 2007/08/20 16:01:30 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +cacosf(float complex z) +{ + float complex w; + + w = casinf(z); + w = ((float)M_PI_2 - crealf(w)) - cimagf(w) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cacosh.c b/lib/mlibc/options/ansi/generic/complex/cacosh.c new file mode 100644 index 0000000..3d42c40 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cacosh.c @@ -0,0 +1,93 @@ +/* $NetBSD: cacosh.c,v 1.2 2009/08/03 19:41:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc hyperbolic cosine + +INDEX + cacosh +INDEX + cacoshf + +ANSI_SYNOPSIS + #include + double complex cacosh(double complex <[z]>); + float complex cacoshf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex arc hyperbolic cosine of <[z]>, + with a branch cut at values less than 1 along the real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc hyperbolic cosine value, + in the range of a half-strip of non-negative values along the + real axis and in the interval [-i * pi, +i * pi] along the + imaginary axis. + @end ifnottex + @tex + These functions return the complex arc hyperbolic cosine value, + in the range of a half-strip of non-negative values along the + real axis and in the interval [$-i\pi$, $+i\pi$] along the + imaginary axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include + +double complex +cacosh(double complex z) +{ + double complex w; + +#if 0 /* does not give the principal value */ + w = I * cacos(z); +#else + w = clog(z + csqrt(z + 1) * csqrt(z - 1)); +#endif + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cacoshf.c b/lib/mlibc/options/ansi/generic/complex/cacoshf.c new file mode 100644 index 0000000..41a557a --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cacoshf.c @@ -0,0 +1,48 @@ +/* $NetBSD: cacoshf.c,v 1.2 2009/08/03 19:41:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +float complex +cacoshf(float complex z) +{ + float complex w; + +#if 0 /* does not give the principal value */ + w = I * cacosf(z); +#else + w = clogf(z + csqrtf(z + 1) * csqrtf(z - 1)); +#endif + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/carg.c b/lib/mlibc/options/ansi/generic/complex/carg.c new file mode 100644 index 0000000..0447420 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/carg.c @@ -0,0 +1,59 @@ +/* $NetBSD: carg.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---argument (phase angle) + +INDEX + carg +INDEX + cargf + +ANSI_SYNOPSIS + #include + double carg(double complex <[z]>); + float cargf(float complex <[z]>); + + +DESCRIPTION + These functions compute the argument (also called phase angle) + of <[z]>, with a branch cut along the negative real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + The carg functions return the value of the argument in the + interval [-pi, +pi] + @end ifnottex + @tex + The carg functions return the value of the argument in the + interval [$-\pi$, $+\pi$] + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include +#include + +double +carg(double complex z) +{ + + return atan2( cimag(z) , creal(z) ); +} diff --git a/lib/mlibc/options/ansi/generic/complex/cargf.c b/lib/mlibc/options/ansi/generic/complex/cargf.c new file mode 100644 index 0000000..1683d21 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cargf.c @@ -0,0 +1,19 @@ +/* $NetBSD: cargf.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float +cargf(float complex z) +{ + + return atan2f( cimagf(z), crealf(z) ); +} diff --git a/lib/mlibc/options/ansi/generic/complex/casin.c b/lib/mlibc/options/ansi/generic/complex/casin.c new file mode 100644 index 0000000..5019fd8 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/casin.c @@ -0,0 +1,165 @@ +/* $NetBSD: casin.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc sine + +INDEX + casin +INDEX + casinf + +ANSI_SYNOPSIS + #include + double complex casin(double complex <[z]>); + float complex casinf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex arc sine of <[z]>, + with branch cuts outside the interval [-1, +1] along the real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc sine value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [-pi/2, +pi/2] along the real axis. + @end ifnottex + @tex + These functions return the complex arc sine value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [$-\pi/2$, $+\pi/2$] along the real axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +#ifdef __weak_alias +__weak_alias(casin, _casin) +#endif + +double complex +casin(double complex z) +{ + double complex w; + double complex ca, ct, zz, z2; + double x, y; + + x = creal(z); + y = cimag(z); + +#if 0 /* MD: test is incorrect, casin(>1) is defined */ + if (y == 0.0) { + if (fabs(x) > 1.0) { + w = M_PI_2 + 0.0 * I; +#if 0 + mtherr ("casin", DOMAIN); +#endif + } else { + w = asin(x) + 0.0 * I; + } + return w; + } +#endif + +/* Power series expansion */ +/* +b = cabs(z); +if( b < 0.125 ) +{ +z2.r = (x - y) * (x + y); +z2.i = 2.0 * x * y; + +cn = 1.0; +n = 1.0; +ca.r = x; +ca.i = y; +sum.r = x; +sum.i = y; +do + { + ct.r = z2.r * ca.r - z2.i * ca.i; + ct.i = z2.r * ca.i + z2.i * ca.r; + ca.r = ct.r; + ca.i = ct.i; + + cn *= n; + n += 1.0; + cn /= n; + n += 1.0; + b = cn/n; + + ct.r *= b; + ct.i *= b; + sum.r += ct.r; + sum.i += ct.i; + b = fabs(ct.r) + fabs(ct.i); + } +while( b > MACHEP ); +w->r = sum.r; +w->i = sum.i; +return; +} +*/ + + + ca = x + y * I; + ct = ca * I; + /* sqrt( 1 - z*z) */ + /* cmul( &ca, &ca, &zz ) */ + /*x * x - y * y */ + zz = (x - y) * (x + y) + (2.0 * x * y) * I; + + zz = 1.0 - creal(zz) - cimag(zz) * I; + z2 = csqrt(zz); + + zz = ct + z2; + zz = clog(zz); + /* multiply by 1/i = -i */ + w = zz * (-1.0 * I); + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/casinf.c b/lib/mlibc/options/ansi/generic/complex/casinf.c new file mode 100644 index 0000000..9a9f759 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/casinf.c @@ -0,0 +1,122 @@ +/* $NetBSD: casinf.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +#ifdef __weak_alias +__weak_alias(casinf, _casinf) +#endif + +float complex +casinf(float complex z) +{ + float complex w; + float complex ca, ct, zz, z2; + float x, y; + + x = crealf(z); + y = cimagf(z); + +#if 0 /* MD: test is incorrect, casin(>1) is defined */ + if (y == 0.0f) { + if (fabsf(x) > 1.0) { + w = M_PI_2 + 0.0f * I; +#if 0 + mtherr ("casin", DOMAIN); +#endif + } else { + w = asinf(x) + 0.0f * I; + } + return w; + } +#endif + +/* Power series expansion */ +/* +b = cabsf(z); +if( b < 0.125 ) +{ +z2.r = (x - y) * (x + y); +z2.i = 2.0 * x * y; + +cn = 1.0; +n = 1.0; +ca.r = x; +ca.i = y; +sum.r = x; +sum.i = y; +do + { + ct.r = z2.r * ca.r - z2.i * ca.i; + ct.i = z2.r * ca.i + z2.i * ca.r; + ca.r = ct.r; + ca.i = ct.i; + + cn *= n; + n += 1.0; + cn /= n; + n += 1.0; + b = cn/n; + + ct.r *= b; + ct.i *= b; + sum.r += ct.r; + sum.i += ct.i; + b = fabsf(ct.r) + fabsf(ct.i); + } +while( b > MACHEP ); +w->r = sum.r; +w->i = sum.i; +return; +} +*/ + + + ca = x + y * I; + ct = ca * I; + /* sqrt( 1 - z*z) */ + /* cmul( &ca, &ca, &zz ) */ + /*x * x - y * y */ + zz = (x - y) * (x + y) + (2.0f * x * y) * I; + + zz = 1.0f - crealf(zz) - cimagf(zz) * I; + z2 = csqrtf(zz); + + zz = ct + z2; + zz = clogf(zz); + /* multiply by 1/i = -i */ + w = zz * (-1.0f * I); + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/casinh.c b/lib/mlibc/options/ansi/generic/complex/casinh.c new file mode 100644 index 0000000..16238a6 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/casinh.c @@ -0,0 +1,97 @@ +/* $NetBSD: casinh.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc hyperbolic sine + +INDEX + casinh +INDEX + casinhf + +ANSI_SYNOPSIS + #include + double complex casinh(double complex <[z]>); + float complex casinhf(float complex <[z]>); + + +DESCRIPTION + @ifnottex + These functions compute the complex arc hyperbolic sine of <[z]>, + with branch cuts outside the interval [-i, +i] along the + imaginary axis. + @end ifnottex + @tex + These functions compute the complex arc hyperbolic sine of <[z]>, + with branch cuts outside the interval [$-i$, $+i$] along the + imaginary axis. + @end tex + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc hyperbolic sine value, + in the range of a strip mathematically unbounded along the + real axis and in the interval [-i*p/2, +i*p/2] along the + imaginary axis. + @end ifnottex + @tex + These functions return the complex arc hyperbolic sine value, + in the range of a strip mathematically unbounded along the + real axis and in the interval [$-i\pi/2$, $+i\pi/2$] along the + imaginary axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include + +double complex +casinh(double complex z) +{ + double complex w; + + w = -1.0 * I * casin(z * I); + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/casinhf.c b/lib/mlibc/options/ansi/generic/complex/casinhf.c new file mode 100644 index 0000000..0db55a0 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/casinhf.c @@ -0,0 +1,44 @@ +/* $NetBSD: casinhf.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +float complex +casinhf(float complex z) +{ + float complex w; + + w = -1.0f * I * casinf(z * I); + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/catan.c b/lib/mlibc/options/ansi/generic/complex/catan.c new file mode 100644 index 0000000..0cf4739 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/catan.c @@ -0,0 +1,130 @@ +/* $NetBSD: catan.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc tangent + +INDEX + catan +INDEX + catanf + +ANSI_SYNOPSIS + #include + double complex catan(double complex <[z]>); + float complex catanf(float complex <[z]>); + + +DESCRIPTION + @ifnottex + These functions compute the complex arc tangent of <[z]>, + with branch cuts outside the interval [-i, +i] along the + imaginary axis. + @end ifnottex + @tex + These functions compute the complex arc tangent of <[z]>, + with branch cuts outside the interval [$-i$, $+i$] along the + imaginary axis. + @end tex + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc tangent value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [-pi/2, +pi/2] along the real axis. + @end ifnottex + @tex + These functions return the complex arc tangent, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [$-\pi/2$, $+\pi/2$] along the real axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include +#include "cephes_subr.h" + +#ifdef __weak_alias +__weak_alias(catan, _catan) +#endif + +double complex +catan(double complex z) +{ + double complex w; + double a, t, x, x2, y; + + x = creal(z); + y = cimag(z); + + if ((x == 0.0) && (y > 1.0)) + goto ovrf; + + x2 = x * x; + a = 1.0 - x2 - (y * y); + if (a == 0.0) + goto ovrf; + + t = 0.5 * atan2(2.0 * x, a); + w = __mlibc_redupi(t); + + t = y - 1.0; + a = x2 + (t * t); + if (a == 0.0) + goto ovrf; + + t = y + 1.0; + a = (x2 + (t * t))/a; + w = w + (0.25 * log(a)) * I; + return w; + +ovrf: +#if 0 + mtherr ("catan", OVERFLOW); +#endif + w = HUGE_VAL + HUGE_VAL * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/catanf.c b/lib/mlibc/options/ansi/generic/complex/catanf.c new file mode 100644 index 0000000..33c47df --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/catanf.c @@ -0,0 +1,79 @@ +/* $NetBSD: catanf.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +#ifdef __weak_alias +__weak_alias(catanf, _catanf) +#endif + +float complex +catanf(float complex z) +{ + float complex w; + float a, t, x, x2, y; + + x = crealf(z); + y = cimagf(z); + + if ((x == 0.0f) && (y > 1.0f)) + goto ovrf; + + x2 = x * x; + a = 1.0f - x2 - (y * y); + if (a == 0.0f) + goto ovrf; + + t = 0.5f * atan2f(2.0f * x, a); + w = __mlibc_redupif(t); + + t = y - 1.0f; + a = x2 + (t * t); + if (a == 0.0f) + goto ovrf; + + t = y + 1.0f; + a = (x2 + (t * t))/a; + w = w + (0.25f * logf(a)) * I; + return w; + +ovrf: +#if 0 + mtherr ("catan", OVERFLOW); +#endif + w = HUGE_VALF + HUGE_VALF * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/catanh.c b/lib/mlibc/options/ansi/generic/complex/catanh.c new file mode 100644 index 0000000..2b9ef9e --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/catanh.c @@ -0,0 +1,90 @@ +/* $NetBSD: catanh.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc hyperbolic tangent + +INDEX + catanh +INDEX + catanhf + +ANSI_SYNOPSIS + #include + double complex catanh(double complex <[z]>); + float complex catanhf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex arc hyperbolic tan of <[z]>, + with branch cuts outside the interval [-1, +1] along the + real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc hyperbolic tangent value, + in the range of a strip mathematically unbounded along the + real axis and in the interval [-i*p/2, +i*p/2] along the + imaginary axis. + @end ifnottex + @tex + These functions return the complex arc hyperbolic tangent value, + in the range of a strip mathematically unbounded along the + real axis and in the interval [$-i\pi/2$, $+i\pi/2$] along the + imaginary axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include + +double complex +catanh(double complex z) +{ + double complex w; + + w = -1.0 * I * catan(z * I); + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/catanhf.c b/lib/mlibc/options/ansi/generic/complex/catanhf.c new file mode 100644 index 0000000..fe6127a --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/catanhf.c @@ -0,0 +1,44 @@ +/* $NetBSD: catanhf.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +float complex +catanhf(float complex z) +{ + float complex w; + + w = -1.0f * I * catanf(z * I); + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ccos.c b/lib/mlibc/options/ansi/generic/complex/ccos.c new file mode 100644 index 0000000..ebb52bf --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ccos.c @@ -0,0 +1,81 @@ +/* $NetBSD: ccos.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex cosine + +INDEX + ccos +INDEX + ccosf + +ANSI_SYNOPSIS + #include + double complex ccos(double complex <[z]>); + float complex ccosf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex cosine of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex cosine value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include +#include "cephes_subr.h" + +double complex +ccos(double complex z) +{ + double complex w; + double ch, sh; + + __mlibc_cchsh(cimag(z), &ch, &sh); + w = cos(creal(z)) * ch - (sin(creal(z)) * sh) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ccosf.c b/lib/mlibc/options/ansi/generic/complex/ccosf.c new file mode 100644 index 0000000..db7fab3 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ccosf.c @@ -0,0 +1,48 @@ +/* $NetBSD: ccosf.c,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +float complex +ccosf(float complex z) +{ + float complex w; + float ch, sh; + + __mlibc_cchshf(cimagf(z), &ch, &sh); + w = cosf(crealf(z)) * ch - (sinf(crealf(z)) * sh) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ccosh.c b/lib/mlibc/options/ansi/generic/complex/ccosh.c new file mode 100644 index 0000000..223a5ed --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ccosh.c @@ -0,0 +1,81 @@ +/* $NetBSD: ccosh.c,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex hyperbolic cosine + +INDEX + ccosh +INDEX + ccoshf + +ANSI_SYNOPSIS + #include + double complex ccosh(double complex <[z]>); + float complex ccoshf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex hyperbolic cosine of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex hyperbolic cosine value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +ccosh(double complex z) +{ + double complex w; + double x, y; + + x = creal(z); + y = cimag(z); + w = cosh(x) * cos(y) + (sinh(x) * sin(y)) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ccoshf.c b/lib/mlibc/options/ansi/generic/complex/ccoshf.c new file mode 100644 index 0000000..af11353 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ccoshf.c @@ -0,0 +1,48 @@ +/* $NetBSD: ccoshf.c,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +ccoshf(float complex z) +{ + float complex w; + float x, y; + + x = crealf(z); + y = cimagf(z); + w = coshf(x) * cosf(y) + (sinhf(x) * sinf(y)) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cephes_subr.c b/lib/mlibc/options/ansi/generic/complex/cephes_subr.c new file mode 100644 index 0000000..fe08b42 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cephes_subr.c @@ -0,0 +1,126 @@ +/* $NetBSD: cephes_subr.c,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subr.h" + +/* calculate cosh and sinh */ + +void +__mlibc_cchsh(double x, double *c, double *s) +{ + double e, ei; + + if (fabs(x) <= 0.5) { + *c = cosh(x); + *s = sinh(x); + } else { + e = exp(x); + ei = 0.5 / e; + e = 0.5 * e; + *s = e - ei; + *c = e + ei; + } +} + +/* Program to subtract nearest integer multiple of PI */ + +/* extended precision value of PI: */ +static const double DP1 = 3.14159265160560607910E0; +static const double DP2 = 1.98418714791870343106E-9; +static const double DP3 = 1.14423774522196636802E-17; +#define MACHEP 1.1e-16 + +double +__mlibc_redupi(double x) +{ + double t; + long i; + + t = x / M_PI; + if (t >= 0.0) + t += 0.5; + else + t -= 0.5; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +/* Taylor series expansion for cosh(2y) - cos(2x) */ + +double +__mlibc_ctans(double complex z) +{ + double f, x, x2, y, y2, rn, t; + double d; + + x = fabs(2.0 * creal(z)); + y = fabs(2.0 * cimag(z)); + + x = __mlibc_redupi(x); + + x = x * x; + y = y * y; + x2 = 1.0; + y2 = 1.0; + f = 1.0; + rn = 0.0; + d = 0.0; + do { + rn += 1.0; + f *= rn; + rn += 1.0; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 + x2; + t /= f; + d += t; + + rn += 1.0; + f *= rn; + rn += 1.0; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 - x2; + t /= f; + d += t; + } while (fabs(t/d) > MACHEP); + return d; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cephes_subr.h b/lib/mlibc/options/ansi/generic/complex/cephes_subr.h new file mode 100644 index 0000000..719075e --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cephes_subr.h @@ -0,0 +1,9 @@ +/* $NetBSD: cephes_subr.h,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +#ifndef __MLIBC_ABI_ONLY + +void __mlibc_cchsh(double, double *, double *); +double __mlibc_redupi(double); +double __mlibc_ctans(double complex); + +#endif /* !__MLIBC_ABI_ONLY */ diff --git a/lib/mlibc/options/ansi/generic/complex/cephes_subrf.c b/lib/mlibc/options/ansi/generic/complex/cephes_subrf.c new file mode 100644 index 0000000..1ce18e5 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cephes_subrf.c @@ -0,0 +1,125 @@ +/* $NetBSD: cephes_subrf.c,v 1.1 2007/08/20 16:01:34 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +/* calculate cosh and sinh */ + +void +__mlibc_cchshf(float x, float *c, float *s) +{ + float e, ei; + + if (fabsf(x) <= 0.5f) { + *c = coshf(x); + *s = sinhf(x); + } else { + e = expf(x); + ei = 0.5f / e; + e = 0.5f * e; + *s = e - ei; + *c = e + ei; + } +} + +/* Program to subtract nearest integer multiple of PI */ + +/* extended precision value of PI: */ +static const double DP1 = 3.140625; +static const double DP2 = 9.67502593994140625E-4; +static const double DP3 = 1.509957990978376432E-7; +#define MACHEPF 3.0e-8 + +float +__mlibc_redupif(float x) +{ + float t; + long i; + + t = x / (float)M_PI; + if (t >= 0.0f) + t += 0.5f; + else + t -= 0.5f; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +/* Taylor series expansion for cosh(2y) - cos(2x) */ + +float +__mlibc_ctansf(float complex z) +{ + float f, x, x2, y, y2, rn, t, d; + + x = fabsf(2.0f * crealf(z)); + y = fabsf(2.0f * cimagf(z)); + + x = __mlibc_redupif(x); + + x = x * x; + y = y * y; + x2 = 1.0f; + y2 = 1.0f; + f = 1.0f; + rn = 0.0f; + d = 0.0f; + do { + rn += 1.0f; + f *= rn; + rn += 1.0f; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 + x2; + t /= f; + d += t; + + rn += 1.0f; + f *= rn; + rn += 1.0f; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 - x2; + t /= f; + d += t; + } while (fabsf(t/d) > MACHEPF); + return d; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cephes_subrf.h b/lib/mlibc/options/ansi/generic/complex/cephes_subrf.h new file mode 100644 index 0000000..84cdd82 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cephes_subrf.h @@ -0,0 +1,9 @@ +/* $NetBSD: cephes_subrf.h,v 1.1 2007/08/20 16:01:34 drochner Exp $ */ + +#ifndef __MLIBC_ABI_ONLY + +void __mlibc_cchshf(float, float *, float *); +float __mlibc_redupif(float); +float __mlibc_ctansf(float complex); + +#endif /* !__MLIBC_ABI_ONLY */ diff --git a/lib/mlibc/options/ansi/generic/complex/cexp.c b/lib/mlibc/options/ansi/generic/complex/cexp.c new file mode 100644 index 0000000..b9a3fd0 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cexp.c @@ -0,0 +1,82 @@ +/* $NetBSD: cexp.c,v 1.1 2007/08/20 16:01:34 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex base-e exponential + +INDEX + cexp +INDEX + cexpf + +ANSI_SYNOPSIS + #include + double complex cexp(double complex <[z]>); + float complex cexpf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex base-<[e]> exponential of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cexp functions return the complex base-<[e]> exponential value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +cexp(double complex z) +{ + double complex w; + double r, x, y; + + x = creal(z); + y = cimag(z); + r = exp(x); + w = r * cos(y) + r * sin(y) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cexpf.c b/lib/mlibc/options/ansi/generic/complex/cexpf.c new file mode 100644 index 0000000..07fab1f --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cexpf.c @@ -0,0 +1,49 @@ +/* $NetBSD: cexpf.c,v 1.1 2007/08/20 16:01:34 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +cexpf(float complex z) +{ + float complex w; + float r, x, y; + + x = crealf(z); + y = cimagf(z); + r = expf(x); + w = r * cosf(y) + r * sinf(y) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cimag.c b/lib/mlibc/options/ansi/generic/complex/cimag.c new file mode 100644 index 0000000..24619f0 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cimag.c @@ -0,0 +1,54 @@ +/* $NetBSD: cimag.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---imaginary part + +INDEX + cimag +INDEX + cimagf + +ANSI_SYNOPSIS + #include + double cimag(double complex <[z]>); + float cimagf(float complex <[z]>); + + +DESCRIPTION + These functions compute the imaginary part of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cimag functions return the imaginary part value (as a real). + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include + +#include "fdlibm.h" + +double +cimag(double complex z) +{ + double_complex w = { .z = z }; + + return (IMAG_PART(w)); +} diff --git a/lib/mlibc/options/ansi/generic/complex/cimagf.c b/lib/mlibc/options/ansi/generic/complex/cimagf.c new file mode 100644 index 0000000..28ed81c --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cimagf.c @@ -0,0 +1,21 @@ +/* $NetBSD: cimagf.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +#include "fdlibm.h" + +float +cimagf(float complex z) +{ + float_complex w = { .z = z }; + + return (IMAG_PART(w)); +} diff --git a/lib/mlibc/options/ansi/generic/complex/clog.c b/lib/mlibc/options/ansi/generic/complex/clog.c new file mode 100644 index 0000000..f7ad3d2 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/clog.c @@ -0,0 +1,91 @@ +/* $NetBSD: clog.c,v 1.1 2007/08/20 16:01:35 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex base-e logarithm + +INDEX + clog +INDEX + clogf + +ANSI_SYNOPSIS + #include + double complex clog(double complex <[z]>); + float complex clogf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex natural (base-<[e]>) logarithm + of <[z]>, with a branch cut along the negative real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + The clog functions return the complex natural logarithm value, in + the range of a strip mathematically unbounded along the real axis + and in the interval [-i*pi , +i*pi] along the imaginary axis. + @end ifnottex + @tex + The clog functions return the complex natural logarithm value, in + the range of a strip mathematically unbounded along the real axis + and in the interval [$-i\pi$, $+i\pi$] along the imaginary axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include +#include + +double complex +clog(double complex z) +{ + double complex w; + double p, rr; + + rr = cabs(z); + p = log(rr); + rr = atan2(cimag(z), creal(z)); + w = p + rr * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/clogf.c b/lib/mlibc/options/ansi/generic/complex/clogf.c new file mode 100644 index 0000000..078cea5 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/clogf.c @@ -0,0 +1,49 @@ +/* $NetBSD: clogf.c,v 1.1 2007/08/20 16:01:35 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +clogf(float complex z) +{ + float complex w; + float p, rr; + + rr = cabsf(z); + p = logf(rr); + rr = atan2f(cimagf(z), crealf(z)); + w = p + rr * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/conj.c b/lib/mlibc/options/ansi/generic/complex/conj.c new file mode 100644 index 0000000..a761b5a --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/conj.c @@ -0,0 +1,56 @@ +/* $NetBSD: conj.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex conjugate + +INDEX + conj +INDEX + conjf + +ANSI_SYNOPSIS + #include + double complex conj(double complex <[z]>); + float complex conjf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex conjugate of <[z]>, + by reversing the sign of its imaginary part. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The conj functions return the complex conjugate value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include + +#include "fdlibm.h" + +double complex +conj(double complex z) +{ + double_complex w = { .z = z }; + + IMAG_PART(w) = -IMAG_PART(w); + + return (w.z); +} diff --git a/lib/mlibc/options/ansi/generic/complex/conjf.c b/lib/mlibc/options/ansi/generic/complex/conjf.c new file mode 100644 index 0000000..0ca71ef --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/conjf.c @@ -0,0 +1,23 @@ +/* $NetBSD: conjf.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +#include "fdlibm.h" + +float complex +conjf(float complex z) +{ + float_complex w = { .z = z }; + + IMAG_PART(w) = -IMAG_PART(w); + + return (w.z); +} diff --git a/lib/mlibc/options/ansi/generic/complex/cpow.c b/lib/mlibc/options/ansi/generic/complex/cpow.c new file mode 100644 index 0000000..b60f7be --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cpow.c @@ -0,0 +1,101 @@ +/* $NetBSD: cpow.c,v 1.1 2007/08/20 16:01:35 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex power + +INDEX + cpow +INDEX + cpowf + +ANSI_SYNOPSIS + #include + double complex cpow(double complex <[x]>, double complex <[y]>); + float complex cpowf(float complex <[x]>, float complex <[y]>); + + +DESCRIPTION + @ifnottex + The cpow functions compute the complex power function x^y + power, with a branch cut for the first parameter along the + negative real axis. + @end ifnottex + @tex + The cpow functions compute the complex power function $x^y$ + power, with a branch cut for the first parameter along the + negative real axis. + @end tex + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cpow functions return the complex power function value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +cpow(double complex a, double complex z) +{ + double complex w; + double x, y, r, theta, absa, arga; + + x = creal(z); + y = cimag(z); + absa = cabs(a); + if (absa == 0.0) { + return (0.0 + 0.0 * I); + } + arga = carg(a); + r = pow(absa, x); + theta = x * arga; + if (y != 0.0) { + r = r * exp(-y * arga); + theta = theta + y * log(absa); + } + w = r * cos(theta) + (r * sin(theta)) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cpowf.c b/lib/mlibc/options/ansi/generic/complex/cpowf.c new file mode 100644 index 0000000..1e736af --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cpowf.c @@ -0,0 +1,59 @@ +/* $NetBSD: cpowf.c,v 1.1 2007/08/20 16:01:36 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +cpowf(float complex a, float complex z) +{ + float complex w; + float x, y, r, theta, absa, arga; + + x = crealf(z); + y = cimagf(z); + absa = cabsf(a); + if (absa == 0.0f) { + return (0.0f + 0.0f * I); + } + arga = cargf(a); + r = powf(absa, x); + theta = x * arga; + if (y != 0.0f) { + r = r * expf(-y * arga); + theta = theta + y * logf(absa); + } + w = r * cosf(theta) + (r * sinf(theta)) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cproj.c b/lib/mlibc/options/ansi/generic/complex/cproj.c new file mode 100644 index 0000000..0ed50f2 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cproj.c @@ -0,0 +1,105 @@ +/* $NetBSD: cproj.c,v 1.3 2010/09/20 17:51:38 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>--- Riemann sphere projection + +INDEX + cproj +INDEX + cprojf + +ANSI_SYNOPSIS + #include + double complex cproj(double complex <[z]>); + float complex cprojf(float complex <[z]>); + + +DESCRIPTION + These functions compute a projection of <[z]> onto the Riemann + sphere: <[z]> projects to <[z]> except that all complex infinities + (even those with one infinite part and one NaN part) project + to positive infinity on the real axis. If <[z]> has an infinite part, + then <>(<[z]>) is equivalent to + + INFINITY + I * copysign(0.0, cimag(z)) + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cproj functions return the value of the projection onto + the Riemann sphere. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +/*__RCSID("$NetBSD: cproj.c,v 1.3 2010/09/20 17:51:38 christos Exp $"); */ + +#include +#include + +#include "fdlibm.h" + +/* + * cproj(double complex z) + * + * These functions return the value of the projection (not stereographic!) + * onto the Riemann sphere. + * + * z projects to z, except that all complex infinities (even those with one + * infinite part and one NaN part) project to positive infinity on the real axis. + * If z has an infinite part, then cproj(z) shall be equivalent to: + * + * INFINITY + I * copysign(0.0, cimag(z)) + */ +double complex +cproj(double complex z) +{ + double_complex w = { .z = z }; + + if (isinf(creal(z)) || isinf(cimag(z))) { +#ifdef __INFINITY + REAL_PART(w) = __INFINITY; +#else + REAL_PART(w) = INFINITY; +#endif + IMAG_PART(w) = copysign(0.0, cimag(z)); + } + + return (w.z); +} diff --git a/lib/mlibc/options/ansi/generic/complex/cprojf.c b/lib/mlibc/options/ansi/generic/complex/cprojf.c new file mode 100644 index 0000000..76c3d8a --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cprojf.c @@ -0,0 +1,67 @@ +/* $NetBSD: cprojf.c,v 1.3 2010/09/20 17:51:38 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/*__RCSID("$NetBSD: cprojf.c,v 1.3 2010/09/20 17:51:38 christos Exp $"); */ + +#include +#include + +#include "fdlibm.h" + +/* + * cprojf(float complex z) + * + * These functions return the value of the projection (not stereographic!) + * onto the Riemann sphere. + * + * z projects to z, except that all complex infinities (even those with one + * infinite part and one NaN part) project to positive infinity on the real axis. + * If z has an infinite part, then cproj(z) shall be equivalent to: + * + * INFINITY + I * copysign(0.0, cimag(z)) + */ + +float complex +cprojf(float complex z) +{ + float_complex w = { .z = z }; + + if (isinf(crealf(z)) || isinf(cimagf(z))) { +#ifdef __INFINITY + REAL_PART(w) = __INFINITY; +#else + REAL_PART(w) = INFINITY; +#endif + IMAG_PART(w) = copysignf(0.0, cimagf(z)); + } + + return (w.z); +} diff --git a/lib/mlibc/options/ansi/generic/complex/creal.c b/lib/mlibc/options/ansi/generic/complex/creal.c new file mode 100644 index 0000000..07bf96f --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/creal.c @@ -0,0 +1,54 @@ +/* $NetBSD: creal.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---real part + +INDEX + creal +INDEX + crealf + +ANSI_SYNOPSIS + #include + double creal(double complex <[z]>); + float crealf(float complex <[z]>); + + +DESCRIPTION + These functions compute the real part of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The creal functions return the real part value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include + +#include "fdlibm.h" + +double +creal(double complex z) +{ + double_complex w = { .z = z }; + + return (REAL_PART(w)); +} diff --git a/lib/mlibc/options/ansi/generic/complex/crealf.c b/lib/mlibc/options/ansi/generic/complex/crealf.c new file mode 100644 index 0000000..245986d --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/crealf.c @@ -0,0 +1,21 @@ +/* $NetBSD: crealf.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +#include "fdlibm.h" + +float +crealf(float complex z) +{ + float_complex w = { .z = z }; + + return (REAL_PART(w)); +} diff --git a/lib/mlibc/options/ansi/generic/complex/csin.c b/lib/mlibc/options/ansi/generic/complex/csin.c new file mode 100644 index 0000000..b32d057 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/csin.c @@ -0,0 +1,81 @@ +/* $NetBSD: csin.c,v 1.1 2007/08/20 16:01:36 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex sine + +INDEX + csin +INDEX + csinf + +ANSI_SYNOPSIS + #include + double complex csin(double complex <[z]>); + float complex csinf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex sine of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex sine value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include +#include "cephes_subr.h" + +double complex +csin(double complex z) +{ + double complex w; + double ch, sh; + + __mlibc_cchsh(cimag(z), &ch, &sh); + w = sin(creal(z)) * ch + (cos(creal(z)) * sh) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/csinf.c b/lib/mlibc/options/ansi/generic/complex/csinf.c new file mode 100644 index 0000000..0d81d41 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/csinf.c @@ -0,0 +1,48 @@ +/* $NetBSD: csinf.c,v 1.1 2007/08/20 16:01:36 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +float complex +csinf(float complex z) +{ + float complex w; + float ch, sh; + + __mlibc_cchshf(cimagf(z), &ch, &sh); + w = sinf(crealf(z)) * ch + (cosf(crealf(z)) * sh) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/csinh.c b/lib/mlibc/options/ansi/generic/complex/csinh.c new file mode 100644 index 0000000..f117162 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/csinh.c @@ -0,0 +1,80 @@ +/* $NetBSD: csinh.c,v 1.1 2007/08/20 16:01:36 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex hyperbolic sine + +INDEX + csinh +INDEX + csinhf + +ANSI_SYNOPSIS + #include + double complex csinh(double complex <[z]>); + float complex csinhf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex hyperbolic sine of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex hyperbolic sine value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include +#include + +double complex +csinh(double complex z) +{ + double complex w; + double x, y; + + x = creal(z); + y = cimag(z); + w = sinh(x) * cos(y) + (cosh(x) * sin(y)) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/csinhf.c b/lib/mlibc/options/ansi/generic/complex/csinhf.c new file mode 100644 index 0000000..3cd6ba7 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/csinhf.c @@ -0,0 +1,48 @@ +/* $NetBSD: csinhf.c,v 1.1 2007/08/20 16:01:37 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +csinhf(float complex z) +{ + float complex w; + float x, y; + + x = crealf(z); + y = cimagf(z); + w = sinhf(x) * cosf(y) + (coshf(x) * sinf(y)) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/csqrt.c b/lib/mlibc/options/ansi/generic/complex/csqrt.c new file mode 100644 index 0000000..b144b7c --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/csqrt.c @@ -0,0 +1,137 @@ +/* $NetBSD: csqrt.c,v 1.1 2007/08/20 16:01:37 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex square root + +INDEX + csqrt +INDEX + csqrtf + +ANSI_SYNOPSIS + #include + double complex csqrt(double complex <[z]>); + float complex csqrtf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex square root of <[z]>, with + a branch cut along the negative real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The csqrt functions return the complex square root value, in + the range of the right halfplane (including the imaginary axis). + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +csqrt(double complex z) +{ + double complex w; + double x, y, r, t, scale; + + x = creal (z); + y = cimag (z); + + if (y == 0.0) { + if (x == 0.0) { + w = 0.0 + y * I; + } else { + r = fabs(x); + r = sqrt(r); + if (x < 0.0) { + w = 0.0 + r * I; + } else { + w = r + y * I; + } + } + return w; + } + if (x == 0.0) { + r = fabs(y); + r = sqrt(0.5 * r); + if (y > 0) + w = r + r * I; + else + w = r - r * I; + return w; + } + /* Rescale to avoid internal overflow or underflow. */ + if ((fabs(x) > 4.0) || (fabs(y) > 4.0)) { + x *= 0.25; + y *= 0.25; + scale = 2.0; + } else { +#if 1 + x *= 1.8014398509481984e16; /* 2^54 */ + y *= 1.8014398509481984e16; + scale = 7.450580596923828125e-9; /* 2^-27 */ +#else + x *= 4.0; + y *= 4.0; + scale = 0.5; +#endif + } + w = x + y * I; + r = cabs(w); + if (x > 0) { + t = sqrt(0.5 * r + 0.5 * x); + r = scale * fabs((0.5 * y) / t ); + t *= scale; + } else { + r = sqrt(0.5 * r - 0.5 * x); + t = scale * fabs((0.5 * y) / r); + r *= scale; + } + if (y < 0) + w = t - r * I; + else + w = t + r * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/csqrtf.c b/lib/mlibc/options/ansi/generic/complex/csqrtf.c new file mode 100644 index 0000000..13451fa --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/csqrtf.c @@ -0,0 +1,102 @@ +/* $NetBSD: csqrtf.c,v 1.1 2007/08/20 16:01:37 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +csqrtf(float complex z) +{ + float complex w; + float x, y, r, t, scale; + + x = crealf (z); + y = cimagf (z); + + if (y == 0.0f) { + if (x < 0.0f) { + w = 0.0f + sqrtf(-x) * I; + return w; + } else if (x == 0.0f) { + return (0.0f + y * I); + } else { + w = sqrtf(x) + y * I; + return w; + } + } + + if (x == 0.0f) { + r = fabsf(y); + r = sqrtf(0.5f * r); + if (y > 0) + w = r + r * I; + else + w = r - r * I; + return w; + } + + /* Rescale to avoid internal overflow or underflow. */ + if ((fabsf(x) > 4.0f) || (fabsf(y) > 4.0f)) { + x *= 0.25f; + y *= 0.25f; + scale = 2.0f; + } else { +#if 1 + x *= 6.7108864e7f; /* 2^26 */ + y *= 6.7108864e7f; + scale = 1.220703125e-4f; /* 2^-13 */ +#else + x *= 4.0f; + y *= 4.0f; + scale = 0.5f; +#endif + } + w = x + y * I; + r = cabsf(w); + if( x > 0 ) { + t = sqrtf(0.5f * r + 0.5f * x); + r = scale * fabsf((0.5f * y) / t); + t *= scale; + } else { + r = sqrtf(0.5f * r - 0.5f * x); + t = scale * fabsf((0.5f * y) / r); + r *= scale; + } + + if (y < 0) + w = t - r * I; + else + w = t + r * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ctan.c b/lib/mlibc/options/ansi/generic/complex/ctan.c new file mode 100644 index 0000000..600989d --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ctan.c @@ -0,0 +1,91 @@ +/* $NetBSD: ctan.c,v 1.1 2007/08/20 16:01:37 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex tangent + +INDEX + ctan +INDEX + ctanf + +ANSI_SYNOPSIS + #include + double complex ctan(double complex <[z]>); + float complex ctanf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex tangent of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex tangent value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include +#include "cephes_subr.h" + +double complex +ctan(double complex z) +{ + double complex w; + double d; + + d = cos(2.0 * creal(z)) + cosh(2.0 * cimag(z)); + + if (fabs(d) < 0.25) + d = __mlibc_ctans(z); + + if (d == 0.0) { + /* mtherr ("ctan", OVERFLOW); */ + w = HUGE_VAL + HUGE_VAL * I; + return w; + } + + w = sin(2.0 * creal(z)) / d + (sinh(2.0 * cimag(z)) / d) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ctanf.c b/lib/mlibc/options/ansi/generic/complex/ctanf.c new file mode 100644 index 0000000..52360e0 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ctanf.c @@ -0,0 +1,58 @@ +/* $NetBSD: ctanf.c,v 1.1 2007/08/20 16:01:38 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +float complex +ctanf(float complex z) +{ + float complex w; + float d; + + d = cosf(2.0f * crealf(z)) + coshf(2.0f * cimagf(z)); + + if (fabsf(d) < 0.25f) + d = __mlibc_ctansf(z); + + if (d == 0.0f) { + /* mtherr ("ctan", OVERFLOW); */ + w = HUGE_VALF + HUGE_VALF * I; + return w; + } + + w = sinf(2.0f * crealf(z)) / d + (sinhf(2.0f * cimagf(z)) / d) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ctanh.c b/lib/mlibc/options/ansi/generic/complex/ctanh.c new file mode 100644 index 0000000..db27e5b --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ctanh.c @@ -0,0 +1,83 @@ +/* $NetBSD: ctanh.c,v 1.1 2007/08/20 16:01:38 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex hyperbolic tangent + +INDEX + ctanh +INDEX + ctanhf + +ANSI_SYNOPSIS + #include + double complex ctanh(double complex <[z]>); + float complex ctanhf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex hyperbolic tangent of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex hyperbolic tangent value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +ctanh(double complex z) +{ + double complex w; + double x, y, d; + + x = creal(z); + y = cimag(z); + d = cosh(2.0 * x) + cos(2.0 * y); + w = sinh(2.0 * x) / d + (sin(2.0 * y) / d) * I; + + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ctanhf.c b/lib/mlibc/options/ansi/generic/complex/ctanhf.c new file mode 100644 index 0000000..6aaf20f --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ctanhf.c @@ -0,0 +1,50 @@ +/* $NetBSD: ctanhf.c,v 1.1 2007/08/20 16:01:38 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +ctanhf(float complex z) +{ + float complex w; + float x, y, d; + + x = crealf(z); + y = cimagf(z); + d = coshf(2.0f * x) + cosf(2.0f * y); + w = sinhf(2.0f * x) / d + (sinf(2.0f * y) / d) * I; + + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/fdlibm.h b/lib/mlibc/options/ansi/generic/complex/fdlibm.h new file mode 100644 index 0000000..75cdd2a --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/fdlibm.h @@ -0,0 +1,17 @@ +#ifndef __MLIBC_FDLIBM_H +#define __MLIBC_FDLIBM_H + +#define REAL_PART(z) ((z).parts[0]) +#define IMAG_PART(z) ((z).parts[1]) + +typedef union { + float complex z; + float parts[2]; +} float_complex; + +typedef union { + double complex z; + double parts[2]; +} double_complex; + +#endif diff --git a/lib/mlibc/options/ansi/generic/ctype-stubs.cpp b/lib/mlibc/options/ansi/generic/ctype-stubs.cpp new file mode 100644 index 0000000..3ce76e9 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/ctype-stubs.cpp @@ -0,0 +1,326 @@ + +#include +#include + +#include +#include + +// -------------------------------------------------------------------------------------- +// char ctype functions. +// -------------------------------------------------------------------------------------- + +int isalpha(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_alpha(cp); +} + +int isdigit(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_digit(cp); +} + +int isxdigit(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_xdigit(cp); +} + +int isalnum(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_alnum(cp); +} + +int ispunct(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_punct(cp); +} + +int isgraph(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_graph(cp); +} + +int isblank(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_blank(cp); +} + +int isspace(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_space(cp); +} + +int isprint(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_print(cp); +} + +int islower(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_lower(cp); +} + +int isupper(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_upper(cp); +} + +int iscntrl(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::generic_is_control(cp); +} + +int isascii(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return cp <= 0x7F; +} + +// -------------------------------------------------------------------------------------- +// wchar_t ctype functions. +// -------------------------------------------------------------------------------------- + +int iswalpha(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_alpha(cp); +} + +int iswdigit(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_digit(cp); +} + +int iswxdigit(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_xdigit(cp); +} + +int iswalnum(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_alnum(cp); +} + +int iswpunct(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_punct(cp); +} + +int iswgraph(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_graph(cp); +} + +int iswblank(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_blank(cp); +} + +int iswspace(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_space(cp); +} + +int iswprint(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_print(cp); +} + +int iswlower(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_lower(cp); +} + +int iswupper(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_upper(cp); +} + +int iswcntrl(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::generic_is_control(cp); +} + +// -------------------------------------------------------------------------------------- +// iswctype functions. +// -------------------------------------------------------------------------------------- + +namespace { + enum { + ct_null, + ct_alnum, + ct_alpha, + ct_blank, + ct_cntrl, + ct_digit, + ct_graph, + ct_lower, + ct_print, + ct_punct, + ct_space, + ct_upper, + ct_xdigit, + ct_count + }; +} + +wctype_t wctype(const char *cs) { + frg::string_view s{cs}; + if(s == "alnum") return ct_alnum; + if(s == "alpha") return ct_alpha; + if(s == "blank") return ct_blank; + if(s == "cntrl") return ct_cntrl; + if(s == "digit") return ct_digit; + if(s == "graph") return ct_graph; + if(s == "lower") return ct_lower; + if(s == "print") return ct_print; + if(s == "punct") return ct_punct; + if(s == "space") return ct_space; + if(s == "upper") return ct_upper; + if(s == "xdigit") return ct_xdigit; + mlibc::infoLogger() << "mlibc: wctype(\"" << cs << "\") is not supported" << frg::endlog; + return ct_null; +} + +int iswctype(wint_t wc, wctype_t type) { + switch (type) { + case ct_alnum: + return iswalnum(wc); + case ct_alpha: + return iswalpha(wc); + case ct_blank: + return iswblank(wc); + case ct_cntrl: + return iswcntrl(wc); + case ct_digit: + return iswdigit(wc); + case ct_graph: + return iswgraph(wc); + case ct_lower: + return iswlower(wc); + case ct_print: + return iswprint(wc); + case ct_punct: + return iswpunct(wc); + case ct_space: + return iswspace(wc); + case ct_upper: + return iswupper(wc); + case ct_xdigit: + return iswxdigit(wc); + } + return 0; +} + +// -------------------------------------------------------------------------------------- +// char conversion functions. +// -------------------------------------------------------------------------------------- + +int tolower(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return nc; + return mlibc::current_charset()->to_lower(cp); +} + +int toupper(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return nc; + return mlibc::current_charset()->to_upper(cp); +} + +// -------------------------------------------------------------------------------------- +// wchar_t conversion functions. +// -------------------------------------------------------------------------------------- + +wint_t towlower(wint_t wc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(wc, cp); e != mlibc::charcode_error::null) + return wc; + return mlibc::current_charset()->to_lower(cp); +} + +wint_t towupper(wint_t wc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(wc, cp); e != mlibc::charcode_error::null) + return wc; + return mlibc::current_charset()->to_upper(cp); +} + diff --git a/lib/mlibc/options/ansi/generic/environment.cpp b/lib/mlibc/options/ansi/generic/environment.cpp new file mode 100644 index 0000000..5625592 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/environment.cpp @@ -0,0 +1,164 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace { + char *empty_environment[] = { nullptr }; +} + +char **environ = empty_environment; + +namespace { + +size_t find_environ_index(frg::string_view name) { + for(size_t i = 0; environ[i]; i++) { + frg::string_view view{environ[i]}; + size_t s = view.find_first('='); + if(s == size_t(-1)) { + mlibc::infoLogger() << "mlibc: environment string \"" + << frg::escape_fmt{view.data(), view.size()} + << "\" does not contain an equals sign (=)" << frg::endlog; + continue; + } + if(view.sub_string(0, s) == name) + return i; + } + + return -1; +} + +// Environment vector that is mutated by putenv() and setenv(). +// Cannot be global as it is accessed during library initialization. +frg::vector &get_vector() { + static frg::vector vector{getAllocator()}; + return vector; +} + +void update_vector() { + auto &vector = get_vector(); + if(environ == vector.data()) + return; + + // If the environ variable was changed, we copy the environment. + // Note that we must only copy the pointers but not the strings themselves! + vector.clear(); + for(size_t i = 0; environ[i]; i++) + vector.push(environ[i]); + vector.push(nullptr); + + environ = vector.data(); +} + +void assign_variable(frg::string_view name, const char *string, bool overwrite) { + auto &vector = get_vector(); + __ensure(environ == vector.data()); + + auto k = find_environ_index(name); + if(k != size_t(-1)) { + if(overwrite) + vector[k] = const_cast(string); + }else{ + // Last pointer of environ must always be a null delimiter. + __ensure(!vector.back()); + vector.back() = const_cast(string); + vector.push(nullptr); + } + + // push() might have re-allocated the vector. + environ = vector.data(); +} + +void unassign_variable(frg::string_view name) { + auto &vector = get_vector(); + __ensure(environ == vector.data()); + + auto k = find_environ_index(name); + if(k == size_t(-1)) + return; + + // Last pointer of environ must always be a null delimiter. + __ensure(vector.size() >= 2 && !vector.back()); + std::swap(vector[k], vector[vector.size() - 2]); + vector.pop(); + vector.back() = nullptr; + + // pop() might have re-allocated the vector. + environ = vector.data(); +} + +} // anonymous namespace + +char *getenv(const char *name) { + auto k = find_environ_index(name); + if(k == size_t(-1)) + return nullptr; + + frg::string_view view{environ[k]}; + size_t s = view.find_first('='); + __ensure(s != size_t(-1)); + return const_cast(view.data() + s + 1); +} + +namespace mlibc { + +int putenv(char *string) { + frg::string_view view{string}; + size_t s = view.find_first('='); + if(s == size_t(-1)) + __ensure(!"Environment strings need to contain an equals sign"); + + update_vector(); + assign_variable(view.sub_string(0, s), string, true); + return 0; +} + +} // namespace mlibc + +#if __MLIBC_POSIX_OPTION + +int putenv(char *string) { + return mlibc::putenv(string); +} + +int setenv(const char *name, const char *value, int overwrite) { + frg::string_view view{name}; + size_t s = view.find_first('='); + if(s != size_t(-1)) { + mlibc::infoLogger() << "mlibc: environment variable \"" + << frg::escape_fmt{view.data(), view.size()} << "\" contains an equals sign" + << frg::endlog; + errno = EINVAL; + return -1; + } + + // We never free strings here. TODO: Reuse them? + char *string; + __ensure(asprintf(&string, "%s=%s", name, value) > 0); + __ensure(string); + + update_vector(); + assign_variable(name, string, overwrite); + return 0; +} + +int unsetenv(const char *name) { + update_vector(); + unassign_variable(name); + return 0; +} + +int clearenv(void) { + auto vector = get_vector(); + vector.clear(); + update_vector(); + return 0; +} + +#endif /* __MLIBC_POSIX_OPTION */ diff --git a/lib/mlibc/options/ansi/generic/errno-stubs.cpp b/lib/mlibc/options/ansi/generic/errno-stubs.cpp new file mode 100644 index 0000000..8229a9a --- /dev/null +++ b/lib/mlibc/options/ansi/generic/errno-stubs.cpp @@ -0,0 +1,12 @@ +#include + +int __thread __mlibc_errno; + +char *program_invocation_name = nullptr; +char *program_invocation_short_name = nullptr; +extern char *__progname __attribute__((__weak__, __alias__("program_invocation_short_name"))); +extern char *__progname_full __attribute__((__weak__, __alias__("program_invocation_name"))); + +int *__errno_location() { + return &__mlibc_errno; +} diff --git a/lib/mlibc/options/ansi/generic/fenv-stubs.cpp b/lib/mlibc/options/ansi/generic/fenv-stubs.cpp new file mode 100644 index 0000000..7153844 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/fenv-stubs.cpp @@ -0,0 +1,43 @@ + +#include +#include + +// The functions that are not in this file but are defined in the header +// are implemented like musl does in assembly. +extern "C" __attribute__((__visibility__("hidden"))) int __fesetround(int); + +int fegetexceptflag(fexcept_t *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int feholdexcept(fenv_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int fesetexceptflag(const fexcept_t *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int fesetround(int r) { + if (r != FE_TONEAREST +#ifdef FE_DOWNWARD + && r != FE_DOWNWARD +#endif +#ifdef FE_UPWARD + && r != FE_UPWARD +#endif +#ifdef FE_TOWARDZERO + && r != FE_TOWARDZERO +#endif + ) + return -1; + return __fesetround(r); +} + +int feupdateenv(const fenv_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/ansi/generic/file-io.cpp b/lib/mlibc/options/ansi/generic/file-io.cpp new file mode 100644 index 0000000..e59b109 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/file-io.cpp @@ -0,0 +1,745 @@ + +#include +#include +#include +#include +#include +#if __MLIBC_GLIBC_OPTION +#include +#endif + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +// -------------------------------------------------------------------------------------- +// abstract_file implementation. +// -------------------------------------------------------------------------------------- + +namespace { + using file_list = frg::intrusive_list< + abstract_file, + frg::locate_member< + abstract_file, + frg::default_list_hook, + &abstract_file::_list_hook + > + >; + + // Useful when debugging the FILE implementation. + constexpr bool globallyDisableBuffering = false; + + // The maximum number of characters we permit the user to ungetc. + constexpr size_t ungetBufferSize = 8; + + // List of files that will be flushed before exit(). + file_list &global_file_list() { + static frg::eternal list; + return list.get(); + }; +} + +// For pipe-like streams (seek returns ESPIPE), we need to make sure +// that the buffer only ever contains all-dirty or all-clean data. +// Regarding _type and _bufmode: +// As we might construct FILE objects for FDs that are not actually +// open (e.g. for std{in,out,err}), we defer the type determination and cache the result. + +abstract_file::abstract_file(void (*do_dispose)(abstract_file *)) +: _type{stream_type::unknown}, _bufmode{buffer_mode::unknown}, _do_dispose{do_dispose} { + // TODO: For __fwriting to work correctly, set the __io_mode to 1 if the write is write-only. + __buffer_ptr = nullptr; + __unget_ptr = nullptr; + __buffer_size = 4096; + __offset = 0; + __io_offset = 0; + __valid_limit = 0; + __dirty_begin = 0; + __dirty_end = 0; + __io_mode = 0; + __status_bits = 0; + + global_file_list().push_back(this); +} + +abstract_file::~abstract_file() { + if(__dirty_begin != __dirty_end) + mlibc::infoLogger() << "mlibc warning: File is not flushed before destruction" + << frg::endlog; + + if(__buffer_ptr) + getAllocator().free(__buffer_ptr - ungetBufferSize); + + auto it = global_file_list().iterator_to(this); + global_file_list().erase(it); +} + +void abstract_file::dispose() { + if(!_do_dispose) + return; + _do_dispose(this); +} + +// Note that read() and write() are asymmetric: +// While read() can trigger a write-back, write() can never trigger a read-ahead(). +// This peculiarity is reflected in their code. + +int abstract_file::read(char *buffer, size_t max_size, size_t *actual_size) { + __ensure(max_size); + + if(_init_bufmode()) + return -1; + + size_t unget_length = 0; + if (__unget_ptr != __buffer_ptr) { + unget_length = frg::min(max_size, (size_t)(__buffer_ptr - __unget_ptr)); + memcpy(buffer, __unget_ptr, unget_length); + + __unget_ptr += unget_length; + buffer += unget_length; + max_size -= unget_length; + + if (max_size == 0) { + *actual_size = unget_length; + return 0; + } + } + + if(globallyDisableBuffering || _bufmode == buffer_mode::no_buffer) { + size_t io_size; + if(int e = io_read(buffer, max_size, &io_size); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + if(!io_size) + __status_bits |= __MLIBC_EOF_BIT; + *actual_size = io_size + unget_length; + return 0; + } + + // Ensure correct buffer type for pipe-like streams. + // TODO: In order to support pipe-like streams we need to write-back the buffer. + if(__io_mode && __valid_limit) + mlibc::panicLogger() << "mlibc: Cannot read-write to same pipe-like stream" + << frg::endlog; + __io_mode = 0; + + // Clear the buffer, then buffer new data. + if(__offset == __valid_limit) { + // TODO: We only have to write-back/reset if __valid_limit reaches the buffer end. + if(int e = _write_back(); e) + return e; + if(int e = _reset(); e) + return e; + + // Perform a read-ahead. + _ensure_allocation(); + size_t io_size; + if(int e = io_read(__buffer_ptr, __buffer_size, &io_size); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + if(!io_size) { + __status_bits |= __MLIBC_EOF_BIT; + *actual_size = 0; + return 0; + } + + __io_offset = io_size; + __valid_limit = io_size; + } + + // Return data from the buffer. + __ensure(__offset < __valid_limit); + + auto chunk = frg::min(size_t(__valid_limit - __offset), max_size); + memcpy(buffer, __buffer_ptr + __offset, chunk); + __offset += chunk; + + *actual_size = chunk + unget_length; + return 0; +} + +int abstract_file::write(const char *buffer, size_t max_size, size_t *actual_size) { + __ensure(max_size); + + if(_init_bufmode()) + return -1; + if(globallyDisableBuffering || _bufmode == buffer_mode::no_buffer) { + // As we do not buffer, nothing can be dirty. + __ensure(__dirty_begin == __dirty_end); + size_t io_size; + if(int e = io_write(buffer, max_size, &io_size); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + *actual_size = io_size; + return 0; + } + + // Flush the buffer if necessary. + if(__offset == __buffer_size) { + if(int e = _write_back(); e) + return e; + if(int e = _reset(); e) + return e; + } + + // Ensure correct buffer type for pipe-like streams. + // TODO: We could full support pipe-like files + // by ungetc()ing all data before a write happens, + // however, for now we just report an error. + if(!__io_mode && __valid_limit) // TODO: Only check this for pipe-like streams. + mlibc::panicLogger() << "mlibc: Cannot read-write to same pipe-like stream" + << frg::endlog; + __io_mode = 1; + + __ensure(__offset < __buffer_size); + auto chunk = frg::min(__buffer_size - __offset, max_size); + + // Line-buffered streams perform I/O on full lines. + bool flush_line = false; + if(_bufmode == buffer_mode::line_buffer) { + auto nl = reinterpret_cast(memchr(buffer, '\n', chunk)); + if(nl) { + chunk = nl + 1 - buffer; + flush_line = true; + } + } + __ensure(chunk); + + // Buffer data (without necessarily performing I/O). + _ensure_allocation(); + memcpy(__buffer_ptr + __offset, buffer, chunk); + + if(__dirty_begin != __dirty_end) { + __dirty_begin = frg::min(__dirty_begin, __offset); + __dirty_end = frg::max(__dirty_end, __offset + chunk); + }else{ + __dirty_begin = __offset; + __dirty_end = __offset + chunk; + } + __valid_limit = frg::max(__offset + chunk, __valid_limit); + __offset += chunk; + + // Flush line-buffered streams. + if(flush_line) { + if(_write_back()) + return -1; + } + + *actual_size = chunk; + return 0; +} + +int abstract_file::unget(char c) { + if (!__unget_ptr) { + // This can happen if the file is unbuffered, but we still need + // a space to store ungetc'd data. + __ensure(!__buffer_ptr); + _ensure_allocation(); + __ensure(__unget_ptr); + } + + if ((size_t)(__buffer_ptr - __unget_ptr) + 1 > ungetBufferSize) + return EOF; + else { + *(--__unget_ptr) = c; + return c; + } +} + +int abstract_file::update_bufmode(buffer_mode mode) { + // setvbuf() has undefined behavior if I/O has been performed. + __ensure(__dirty_begin == __dirty_end + && "update_bufmode() must only be called before performing I/O"); + _bufmode = mode; + return 0; +} + +void abstract_file::purge() { + __offset = 0; + __io_offset = 0; + __valid_limit = 0; + __dirty_end = __dirty_begin; + __unget_ptr = __buffer_ptr; +} + +int abstract_file::flush() { + if (__dirty_end != __dirty_begin) { + if (int e = _write_back(); e) + return e; + } + + if (int e = _save_pos(); e) + return e; + purge(); + return 0; +} + +int abstract_file::tell(off_t *current_offset) { + off_t seek_offset; + if(int e = io_seek(0, SEEK_CUR, &seek_offset); e) + return e; + + *current_offset = seek_offset + (off_t(__offset) - off_t(__io_offset)); + return 0; +} + +int abstract_file::seek(off_t offset, int whence) { + if(int e = _write_back(); e) + return e; + + off_t new_offset; + if(whence == SEEK_CUR) { + auto seek_offset = offset + (off_t(__offset) - off_t(__io_offset)); + if(int e = io_seek(seek_offset, whence, &new_offset); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + }else{ + __ensure(whence == SEEK_SET || whence == SEEK_END); + if(int e = io_seek(offset, whence, &new_offset); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + } + + // We just forget the current buffer. + // TODO: If the seek is "small", we can just modify our internal offset. + purge(); + + return 0; +} + +int abstract_file::_init_type() { + if(_type != stream_type::unknown) + return 0; + + if(int e = determine_type(&_type); e) + return e; + __ensure(_type != stream_type::unknown); + return 0; +} + +int abstract_file::_init_bufmode() { + if(_bufmode != buffer_mode::unknown) + return 0; + + if(determine_bufmode(&_bufmode)) + return -1; + __ensure(_bufmode != buffer_mode::unknown); + return 0; +} + +int abstract_file::_write_back() { + if(int e = _init_type(); e) + return e; + + if(__dirty_begin == __dirty_end) + return 0; + + // For non-pipe streams, first do a seek to reset the + // I/O position to zero, then do a write(). + if(_type == stream_type::file_like) { + if(__io_offset != __dirty_begin) { + __ensure(__dirty_begin - __io_offset > 0); + off_t new_offset; + if(int e = io_seek(off_t(__dirty_begin) - off_t(__io_offset), SEEK_CUR, &new_offset); e) + return e; + __io_offset = __dirty_begin; + } + }else{ + __ensure(_type == stream_type::pipe_like); + __ensure(__io_offset == __dirty_begin); + } + + // Now, we are in the correct position to write-back everything. + while(__io_offset < __dirty_end) { + size_t io_size; + if(int e = io_write(__buffer_ptr + __io_offset, __dirty_end - __io_offset, &io_size); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + __ensure(io_size > 0 && "io_write() is expected to always write at least one byte"); + __io_offset += io_size; + __dirty_begin += io_size; + } + + return 0; +} + +int abstract_file::_save_pos() { + if (int e = _init_type(); e) + return e; + if (int e = _init_bufmode(); e) + return e; + + if (_type == stream_type::file_like && _bufmode != buffer_mode::no_buffer) { + off_t new_offset; + auto seek_offset = (off_t(__offset) - off_t(__io_offset)); + if (int e = io_seek(seek_offset, SEEK_CUR, &new_offset); e) { + __status_bits |= __MLIBC_ERROR_BIT; + mlibc::infoLogger() << "hit io_seek() error " << e << frg::endlog; + return e; + } + return 0; + } + return 0; // nothing to do for the rest +} + +int abstract_file::_reset() { + if(int e = _init_type(); e) + return e; + + // For pipe-like files, we must not forget already read data. + // TODO: Report this error to the user. + if(_type == stream_type::pipe_like) + __ensure(__offset == __valid_limit); + + __ensure(__dirty_begin == __dirty_end); + __offset = 0; + __io_offset = 0; + __valid_limit = 0; + + return 0; +} + +// This may still be called when buffering is disabled, for ungetc. +void abstract_file::_ensure_allocation() { + if(__buffer_ptr) + return; + + auto ptr = getAllocator().allocate(__buffer_size + ungetBufferSize); + __buffer_ptr = reinterpret_cast(ptr) + ungetBufferSize; + __unget_ptr = __buffer_ptr; +} + +// -------------------------------------------------------------------------------------- +// fd_file implementation. +// -------------------------------------------------------------------------------------- + +fd_file::fd_file(int fd, void (*do_dispose)(abstract_file *), bool force_unbuffered) +: abstract_file{do_dispose}, _fd{fd}, _force_unbuffered{force_unbuffered} { } + +int fd_file::fd() { + return _fd; +} + +int fd_file::close() { + if(__dirty_begin != __dirty_end) + mlibc::infoLogger() << "mlibc warning: File is not flushed before closing" + << frg::endlog; + if(int e = mlibc::sys_close(_fd); e) + return e; + return 0; +} + +int fd_file::reopen(const char *path, const char *mode) { + int mode_flags = parse_modestring(mode); + + int fd; + if(int e = sys_open(path, mode_flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, &fd); e) { + return e; + } + + flush(); + close(); + getAllocator().deallocate(__buffer_ptr, __buffer_size + ungetBufferSize); + + __buffer_ptr = nullptr; + __unget_ptr = nullptr; + __buffer_size = 4096; + _reset(); + _fd = fd; + + if(mode_flags & O_APPEND) { + seek(0, SEEK_END); + } + + return 0; +} + +int fd_file::determine_type(stream_type *type) { + off_t offset; + int e = mlibc::sys_seek(_fd, 0, SEEK_CUR, &offset); + if(!e) { + *type = stream_type::file_like; + return 0; + }else if(e == ESPIPE) { + *type = stream_type::pipe_like; + return 0; + }else{ + return e; + } +} + +int fd_file::determine_bufmode(buffer_mode *mode) { + // When isatty() is not implemented, we fall back to the safest default (no buffering). + if(!mlibc::sys_isatty) { + MLIBC_MISSING_SYSDEP(); + *mode = buffer_mode::no_buffer; + return 0; + } + if(_force_unbuffered) { + *mode = buffer_mode::no_buffer; + return 0; + } + + if(int e = mlibc::sys_isatty(_fd); !e) { + *mode = buffer_mode::line_buffer; + return 0; + }else if(e == ENOTTY) { + *mode = buffer_mode::full_buffer; + return 0; + }else{ + mlibc::infoLogger() << "mlibc: sys_isatty() failed while determining whether" + " stream is interactive" << frg::endlog; + return -1; + } +} + +int fd_file::io_read(char *buffer, size_t max_size, size_t *actual_size) { + ssize_t s; + if(int e = mlibc::sys_read(_fd, buffer, max_size, &s); e) + return e; + *actual_size = s; + return 0; +} + +int fd_file::io_write(const char *buffer, size_t max_size, size_t *actual_size) { + ssize_t s; + if(int e = mlibc::sys_write(_fd, buffer, max_size, &s); e) + return e; + *actual_size = s; + return 0; +} + +int fd_file::io_seek(off_t offset, int whence, off_t *new_offset) { + if(int e = mlibc::sys_seek(_fd, offset, whence, new_offset); e) + return e; + return 0; +} + +int fd_file::parse_modestring(const char *mode) { + // Consume the first char; this must be 'r', 'w' or 'a'. + int flags = 0; + bool has_plus = strchr(mode, '+'); + if(*mode == 'r') { + if(has_plus) { + flags = O_RDWR; + }else{ + flags = O_RDONLY; + } + }else if(*mode == 'w') { + if(has_plus) { + flags = O_RDWR; + }else{ + flags = O_WRONLY; + } + flags |= O_CREAT | O_TRUNC; + }else if(*mode == 'a') { + if(has_plus) { + flags = O_APPEND | O_RDWR; + }else{ + flags = O_APPEND | O_WRONLY; + } + flags |= O_CREAT; + }else{ + mlibc::infoLogger() << "Illegal fopen() mode '" << *mode << "'" << frg::endlog; + } + mode += 1; + + // Consume additional flags. + while(*mode) { + if(*mode == '+') { + mode++; // This is already handled above. + }else if(*mode == 'b') { + mode++; // mlibc assumes that there is no distinction between text and binary. + }else if(*mode == 'e') { + flags |= O_CLOEXEC; + mode++; + }else{ + mlibc::infoLogger() << "Illegal fopen() flag '" << mode << "'" << frg::endlog; + mode++; + } + } + + return flags; +} + +} // namespace mlibc + +namespace { + mlibc::fd_file stdin_file{0}; + mlibc::fd_file stdout_file{1}; + mlibc::fd_file stderr_file{2, nullptr, true}; + + struct stdio_guard { + stdio_guard() { } + + ~stdio_guard() { + // Only flush the files but do not close them. + for(auto it : mlibc::global_file_list()) { + if(int e = it->flush(); e) + mlibc::infoLogger() << "mlibc warning: Failed to flush file before exit()" + << frg::endlog; + } + } + } global_stdio_guard; +} + +FILE *stderr = &stderr_file; +FILE *stdin = &stdin_file; +FILE *stdout = &stdout_file; + +int fileno_unlocked(FILE *file_base) { + auto file = static_cast(file_base); + return file->fd(); +} + +int fileno(FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + return fileno_unlocked(file_base); +} + +FILE *fopen(const char *path, const char *mode) { + int flags = mlibc::fd_file::parse_modestring(mode); + + int fd; + if(int e = mlibc::sys_open(path, flags, 0666, &fd); e) { + errno = e; + return nullptr; + } + + return frg::construct(getAllocator(), fd, + mlibc::file_dispose_cb); +} + +int fclose(FILE *file_base) { + auto file = static_cast(file_base); + int e = 0; + if(file->flush()) + e = EOF; + if(file->close()) + e = EOF; + file->dispose(); + return e; +} + +int fseek(FILE *file_base, long offset, int whence) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + if(int e = file->seek(offset, whence); e) { + errno = e; + return -1; + } + return 0; +} + +long ftell(FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + off_t current_offset; + if(int e = file->tell(¤t_offset); e) { + errno = e; + return -1; + } + return current_offset; +} + +int fflush_unlocked(FILE *file_base) { + if(file_base == NULL) { + // Only flush the files but do not close them. + for(auto it : mlibc::global_file_list()) { + if(int e = it->flush(); e) + mlibc::infoLogger() << "mlibc warning: Failed to flush file" + << frg::endlog; + } + return 0; + } + auto file = static_cast(file_base); + if(file->flush()) + return EOF; + return 0; +} +int fflush(FILE *file_base) { + if(file_base == NULL) { + // Only flush the files but do not close them. + for(auto it : mlibc::global_file_list()) { + frg::unique_lock lock(it->_lock); + if(int e = it->flush(); e) + mlibc::infoLogger() << "mlibc warning: Failed to flush file" + << frg::endlog; + } + return 0; + } + + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + if (file->flush()) + return EOF; + return 0; +} + +int setvbuf(FILE *file_base, char *, int mode, size_t) { + // TODO: We could also honor the buffer, but for now use just set the mode. + auto file = static_cast(file_base); + if(mode == _IONBF) { + if(int e = file->update_bufmode(mlibc::buffer_mode::no_buffer); e) { + errno = e; + return -1; + } + }else if(mode == _IOLBF) { + if(int e = file->update_bufmode(mlibc::buffer_mode::line_buffer); e) { + errno = e; + return -1; + } + }else if(mode == _IOFBF) { + if(int e = file->update_bufmode(mlibc::buffer_mode::full_buffer); e) { + errno = e; + return -1; + } + }else{ + errno = EINVAL; + return -1; + } + + return 0; +} + +void rewind(FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + file->seek(0, SEEK_SET); + file_base->__status_bits &= ~(__MLIBC_EOF_BIT | __MLIBC_ERROR_BIT); +} + +int ungetc(int c, FILE *file_base) { + if (c == EOF) + return EOF; + + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + return file->unget(c); +} + +#if __MLIBC_GLIBC_OPTION +void __fpurge(FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + file->purge(); +} +#endif + diff --git a/lib/mlibc/options/ansi/generic/inttypes-stubs.cpp b/lib/mlibc/options/ansi/generic/inttypes-stubs.cpp new file mode 100644 index 0000000..ae0f9e7 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/inttypes-stubs.cpp @@ -0,0 +1,100 @@ + +#include +#include +#include + +#include +#include + +static const char *__mlibc_digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + +intmax_t imaxabs(intmax_t num) { + return num < 0 ? -num : num; +} +imaxdiv_t imaxdiv(intmax_t number, intmax_t denom) { + imaxdiv_t r; + r.quot = number / denom; + r.rem = number % denom; + return r; +} + +template T strtoxmax(const char *it, char **out, int base) { + T v = 0; + bool negate = false; + const unsigned char *s = (const unsigned char *)it; + int c; + + if(std::is_signed::value) { + if(*s == '+') { + s++; + }else if(*s == '-') { + negate = true; + s++; + } + } + + do { + c = *s++; + } while (isspace(c)); + if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + if(base == 8) { + if(*it != 0) + goto parse_digits; + it++; + }else if(base == 16) { + if(*it != 0) + goto parse_digits; + it++; + if(*it != 'x' && *it != 'X') + goto parse_digits; + it++; + } + +parse_digits: + while(*it) { + if(isspace(*it)) { + it++; + continue; + } + + __ensure(base <= 10); // TODO: For base > 10 we need to implement tolower(). + //auto c = strchr(__mlibc_digits, tolower(*it)); + auto c = strchr(__mlibc_digits, *it); + if(!c || (c - __mlibc_digits) >= base) + break; + v = v * base + (c - __mlibc_digits); + it++; + } + + if(std::is_signed::value) { + if(negate) + v = -v; + } + + if(out) + *out = const_cast(it); + return v; +} + +intmax_t strtoimax(const char *it, char **out, int base) { + // TODO: This function has to check for overflow! + return strtoxmax(it, out, base); +} +uintmax_t strtoumax(const char *it, char **out, int base) { + return strtoxmax(it, out, base); +} +intmax_t wcstoimax(const wchar_t *__restrict, wchar_t **__restrict, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +uintmax_t wcstoumax(const wchar_t *__restrict, wchar_t **__restrict, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/ansi/generic/locale-stubs.cpp b/lib/mlibc/options/ansi/generic/locale-stubs.cpp new file mode 100644 index 0000000..38f5859 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/locale-stubs.cpp @@ -0,0 +1,195 @@ + +#include +#include +#include + +#include + +#include +#include + +namespace { + // Values of the C locale are defined by the C standard. + constexpr lconv c_lconv = { + const_cast("."), // decimal_point + const_cast(""), // thousands_sep + const_cast(""), // grouping + const_cast(""), // mon_decimal_point + const_cast(""), // mon_thousands_sep + const_cast(""), // mon_grouping + const_cast(""), // positive_sign + const_cast(""), // negative_sign + const_cast(""), // currency_symbol + CHAR_MAX, // frac_digits + CHAR_MAX, // p_cs_precedes + CHAR_MAX, // n_cs_precedes + CHAR_MAX, // p_sep_by_space + CHAR_MAX, // n_sep_by_space + CHAR_MAX, // p_sign_posn + CHAR_MAX, // n_sign_posn + const_cast(""), // int_curr_symbol + CHAR_MAX, // int_frac_digits + CHAR_MAX, // int_p_cs_precedes + CHAR_MAX, // int_n_cs_precedes + CHAR_MAX, // int_p_sep_by_space + CHAR_MAX, // int_n_sep_by_space + CHAR_MAX, // int_p_sign_posn + CHAR_MAX // int_n_sign_posn + }; +} + +namespace mlibc { + struct locale_description { + // Identifier of this locale. used in setlocale(). + const char *name; + lconv lc; + }; + + constinit const locale_description c_locale{ + .name = "C", + .lc = c_lconv + }; + + constinit const locale_description posix_locale{ + .name = "POSIX", + .lc = c_lconv + }; + + const locale_description *query_locale_description(const char *name) { + if(!strcmp(name, "C")) + return &c_locale; + if(!strcmp(name, "POSIX")) + return &posix_locale; + return nullptr; + } + + const locale_description *collate_facet; + const locale_description *ctype_facet; + const locale_description *monetary_facet; + const locale_description *numeric_facet; + const locale_description *time_facet; + const locale_description *messages_facet; +} + +void __mlibc_initLocale() { + mlibc::collate_facet = &mlibc::c_locale; + mlibc::ctype_facet = &mlibc::c_locale; + mlibc::monetary_facet = &mlibc::c_locale; + mlibc::numeric_facet = &mlibc::c_locale; + mlibc::time_facet = &mlibc::c_locale; + mlibc::messages_facet = &mlibc::c_locale; +} + +char *setlocale(int category, const char *name) { + if(category == LC_ALL) { + // ´TODO: Implement correct return value when categories differ. + auto current_desc = mlibc::collate_facet; + __ensure(current_desc == mlibc::ctype_facet); + __ensure(current_desc == mlibc::monetary_facet); + __ensure(current_desc == mlibc::numeric_facet); + __ensure(current_desc == mlibc::time_facet); + __ensure(current_desc == mlibc::messages_facet); + + if(name) { + // Our default C locale is the C locale. + if(!strlen(name)) + name = "C"; + + auto new_desc = mlibc::query_locale_description(name); + if(!new_desc) { + mlibc::infoLogger() << "mlibc: Locale " << name + << " is not supported" << frg::endlog; + return nullptr; + } + + mlibc::collate_facet = new_desc; + mlibc::ctype_facet = new_desc; + mlibc::monetary_facet = new_desc; + mlibc::numeric_facet = new_desc; + mlibc::time_facet = new_desc; + mlibc::messages_facet = new_desc; + } + return const_cast(current_desc->name); + }else{ + const mlibc::locale_description **facet_ptr; + switch(category) { + case LC_COLLATE: + facet_ptr = &mlibc::collate_facet; + break; + case LC_CTYPE: + facet_ptr = &mlibc::ctype_facet; + break; + case LC_MONETARY: + facet_ptr = &mlibc::monetary_facet; + break; + case LC_NUMERIC: + facet_ptr = &mlibc::numeric_facet; + break; + case LC_TIME: + facet_ptr = &mlibc::time_facet; + break; + case LC_MESSAGES: + facet_ptr = &mlibc::messages_facet; + break; + default: + mlibc::infoLogger() << "mlibc: Unexpected value " << category + << " for category in setlocale()" << frg::endlog; + return nullptr; + } + + auto current_desc = *facet_ptr; + if(name) { + // Our default C locale is the C locale. + if(!strlen(name)) + name = "C"; + + auto new_desc = mlibc::query_locale_description(name); + if(!new_desc) { + mlibc::infoLogger() << "mlibc: Locale " << name + << " is not supported" << frg::endlog; + return nullptr; + } + + *facet_ptr = new_desc; + } + return const_cast(current_desc->name); + } +} + +namespace { + lconv effective_lc; +} + +struct lconv *localeconv(void) { + // Numeric locale. + const auto &numeric_lc = mlibc::numeric_facet->lc; + effective_lc.decimal_point = numeric_lc.decimal_point; + effective_lc.thousands_sep = numeric_lc.thousands_sep; + effective_lc.grouping = numeric_lc.grouping; + + // Monetary locale. + const auto &monetary_lc = mlibc::monetary_facet->lc; + effective_lc.mon_decimal_point = monetary_lc.mon_decimal_point; + effective_lc.mon_thousands_sep = monetary_lc.mon_thousands_sep; + effective_lc.mon_grouping = monetary_lc.mon_grouping; + effective_lc.positive_sign = monetary_lc.positive_sign; + effective_lc.negative_sign = monetary_lc.negative_sign; + effective_lc.currency_symbol = monetary_lc.currency_symbol; + effective_lc.frac_digits = monetary_lc.frac_digits; + effective_lc.p_cs_precedes = monetary_lc.p_cs_precedes; + effective_lc.n_cs_precedes = monetary_lc.n_cs_precedes; + effective_lc.p_sep_by_space = monetary_lc.p_sep_by_space; + effective_lc.n_sep_by_space = monetary_lc.n_sep_by_space; + effective_lc.p_sign_posn = monetary_lc.p_sign_posn; + effective_lc.n_sign_posn = monetary_lc.n_sign_posn; + effective_lc.int_curr_symbol = monetary_lc.int_curr_symbol; + effective_lc.int_frac_digits = monetary_lc.int_frac_digits; + effective_lc.int_p_cs_precedes = monetary_lc.int_p_cs_precedes; + effective_lc.int_n_cs_precedes = monetary_lc.int_n_cs_precedes; + effective_lc.int_p_sep_by_space = monetary_lc.int_p_sep_by_space; + effective_lc.int_n_sep_by_space = monetary_lc.int_n_sep_by_space; + effective_lc.int_p_sign_posn = monetary_lc.int_p_sign_posn; + effective_lc.int_n_sign_posn = monetary_lc.int_n_sign_posn; + + return &effective_lc; +} diff --git a/lib/mlibc/options/ansi/generic/math-stubs.ignored-cpp b/lib/mlibc/options/ansi/generic/math-stubs.ignored-cpp new file mode 100644 index 0000000..9be985f --- /dev/null +++ b/lib/mlibc/options/ansi/generic/math-stubs.ignored-cpp @@ -0,0 +1,1831 @@ + +#include +#include + +#include + +#include + +#include + +// Taken from musl. See musl for the license/copyright! +#define FORCE_EVAL(x) do { \ + if (sizeof(x) == sizeof(float)) { \ + volatile float __x; \ + __x = (x); \ + } else if (sizeof(x) == sizeof(double)) { \ + volatile double __x; \ + __x = (x); \ + } else { \ + volatile long double __x; \ + __x = (x); \ + } \ +} while(0) + +namespace ieee754 { + +struct SoftDouble { + typedef uint64_t Bits; + typedef uint64_t Mantissa; + typedef int16_t Exp; + + static constexpr int kMantissaBits = 52; + static constexpr int kExpBits = 11; + static constexpr int kBias = 1023; + + // this exponent represents zeros (when mantissa = 0) and subnormals (when mantissa != 0) + static constexpr Exp kSubExp = -kBias; + // this exponent represents infinities (when mantissa = 0) and NaNs (when mantissa != 0) + static constexpr Exp kInfExp = ((Exp(1) << kExpBits) - 1) - kBias; + + static constexpr Bits kMantissaMask = (Bits(1) << kMantissaBits) - 1; + static constexpr Bits kExpMask = ((Bits(1) << kExpBits) - 1) << kMantissaBits; + static constexpr Bits kSignMask = Bits(1) << (kMantissaBits + kExpBits); + + SoftDouble(bool negative, Mantissa mantissa, Exp exp) + : negative(negative), mantissa(mantissa), exp(exp) { +// mlibc::infoLogger.log() << "(" << (int)negative << ", " << (void *)mantissa +// << ", " << exp << ")" << frg::end_log; + __ensure(mantissa < (Mantissa(1) << kMantissaBits)); + __ensure((exp + kBias) >= 0); + __ensure((exp + kBias) < (Exp(1) << kExpBits)); + } + + const bool negative; + const Mantissa mantissa; + const Exp exp; +}; + +template +using Bits = typename F::Bits; + +template +using Mantissa = typename F::Mantissa; + +template +using Exp = typename F::Exp; + +template +bool isZero(F x) { + return x.exp == F::kSubExp && x.mantissa == 0; +} + +template +bool isFinite(F x) { + return x.exp != F::kInfExp; +} + +// -------------------------------------------------------- +// Soft float operations +// -------------------------------------------------------- + +template +F constZero(bool negative) { + return F(negative, 0, F::kSubExp); +} + +template +F constOne(bool negative) { + return F(negative, 0, 0); +} + +template +F floor(F x) { + if(!isFinite(x) || isZero(x)) // TODO: need exception for the not-finite case? + return x; + + if(x.exp > F::kMantissaBits) + return x; // x is already integral + + if(x.exp < 0) { + // TODO: raise inexact + // return -1 or +0 + return x.negative ? constOne(true) : constZero(false); + } + + Mantissa mask = F::kMantissaMask >> x.exp; + if(!(x.mantissa & mask)) + return x; // x is already integral + + // TODO: raise inexact + Mantissa integral_position = (Mantissa(1) << F::kMantissaBits) >> x.exp; + if(x.negative) + return F(true, (x.mantissa + integral_position) & (~mask), x.exp); + return F(false, x.mantissa & (~mask), x.exp); +} + +template +F ceil(F x) { + if(!isFinite(x) || isZero(x)) // TODO: need exception for the not-finite case? + return x; + + if(x.exp > F::kMantissaBits) + return x; // x is already integral + + if(x.exp < 0) { + // TODO: raise inexact + // return -0 or +1 + return x.negative ? constZero(true) : constOne(false); + } + + Mantissa mask = F::kMantissaMask >> x.exp; + if(!(x.mantissa & mask)) + return x; // x is already integral + + // TODO: raise inexact + Mantissa integral_position = (Mantissa(1) << F::kMantissaBits) >> x.exp; + if(x.negative) + return F(true, x.mantissa & (~mask), x.exp); + return F(false, (x.mantissa + integral_position) & (~mask), x.exp); +} + +// -------------------------------------------------------- +// Soft float <-> bit string conversion functions +// -------------------------------------------------------- + +template +uint64_t compileBits(F soft) { + auto bits = Bits(soft.mantissa) | ((Bits(soft.exp) + F::kBias) << soft.kMantissaBits); + return soft.negative ? (F::kSignMask | bits) : bits; +} + +SoftDouble extractBits(uint64_t bits) { + return SoftDouble(bits & SoftDouble::kSignMask, bits & SoftDouble::kMantissaMask, + ((bits & SoftDouble::kExpMask) >> SoftDouble::kMantissaBits) - SoftDouble::kBias); +} + +// -------------------------------------------------------- +// Soft float -> native float conversion functions +// -------------------------------------------------------- + +union DoubleBits { + double fp; + uint64_t bits; +}; + +double compileNative(SoftDouble soft) { + DoubleBits word; + word.bits = compileBits(soft); + return word.fp; +} + +SoftDouble extractNative(double native) { + DoubleBits word; + word.fp = native; + return extractBits(word.bits); +} + +} // namespace ieee754 + +int __mlibc_fpclassify(double x) { + return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x); +} +int __mlibc_fpclassifyf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +int __mlibc_fpclassifyl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double acos(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float acosf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double acosl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double asin(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float asinf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double asinl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double atan(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float atanf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double atanl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double atan2(double x, double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float atan2f(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double atan2l(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// Taken from musl. See musl for the license/copyright! +float __sindf(double x) { + /* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ + static const double S1 = -0x15555554cbac77.0p-55, /* -0.166666666416265235595 */ + S2 = 0x111110896efbb2.0p-59, /* 0.0083333293858894631756 */ + S3 = -0x1a00f9e2cae774.0p-65, /* -0.000198393348360966317347 */ + S4 = 0x16cd878c3b46a7.0p-71; /* 0.0000027183114939898219064 */ + + double r, s, w, z; + + /* Try to optimize for parallel evaluation as in __tandf.c. */ + z = x*x; + w = z*z; + r = S3 + z*S4; + s = z*x; + return (x + s*(S1 + z*S2)) + s*w*r; +} + +// Taken from musl. See musl for the license/copyright! +float __cosdf(double x) { + /* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ + static const double C0 = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */ + C1 = 0x155553e1053a42.0p-57, /* 0.0416666233237390631894 */ + C2 = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */ + C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */ + + double r, w, z; + + /* Try to optimize for parallel evaluation as in __tandf.c. */ + z = x*x; + w = z*z; + r = C2+z*C3; + return ((1.0+z*C0) + w*C1) + (w*z)*r; +} + +float __tandf(double x, int odd) { + /* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ + static const double T[] = { + 0x15554d3418c99f.0p-54, /* 0.333331395030791399758 */ + 0x1112fd38999f72.0p-55, /* 0.133392002712976742718 */ + 0x1b54c91d865afe.0p-57, /* 0.0533812378445670393523 */ + 0x191df3908c33ce.0p-58, /* 0.0245283181166547278873 */ + 0x185dadfcecf44e.0p-61, /* 0.00297435743359967304927 */ + 0x1362b9bf971bcd.0p-59, /* 0.00946564784943673166728 */ + }; + + double z,r,w,s,t,u; + + z = x*x; + /* + * Split up the polynomial into small independent terms to give + * opportunities for parallel evaluation. The chosen splitting is + * micro-optimized for Athlons (XP, X64). It costs 2 multiplications + * relative to Horner's method on sequential machines. + * + * We add the small terms from lowest degree up for efficiency on + * non-sequential machines (the lowest degree terms tend to be ready + * earlier). Apart from this, we don't care about order of + * operations, and don't need to to care since we have precision to + * spare. However, the chosen splitting is good for accuracy too, + * and would give results as accurate as Horner's method if the + * small terms were added from highest degree down. + */ + r = T[4] + z*T[5]; + t = T[2] + z*T[3]; + w = z*z; + s = z*x; + u = T[0] + z*T[1]; + r = (x + s*u) + (s*w)*(t + w*r); + return odd ? -1.0/r : r; +} + +#define DBL_EPSILON 2.22044604925031308085e-16 +#define EPS DBL_EPSILON + +/* Get a 32 bit int from a float. */ +#define GET_FLOAT_WORD(w,d) \ +do { \ + union {float f; uint32_t i;} __u; \ + __u.f = (d); \ + (w) = __u.i; \ +} while (0) + +/* Get the more significant 32 bit int from a double. */ +#define GET_HIGH_WORD(hi,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (hi) = __u.i >> 32; \ +} while (0) + +/* Get the less significant 32 bit int from a double. */ +#define GET_LOW_WORD(lo,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (lo) = (uint32_t)__u.i; \ +} while (0) + +// Taken from musl. See musl for the license/copyright! +int __rem_pio2_large(double *x, double *y, int e0, int nx, int prec) +{ + static const int init_jk[] = {3,4,4,6}; /* initial value for jk */ + + /* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + * + * integer array, contains the (24*i)-th to (24*i+23)-th + * bit of 2/pi after binary point. The corresponding + * floating value is + * + * ipio2[i] * 2^(-24(i+1)). + * + * NB: This table must have at least (e0-3)/24 + jk terms. + * For quad precision (e0 <= 16360, jk = 6), this is 686. + */ + static const int32_t ipio2[] = { + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, + 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, + 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, + 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, + 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, + 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, + 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, + 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, + + #if LDBL_MAX_EXP > 1024 + 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, + 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, + 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, + 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, + 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, + 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, + 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, + 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, + 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, + 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, + 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, + 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, + 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, + 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, + 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, + 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, + 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, + 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, + 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, + 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, + 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, + 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, + 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, + 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, + 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, + 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, + 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, + 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, + 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, + 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, + 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, + 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, + 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, + 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, + 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, + 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, + 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, + 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, + 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, + 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, + 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, + 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, + 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, + 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, + 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, + 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, + 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, + 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, + 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, + 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, + 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, + 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, + 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, + 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, + 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, + 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, + 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, + 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, + 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, + 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, + 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, + 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, + 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, + 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, + 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, + 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, + 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, + 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, + 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, + 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, + 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, + 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, + 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, + 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, + 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, + 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, + 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, + 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, + 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, + 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, + 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, + 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, + 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, + 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, + 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, + 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, + 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, + 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, + 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, + 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, + 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, + 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, + 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, + 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, + 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, + 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, + 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, + 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, + 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, + 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, + 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, + 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, + 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, + 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, + #endif + }; + + static const double PIo2[] = { + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ + }; + + int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + double z,fw,f[20],fq[20],q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx-1; + jv = (e0-3)/24; if(jv<0) jv=0; + q0 = e0-24*(jv+1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv-jx; m = jx+jk; + for (i=0; i<=m; i++,j++) + f[i] = j<0 ? 0.0 : (double)ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i=0; i<=jk; i++) { + for (j=0,fw=0.0; j<=jx; j++) + fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for (i=0,j=jz,z=q[jz]; j>0; i++,j--) { + fw = (double)(int32_t)(0x1p-24*z); + iq[i] = (int32_t)(z - 0x1p24*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbn(z,q0); /* actual value of z */ + z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ + n = (int32_t)z; + z -= (double)n; + ih = 0; + if (q0 > 0) { /* need iq[jz-1] to determine n */ + i = iq[jz-1]>>(24-q0); n += i; + iq[jz-1] -= i<<(24-q0); + ih = iq[jz-1]>>(23-q0); + } + else if (q0 == 0) ih = iq[jz-1]>>23; + else if (z >= 0.5) ih = 2; + + if (ih > 0) { /* q > 0.5 */ + n += 1; carry = 0; + for (i=0; i 0) { /* rare case: chance is 1 in 12 */ + switch(q0) { + case 1: + iq[jz-1] &= 0x7fffff; break; + case 2: + iq[jz-1] &= 0x3fffff; break; + } + } + if (ih == 2) { + z = 1.0 - z; + if (carry != 0) + z -= scalbn(1.0,q0); + } + } + + /* check if recomputation is needed */ + if (z == 0.0) { + j = 0; + for (i=jz-1; i>=jk; i--) j |= iq[i]; + if (j == 0) { /* need recomputation */ + for (k=1; iq[jk-k]==0; k++); /* k = no. of terms needed */ + + for (i=jz+1; i<=jz+k; i++) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = (double)ipio2[jv+i]; + for (j=0,fw=0.0; j<=jx; j++) + fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if (z == 0.0) { + jz -= 1; + q0 -= 24; + while (iq[jz] == 0) { + jz--; + q0 -= 24; + } + } else { /* break z into 24-bit if necessary */ + z = scalbn(z,-q0); + if (z >= 0x1p24) { + fw = (double)(int32_t)(0x1p-24*z); + iq[jz] = (int32_t)(z - 0x1p24*fw); + jz += 1; + q0 += 24; + iq[jz] = (int32_t)fw; + } else + iq[jz] = (int32_t)z; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(1.0,q0); + for (i=jz; i>=0; i--) { + q[i] = fw*(double)iq[i]; + fw *= 0x1p-24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for(i=jz; i>=0; i--) { + for (fw=0.0,k=0; k<=jp && k<=jz-i; k++) + fw += PIo2[k]*q[i+k]; + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + switch(prec) { + case 0: + fw = 0.0; + for (i=jz; i>=0; i--) + fw += fq[i]; + y[0] = ih==0 ? fw : -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i=jz; i>=0; i--) + fw += fq[i]; + // TODO: drop excess precision here once double_t is used + fw = (double)fw; + y[0] = ih==0 ? fw : -fw; + fw = fq[0]-fw; + for (i=1; i<=jz; i++) + fw += fq[i]; + y[1] = ih==0 ? fw : -fw; + break; + case 3: /* painful */ + for (i=jz; i>0; i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (i=jz; i>1; i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (fw=0.0,i=jz; i>=2; i--) + fw += fq[i]; + if (ih==0) { + y[0] = fq[0]; y[1] = fq[1]; y[2] = fw; + } else { + y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; + } + } + return n&7; +} + +int __rem_pio2f(float x, double *y) { + /* + * invpio2: 53 bits of 2/pi + * pio2_1: first 25 bits of pi/2 + * pio2_1t: pi/2 - pio2_1 + */ + static const double toint = 1.5/EPS, + invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ + pio2_1 = 1.57079631090164184570e+00, /* 0x3FF921FB, 0x50000000 */ + pio2_1t = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + + union {float f; uint32_t i;} u = {x}; + double tx[1],ty[1]; + double fn; + uint32_t ix; + int n, sign, e0; + + ix = u.i & 0x7fffffff; + /* 25+53 bit pi is good enough for medium size */ + if (ix < 0x4dc90fdb) { /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + fn = (double)x*invpio2 + toint - toint; + n = (int32_t)fn; + *y = x - fn*pio2_1 - fn*pio2_1t; + return n; + } + if(ix>=0x7f800000) { /* x is inf or NaN */ + *y = x-x; + return 0; + } + /* scale x into [2^23, 2^24-1] */ + sign = u.i>>31; + e0 = (ix>>23) - (0x7f+23); /* e0 = ilogb(|x|)-23, positive */ + u.i = ix - (e0<<23); + tx[0] = u.f; + n = __rem_pio2_large(tx,ty,e0,1,0); + if (sign) { + *y = -ty[0]; + return -n; + } + *y = ty[0]; + return n; +} + +double cos(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +// Taken from musl. See musl for the license/copyright! +float cosf(float x) { + /* Small multiples of pi/2 rounded to double precision. */ + static const double c1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ + c2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ + c3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ + c4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + + double y; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x != 0 */ + FORCE_EVAL(x + 0x1p120f); + return 1.0f; + } + return __cosdf(x); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix > 0x4016cbe3) /* |x| ~> 3*pi/4 */ + return -__cosdf(sign ? x+c2pio2 : x-c2pio2); + else { + if (sign) + return __sindf(x + c1pio2); + else + return __sindf(c1pio2 - x); + } + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix > 0x40afeddf) /* |x| ~> 7*pi/4 */ + return __cosdf(sign ? x+c4pio2 : x-c4pio2); + else { + if (sign) + return __sindf(-x - c3pio2); + else + return __sindf(x - c3pio2); + } + } + + /* cos(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) + return x-x; + + /* general argument reduction needed */ + n = __rem_pio2f(x,&y); + switch (n&3) { + case 0: return __cosdf(y); + case 1: return __sindf(-y); + case 2: return -__cosdf(y); + default: + return __sindf(y); + } +} +long double cosl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double sin(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +// Taken from musl. See musl for the license/copyright! +float sinf(float x) { + /* Small multiples of pi/2 rounded to double precision. */ + static const double s1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ + s2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ + s3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ + s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + + double y; + uint32_t ix; + int n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00800000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __sindf(x); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix <= 0x4016cbe3) { /* |x| ~<= 3pi/4 */ + if (sign) + return -__cosdf(x + s1pio2); + else + return __cosdf(x - s1pio2); + } + return __sindf(sign ? -(x + s2pio2) : -(x - s2pio2)); + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40afeddf) { /* |x| ~<= 7*pi/4 */ + if (sign) + return __cosdf(x + s3pio2); + else + return -__cosdf(x - s3pio2); + } + return __sindf(sign ? x + s4pio2 : x - s4pio2); + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) + return x - x; + + /* general argument reduction needed */ + n = __rem_pio2f(x, &y); + switch (n&3) { + case 0: return __sindf(y); + case 1: return __cosdf(y); + case 2: return __sindf(-y); + default: + return -__cosdf(y); + } +} +long double sinl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double tan(double x) { + mlibc::infoLogger() << "mlibc: tan() is not precise" << frg::endlog; + return tanf(x); +} +// Taken from musl. See musl for the license/copyright! +float tanf(float x) { + /* Small multiples of pi/2 rounded to double precision. */ + static const double t1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ + t2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ + t3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ + t4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + + double y; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00800000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __tandf(x, 0); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix <= 0x4016cbe3) /* |x| ~<= 3pi/4 */ + return __tandf((sign ? x+t1pio2 : x-t1pio2), 1); + else + return __tandf((sign ? x+t2pio2 : x-t2pio2), 0); + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40afeddf) /* |x| ~<= 7*pi/4 */ + return __tandf((sign ? x+t3pio2 : x-t3pio2), 1); + else + return __tandf((sign ? x+t4pio2 : x-t4pio2), 0); + } + + /* tan(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) + return x - x; + + /* argument reduction */ + n = __rem_pio2f(x, &y); + return __tandf(y, n&1); +} +long double tanl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double acosh(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float acoshf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double acoshl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double asinh(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float asinhf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double asinhl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double atanh(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float atanhf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double atanhl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double cosh(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float coshf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double coshl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double sinh(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float sinhf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double sinhl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double tanh(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float tanhf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double tanhl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double exp(double x) { + static const double half[2] = {0.5,-0.5}, + ln2hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ + ln2lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ + invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ + P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ + P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ + P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ + P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ + P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + + double hi, lo, c, xx, y; + int k, sign; + uint32_t hx; + + GET_HIGH_WORD(hx, x); + sign = hx>>31; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if (hx >= 0x4086232b) { /* if |x| >= 708.39... */ + if (isnan(x)) + return x; + if (x > 709.782712893383973096) { + /* overflow if x!=inf */ + x *= 0x1p1023; + return x; + } + if (x < -708.39641853226410622) { + /* underflow if x!=-inf */ + FORCE_EVAL((float)(-0x1p-149/x)); + if (x < -745.13321910194110842) + return 0; + } + } + + /* argument reduction */ + if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if (hx >= 0x3ff0a2b2) /* if |x| >= 1.5 ln2 */ + k = (int)(invln2*x + half[sign]); + else + k = 1 - sign - sign; + hi = x - k*ln2hi; /* k*ln2hi is exact here */ + lo = k*ln2lo; + x = hi - lo; + } else if (hx > 0x3e300000) { /* if |x| > 2**-28 */ + k = 0; + hi = x; + lo = 0; + } else { + /* inexact if x!=0 */ + FORCE_EVAL(0x1p1023 + x); + return 1 + x; + } + + /* x is now in primary range */ + xx = x*x; + c = x - xx*(P1+xx*(P2+xx*(P3+xx*(P4+xx*P5)))); + y = 1 + (x*c/(2-c) - lo + hi); + if (k == 0) + return y; + return scalbn(y, k); +} +float expf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double expl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double exp2(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +// Taken from musl. See musl for the license/copyright! +float exp2f(float x) { + constexpr int TBLSIZE = 16; + + constexpr float redux = 0x1.8p23f / TBLSIZE; + constexpr float P1 = 0x1.62e430p-1f; + constexpr float P2 = 0x1.ebfbe0p-3f; + constexpr float P3 = 0x1.c6b348p-5f; + constexpr float P4 = 0x1.3b2c9cp-7f; + + constexpr double exp2ft[TBLSIZE] = { + 0x1.6a09e667f3bcdp-1, + 0x1.7a11473eb0187p-1, + 0x1.8ace5422aa0dbp-1, + 0x1.9c49182a3f090p-1, + 0x1.ae89f995ad3adp-1, + 0x1.c199bdd85529cp-1, + 0x1.d5818dcfba487p-1, + 0x1.ea4afa2a490dap-1, + 0x1.0000000000000p+0, + 0x1.0b5586cf9890fp+0, + 0x1.172b83c7d517bp+0, + 0x1.2387a6e756238p+0, + 0x1.306fe0a31b715p+0, + 0x1.3dea64c123422p+0, + 0x1.4bfdad5362a27p+0, + 0x1.5ab07dd485429p+0, + }; + + double t, r, z; + union {float f; uint32_t i;} u = {x}; + union {double f; uint64_t i;} uk; + uint32_t ix, i0, k; + + /* Filter out exceptional cases. */ + ix = u.i & 0x7fffffff; + if (ix > 0x42fc0000) { /* |x| > 126 */ + if (ix > 0x7f800000) /* NaN */ + return x; + if (u.i >= 0x43000000 && u.i < 0x80000000) { /* x >= 128 */ + x *= 0x1p127f; + return x; + } + if (u.i >= 0x80000000) { /* x < -126 */ + if (u.i >= 0xc3160000 || (u.i & 0x0000ffff)) + FORCE_EVAL(-0x1p-149f/x); + if (u.i >= 0xc3160000) /* x <= -150 */ + return 0; + } + } else if (ix <= 0x33000000) { /* |x| <= 0x1p-25 */ + return 1.0f + x; + } + + /* Reduce x, computing z, i0, and k. */ + u.f = x + redux; + i0 = u.i; + i0 += TBLSIZE / 2; + k = i0 / TBLSIZE; + uk.i = (uint64_t)(0x3ff + k)<<52; + i0 &= TBLSIZE - 1; + u.f -= redux; + z = x - u.f; + /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ + r = exp2ft[i0]; + t = r * z; + r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4); + + /* Scale by 2**k */ + return r * uk.f; +} +long double exp2l(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double expm1(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float expm1f(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double expm1l(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double frexp(double x, int *power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float frexpf(float x, int *power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double frexpl(long double x, int *power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double ilogb(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float ilogbf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double ilogbl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double ldexp(double x, int power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float ldexpf(float x, int power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double ldexpl(long double x, int power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double log(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float logf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double logl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double log10(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float log10f(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double log10l(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double log1p(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float log1pf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double log1pl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// Taken from musl. See musl for the license/copyright! +double log2(double x) { + static const double + ivln2hi = 1.44269504072144627571e+00, /* 0x3ff71547, 0x65200000 */ + ivln2lo = 1.67517131648865118353e-10, /* 0x3de705fc, 0x2eefa200 */ + Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ + Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ + Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ + Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ + Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ + Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ + Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + + union {double f; uint64_t i;} u = {x}; + double hfsq,f,s,z,R,w,t1,t2,y,hi,lo,val_hi,val_lo; + uint32_t hx; + int k; + + hx = u.i>>32; + k = 0; + if (hx < 0x00100000 || hx>>31) { + if (u.i<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (hx>>31) + return (x-x)/0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i>>32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i<<32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx>>20) - 0x3ff; + hx = (hx&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx<<32 | (u.i&0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + + /* + * f-hfsq must (for args near 1) be evaluated in extra precision + * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2). + * This is fairly efficient since f-hfsq only depends on f, so can + * be evaluated in parallel with R. Not combining hfsq with R also + * keeps R small (though not as small as a true `lo' term would be), + * so that extra precision is not needed for terms involving R. + * + * Compiler bugs involving extra precision used to break Dekker's + * theorem for spitting f-hfsq as hi+lo, unless double_t was used + * or the multi-precision calculations were avoided when double_t + * has extra precision. These problems are now automatically + * avoided as a side effect of the optimization of combining the + * Dekker splitting step with the clear-low-bits step. + * + * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra + * precision to avoid a very large cancellation when x is very near + * these values. Unlike the above cancellations, this problem is + * specific to base 2. It is strange that adding +-1 is so much + * harder than adding +-ln2 or +-log10_2. + * + * This uses Dekker's theorem to normalize y+val_hi, so the + * compiler bugs are back in some configurations, sigh. And I + * don't want to used double_t to avoid them, since that gives a + * pessimization and the support for avoiding the pessimization + * is not yet available. + * + * The multi-precision calculations for the multiplications are + * routine. + */ + + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + u.f = hi; + u.i &= (uint64_t)-1<<32; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + + val_hi = hi*ivln2hi; + val_lo = (lo+hi)*ivln2lo + lo*ivln2hi; + + /* spadd(val_hi, val_lo, y), except for not using double_t: */ + y = k; + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} +float log2f(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double log2l(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double logb(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float logbf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double logbl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double modf(double x, double *integral) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float modff(float x, float *integral) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double modfl(long double x, long double *integral) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double scalbn(double x, int n) { + union {double f; uint64_t i;} u; + double y = x; + + if (n > 1023) { + y *= 0x1p1023; + n -= 1023; + if (n > 1023) { + y *= 0x1p1023; + n -= 1023; + if (n > 1023) + n = 1023; + } + } else if (n < -1022) { + /* make sure final n < -53 to avoid double + rounding in the subnormal range */ + y *= 0x1p-1022 * 0x1p53; + n += 1022 - 53; + if (n < -1022) { + y *= 0x1p-1022 * 0x1p53; + n += 1022 - 53; + if (n < -1022) + n = -1022; + } + } + u.i = (uint64_t)(0x3ff+n)<<52; + x = y * u.f; + return x; +} +float scalbnf(float x, int power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double scalbnl(long double x, int power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double scalbln(double x, long power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float scalblnf(float x, long power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double scalblnl(long double x, long power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double cbrt(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float cbrtf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double cbrtl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double fabs(double x) { + return signbit(x) ? -x : x; +} +float fabsf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double fabsl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double hypot(double x, double y) { + __ensure(isfinite(x)); + __ensure(isfinite(y)); + // TODO: fix exception handling + double u = fabs(x); + double v = fabs(y); + if(u > v) + return u * sqrt(1 + (v / u) * (v / u)); + return v * sqrt(1 + (u / v) * (u / v)); +} +float hypotf(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double hypotl(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double pow(double x, double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float powf(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double powl(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double sqrt(double x) { + auto sse_x = _mm_set_sd(x); + return _mm_cvtsd_f64(_mm_sqrt_sd(sse_x, sse_x)); +} +float sqrtf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double sqrtl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double erf(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float erff(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double erfl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double erfc(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float erfcf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double erfcl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double lgamma(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float lgammaf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double lgammal(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double tgamma(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float tgammaf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double tgammal(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double ceil(double x) { + auto soft_x = ieee754::extractNative(x); + auto result = ieee754::ceil(soft_x); + return ieee754::compileNative(result); +} +float ceilf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double ceill(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double floor(double x) { + auto soft_x = ieee754::extractNative(x); + auto result = ieee754::floor(soft_x); + return ieee754::compileNative(result); +} +float floorf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double floorl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double nearbyint(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float nearbyintf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double nearbyintl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double rint(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float rintf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double rintl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +long lrint(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long lrintf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long lrintl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +long long llrint(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long long llrintf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long long llrintl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double round(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float roundf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double roundl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +long lround(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long lroundf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long lroundl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +long long llround(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long long llroundf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long long llroundl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double trunc(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float truncf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double truncl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double fmod(double x, double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float fmodf(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double fmodl(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double remainder(double x, double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float remainderf(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double remainderl(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double remquo(double x, double y, int *quotient) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float remquof(float x, float y, int *quotient) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double remquol(long double x, long double y, int *quotient) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double copysign(double x, double sign) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float copysignf(float x, float sign) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double copysignl(long double x, long double sign) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double nan(const char *tag) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float nanf(const char *tag) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double nanl(const char *tag) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double nextafter(double x, double dir) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float nextafterf(float x, float dir) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double nextafterl(long double x, long double dir) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double nexttoward(double x, long double dir) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float nexttowardf(float x, long double dir) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double nexttowardl(long double x, long double dir) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double fdim(double x, double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float fdimf(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double fdiml(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double fmax(double x, double y) { + __ensure(isfinite(x) && isfinite(y)); + return x < y ? y : x; +} +float fmaxf(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double fmaxl(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double fmin(double x, double y) { + __ensure(isfinite(x) && isfinite(y)); + return x < y ? x : y; +} +float fminf(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double fminl(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +//gnu extension + +void sincos(double x, double *sx, double *cx) { + mlibc::infoLogger() << "mlibc: sincos() is not precise" << frg::endlog; + float sxf; + float cxf; + sincosf(x, &sxf, &cxf); + *sx = sxf; + *cx = cxf; +} + +void sincosf(float x, float *sx, float *cx) { + // This is a lazy implementation. + __ensure(sx); + __ensure(cx); + *sx = sinf(x); + *cx = cosf(x); +} +void sincosl(long double, long double *, long double *) { + __ensure(!"sincosl() not implemented"); + __builtin_unreachable(); +} + +double exp10(double) { + __ensure(!"exp10() not implemented"); + __builtin_unreachable(); +} +float exp10f(float) { + __ensure(!"exp10f() not implemented"); + __builtin_unreachable(); +} +long double exp10l(long double) { + __ensure(!"exp10l() not implemented"); + __builtin_unreachable(); +} + +double pow10(double) { + __ensure(!"pow10() not implemented"); + __builtin_unreachable(); +} +float pow10f(float) { + __ensure(!"pow10f() not implemented"); + __builtin_unreachable(); +} +long double pow10l(long double) { + __ensure(!"pow10l() not implemented"); + __builtin_unreachable(); +} + diff --git a/lib/mlibc/options/ansi/generic/signal-stubs.cpp b/lib/mlibc/options/ansi/generic/signal-stubs.cpp new file mode 100644 index 0000000..6da9dc1 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/signal-stubs.cpp @@ -0,0 +1,44 @@ + +#include +#include +#include + +#include +#include + +__sighandler signal(int sn, __sighandler handler) { + struct sigaction sa; + sa.sa_handler = handler; + sa.sa_flags = 0; + sa.sa_mask = 0; + struct sigaction old; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigaction, SIG_ERR); + if(int e = mlibc::sys_sigaction(sn, &sa, &old)){ + errno = e; + return SIG_ERR; + } + return old.sa_handler; +} + +int raise(int sig) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getpid && mlibc::sys_kill, -1); + pid_t pid = mlibc::sys_getpid(); + + if (int e = mlibc::sys_kill(pid, sig)) { + errno = e; + return -1; + } + + return 0; +} + +// This is a POSIX extension, but we have it in here for sigsetjmp +int sigprocmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigprocmask, -1); + if(int e = mlibc::sys_sigprocmask(how, set, retrieve); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/lib/mlibc/options/ansi/generic/stdio-stubs.cpp b/lib/mlibc/options/ansi/generic/stdio-stubs.cpp new file mode 100644 index 0000000..479a655 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/stdio-stubs.cpp @@ -0,0 +1,1270 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +template +struct PrintfAgent { + PrintfAgent(F *formatter, frg::va_struct *vsp) + : _formatter{formatter}, _vsp{vsp} { } + + frg::expected operator() (char c) { + _formatter->append(c); + return {}; + } + frg::expected operator() (const char *c, size_t n) { + _formatter->append(c, n); + return {}; + } + + frg::expected operator() (char t, frg::format_options opts, + frg::printf_size_mod szmod) { + switch(t) { + case 'c': + if (szmod == frg::printf_size_mod::long_size) { + char c_buf[sizeof(wchar_t)]; + auto c = static_cast(va_arg(_vsp->args, wint_t)); + mbstate_t shift_state = {}; + if (wcrtomb(c_buf, c, &shift_state) == size_t(-1)) + return frg::format_error::agent_error; + _formatter->append(c_buf); + break; + } + frg::do_printf_chars(*_formatter, t, opts, szmod, _vsp); + break; + case 'p': case 's': + frg::do_printf_chars(*_formatter, t, opts, szmod, _vsp); + break; + case 'd': case 'i': case 'o': case 'x': case 'X': case 'u': + frg::do_printf_ints(*_formatter, t, opts, szmod, _vsp); + break; + case 'f': case 'F': case 'g': case 'G': case 'e': case 'E': + frg::do_printf_floats(*_formatter, t, opts, szmod, _vsp); + break; + case 'm': + __ensure(!opts.fill_zeros); + __ensure(!opts.left_justify); + __ensure(!opts.alt_conversion); + __ensure(opts.minimum_width == 0); + __ensure(szmod == frg::printf_size_mod::default_size); + __ensure(!opts.precision); + _formatter->append(strerror(errno)); + break; + case 'n': { + __ensure(szmod == frg::printf_size_mod::default_size); + auto p = va_arg(_vsp->args, int *); + *p = _formatter->count; + break; + } + default: + mlibc::infoLogger() << "\e[31mmlibc: Unknown printf terminator '" + << t << "'\e[39m" << frg::endlog; + __ensure(!"Illegal printf terminator"); + } + + return {}; + } + +private: + F *_formatter; + frg::va_struct *_vsp; +}; + +struct StreamPrinter { + StreamPrinter(FILE *stream) + : stream(stream), count(0) { } + + void append(char c) { + fwrite_unlocked(&c, 1, 1, stream); + count++; + } + + void append(const char *str) { + fwrite_unlocked(str, strlen(str), 1, stream); + count += strlen(str); + } + + void append(const char *str, size_t n) { + fwrite_unlocked(str, n, 1, stream); + count += n; + } + + FILE *stream; + size_t count; +}; + +struct BufferPrinter { + BufferPrinter(char *buffer) + : buffer(buffer), count(0) { } + + void append(char c) { + buffer[count] = c; + count++; + } + + void append(const char *str) { + // TODO: use strcat + for(size_t i = 0; str[i]; i++) { + buffer[count] = str[i]; + count++; + } + } + + void append(const char *str, size_t n) { + // TODO: use strcat + for(size_t i = 0; i < n; i++) { + buffer[count] = str[i]; + count++; + } + } + + char *buffer; + size_t count; +}; + +struct LimitedPrinter { + LimitedPrinter(char *buffer, size_t limit) + : buffer(buffer), limit(limit), count(0) { } + + void append(char c) { + if(count < limit) + buffer[count] = c; + count++; + } + + void append(const char *str) { + // TODO: use strcat + for(size_t i = 0; str[i]; i++) + append(str[i]); + } + + void append(const char *str, size_t n) { + // TODO: use strcat + for(size_t i = 0; i < n; i++) + append(str[i]); + } + + char *buffer; + size_t limit; + size_t count; +}; + +struct ResizePrinter { + ResizePrinter() + : buffer(nullptr), limit(0), count(0) { } + + void expand() { + if(count == limit) { + auto new_limit = frg::max(2 * limit, size_t(16)); + auto new_buffer = reinterpret_cast(malloc(new_limit)); + __ensure(new_buffer); + memcpy(new_buffer, buffer, count); + free(buffer); + buffer = new_buffer; + limit = new_limit; + } + __ensure(count < limit); + } + + void append(char c) { + expand(); + buffer[count] = c; + count++; + } + + void append(const char *str) { + for(size_t i = 0; str[i]; i++) + append(str[i]); + } + + void append(const char *str, size_t n) { + for(size_t i = 0; i < n; i++) + append(str[i]); + } + + char *buffer; + size_t limit; + size_t count; +}; + +int remove(const char *filename) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_rmdir, -1); + if(int e = mlibc::sys_rmdir(filename); e) { + if (e == ENOTDIR) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_unlinkat, -1); + if(e = mlibc::sys_unlinkat(AT_FDCWD, filename, 0); e) { + errno = e; + return -1; + } + + return 0; + } + return -1; + } + + return 0; +} + +int rename(const char *path, const char *new_path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_rename, -1); + if(int e = mlibc::sys_rename(path, new_path); e) { + errno = e; + return -1; + } + return 0; +} + +int renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_renameat, -1); + if(int e = mlibc::sys_renameat(olddirfd, old_path, newdirfd, new_path); e) { + errno = e; + return -1; + } + return 0; +} + +FILE *tmpfile(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *tmpnam(char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// fflush() is provided by the POSIX sublibrary +// fopen() is provided by the POSIX sublibrary +FILE *freopen(const char *__restrict path, const char *__restrict mode, FILE *__restrict f) { + auto file = static_cast(f); + frg::unique_lock lock(file->_lock); + + if(file->reopen(path, mode) == -1) { + errno = EINVAL; + return nullptr; + } + + return f; +} + +void setbuf(FILE *__restrict stream, char *__restrict buffer) { + setvbuf(stream, buffer, buffer ? _IOFBF : _IONBF, BUFSIZ); +} +// setvbuf() is provided by the POSIX sublibrary + +void setlinebuf(FILE *stream) { + setvbuf(stream, NULL, _IOLBF, 0); +} + +void setbuffer(FILE *f, char *buf, size_t size) { + setvbuf(f, buf, buf ? _IOFBF : _IONBF, size); +} + +int fprintf(FILE *__restrict stream, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vfprintf(stream, format, args); + va_end(args); + return result; +} + +int fscanf(FILE *__restrict stream, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vfscanf(stream, format, args); + va_end(args); + return result; +} + +int printf(const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vfprintf(stdout, format, args); + va_end(args); + return result; +} + +namespace { + enum { + SCANF_TYPE_CHAR, + SCANF_TYPE_SHORT, + SCANF_TYPE_INTMAX, + SCANF_TYPE_L, + SCANF_TYPE_LL, + SCANF_TYPE_PTRDIFF, + SCANF_TYPE_SIZE_T, + SCANF_TYPE_INT + }; +} + +static void store_int(void *dest, unsigned int size, unsigned long long i) { + switch (size) { + case SCANF_TYPE_CHAR: + *(char *)dest = i; + break; + case SCANF_TYPE_SHORT: + *(short *)dest = i; + break; + case SCANF_TYPE_INTMAX: + *(intmax_t *)dest = i; + break; + case SCANF_TYPE_L: + *(long *)dest = i; + break; + case SCANF_TYPE_LL: + *(long long *)dest = i; + break; + case SCANF_TYPE_PTRDIFF: + *(ptrdiff_t *)dest = i; + break; + case SCANF_TYPE_SIZE_T: + *(size_t *)dest = i; + break; + /* fallthrough */ + case SCANF_TYPE_INT: + default: + *(int *)dest = i; + break; + } +} + +template +static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) { + int match_count = 0; + for (; *fmt; fmt++) { + + if (isspace(*fmt)) { + while (isspace(fmt[1])) fmt++; + while (isspace(handler.look_ahead())) + handler.consume(); + continue; + } + + if (*fmt != '%' || fmt[1] == '%') { + if (*fmt == '%') + fmt++; + char c = handler.consume(); + if (c != *fmt) + break; + continue; + } + + void *dest = NULL; + /* %n$ format */ + if (isdigit(*fmt) && fmt[1] == '$') { + /* TODO: dest = get_arg_at_pos(args, *fmt -'0'); */ + fmt += 3; + } else { + if (fmt[1] != '*') { + dest = va_arg(args, void*); + } + fmt++; + } + + int width = 0; + if (*fmt == '*') { + fmt++; + } else if (*fmt == '\'') { + /* TODO: numeric seperators locale stuff */ + mlibc::infoLogger() << "do_scanf: \' not implemented!" << frg::endlog; + fmt++; + continue; + } else if (*fmt == 'm') { + /* TODO: allocate buffer for them */ + mlibc::infoLogger() << "do_scanf: m not implemented!" << frg::endlog; + fmt++; + continue; + } else if (*fmt >= '0' && *fmt <= '9') { + /* read in width specifier */ + width = 0; + while (*fmt >= '0' && *fmt <= '9') { + width = width * 10 + (*fmt - '0'); + fmt++; + continue; + } + } + + /* type modifiers */ + unsigned int type = SCANF_TYPE_INT; + unsigned int base = 10; + switch (*fmt) { + case 'h': { + if (fmt[1] == 'h') { + type = SCANF_TYPE_CHAR; + fmt += 2; + break; + } + type = SCANF_TYPE_SHORT; + fmt++; + break; + } + case 'j': { + type = SCANF_TYPE_INTMAX; + fmt++; + break; + } + case 'l': { + if (fmt[1] == 'l') { + type = SCANF_TYPE_LL; + fmt += 2; + break; + } + type = SCANF_TYPE_L; + fmt++; + break; + } + case 'L': { + type = SCANF_TYPE_LL; + fmt++; + break; + } + case 'q': { + type = SCANF_TYPE_LL; + fmt++; + break; + } + case 't': { + type = SCANF_TYPE_PTRDIFF; + fmt++; + break; + } + case 'z': { + type = SCANF_TYPE_SIZE_T; + fmt++; + break; + } + } + + // Leading whitespace is skipped for most conversions except these. + if (*fmt != 'c' && *fmt != '[' && *fmt != 'n') { + while (isspace(handler.look_ahead())) + handler.consume(); + } + + switch (*fmt) { + case 'd': + case 'u': + base = 10; + [[fallthrough]]; + case 'i': { + bool is_negative = false; + unsigned long long res = 0; + + if((*fmt == 'i' || *fmt == 'd') && handler.look_ahead() == '-') { + handler.consume(); + is_negative = true; + } + + if(*fmt == 'i' && handler.look_ahead() == '0') { + handler.consume(); + if(handler.look_ahead() == 'x') { + handler.consume(); + base = 16; + } else { + base = 8; + } + } + + char c = handler.look_ahead(); + switch (base) { + case 10: + if(!isdigit(c)) + return match_count; + while (c >= '0' && c <= '9') { + handler.consume(); + res = res * 10 + (c - '0'); + c = handler.look_ahead(); + } + break; + case 16: + if (c == '0') { + handler.consume(); + c = handler.look_ahead(); + if (c == 'x') { + handler.consume(); + c = handler.look_ahead(); + } + } + while (true) { + if (c >= '0' && c <= '9') { + handler.consume(); + res = res * 16 + (c - '0'); + } else if (c >= 'a' && c <= 'f') { + handler.consume(); + res = res * 16 + (c - 'a' + 10); + } else if (c >= 'A' && c <= 'F') { + handler.consume(); + res = res * 16 + (c - 'A' + 10); + } else { + break; + } + c = handler.look_ahead(); + } + break; + case 8: + while (c >= '0' && c <= '7') { + handler.consume(); + res = res * 8 + (c - '0'); + c = handler.look_ahead(); + } + break; + } + if (dest) { + if(is_negative) + store_int(dest, type, -res); + else + store_int(dest, type, res); + } + break; + } + case 'o': { + unsigned long long res = 0; + char c = handler.look_ahead(); + while (c >= '0' && c <= '7') { + handler.consume(); + res = res * 8 + (c - '0'); + c = handler.look_ahead(); + } + if (dest) + store_int(dest, type, res); + break; + } + case 'x': + case 'X': { + unsigned long long res = 0; + char c = handler.look_ahead(); + if (c == '0') { + handler.consume(); + c = handler.look_ahead(); + if (c == 'x') { + handler.consume(); + c = handler.look_ahead(); + } + } + while (true) { + if (c >= '0' && c <= '9') { + handler.consume(); + res = res * 16 + (c - '0'); + } else if (c >= 'a' && c <= 'f') { + handler.consume(); + res = res * 16 + (c - 'a' + 10); + } else if (c >= 'A' && c <= 'F') { + handler.consume(); + res = res * 16 + (c - 'A' + 10); + } else { + break; + } + c = handler.look_ahead(); + } + if (dest) + store_int(dest, type, res); + break; + } + case 's': { + char *typed_dest = (char *)dest; + char c = handler.look_ahead(); + int count = 0; + while (c && !isspace(c)) { + handler.consume(); + if (typed_dest) + typed_dest[count] = c; + c = handler.look_ahead(); + count++; + if (width && count >= width) + break; + } + if (typed_dest) + typed_dest[count] = '\0'; + break; + } + case 'c': { + char *typed_dest = (char *)dest; + char c = handler.look_ahead(); + int count = 0; + if (!width) + width = 1; + while (c && count < width) { + handler.consume(); + if (typed_dest) + typed_dest[count] = c; + c = handler.look_ahead(); + count++; + } + break; + } + case '[': { + fmt++; + int invert = 0; + if (*fmt == '^') { + invert = 1; + fmt++; + } + + char scanset[257]; + memset(&scanset[0], invert, sizeof(char) * 257); + scanset[0] = '\0'; + + if (*fmt == '-') { + fmt++; + scanset[1+'-'] = 1 - invert; + } else if (*fmt == ']') { + fmt++; + scanset[1+']'] = 1 - invert; + } + + for (; *fmt != ']'; fmt++) { + if (!*fmt) return EOF; + if (*fmt == '-' && *fmt != ']') { + fmt++; + for (char c = *(fmt - 2); c < *fmt; c++) + scanset[1 + c] = 1 - invert; + } + scanset[1 + *fmt] = 1 - invert; + } + + char *typed_dest = (char *)dest; + int count = 0; + char c = handler.look_ahead(); + while (c && (!width || count < width)) { + handler.consume(); + if (!scanset[1 + c]) + break; + if (typed_dest) + typed_dest[count] = c; + c = handler.look_ahead(); + count++; + } + if (typed_dest) + typed_dest[count] = '\0'; + break; + } + case 'p': { + unsigned long long res = 0; + char c = handler.look_ahead(); + if (c == '0') { + handler.consume(); + c = handler.look_ahead(); + if (c == 'x') { + handler.consume(); + c = handler.look_ahead(); + } + } + while (true) { + if (c >= '0' && c <= '9') { + handler.consume(); + res = res * 16 + (c - '0'); + } else if (c >= 'a' && c <= 'f') { + handler.consume(); + res = res * 16 + (c - 'a'); + } else if (c >= 'A' && c <= 'F') { + handler.consume(); + res = res * 16 + (c - 'A'); + } else { + break; + } + c = handler.look_ahead(); + } + void **typed_dest = (void **)dest; + *typed_dest = (void *)(uintptr_t)res; + break; + } + case 'n': { + int *typed_dest = (int *)dest; + if (typed_dest) + *typed_dest = handler.num_consumed; + continue; + } + } + if (dest) match_count++; + } + return match_count; +} + +int scanf(const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vfscanf(stdin, format, args); + va_end(args); + return result; +} + +int snprintf(char *__restrict buffer, size_t max_size, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vsnprintf(buffer, max_size, format, args); + va_end(args); + return result; +} + +int sprintf(char *__restrict buffer, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vsprintf(buffer, format, args); + va_end(args); + return result; +} + +int sscanf(const char *__restrict buffer, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + + int result = vsscanf(buffer, format, args); + + va_end(args); + return result; +} + +int vfprintf(FILE *__restrict stream, const char *__restrict format, __builtin_va_list args) { + frg::va_struct vs; + frg::arg arg_list[NL_ARGMAX + 1]; + vs.arg_list = arg_list; + va_copy(vs.args, args); + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + StreamPrinter p{stream}; +// mlibc::infoLogger() << "printf(" << format << ")" << frg::endlog; + auto res = frg::printf_format(PrintfAgent{&p, &vs}, format, &vs); + if (!res) + return -static_cast(res.error()); + + return p.count; +} + +int vfscanf(FILE *__restrict stream, const char *__restrict format, __builtin_va_list args) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + + struct { + char look_ahead() { + char c; + size_t actual_size; + file->read(&c, 1, &actual_size); + if (actual_size) + file->unget(c); + return actual_size ? c : 0; + } + + char consume() { + char c; + size_t actual_size; + file->read(&c, 1, &actual_size); + if (actual_size) + num_consumed++; + return actual_size ? c : 0; + } + + mlibc::abstract_file *file; + int num_consumed; + } handler = {file, 0}; + + return do_scanf(handler, format, args); +} + +int vprintf(const char *__restrict format, __builtin_va_list args){ + return vfprintf(stdout, format, args); +} + +int vscanf(const char *__restrict, __builtin_va_list) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int vsnprintf(char *__restrict buffer, size_t max_size, + const char *__restrict format, __builtin_va_list args) { + frg::va_struct vs; + frg::arg arg_list[NL_ARGMAX + 1]; + vs.arg_list = arg_list; + va_copy(vs.args, args); + LimitedPrinter p{buffer, max_size ? max_size - 1 : 0}; +// mlibc::infoLogger() << "printf(" << format << ")" << frg::endlog; + auto res = frg::printf_format(PrintfAgent{&p, &vs}, format, &vs); + if (!res) + return -static_cast(res.error()); + if (max_size) + p.buffer[frg::min(max_size - 1, p.count)] = 0; + return p.count; +} + +int vsprintf(char *__restrict buffer, const char *__restrict format, __builtin_va_list args) { + frg::va_struct vs; + frg::arg arg_list[NL_ARGMAX + 1]; + vs.arg_list = arg_list; + va_copy(vs.args, args); + BufferPrinter p(buffer); +// mlibc::infoLogger() << "printf(" << format << ")" << frg::endlog; + auto res = frg::printf_format(PrintfAgent{&p, &vs}, format, &vs); + if (!res) + return -static_cast(res.error()); + p.buffer[p.count] = 0; + return p.count; +} + +int vsscanf(const char *__restrict buffer, const char *__restrict format, __builtin_va_list args) { + struct { + char look_ahead() { + return *buffer; + } + + char consume() { + num_consumed++; + return *buffer++; + } + + const char *buffer; + int num_consumed; + } handler = {buffer, 0}; + + int result = do_scanf(handler, format, args); + + return result; +} + +int fwprintf(FILE *__restrict, const wchar_t *__restrict, ...) MLIBC_STUB_BODY +int fwscanf(FILE *__restrict, const wchar_t *__restrict, ...) MLIBC_STUB_BODY +int vfwprintf(FILE *__restrict, const wchar_t *__restrict, __builtin_va_list) MLIBC_STUB_BODY +int vfwscanf(FILE *__restrict, const wchar_t *__restrict, __builtin_va_list) MLIBC_STUB_BODY + +int swprintf(wchar_t *__restrict, size_t, const wchar_t *__restrict, ...) MLIBC_STUB_BODY +int swscanf(wchar_t *__restrict, size_t, const wchar_t *__restrict, ...) MLIBC_STUB_BODY +int vswprintf(wchar_t *__restrict, size_t, const wchar_t *__restrict, __builtin_va_list) MLIBC_STUB_BODY +int vswscanf(wchar_t *__restrict, size_t, const wchar_t *__restrict, __builtin_va_list) MLIBC_STUB_BODY + +int wprintf(const wchar_t *__restrict, ...) MLIBC_STUB_BODY +int wscanf(const wchar_t *__restrict, ...) MLIBC_STUB_BODY +int vwprintf(const wchar_t *__restrict, __builtin_va_list) MLIBC_STUB_BODY +int vwscanf(const wchar_t *__restrict, __builtin_va_list) MLIBC_STUB_BODY + +int fgetc(FILE *stream) { + char c; + auto bytes_read = fread(&c, 1, 1, stream); + if(bytes_read != 1) + return EOF; + return c; +} + +char *fgets(char *__restrict buffer, size_t max_size, FILE *__restrict stream) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + return fgets_unlocked(buffer, max_size, stream); +} + +int fputc_unlocked(int c, FILE *stream) { + char d = c; + if(fwrite_unlocked(&d, 1, 1, stream) != 1) + return EOF; + return 1; +} + +int fputc(int c, FILE *stream) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + return fputc_unlocked(c, stream); +} + +int fputs_unlocked(const char *__restrict string, FILE *__restrict stream) { + if(fwrite_unlocked(string, strlen(string), 1, stream) != 1) + return EOF; + return 1; +} + +int fputs(const char *__restrict string, FILE *__restrict stream) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + return fputs_unlocked(string, stream); +} + +int getc_unlocked(FILE *stream) { + return fgetc_unlocked(stream); +} + +int getc(FILE *stream) { + return fgetc(stream); +} + +int getchar_unlocked(void) { + return fgetc_unlocked(stdin); +} + +int getchar(void) { + return fgetc(stdin); +} + +char *gets(char *s){ + return fgets(s, SIZE_MAX, stdin); +} + +int putc_unlocked(int c, FILE *stream) { + char d = c; + if(fwrite_unlocked(&d, 1, 1, stream) != 1) + return EOF; + return c; +} + +int putc(int c, FILE *stream) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + return putc_unlocked(c, stream); +} + +int putchar_unlocked(int c) { + return putc_unlocked(c, stdout); +} + +int putchar(int c) { + auto file = static_cast(stdout); + frg::unique_lock lock(file->_lock); + return putchar_unlocked(c); +} + +int puts(const char *string) { + auto file = static_cast(stdout); + frg::unique_lock lock(file->_lock); + + size_t progress = 0; + size_t len = strlen(string); + while(progress < len) { + size_t chunk; + if(file->write(string + progress, + len - progress, &chunk)) { + return EOF; + }else if(!chunk) { + return EOF; + } + + progress += chunk; + } + + size_t unused; + if (!file->write("\n", 1, &unused)) { + return EOF; + } + + return 1; +} + +wint_t fgetwc(FILE *) MLIBC_STUB_BODY +wchar_t *fgetws(wchar_t *__restrict, int, FILE *__restrict) MLIBC_STUB_BODY +wint_t fputwc(wchar_t, FILE *) MLIBC_STUB_BODY +int fputws(const wchar_t *__restrict, FILE *__restrict) MLIBC_STUB_BODY +int fwide(FILE *, int) MLIBC_STUB_BODY +wint_t getwc(FILE *) MLIBC_STUB_BODY +wint_t getwchar(void) MLIBC_STUB_BODY +wint_t putwc(wchar_t, FILE *) MLIBC_STUB_BODY +wint_t putwchar(wchar_t) MLIBC_STUB_BODY +wint_t ungetwc(wint_t, FILE *) MLIBC_STUB_BODY + +size_t fread(void *buffer, size_t size, size_t count, FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + return fread_unlocked(buffer, size, count, file_base); +} + +size_t fwrite(const void *buffer, size_t size , size_t count, FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + return fwrite_unlocked(buffer, size, count, file_base); +} + +int fgetpos(FILE *__restrict, fpos_t *__restrict) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// fseek() is provided by the POSIX sublibrary +int fsetpos(FILE *, const fpos_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +// ftell() is provided by the POSIX sublibrary + +void clearerr(FILE *file_base) { + file_base->__status_bits = 0; +} + +int feof(FILE *file_base) { + return file_base->__status_bits & __MLIBC_EOF_BIT; +} + +int ferror(FILE *file_base) { + return file_base->__status_bits & __MLIBC_ERROR_BIT; +} + +void perror(const char *string) { + int error = errno; + if (string && *string) { + fprintf(stderr, "%s: ", string); + } + fprintf(stderr, "%s\n", strerror(error)); +} + +// POSIX extensions. + +ssize_t getline(char **line, size_t *n, FILE *stream) { + return getdelim(line, n, '\n', stream); +} + +ssize_t getdelim(char **line, size_t *n, int delim, FILE *stream) { + // Otherwise, we cannot store the buffer / size. + if(!line || !n) { + errno = EINVAL; + return -1; + } + + char *buffer = *line; + /* set the starting capacity to 512 if buffer = NULL */ + size_t capacity = (!buffer) ? 512 : *n; + size_t nwritten = 0; + + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + + // Avoid allocating if we've already hit the end + auto c = fgetc_unlocked(stream); + if (c == EOF || ferror(stream)) { + return -1; + } else { + file->unget(c); + } + + while (true) { + // Fill the buffer + while (buffer && capacity > 0 && nwritten < capacity - 1) { + auto c = fgetc_unlocked(stream); + if (ferror(stream)) { + return -1; + } else if (c == EOF) { + buffer[nwritten] = 0; + return nwritten; + } + + buffer[nwritten++] = c; + + if (c == delim) { + buffer[nwritten] = 0; + return nwritten; + } + } + + // Double the size of the buffer (but make sure it's at least 1024) + capacity = (capacity >= 1024) ? capacity * 2 : 1024; + buffer = reinterpret_cast(getAllocator().reallocate(*line, capacity)); + if (!buffer) { + errno = ENOMEM; + return -1; + } + + *line = buffer; + *n = capacity; + } +} + +// GLIBC extensions. + +int asprintf(char **out, const char *format, ...) { + va_list args; + va_start(args, format); + int result = vasprintf(out, format, args); + va_end(args); + return result; +} + +int vasprintf(char **out, const char *format, __builtin_va_list args) { + frg::va_struct vs; + frg::arg arg_list[NL_ARGMAX + 1]; + vs.arg_list = arg_list; + va_copy(vs.args, args); + ResizePrinter p; +// mlibc::infoLogger() << "printf(" << format << ")" << frg::endlog; + auto res = frg::printf_format(PrintfAgent{&p, &vs}, format, &vs); + if (!res) + return -static_cast(res.error()); + p.expand(); + p.buffer[p.count] = 0; + *out = p.buffer; + return p.count; +} + +// Linux unlocked I/O extensions. + +void flockfile(FILE *file_base) { + static_cast(file_base)->_lock.lock(); +} + +void funlockfile(FILE *file_base) { + static_cast(file_base)->_lock.unlock(); +} + +int ftrylockfile(FILE *file_base) { + static_cast(file_base)->_lock.try_lock(); + return 0; +} + +void clearerr_unlocked(FILE *file_base) { + file_base->__status_bits = 0; +} + +int feof_unlocked(FILE *file_base) { + return file_base->__status_bits & __MLIBC_EOF_BIT; +} + +int ferror_unlocked(FILE *file_base) { + return file_base->__status_bits & __MLIBC_ERROR_BIT; +} + +int fgetc_unlocked(FILE *stream) { + unsigned char d; + if(fread_unlocked(&d, 1, 1, stream) != 1) + return EOF; + return (int)d; +} + +size_t fread_unlocked(void *buffer, size_t size, size_t count, FILE *file_base) { + auto file = static_cast(file_base); + if(!size || !count) + return 0; + + // Distinguish two cases here: If the object size is one, we perform byte-wise reads. + // Otherwise, we try to read each object individually. + if(size == 1) { + size_t progress = 0; + while(progress < count) { + size_t chunk; + if(int e = file->read((char *)buffer + progress, + count - progress, &chunk)) { + errno = e; + return 0; + }else if(!chunk) { + // TODO: Handle eof. + break; + } + + progress += chunk; + } + + return progress; + }else{ + for(size_t i = 0; i < count; i++) { + size_t progress = 0; + while(progress < size) { + size_t chunk; + if(int e = file->read((char *)buffer + i * size + progress, + size - progress, &chunk)) { + errno = e; + return 0; + }else if(!chunk) { + // TODO: Handle eof. + break; + } + + progress += chunk; + } + + if(progress < size) + return i; + } + + return count; + } +} + +size_t fwrite_unlocked(const void *buffer, size_t size, size_t count, FILE *file_base) { + auto file = static_cast(file_base); + if(!size || !count) + return 0; + + // Distinguish two cases here: If the object size is one, we perform byte-wise writes. + // Otherwise, we try to write each object individually. + if(size == 1) { + size_t progress = 0; + while(progress < count) { + size_t chunk; + if(file->write((const char *)buffer + progress, + count - progress, &chunk)) { + // TODO: Handle I/O errors. + mlibc::infoLogger() << "mlibc: fwrite() I/O errors are not handled" + << frg::endlog; + break; + }else if(!chunk) { + // TODO: Handle eof. + break; + } + + progress += chunk; + } + + return progress; + }else{ + for(size_t i = 0; i < count; i++) { + size_t progress = 0; + while(progress < size) { + size_t chunk; + if(file->write((const char *)buffer + i * size + progress, + size - progress, &chunk)) { + // TODO: Handle I/O errors. + mlibc::infoLogger() << "mlibc: fwrite() I/O errors are not handled" + << frg::endlog; + break; + }else if(!chunk) { + // TODO: Handle eof. + break; + } + + progress += chunk; + } + + if(progress < size) + return i; + } + + return count; + } +} + +char *fgets_unlocked(char *__restrict buffer, int max_size, FILE *stream) { + __ensure(max_size > 0); + for(int i = 0; ; i++) { + if(i == max_size - 1) { + buffer[i] = 0; + return buffer; + } + + auto c = fgetc_unlocked(stream); + + // If fgetc() fails, there is either an EOF or an I/O error. + if(c == EOF) { + if(i) { + buffer[i] = 0; + return buffer; + } else { + // In this case, the buffer is not changed. + return nullptr; + } + } else { + buffer[i] = c; + } + + if(c == '\n') { + buffer[i + 1] = 0; + return buffer; + } + } +} diff --git a/lib/mlibc/options/ansi/generic/stdlib-stubs.cpp b/lib/mlibc/options/ansi/generic/stdlib-stubs.cpp new file mode 100644 index 0000000..86b8a9a --- /dev/null +++ b/lib/mlibc/options/ansi/generic/stdlib-stubs.cpp @@ -0,0 +1,511 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if __MLIBC_POSIX_OPTION +#include +#endif // __MLIBC_POSIX_OPTION + +extern "C" int __cxa_atexit(void (*function)(void *), void *argument, void *dso_tag); +void __mlibc_do_finalize(); + +namespace { + // According to the first paragraph of [C11 7.22.7], + // mblen(), mbtowc() and wctomb() have an internal state. + // The string functions mbstowcs() and wcstombs() do *not* have this state. + thread_local __mlibc_mbstate mblen_state = __MLIBC_MBSTATE_INITIALIZER; + thread_local __mlibc_mbstate mbtowc_state = __MLIBC_MBSTATE_INITIALIZER; +} + +double atof(const char *string) { + return strtod(string, NULL); +} +int atoi(const char *string) { + return strtol(string, nullptr, 10); +} +long atol(const char *string) { + return strtol(string, nullptr, 10); +} +long long atoll(const char *string) { + return strtoll(string, nullptr, 10); +} + +// POSIX extensions but are here for simplicities sake. Forward declaration is here +// to avoid exporting sigprocmask when posix is disabled. +int sigprocmask(int, const sigset_t *__restrict, sigset_t *__restrict); +extern "C" { + __attribute__((__returns_twice__)) int __sigsetjmp(sigjmp_buf buffer, int savesigs) { + buffer[0].savesigs = savesigs; + if (savesigs) + sigprocmask(0, NULL, &buffer[0].sigset); + return 0; + } +} + +__attribute__((__noreturn__)) void siglongjmp(sigjmp_buf buffer, int value) { + if (buffer[0].savesigs) + sigprocmask(SIG_SETMASK, &buffer[0].sigset, NULL); + jmp_buf b; + b[0].reg_state = buffer[0].reg_state; + longjmp(b, value); +} + +double strtod(const char *__restrict string, char **__restrict end) { + return mlibc::strtofp(string, end); +} +float strtof(const char *__restrict string, char **__restrict end) { + return mlibc::strtofp(string, end); +} +long double strtold(const char *__restrict string, char **__restrict end) { + return mlibc::strtofp(string, end); +} + +long strtol(const char *__restrict string, char **__restrict end, int base) { + return mlibc::stringToInteger(string, end, base); +} +long long strtoll(const char *__restrict string, char **__restrict end, int base) { + return mlibc::stringToInteger(string, end, base); +} +unsigned long strtoul(const char *__restrict string, char **__restrict end, int base) { + return mlibc::stringToInteger(string, end, base); +} +unsigned long long strtoull(const char *__restrict string, char **__restrict end, int base) { + return mlibc::stringToInteger(string, end, base); +} + +frg::mt19937 __mlibc_rand_engine; + +int rand() { + // rand() is specified to return a positive number so we discard the MSB. + return static_cast(__mlibc_rand_engine() & 0x7FFFFFFF); +} + +static unsigned temper(unsigned x) { + x ^= x >> 11; + x ^= x << 7 & 0x9D2C5680; + x ^= x << 15 & 0xEFC60000; + x ^= x >> 18; + return x; +} + +int rand_r(unsigned *seed) { + return temper(*seed = *seed * 1103515245 + 12345) / 2; +} + +void srand(unsigned int s) { + __mlibc_rand_engine.seed(s); +} + +void *aligned_alloc(size_t alignment, size_t size) { + void *ptr; + + // alignment must be a power of two, and size % alignment must be 0 + if (alignment & (alignment - 1) || size & (alignment - 1)) { + errno = EINVAL; + return nullptr; + } + + // posix_memalign requires that the alignment is a multiple of sizeof(void *) + if (alignment < sizeof(void *)) + alignment = sizeof(void *); + + int ret = posix_memalign(&ptr, alignment, size); + if (ret) { + errno = ret; + return nullptr; + } + return ptr; + +} +void *calloc(size_t count, size_t size) { + // we want to ensure that count*size > SIZE_MAX doesn't happen + // to prevent overflowing, we divide both sides of the inequality by size and check with that + if(size && count > (SIZE_MAX / size)) { + errno = EINVAL; + return NULL; + } + + // TODO: this could be done more efficient if the OS gives us already zero'd pages + void *ptr = malloc(count * size); + if(!ptr) + return nullptr; + memset(ptr, 0, count * size); + return ptr; +} +// free() is provided by the platform +// malloc() is provided by the platform +// realloc() is provided by the platform + +void abort(void) { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGABRT); + if (mlibc::sys_sigprocmask) { + mlibc::sys_sigprocmask(SIG_UNBLOCK, &set, nullptr); + } + + raise(SIGABRT); + + sigfillset(&set); + sigdelset(&set, SIGABRT); + if (mlibc::sys_sigprocmask) { + mlibc::sys_sigprocmask(SIG_SETMASK, &set, nullptr); + } + + struct sigaction sa; + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + + if (mlibc::sys_sigaction(SIGABRT, &sa, nullptr)) + mlibc::panicLogger() << "mlibc: sigaction failed in abort" << frg::endlog; + + if (raise(SIGABRT)) + mlibc::panicLogger() << "mlibc: raise failed in abort" << frg::endlog; + + __builtin_trap(); +} + +int atexit(void (*func)(void)) { + // TODO: the function pointer types are not compatible; + // the conversion here is undefined behavior. its fine to do + // this on the x86_64 abi though. + __cxa_atexit((void (*) (void *))func, nullptr, nullptr); + return 0; +} +int at_quick_exit(void (*func)(void)) { + (void)func; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void exit(int status) { + __mlibc_do_finalize(); + mlibc::sys_exit(status); +} + +void _Exit(int status) { + mlibc::sys_exit(status); +} + +// getenv() is provided by POSIX +void quick_exit(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +extern char **environ; + +int system(const char *command) { + int status = -1; + pid_t child; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fork && mlibc::sys_waitpid && + mlibc::sys_execve && mlibc::sys_sigprocmask && mlibc::sys_sigaction, -1); + +#if __MLIBC_POSIX_OPTION + pthread_testcancel(); +#endif // __MLIBC_POSIX_OPTION + + if (!command) { + return 1; + } + + struct sigaction new_sa, old_int, old_quit; + sigset_t new_mask, old_mask; + + new_sa.sa_handler = SIG_IGN; + new_sa.sa_flags = 0; + sigemptyset(&new_sa.sa_mask); + mlibc::sys_sigaction(SIGINT, &new_sa, &old_int); + mlibc::sys_sigaction(SIGQUIT, &new_sa, &old_quit); + + sigemptyset(&new_mask); + sigaddset(&new_mask, SIGCHLD); + mlibc::sys_sigprocmask(SIG_BLOCK, &new_mask, &old_mask); + + if (int e = mlibc::sys_fork(&child)) { + errno = e; + } else if (!child) { + mlibc::sys_sigaction(SIGINT, &old_int, nullptr); + mlibc::sys_sigaction(SIGQUIT, &old_quit, nullptr); + mlibc::sys_sigprocmask(SIG_SETMASK, &old_mask, nullptr); + + const char *args[] = { + "sh", "-c", command, nullptr + }; + + mlibc::sys_execve("/bin/sh", const_cast(args), environ); + _Exit(127); + } else { + int err; + pid_t unused; + + while ((err = mlibc::sys_waitpid(child, &status, 0, NULL, &unused)) < 0) { + if (err == EINTR) + continue; + + errno = err; + status = -1; + } + } + + mlibc::sys_sigaction(SIGINT, &old_int, nullptr); + mlibc::sys_sigaction(SIGQUIT, &old_quit, nullptr); + mlibc::sys_sigprocmask(SIG_SETMASK, &old_mask, nullptr); + + return status; +} + +char *mktemp(char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void *bsearch(const void *key, const void *base, size_t count, size_t size, + int (*compare)(const void *, const void *)) { + // Invariant: Element is in the interval [i, j). + size_t i = 0; + size_t j = count; + + while(i < j) { + size_t k = (j - i) / 2; + auto element = reinterpret_cast(base) + (i + k) * size; + auto res = compare(key, element); + if(res < 0) { + j = i + k; + }else if(res > 0) { + i = i + k + 1; + }else{ + return const_cast(element); + } + } + __ensure(i == j); + + return nullptr; +} + +static int qsort_callback(const void *a, const void *b, void *arg) { + auto compare = reinterpret_cast(arg); + + return compare(a, b); +} + +void qsort(void *base, size_t count, size_t size, + int (*compare)(const void *, const void *)) { + return qsort_r(base, count, size, qsort_callback, (void *) compare); +} + +void qsort_r(void *base, size_t count, size_t size, + int (*compare)(const void *, const void *, void *), + void *arg) { + // TODO: implement a faster sort + for(size_t i = 0; i < count; i++) { + void *u = (void *)((uintptr_t)base + i * size); + for(size_t j = i + 1; j < count; j++) { + void *v = (void *)((uintptr_t)base + j * size); + if(compare(u, v, arg) <= 0) + continue; + + // swap u and v + char *u_bytes = (char *)u; + char *v_bytes = (char *)v; + for(size_t k = 0; k < size; k++) { + char temp = u_bytes[k]; + u_bytes[k] = v_bytes[k]; + v_bytes[k] = temp; + } + } + } +} + +int abs(int num) { + return num < 0 ? -num : num; +} + +long labs(long num) { + return num < 0 ? -num : num; +} + +long long llabs(long long num) { + return num < 0 ? -num : num; +} + +div_t div(int number, int denom) { + div_t r; + r.quot = number / denom; + r.rem = number % denom; + return r; +} + +ldiv_t ldiv(long number, long denom) { + ldiv_t r; + r.quot = number / denom; + r.rem = number % denom; + return r; +} + +lldiv_t lldiv(long long number, long long denom) { + lldiv_t r; + r.quot = number / denom; + r.rem = number % denom; + return r; +} + +int mblen(const char *mbs, size_t mb_limit) { + auto cc = mlibc::current_charcode(); + wchar_t wc; + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + mlibc::code_seq wseq{&wc, &wc + 1}; + + if(!mbs) { + mblen_state = __MLIBC_MBSTATE_INITIALIZER; + return cc->has_shift_states; + } + + if(auto e = cc->decode_wtranscode(nseq, wseq, mblen_state); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return nseq.it - mbs; +} + +int mbtowc(wchar_t *__restrict wc, const char *__restrict mb, size_t max_size) { + auto cc = mlibc::current_charcode(); + __ensure(max_size); + + // If wc is NULL, decode into a single local character which we discard + // to obtain the length. + wchar_t tmp_wc; + if (!wc) + wc = &tmp_wc; + + if (mb) { + if (*mb) { + mlibc::code_seq wseq{wc, wc + 1}; + mlibc::code_seq nseq{mb, mb + max_size}; + auto e = cc->decode_wtranscode(nseq, wseq, mbtowc_state); + switch(e) { + // We keep the state, so we can simply return here. + case mlibc::charcode_error::input_underflow: + case mlibc::charcode_error::null: { + return nseq.it - mb; + } + case mlibc::charcode_error::illegal_input: { + errno = -EILSEQ; + return -1; + } + case mlibc::charcode_error::dirty: { + mlibc::panicLogger() << "decode_wtranscode() charcode_error::dirty errors are not handled" << frg::endlog; + break; + } + case mlibc::charcode_error::output_overflow: { + mlibc::panicLogger() << "decode_wtranscode() charcode_error::output_overflow errors are not handled" << frg::endlog; + break; + } + } + __builtin_unreachable(); + } else { + *wc = L'\0'; + return 0; // When mbs is a null byte, return 0 + } + } else { + mblen_state = __MLIBC_MBSTATE_INITIALIZER; + return cc->has_shift_states; + } +} + +int wctomb(char *, wchar_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +size_t mbstowcs(wchar_t *wcs, const char *mbs, size_t wc_limit) { + auto cc = mlibc::current_charcode(); + __mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER; + mlibc::code_seq nseq{mbs, nullptr}; + mlibc::code_seq wseq{wcs, wcs + wc_limit}; + + if(!wcs) { + size_t size; + if(auto e = cc->decode_wtranscode_length(nseq, &size, st); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + if(auto e = cc->decode_wtranscode(nseq, wseq, st); e != mlibc::charcode_error::null) { + __ensure(!"decode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + size_t n = wseq.it - wcs; + if(n < wc_limit) // Null-terminate resulting wide string. + wcs[n] = 0; + return n; + } +} + +size_t wcstombs(char *mb_string, const wchar_t *wc_string, size_t max_size) { + return wcsrtombs(mb_string, &wc_string, max_size, 0); +} + +void free(void *ptr) { + // TODO: Print PID only if POSIX option is enabled. + if (mlibc::globalConfig().debugMalloc) { + mlibc::infoLogger() << "mlibc (PID ?): free() on " + << ptr << frg::endlog; + if((uintptr_t)ptr & 1) + mlibc::infoLogger() << __builtin_return_address(0) << frg::endlog; + } + getAllocator().free(ptr); +} + +void *malloc(size_t size) { + auto nptr = getAllocator().allocate(size); + // TODO: Print PID only if POSIX option is enabled. + if (mlibc::globalConfig().debugMalloc) + mlibc::infoLogger() << "mlibc (PID ?): malloc() returns " + << nptr << frg::endlog; + return nptr; +} + +void *realloc(void *ptr, size_t size) { + auto nptr = getAllocator().reallocate(ptr, size); + // TODO: Print PID only if POSIX option is enabled. + if (mlibc::globalConfig().debugMalloc) + mlibc::infoLogger() << "mlibc (PID ?): realloc() on " + << ptr << " returns " << nptr << frg::endlog; + return nptr; +} + +int posix_memalign(void **out, size_t align, size_t size) { + if(align < sizeof(void *)) + return EINVAL; + if(align & (align - 1)) // Make sure that align is a power of two. + return EINVAL; + auto p = getAllocator().allocate(frg::max(align, size)); + if(!p) + return ENOMEM; + // Hope that the alignment was respected. This works on the current allocator. + // TODO: Make the allocator alignment-aware. + __ensure(!(reinterpret_cast(p) & (align - 1))); + *out = p; + return 0; +} diff --git a/lib/mlibc/options/ansi/generic/string-stubs.cpp b/lib/mlibc/options/ansi/generic/string-stubs.cpp new file mode 100644 index 0000000..8defd0e --- /dev/null +++ b/lib/mlibc/options/ansi/generic/string-stubs.cpp @@ -0,0 +1,542 @@ +#include +#include +#include +#include + +#include +#include + +// memset() is defined in options/internals. +// memcpy() is defined in options/internals. +// memmove() is defined in options/internals. +// strlen() is defined in options/internals. + +char *strcpy(char *__restrict dest, const char *src) { + char *dest_bytes = (char *)dest; + char *src_bytes = (char *)src; + while(*src_bytes) + *(dest_bytes++) = *(src_bytes++); + *dest_bytes = 0; + return dest; +} +char *strncpy(char *__restrict dest, const char *src, size_t max_size) { + auto dest_bytes = static_cast(dest); + auto src_bytes = static_cast(src); + size_t i = 0; + while(*src_bytes && i < max_size) { + *(dest_bytes++) = *(src_bytes++); + i++; + } + while(i < max_size) { + *(dest_bytes++) = 0; + i++; + } + return dest; +} + +char *strcat(char *__restrict dest, const char *__restrict src) { + strcpy(dest + strlen(dest), src); + return dest; +} +char *strncat(char *__restrict dest, const char *__restrict src, size_t max_size) { + auto dest_bytes = static_cast(dest); + auto src_bytes = static_cast(src); + dest_bytes += strlen(dest); + size_t i = 0; + while(*src_bytes && i < max_size) { + *(dest_bytes++) = *(src_bytes++); + i++; + } + *dest_bytes = 0; + return dest; +} + +int memcmp(const void *a, const void *b, size_t size) { + for(size_t i = 0; i < size; i++) { + auto a_byte = static_cast(a)[i]; + auto b_byte = static_cast(b)[i]; + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + } + return 0; +} +int strcmp(const char *a, const char *b) { + size_t i = 0; + while(true) { + unsigned char a_byte = a[i]; + unsigned char b_byte = b[i]; + if(!a_byte && !b_byte) + return 0; + // If only one char is null, one of the following cases applies. + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + i++; + } +} + +int strcoll(const char *a, const char *b) { + // TODO: strcoll should take "LC_COLLATE" into account. + return strcmp(a, b); +} + +int strncmp(const char *a, const char *b, size_t max_size) { + size_t i = 0; + while(true) { + if(!(i < max_size)) + return 0; + unsigned char a_byte = a[i]; + unsigned char b_byte = b[i]; + if(!a_byte && !b_byte) + return 0; + // If only one char is null, one of the following cases applies. + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + i++; + } +} + +size_t strxfrm(char *__restrict dest, const char *__restrict src, size_t n) { + // NOTE: This might not work for non ANSI charsets. + size_t l = strlen(src); + + // man page: If the value returned is n or more, the contents of dest are indeterminate. + if(n > l) + strncpy(dest, src, n); + + return l; +} + +void *memchr(const void *s, int c, size_t size) { + auto s_bytes = static_cast(s); + for(size_t i = 0; i < size; i++) + if(s_bytes[i] == static_cast(c)) + return const_cast(s_bytes + i); + return nullptr; +} +char *strchr(const char *s, int c) { + size_t i = 0; + while(s[i]) { + if(s[i] == c) + return const_cast(&s[i]); + i++; + } + if(c == 0) + return const_cast(&s[i]); + return nullptr; +} +size_t strcspn(const char *s, const char *chrs) { + size_t n = 0; + while(true) { + if(!s[n] || strchr(chrs, s[n])) + return n; + n++; + } +} +char *strpbrk(const char *s, const char *chrs) { + size_t n = 0; + while(s[n]) { + if(strchr(chrs, s[n])) + return const_cast(s + n); + n++; + } + return nullptr; +} +char *strrchr(const char *s, int c) { + // The null-terminator is considered to be part of the string. + size_t length = strlen(s); + for(size_t i = 0; i <= length; i++) { + if(s[length - i] == c) + return const_cast(s + (length - i)); + } + return nullptr; +} +size_t strspn(const char *s, const char *chrs) { + size_t n = 0; + while(true) { + if(!s[n] || !strchr(chrs, s[n])) + return n; + n++; + } +} +char *strstr(const char *s, const char *pattern) { + for(size_t i = 0; s[i]; i++) { + bool found = true; + for(size_t j = 0; pattern[j]; j++) { + if(!pattern[j] || s[i + j] == pattern[j]) + continue; + + found = false; + break; + } + + if(found) + return const_cast(&s[i]); + } + + return nullptr; +} +char *strtok_r(char *__restrict s, const char *__restrict del, char **__restrict m) { + __ensure(m); + + // We use *m = null to memorize that the entire string was consumed. + char *tok; + if(s) { + tok = s; + }else if(*m) { + tok = *m; + }else { + return nullptr; + } + + // Skip initial delimiters. + // After this loop: *tok is non-null iff we return a token. + while(*tok && strchr(del, *tok)) + tok++; + + // Replace the following delimiter by a null-terminator. + // After this loop: *p is null iff we reached the end of the string. + auto p = tok; + while(*p && !strchr(del, *p)) + p++; + + if(*p) { + *p = 0; + *m = p + 1; + }else{ + *m = nullptr; + } + if(p == tok) + return nullptr; + return tok; +} +char *strtok(char *__restrict s, const char *__restrict delimiter) { + static char *saved; + return strtok_r(s, delimiter, &saved); +} + +// This is a GNU extension. +char *strchrnul(const char *s, int c) { + size_t i = 0; + while(s[i]) { + if(s[i] == c) + return const_cast(s + i); + i++; + } + return const_cast(s + i); +} + +double wcstod(const wchar_t *__restrict, wchar_t **__restrict) MLIBC_STUB_BODY +float wcstof(const wchar_t *__restrict, wchar_t **__restrict) MLIBC_STUB_BODY +long double wcstold(const wchar_t *__restrict, wchar_t **__restrict) MLIBC_STUB_BODY + +long wcstol(const wchar_t *__restrict nptr, wchar_t **__restrict endptr, int base) { + return mlibc::stringToInteger(nptr, endptr, base); +} +unsigned long wcstoul(const wchar_t *__restrict nptr, wchar_t **__restrict endptr, int base) { + return mlibc::stringToInteger(nptr, endptr, base); +} +long long wcstoll(const wchar_t *__restrict nptr, wchar_t **__restrict endptr, int base) { + return mlibc::stringToInteger(nptr, endptr, base); +} +unsigned long long wcstoull(const wchar_t *__restrict nptr, wchar_t **__restrict endptr, int base) { + return mlibc::stringToInteger(nptr, endptr, base); +} + +wchar_t *wcscpy(wchar_t *__restrict dest, const wchar_t *__restrict src) { + wchar_t *a = dest; + while((*dest++ = *src++)); + return a; +} + +wchar_t *wcsncpy(wchar_t *__restrict dest, const wchar_t *__restrict src, size_t n) { + wchar_t *a = dest; + while(n && *src) + n--, *dest++ = *src++; + wmemset(dest, 0, n); + return a; +} + +wchar_t *wmemcpy(wchar_t *__restrict dest, const wchar_t *__restrict src, size_t n) { + memcpy(dest, src, n * sizeof(wchar_t)); + return dest; +} + +wchar_t *wmemmove(wchar_t *dest, const wchar_t *src, size_t n) { + memmove(dest, src, n * sizeof(wchar_t)); + return dest; +} + +wchar_t *wcscat(wchar_t *__restrict dest, const wchar_t *__restrict src) { + wcscpy(dest + wcslen(dest), src); + return dest; +} + +wchar_t *wcsncat(wchar_t *__restrict, const wchar_t *__restrict, size_t) MLIBC_STUB_BODY + +int wcscmp(const wchar_t *l, const wchar_t *r) { + for(; *l == *r && *l && *r; l++, r++); + return *l - *r; +} + +int wcscoll(const wchar_t *, const wchar_t *) MLIBC_STUB_BODY +int wcsncmp(const wchar_t *, const wchar_t *, size_t) MLIBC_STUB_BODY +int wcsxfrm(wchar_t *__restrict, const wchar_t *__restrict, size_t) MLIBC_STUB_BODY + +int wmemcmp(const wchar_t *a, const wchar_t *b, size_t size) { + for(size_t i = 0; i < size; i++) { + auto a_byte = a[i]; + auto b_byte = b[i]; + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + } + return 0; +} + +wchar_t *wcschr(const wchar_t *s, wchar_t c) { + if(!c) + return (wchar_t *)s + wcslen(s); + for(; *s && *s != c; s++); + return *s ? (wchar_t *)s : 0; +} + +size_t wcscspn(const wchar_t *, const wchar_t *) MLIBC_STUB_BODY +wchar_t *wcspbrk(const wchar_t *, const wchar_t *) MLIBC_STUB_BODY + +wchar_t *wcsrchr(const wchar_t *s, wchar_t c) { + const wchar_t *p; + for(p = s + wcslen(s); p >= s && *p != c; p--); + return p >= s ? (wchar_t *)p : 0; +} + +size_t wcsspn(const wchar_t *, const wchar_t *) MLIBC_STUB_BODY +wchar_t *wcsstr(const wchar_t *, const wchar_t *) MLIBC_STUB_BODY +wchar_t *wcstok(wchar_t *__restrict, const wchar_t *__restrict, wchar_t **__restrict) MLIBC_STUB_BODY + +wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t size) { + auto s_bytes = s; + for(size_t i = 0; i < size; i++) + if(s_bytes[i] == c) + return const_cast(s_bytes + i); + return nullptr; +} + +size_t wcslen(const wchar_t *s) { + const wchar_t *a; + for(a = s; *s; s++); + return s-a; +} + +wchar_t *wmemset(wchar_t *d, wchar_t c, size_t n) { + wchar_t *ret = d; + while(n--) + *d++ = c; + return ret; +} + +char *strerror(int e) { + const char *s; + switch(e) { + case EAGAIN: s = "Operation would block (EAGAIN)"; break; + case EACCES: s = "Access denied (EACCESS)"; break; + case EBADF: s = "Bad file descriptor (EBADF)"; break; + case EEXIST: s = "File exists already (EEXIST)"; break; + case EFAULT: s = "Access violation (EFAULT)"; break; + case EINTR: s = "Operation interrupted (EINTR)"; break; + case EINVAL: s = "Invalid argument (EINVAL)"; break; + case EIO: s = "I/O error (EIO)"; break; + case EISDIR: s = "Resource is directory (EISDIR)"; break; + case ENOENT: s = "No such file or directory (ENOENT)"; break; + case ENOMEM: s = "Out of memory (ENOMEM)"; break; + case ENOTDIR: s = "Expected directory instead of file (ENOTDIR)"; break; + case ENOSYS: s = "Operation not implemented (ENOSYS)"; break; + case EPERM: s = "Operation not permitted (EPERM)"; break; + case EPIPE: s = "Broken pipe (EPIPE)"; break; + case ESPIPE: s = "Seek not possible (ESPIPE)"; break; + case ENXIO: s = "No such device or address (ENXIO)"; break; + case ENOEXEC: s = "Exec format error (ENOEXEC)"; break; + case ENOSPC: s = "No space left on device (ENOSPC)"; break; + case ENOTSOCK: s = "Socket operation on non-socket (ENOTSOCK)"; break; + case ENOTCONN: s = "Transport endpoint is not connected (ENOTCONN)"; break; + case EDOM: s = "Numerical argument out of domain (EDOM)"; break; + case EILSEQ: s = "Invalid or incomplete multibyte or wide character (EILSEQ)"; break; + case ERANGE: s = "Numerical result out of range (ERANGE)"; break; + case E2BIG: s = "Argument list too long (E2BIG)"; break; + case EADDRINUSE: s = "Address already in use (EADDRINUSE)"; break; + case EADDRNOTAVAIL: s = "Cannot assign requested address (EADDRNOTAVAIL)"; break; + case EAFNOSUPPORT: s = "Address family not supported by protocol (EAFNOSUPPORT)"; break; + case EALREADY: s = "Operation already in progress (EALREADY)"; break; + case EBADMSG: s = "Bad message (EBADMSG)"; break; + case EBUSY: s = "Device or resource busy (EBUSY)"; break; + case ECANCELED: s = "Operation canceled (ECANCELED)"; break; + case ECHILD: s = "No child processes (ECHILD)"; break; + case ECONNABORTED: s = "Software caused connection abort (ECONNABORTED)"; break; + case ECONNREFUSED: s = "Connection refused (ECONNREFUSED)"; break; + case ECONNRESET: s = "Connection reset by peer (ECONNRESET)"; break; + case EDEADLK: s = "Resource deadlock avoided (EDEADLK)"; break; + case EDESTADDRREQ: s = "Destination address required (EDESTADDRREQ)"; break; + case EDQUOT: s = "Disk quota exceeded (EDQUOT)"; break; + case EFBIG: s = "File too large (EFBIG)"; break; + case EHOSTUNREACH: s = "No route to host (EHOSTUNREACH)"; break; + case EIDRM: s = "Identifier removed (EIDRM)"; break; + case EINPROGRESS: s = "Operation now in progress (EINPROGRESS)"; break; + case EISCONN: s = "Transport endpoint is already connected (EISCONN)"; break; + case ELOOP: s = "Too many levels of symbolic links (ELOOP)"; break; + case EMFILE: s = "Too many open files (EMFILE)"; break; + case EMLINK: s = "Too many links (EMLINK)"; break; + case EMSGSIZE: s = "Message too long (EMSGSIZE)"; break; + case EMULTIHOP: s = "Multihop attempted (EMULTIHOP)"; break; + case ENAMETOOLONG: s = "File name too long (ENAMETOOLONG)"; break; + case ENETDOWN: s = "Network is down (ENETDOWN)"; break; + case ENETRESET: s = "Network dropped connection on reset (ENETRESET)"; break; + case ENETUNREACH: s = "Network is unreachable (ENETUNREACH)"; break; + case ENFILE: s = "Too many open files in system (ENFILE)"; break; + case ENOBUFS: s = "No buffer space available (ENOBUFS)"; break; + case ENODEV: s = "No such device (ENODEV)"; break; + case ENOLCK: s = "No locks available (ENOLCK)"; break; + case ENOLINK: s = "Link has been severed (ENOLINK)"; break; + case ENOMSG: s = "No message of desired type (ENOMSG)"; break; + case ENOPROTOOPT: s = "Protocol not available (ENOPROTOOPT)"; break; + case ENOTEMPTY: s = "Directory not empty (ENOTEMPTY)"; break; + case ENOTRECOVERABLE: s = "Sate not recoverable (ENOTRECOVERABLE)"; break; + case ENOTSUP: s = "Operation not supported (ENOTSUP)"; break; + case ENOTTY: s = "Inappropriate ioctl for device (ENOTTY)"; break; + case EOVERFLOW: s = "Value too large for defined datatype (EOVERFLOW)"; break; +#if EOPNOTSUPP != ENOTSUP + /* these are aliases on the mlibc abi */ + case EOPNOTSUPP: s = "Operation not supported (EOPNOTSUP)"; break; +#endif + case EOWNERDEAD: s = "Owner died (EOWNERDEAD)"; break; + case EPROTO: s = "Protocol error (EPROTO)"; break; + case EPROTONOSUPPORT: s = "Protocol not supported (EPROTONOSUPPORT)"; break; + case EPROTOTYPE: s = "Protocol wrong type for socket (EPROTOTYPE)"; break; + case EROFS: s = "Read-only file system (EROFS)"; break; + case ESRCH: s = "No such process (ESRCH)"; break; + case ESTALE: s = "Stale file handle (ESTALE)"; break; + case ETIMEDOUT: s = "Connection timed out (ETIMEDOUT)"; break; + case ETXTBSY: s = "Text file busy (ETXTBSY)"; break; + case EXDEV: s = "Invalid cross-device link (EXDEV)"; break; + case ENODATA: s = "No data available (ENODATA)"; break; + case ETIME: s = "Timer expired (ETIME)"; break; + case ENOKEY: s = "Required key not available (ENOKEY)"; break; + case ESHUTDOWN: s = "Cannot send after transport endpoint shutdown (ESHUTDOWN)"; break; + case EHOSTDOWN: s = "Host is down (EHOSTDOWN)"; break; + case EBADFD: s = "File descriptor in bad state (EBADFD)"; break; + case ENOMEDIUM: s = "No medium found (ENOMEDIUM)"; break; + case ENOTBLK: s = "Block device required (ENOTBLK)"; break; + case ENONET: s = "Machine is not on the network (ENONET)"; break; + case EPFNOSUPPORT: s = "Protocol family not supported (EPFNOSUPPORT)"; break; + case ESOCKTNOSUPPORT: s = "Socket type not supported (ESOCKTNOSUPPORT)"; break; + case ESTRPIPE: s = "Streams pipe error (ESTRPIPE)"; break; + case EREMOTEIO: s = "Remote I/O error (EREMOTEIO)"; break; + case ERFKILL: s = "Operation not possible due to RF-kill (ERFKILL)"; break; + case EBADR: s = "Invalid request descriptor (EBADR)"; break; + case EUNATCH: s = "Protocol driver not attached (EUNATCH)"; break; + case EMEDIUMTYPE: s = "Wrong medium type (EMEDIUMTYPE)"; break; + case EREMOTE: s = "Object is remote (EREMOTE)"; break; + case EKEYREJECTED: s = "Key was rejected by service (EKEYREJECTED)"; break; + case EUCLEAN: s = "Structure needs cleaning (EUCLEAN)"; break; + case EBADSLT: s = "Invalid slot (EBADSLT)"; break; + case ENOANO: s = "No anode (ENOANO)"; break; + case ENOCSI: s = "No CSI structure available (ENOCSI)"; break; + case ENOSTR: s = "Device not a stream (ENOSTR)"; break; + case ETOOMANYREFS: s = "Too many references: cannot splice (ETOOMANYREFS)"; break; + case ENOPKG: s = "Package not installed (ENOPKG)"; break; + case EKEYREVOKED: s = "Key has been revoked (EKEYREVOKED)"; break; + case EXFULL: s = "Exchange full (EXFULL)"; break; + case ELNRNG: s = "Link number out of range (ELNRNG)"; break; + case ENOTUNIQ: s = "Name not unique on network (ENOTUNIQ)"; break; + case ERESTART: s = "Interrupted system call should be restarted (ERESTART)"; break; + case EUSERS: s = "Too many users (EUSERS)"; break; + +#ifdef EIEIO + case EIEIO: s = "Computer bought the farm; OS internal error (EIEIO)"; break; +#endif + + default: + s = "Unknown error code (?)"; + } + return const_cast(s); +} +// strlen() is defined in options/internals. + +// POSIX extensions. + +int strerror_r(int e, char *buffer, size_t bufsz) { + auto s = strerror(e); + strncpy(buffer, s, bufsz); + // Note that strerror_r does not set errno on error! + if(strlen(s) >= bufsz) + return ERANGE; + return 0; +} + +void *mempcpy(void *dest, const void *src, size_t len) { + return (char *)memcpy(dest, src, len) + len; +} + +// GNU extensions. +// Taken from musl. +int strverscmp(const char *l0, const char *r0) { + const unsigned char *l = (const unsigned char *)l0; + const unsigned char *r = (const unsigned char *)r0; + size_t i, dp, j; + int z = 1; + + /* Find maximal matching prefix and track its maximal digit + * suffix and whether those digits are all zeros. */ + for(dp = i = 0; l[i] == r[i]; i++) { + int c = l[i]; + if(!c) + return 0; + if(!isdigit(c)) + dp = i + 1, z = 1; + else if(c != '0') + z = 0; + } + + if(l[dp] != '0' && r[dp] != '0') { + /* If we're not looking at a digit sequence that began + * with a zero, longest digit string is greater. */ + for(j = i; isdigit(l[j]); j++) { + if(!isdigit(r[j])) + return 1; + } + if(isdigit(r[j])) + return -1; + } else if(z && dp < i && (isdigit(l[i]) || isdigit(r[i]))) { + /* Otherwise, if common prefix of digit sequence is + * all zeros, digits order less than non-digits. */ + return (unsigned char)(l[i] - '0') - (unsigned char)(r[i] - '0'); + } + + return l[i] - r[i]; +} + +void *memmem(const void *hs, size_t haystackLen, const void *nd, size_t needleLen) { + const char *haystack = static_cast(hs); + const char *needle = static_cast(nd); + + for (size_t i = 0; i < haystackLen; i++) { + bool found = true; + + for (size_t j = 0; j < needleLen; j++) { + if (i + j >= haystackLen || haystack[i + j] != needle[j]) { + found = false; + break; + } + } + + if(found) + return const_cast(&haystack[i]); + } + + return nullptr; +} diff --git a/lib/mlibc/options/ansi/generic/threads.cpp b/lib/mlibc/options/ansi/generic/threads.cpp new file mode 100644 index 0000000..70fa055 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/threads.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) { + int res = mlibc::thread_create(thr, 0, reinterpret_cast(func), arg, true); + + if(!res) { + return thrd_success; + } + + return (res == ENOMEM) ? thrd_nomem : thrd_error; +} + +int thrd_equal(thrd_t t1, thrd_t t2) { + if(t1 == t2) { + return 1; + } + return 0; +} + +thrd_t thrd_current(void) { + return reinterpret_cast(mlibc::get_current_tcb()); +} + +int thrd_sleep(const struct timespec *, struct timespec *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void thrd_yield(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int thrd_detach(thrd_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int thrd_join(thrd_t thr, int *res) { + if(mlibc::thread_join(thr, res) != 0) { + return thrd_error; + } + + return thrd_success; +} + +__attribute__((__noreturn__)) void thrd_exit(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int mtx_init(mtx_t *mtx, int type) { + struct __mlibc_mutexattr attr; + mlibc::thread_mutexattr_init(&attr); + + if(type & mtx_recursive) { + mlibc::thread_mutexattr_settype(&attr, __MLIBC_THREAD_MUTEX_RECURSIVE); + } + + int res = mlibc::thread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error; + mlibc::thread_mutexattr_destroy(&attr); + + return res; +} + +void mtx_destroy(mtx_t *mtx) { + mlibc::thread_mutex_destroy(mtx); +} + +int mtx_lock(mtx_t *mtx) { + return mlibc::thread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; +} + +int mtx_unlock(mtx_t *mtx) { + return mlibc::thread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error; +} + +int cnd_init(cnd_t *cond) { + return mlibc::thread_cond_init(cond, 0) == 0 ? thrd_success : thrd_error; +} + +void cnd_destroy(cnd_t *cond) { + mlibc::thread_cond_destroy(cond); +} + +int cnd_broadcast(cnd_t *cond) { + return mlibc::thread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error; +} + +int cnd_wait(cnd_t *cond, mtx_t *mtx) { + return mlibc::thread_cond_timedwait(cond, mtx, nullptr) == 0 ? thrd_success : thrd_error; +} diff --git a/lib/mlibc/options/ansi/generic/time-stubs.cpp b/lib/mlibc/options/ansi/generic/time-stubs.cpp new file mode 100644 index 0000000..b8c7cf5 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/time-stubs.cpp @@ -0,0 +1,729 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +const char __utc[] = "UTC"; + +// Variables defined by POSIX. +int daylight; +long timezone; +char *tzname[2]; + +static FutexLock __time_lock; +static file_window *get_localtime_window() { + static file_window window{"/etc/localtime"}; + return &window; +} + +// Function taken from musl +clock_t clock(void) { + struct timespec ts; + + if(clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)) + return -1; + + if(ts.tv_sec > LONG_MAX / 1000000 || ts.tv_nsec / 1000 > LONG_MAX - 1000000 * ts.tv_sec) + return -1; + + return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; +} + +double difftime(time_t a, time_t b) { + return a - b; +} + +time_t mktime(struct tm *tm) { + return timegm(tm); +} + +/* There is no other implemented value than TIME_UTC; all other values + * are considered erroneous. */ +// Function taken from musl +int timespec_get(struct timespec *ts, int base) { + if(base != TIME_UTC) + return 0; + int ret = clock_gettime(CLOCK_REALTIME, ts); + return ret < 0 ? 0 : base; +} + +char *asctime(const struct tm *ptr) { + static char buf[26]; + return asctime_r(ptr, buf); +} + +char *ctime(const time_t *timer) { + struct tm *tm = localtime(timer); + if(!tm) { + return 0; + } + return asctime(tm); +} + +struct tm *gmtime(const time_t *unix_gmt) { + static thread_local struct tm per_thread_tm; + return gmtime_r(unix_gmt, &per_thread_tm); +} + +struct tm *localtime(const time_t *unix_gmt) { + tzset(); + static thread_local struct tm per_thread_tm; + return localtime_r(unix_gmt, &per_thread_tm); +} + +size_t strftime(char *__restrict dest, size_t max_size, + const char *__restrict format, const struct tm *__restrict tm) { + auto c = format; + auto p = dest; + + while(*c) { + int chunk; + auto space = (dest + max_size) - p; + __ensure(space >= 0); + + if(*c != '%') { + if(!space) + return 0; + *p = *c; + c++; + p++; + continue; + } + + switch(*++c) { + case 'Y': { + chunk = snprintf(p, space, "%d", 1900 + tm->tm_year); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'm': { + chunk = snprintf(p, space, "%.2d", tm->tm_mon + 1); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'd': { + chunk = snprintf(p, space, "%.2d", tm->tm_mday); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'Z': { + chunk = snprintf(p, space, "%s", "GMT"); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'H': { + chunk = snprintf(p, space, "%.2i", tm->tm_hour); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'M': { + chunk = snprintf(p, space, "%.2i", tm->tm_min); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'S': { + chunk = snprintf(p, space, "%.2d", tm->tm_sec); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'R': { + chunk = snprintf(p, space, "%.2i:%.2i", tm->tm_hour, tm->tm_min); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'T': { + chunk = snprintf(p, space, "%.2i:%.2i:%.2i", tm->tm_hour, tm->tm_min, tm->tm_sec); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'F': { + chunk = snprintf(p, space, "%d-%.2d-%.2d", 1900 + tm->tm_year, tm->tm_mon + 1, + tm->tm_mday); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'D': { + chunk = snprintf(p, space, "%.2d/%.2d/%.2d", tm->tm_mon + 1, tm->tm_mday, tm->tm_year % 100); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'a': { + int day = tm->tm_wday; + if(day < 0 || day > 6) + __ensure(!"Day not in bounds."); + + chunk = snprintf(p, space, "%s", mlibc::nl_langinfo(ABDAY_1 + day)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'b': + case 'B': + case 'h': { + int mon = tm->tm_mon; + if(mon < 0 || mon > 11) + __ensure(!"Month not in bounds."); + + nl_item item = (*c == 'B') ? MON_1 : ABMON_1; + + chunk = snprintf(p, space, "%s", mlibc::nl_langinfo(item + mon)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'c': { + chunk = snprintf(p, space, "%d/%.2d/%.2d %.2d:%.2d:%.2d", 1900 + tm->tm_year, + tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'e': { + chunk = snprintf(p, space, "%2d", tm->tm_mday); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'l': { + int hour = tm->tm_hour; + if(!hour) + hour = 12; + if(hour > 12) + hour -= 12; + chunk = snprintf(p, space, "%2d", hour); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'I': { + int hour = tm->tm_hour; + if(!hour) + hour = 12; + if(hour > 12) + hour -= 12; + chunk = snprintf(p, space, "%.2d", hour); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'p': { + chunk = snprintf(p, space, "%s", mlibc::nl_langinfo((tm->tm_hour < 12) ? AM_STR : PM_STR)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'C': { + chunk = snprintf(p, space, "%.2d", (1900 + tm->tm_year) / 100); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'y': { + chunk = snprintf(p, space, "%.2d", (1900 + tm->tm_year) % 100); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'j': { + chunk = snprintf(p, space, "%.3d", tm->tm_yday + 1); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'A': { + chunk = snprintf(p, space, "%s", mlibc::nl_langinfo(DAY_1 + tm->tm_wday)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'r': { + int hour = tm->tm_hour; + if(!hour) + hour = 12; + if(hour > 12) + hour -= 12; + chunk = snprintf(p, space, "%.2i:%.2i:%.2i %s", hour, tm->tm_min, tm->tm_sec, + mlibc::nl_langinfo((tm->tm_hour < 12) ? AM_STR : PM_STR)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case '%': { + chunk = snprintf(p, space, "%%"); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 't': { + chunk = snprintf(p, space, "\t"); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'x': { + return strftime(dest, max_size, mlibc::nl_langinfo(D_FMT), tm); + } + case 'X': { + return strftime(dest, max_size, mlibc::nl_langinfo(T_FMT), tm); + } + case '\0': { + chunk = snprintf(p, space, "%%"); + if(chunk >= space) + return 0; + p += chunk; + break; + } + default: + mlibc::panicLogger() << "mlibc: strftime unknown format type: " << c << frg::endlog; + } + } + + auto space = (dest + max_size) - p; + if(!space) + return 0; + + *p = '\0'; + return (p - dest); +} + +size_t wcsftime(wchar_t *__restrict, size_t, const wchar_t *__restrict, + const struct tm *__restrict) { + mlibc::infoLogger() << "mlibc: wcsftime is a stub" << frg::endlog; + return 0; +} + +namespace { + +struct tzfile { + uint8_t magic[4]; + uint8_t version; + uint8_t reserved[15]; + uint32_t tzh_ttisgmtcnt; + uint32_t tzh_ttisstdcnt; + uint32_t tzh_leapcnt; + uint32_t tzh_timecnt; + uint32_t tzh_typecnt; + uint32_t tzh_charcnt; +}; + +struct[[gnu::packed]] ttinfo { + int32_t tt_gmtoff; + unsigned char tt_isdst; + unsigned char tt_abbrind; +}; + +} + +// TODO(geert): this function doesn't parse the TZ environment variable +// or properly handle the case where information might be missing from /etc/localtime +// also we should probably unify the code for this and unix_local_from_gmt() +void tzset(void) { + frg::unique_lock lock(__time_lock); + // TODO(geert): we can probably cache this somehow + tzfile tzfile_time; + memcpy(&tzfile_time, reinterpret_cast(get_localtime_window()->get()), sizeof(tzfile)); + tzfile_time.tzh_ttisgmtcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_ttisgmtcnt); + tzfile_time.tzh_ttisstdcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_ttisstdcnt); + tzfile_time.tzh_leapcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_leapcnt); + tzfile_time.tzh_timecnt = mlibc::bit_util::byteswap(tzfile_time.tzh_timecnt); + tzfile_time.tzh_typecnt = mlibc::bit_util::byteswap(tzfile_time.tzh_typecnt); + tzfile_time.tzh_charcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_charcnt); + + if(tzfile_time.magic[0] != 'T' || tzfile_time.magic[1] != 'Z' || tzfile_time.magic[2] != 'i' + || tzfile_time.magic[3] != 'f') { + mlibc::infoLogger() << "mlibc: /etc/localtime is not a valid TZinfo file" << frg::endlog; + return; + } + + if(tzfile_time.version != '\0' && tzfile_time.version != '2' && tzfile_time.version != '3') { + mlibc::infoLogger() << "mlibc: /etc/localtime has an invalid TZinfo version" + << frg::endlog; + return; + } + + // There should be at least one entry in the ttinfo table. + // TODO: If there is not, we might want to fall back to UTC, no DST (?). + __ensure(tzfile_time.tzh_typecnt); + + char *abbrevs = reinterpret_cast(get_localtime_window()->get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + tzfile_time.tzh_timecnt * sizeof(uint8_t) + + tzfile_time.tzh_typecnt * sizeof(struct ttinfo); + // start from the last ttinfo entry, this matches the behaviour of glibc and musl + for (int i = tzfile_time.tzh_typecnt; i > 0; i--) { + ttinfo time_info; + memcpy(&time_info, reinterpret_cast(get_localtime_window()->get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + tzfile_time.tzh_timecnt * sizeof(uint8_t) + + i * sizeof(ttinfo), sizeof(ttinfo)); + time_info.tt_gmtoff = mlibc::bit_util::byteswap(time_info.tt_gmtoff); + if (!time_info.tt_isdst && !tzname[0]) { + tzname[0] = abbrevs + time_info.tt_abbrind; + timezone = -time_info.tt_gmtoff; + } + if (time_info.tt_isdst && !tzname[1]) { + tzname[1] = abbrevs + time_info.tt_abbrind; + timezone = -time_info.tt_gmtoff; + daylight = 1; + } + } +} + +// POSIX extensions. + +int nanosleep(const struct timespec *req, struct timespec *) { + if (req->tv_sec < 0 || req->tv_nsec > 999999999 || req->tv_nsec < 0) { + errno = EINVAL; + return -1; + } + + if(!mlibc::sys_sleep) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_sleep()"); + } + + struct timespec tmp = *req; + + int e = mlibc::sys_sleep(&tmp.tv_sec, &tmp.tv_nsec); + if (!e) { + return 0; + } else { + errno = e; + return -1; + } +} + +int clock_getres(clockid_t clockid, struct timespec *res) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_clock_getres, -1); + if(int e = mlibc::sys_clock_getres(clockid, &res->tv_sec, &res->tv_nsec); e) { + errno = e; + return -1; + } + return 0; +} + +int clock_gettime(clockid_t clock, struct timespec *time) { + if(int e = mlibc::sys_clock_get(clock, &time->tv_sec, &time->tv_nsec); e) { + errno = e; + return -1; + } + return 0; +} + +int clock_nanosleep(clockid_t clockid, int, const struct timespec *req, struct timespec *) { + mlibc::infoLogger() << "clock_nanosleep is implemented as nanosleep!" << frg::endlog; + __ensure(clockid == CLOCK_REALTIME || clockid == CLOCK_MONOTONIC); + return nanosleep(req, nullptr); +} + +int clock_settime(clockid_t, const struct timespec *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +time_t time(time_t *out) { + time_t secs; + long nanos; + if(int e = mlibc::sys_clock_get(CLOCK_REALTIME, &secs, &nanos); e) { + errno = e; + return (time_t)-1; + } + if(out) + *out = secs; + return secs; +} + +namespace { + +void civil_from_days(time_t days_since_epoch, int *year, unsigned int *month, unsigned int *day) { + time_t time = days_since_epoch + 719468; + int era = (time >= 0 ? time : time - 146096) / 146097; + unsigned int doe = static_cast(time - era * 146097); + unsigned int yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; + int y = static_cast(yoe) + era * 400; + unsigned int doy = doe - (365*yoe + yoe/4 - yoe/100); + unsigned int mp = (5*doy + 2)/153; + unsigned int d = doy - (153*mp+2)/5 + 1; + unsigned int m = mp + (mp < 10 ? 3 : -9); + + *year = y + (m <= 2); + *month = m; + *day = d; +} + +void weekday_from_days(time_t days_since_epoch, unsigned int *weekday) { + *weekday = static_cast(days_since_epoch >= -4 ? + (days_since_epoch+4) % 7 : (days_since_epoch+5) % 7 + 6); +} + +void yearday_from_date(unsigned int year, unsigned int month, unsigned int day, unsigned int *yday) { + unsigned int n1 = 275 * month / 9; + unsigned int n2 = (month + 9) / 12; + unsigned int n3 = (1 + (year - 4 * year / 4 + 2) / 3); + *yday = n1 - (n2 * n3) + day - 30; +} + +// Looks up the local time rules for a given +// UNIX GMT timestamp (seconds since 1970 GMT, ignoring leap seconds). +// This function assumes the __time_lock has been taken +// TODO(geert): if /etc/localtime isn't available this will fail... In that case +// we should call tzset() and use the variables to compute the variables from +// the tzset() global variables. Look at the musl code for how to do that +int unix_local_from_gmt(time_t unix_gmt, time_t *offset, bool *dst, char **tm_zone) { + tzfile tzfile_time; + memcpy(&tzfile_time, reinterpret_cast(get_localtime_window()->get()), sizeof(tzfile)); + tzfile_time.tzh_ttisgmtcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_ttisgmtcnt); + tzfile_time.tzh_ttisstdcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_ttisstdcnt); + tzfile_time.tzh_leapcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_leapcnt); + tzfile_time.tzh_timecnt = mlibc::bit_util::byteswap(tzfile_time.tzh_timecnt); + tzfile_time.tzh_typecnt = mlibc::bit_util::byteswap(tzfile_time.tzh_typecnt); + tzfile_time.tzh_charcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_charcnt); + + if(tzfile_time.magic[0] != 'T' || tzfile_time.magic[1] != 'Z' || tzfile_time.magic[2] != 'i' + || tzfile_time.magic[3] != 'f') { + mlibc::infoLogger() << "mlibc: /etc/localtime is not a valid TZinfo file" << frg::endlog; + return -1; + } + + if(tzfile_time.version != '\0' && tzfile_time.version != '2' && tzfile_time.version != '3') { + mlibc::infoLogger() << "mlibc: /etc/localtime has an invalid TZinfo version" + << frg::endlog; + return -1; + } + + int index = -1; + for(size_t i = 0; i < tzfile_time.tzh_timecnt; i++) { + int32_t ttime; + memcpy(&ttime, reinterpret_cast(get_localtime_window()->get()) + sizeof(tzfile) + + i * sizeof(int32_t), sizeof(int32_t)); + ttime = mlibc::bit_util::byteswap(ttime); + // If we are before the first transition, the format dicates that + // the first ttinfo entry should be used (and not the ttinfo entry pointed + // to by the first transition time). + if(i && ttime > unix_gmt) { + index = i - 1; + break; + } + } + + // The format dictates that if no transition is applicable, + // the first entry in the file is chosen. + uint8_t ttinfo_index = 0; + if(index >= 0) { + memcpy(&ttinfo_index, reinterpret_cast(get_localtime_window()->get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + index * sizeof(uint8_t), sizeof(uint8_t)); + } + + // There should be at least one entry in the ttinfo table. + // TODO: If there is not, we might want to fall back to UTC, no DST (?). + __ensure(tzfile_time.tzh_typecnt); + + ttinfo time_info; + memcpy(&time_info, reinterpret_cast(get_localtime_window()->get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + tzfile_time.tzh_timecnt * sizeof(uint8_t) + + ttinfo_index * sizeof(ttinfo), sizeof(ttinfo)); + time_info.tt_gmtoff = mlibc::bit_util::byteswap(time_info.tt_gmtoff); + + char *abbrevs = reinterpret_cast(get_localtime_window()->get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + tzfile_time.tzh_timecnt * sizeof(uint8_t) + + tzfile_time.tzh_typecnt * sizeof(struct ttinfo); + + *offset = time_info.tt_gmtoff; + *dst = time_info.tt_isdst; + *tm_zone = abbrevs + time_info.tt_abbrind; + return 0; +} + +} //anonymous namespace + +struct tm *gmtime_r(const time_t *unix_gmt, struct tm *res) { + int year; + unsigned int month; + unsigned int day; + unsigned int weekday; + unsigned int yday; + + time_t unix_local = *unix_gmt; + + int days_since_epoch = unix_local / (60*60*24); + civil_from_days(days_since_epoch, &year, &month, &day); + weekday_from_days(days_since_epoch, &weekday); + yearday_from_date(year, month, day, &yday); + + res->tm_sec = unix_local % 60; + res->tm_min = (unix_local / 60) % 60; + res->tm_hour = (unix_local / (60*60)) % 24; + res->tm_mday = day; + res->tm_mon = month - 1; + res->tm_year = year - 1900; + res->tm_wday = weekday; + res->tm_yday = yday - 1; + res->tm_isdst = -1; + res->tm_zone = __utc; + res->tm_gmtoff = 0; + + return res; +} + +struct tm *localtime_r(const time_t *unix_gmt, struct tm *res) { + int year; + unsigned int month; + unsigned int day; + unsigned int weekday; + unsigned int yday; + + time_t offset = 0; + bool dst; + char *tm_zone; + frg::unique_lock lock(__time_lock); + // TODO: Set errno if the conversion fails. + if(unix_local_from_gmt(*unix_gmt, &offset, &dst, &tm_zone)) { + __ensure(!"Error parsing /etc/localtime"); + __builtin_unreachable(); + } + time_t unix_local = *unix_gmt + offset; + + int days_since_epoch = unix_local / (60*60*24); + civil_from_days(days_since_epoch, &year, &month, &day); + weekday_from_days(days_since_epoch, &weekday); + yearday_from_date(year, month, day, &yday); + + res->tm_sec = unix_local % 60; + res->tm_min = (unix_local / 60) % 60; + res->tm_hour = (unix_local / (60*60)) % 24; + res->tm_mday = day; + res->tm_mon = month - 1; + res->tm_year = year - 1900; + res->tm_wday = weekday; + res->tm_yday = yday - 1; + res->tm_isdst = dst; + res->tm_zone = tm_zone; + res->tm_gmtoff = offset; + + return res; +} + +// This implementation of asctime_r is taken from sortix +char *asctime_r(const struct tm *tm, char *buf) { + static char weekday_names[7][4] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + static char month_names[12][4] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", + "Nov", "Dec" }; + sprintf(buf, "%.3s %.3s%3d %.2d:%.2d%.2d %d\n", + weekday_names[tm->tm_wday], + month_names[tm->tm_mon], + tm->tm_mday, + tm->tm_hour, + tm->tm_min, + tm->tm_sec, + tm->tm_year + 1900); + return buf; +} + +char *ctime_r(const time_t *clock, char *buf) { + return asctime_r(localtime(clock), buf); +} + +time_t timelocal(struct tm *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +constexpr static int days_from_civil(int y, unsigned m, unsigned d) noexcept { + y -= m <= 2; + const int era = (y >= 0 ? y : y - 399) / 400; + const unsigned yoe = static_cast(y - era * 400); // [0, 399] + const unsigned doy = (153 * (m > 2 ? m - 3 : m + 9) + 2) / 5 + d - 1; // [0, 365] + const unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096] + return era * 146097 + static_cast(doe) - 719468; +} + +time_t timegm(struct tm *tm) { + time_t year = tm->tm_year + 1900; + time_t month = tm->tm_mon + 1; + time_t days = days_from_civil(year, month, tm->tm_mday); + time_t secs = (days * 86400) + (tm->tm_hour * 60 * 60) + (tm->tm_min * 60) + tm->tm_sec; + return secs; +} diff --git a/lib/mlibc/options/ansi/generic/uchar.cpp b/lib/mlibc/options/ansi/generic/uchar.cpp new file mode 100644 index 0000000..cb13c12 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/uchar.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +size_t c32rtomb(char *, char32_t, mbstate_t *) MLIBC_STUB_BODY + +size_t mbrtoc32(char32_t *__restrict pc32, const char *__restrict pmb, size_t max, mbstate_t *__restrict ps) { + static mbstate_t internal_state; + + if(!ps) + ps = &internal_state; + + if(!pmb) + return mbrtoc32(0, "", 1, ps); + + wchar_t wc; + size_t ret = mbrtowc(&wc, pmb, max, ps); + + if (ret <= 4 && pc32) + *pc32 = wc; + + return ret; +} diff --git a/lib/mlibc/options/ansi/generic/wchar-stubs.cpp b/lib/mlibc/options/ansi/generic/wchar-stubs.cpp new file mode 100644 index 0000000..d9f6598 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/wchar-stubs.cpp @@ -0,0 +1,783 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace { + // All conversion functions mbrlen(), mbrtowc(), wcrtomb(), + // mbsrtowcs() and wcsrtombs() have an internal state. + __mlibc_mbstate mbrlen_state = __MLIBC_MBSTATE_INITIALIZER; + __mlibc_mbstate mbrtowc_state = __MLIBC_MBSTATE_INITIALIZER; + __mlibc_mbstate mbsrtowcs_state = __MLIBC_MBSTATE_INITIALIZER; + __mlibc_mbstate wcsrtombs_state = __MLIBC_MBSTATE_INITIALIZER; +} + +wint_t btowc(int c) { + if(c == EOF) + return WEOF; + + char nc = c; + auto cc = mlibc::current_charcode(); + wchar_t wc; + if(auto e = cc->promote_wtranscode(nc, wc); e != mlibc::charcode_error::null) + return WEOF; + return wc; +} + +int wctob(wint_t wc) { + // TODO: Revisit this once we have character encoding functions. + return wc; +} + +int mbsinit(const mbstate_t *stp) { + if(!stp) + return -1; + return !stp->__progress && !stp->__shift; +} + +size_t mbrlen(const char *mbs, size_t mb_limit, mbstate_t *stp) { + auto cc = mlibc::current_charcode(); + wchar_t wc; + + if(!stp) + stp = &mbrlen_state; + if(!mbs) { + *stp = __MLIBC_MBSTATE_INITIALIZER; + return 0; + } + + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + mlibc::code_seq wseq{&wc, &wc + 1}; + if(auto e = cc->decode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return nseq.it - mbs; +} + +size_t mbrtowc(wchar_t *wcp, const char *mbs, size_t mb_limit, mbstate_t *stp) { + auto cc = mlibc::current_charcode(); + + if(!stp) + stp = &mbrtowc_state; + if(!mbs) { + *stp = __MLIBC_MBSTATE_INITIALIZER; + return 0; + } + + wchar_t temp = 0; + if(!wcp) + wcp = &temp; + + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + mlibc::code_seq wseq{wcp, wcp + 1}; + if(auto e = cc->decode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) { + if(e == mlibc::charcode_error::input_underflow) + return static_cast(-2); + __ensure(e == mlibc::charcode_error::illegal_input); + errno = EILSEQ; + return static_cast(-1); + }else{ + if (*mbs) { + return nseq.it - mbs; + } else { + *stp = __MLIBC_MBSTATE_INITIALIZER; + *wcp = 0; + return 0; + } + } +} + +size_t wcrtomb(char *mbs, wchar_t wc, mbstate_t *stp) { + auto cc = mlibc::current_charcode(); + + // wcrtomb() always takes a mbstate_t. + __ensure(stp); + + // TODO: Implement the following case: + __ensure(mbs); + + mlibc::code_seq wseq{&wc, &wc + 1}; + mlibc::code_seq nseq{mbs, mbs + 4}; // TODO: Replace 4 by some named constant. + if(auto e = cc->encode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) { + __ensure(!"encode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + size_t n = nseq.it - mbs; + if(!n) // Null-terminate resulting wide string. + *mbs = 0; + return n; + } +} + +size_t mbsrtowcs(wchar_t *wcs, const char **mbsp, size_t wc_limit, mbstate_t *stp) { + __ensure(mbsp); + + auto cc = mlibc::current_charcode(); + __mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER; + mlibc::code_seq nseq{*mbsp, nullptr}; + mlibc::code_seq wseq{wcs, wcs + wc_limit}; + + if(!stp) + stp = &mbsrtowcs_state; + + if(!wcs) { + size_t size; + if(auto e = cc->decode_wtranscode_length(nseq, &size, st); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + if(auto e = cc->decode_wtranscode(nseq, wseq, st); e != mlibc::charcode_error::null) { + __ensure(!"decode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + size_t n = wseq.it - wcs; + if(n < wc_limit) // Null-terminate resulting wide string. + wcs[n] = 0; + *mbsp = nullptr; + return n; + } +} + +size_t mbsnrtowcs(wchar_t *wcs, const char **mbsp, size_t mb_limit, size_t wc_limit, mbstate_t *stp) { + __ensure(mbsp); + + auto cc = mlibc::current_charcode(); + __mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER; + mlibc::code_seq nseq{*mbsp, (*mbsp) + mb_limit}; + mlibc::code_seq wseq{wcs, wcs + wc_limit}; + + if(!stp) + stp = &mbsrtowcs_state; + + if(!wcs) { + size_t size; + if(auto e = cc->decode_wtranscode_length(nseq, &size, st); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + if(auto e = cc->decode_wtranscode(nseq, wseq, st); e != mlibc::charcode_error::null) { + __ensure(!"decode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + size_t n = wseq.it - wcs; + if(n < wc_limit) // Null-terminate resulting wide string. + wcs[n] = 0; + *mbsp = nullptr; + return n; + } +} + +size_t wcsrtombs(char *mbs, const wchar_t **wcsp, size_t mb_limit, mbstate_t *stp) { + __ensure(wcsp && "wcsrtombs() with null input"); + auto cc = mlibc::current_charcode(); + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + mlibc::code_seq wseq{*wcsp, nullptr}; + + if(!stp) + stp = &wcsrtombs_state; + + if(!mbs) { + size_t size; + if(auto e = cc->encode_wtranscode_length(wseq, &size, *stp); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + if(auto e = cc->encode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) { + __ensure(!"encode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + *wcsp = wseq.it; + size_t n = nseq.it - mbs; + if(n < mb_limit) // Null-terminate resulting narrow string. + mbs[n] = 0; + return n; + } +} + +size_t wcsnrtombs(char *mbs, const wchar_t **wcsp, size_t wc_limit, size_t mb_limit, mbstate_t *stp) { + __ensure(wcsp && "wcsrtombs() with null input"); + auto cc = mlibc::current_charcode(); + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + mlibc::code_seq wseq{*wcsp, (*wcsp) + wc_limit}; + + if(!stp) + stp = &wcsrtombs_state; + + if(!mbs) { + size_t size; + if(auto e = cc->encode_wtranscode_length(wseq, &size, *stp); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + if(auto e = cc->encode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) { + __ensure(!"encode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + *wcsp = wseq.it; + size_t n = nseq.it - mbs; + if(n < mb_limit) // Null-terminate resulting narrow string. + mbs[n] = 0; + return n; + } +} + +/* + * The code in this anonymous namespace and the wcwidth function below + * are taken from https://github.com/termux/wcwidth/, under the following license: + * + * Copyright (C) Fredrik Fornwall 2016. + * Distributed under the MIT License. + * + * Implementation of wcwidth(3) as a C port of: + * https://github.com/jquast/wcwidth + * + * Report issues at: + * https://github.com/termux/wcwidth + */ + +namespace { + +struct width_interval { + int start; + int end; +}; + +// From https://github.com/jquast/wcwidth/blob/master/wcwidth/table_zero.py +// at commit b29897e5a1b403a0e36f7fc991614981cbc42475 (2020-07-14): +struct width_interval ZERO_WIDTH[] = { + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x007fd, 0x007fd}, // Nko Dantayalan ..Nko Dantayalan + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x008d3, 0x008e1}, // Arabic Small Low Waw ..Arabic Small High Sign S + {0x008e3, 0x00902}, // Arabic Turned Damma Belo..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x009fe, 0x009fe}, // Bengali Sandhi Mark ..Bengali Sandhi Mark + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00afa, 0x00aff}, // Gujarati Sign Sukun ..Gujarati Sign Two-circle + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b55, 0x00b56}, // (nil) ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c00, 0x00c00}, // Telugu Sign Combining Ca..Telugu Sign Combining Ca + {0x00c04, 0x00c04}, // Telugu Sign Combining An..Telugu Sign Combining An + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00c81, 0x00c81}, // Kannada Sign Candrabindu..Kannada Sign Candrabindu + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d00, 0x00d01}, // Malayalam Sign Combining..Malayalam Sign Candrabin + {0x00d3b, 0x00d3c}, // Malayalam Sign Vertical ..Malayalam Sign Circular + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00d81, 0x00d81}, // (nil) ..(nil) + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00ebc}, // Lao Vowel Sign I ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b4, 0x017b5}, // Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x01885, 0x01886}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a1b, 0x01a1b}, // Buginese Vowel Sign Ae ..Buginese Vowel Sign Ae + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01ab0, 0x01ac0}, // Combining Doubled Circum..(nil) + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01bab, 0x01bad}, // Sundanese Sign Virama ..Sundanese Consonant Sign + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01cf4, 0x01cf4}, // Vedic Tone Candra Above ..Vedic Tone Candra Above + {0x01cf8, 0x01cf9}, // Vedic Tone Ring Above ..Vedic Tone Double Ring A + {0x01dc0, 0x01df9}, // Combining Dotted Grave A..Combining Wide Inverted + {0x01dfb, 0x01dff}, // Combining Deletion Mark ..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302d}, // Ideographic Level Tone M..Ideographic Entering Ton + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a674, 0x0a67d}, // Combining Cyrillic Lette..Combining Cyrillic Payer + {0x0a69e, 0x0a69f}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a82c, 0x0a82c}, // (nil) ..(nil) + {0x0a8c4, 0x0a8c5}, // Saurashtra Sign Virama ..Saurashtra Sign Candrabi + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a8ff, 0x0a8ff}, // Devanagari Vowel Sign Ay..Devanagari Vowel Sign Ay + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bd}, // Javanese Vowel Sign Pepe..Javanese Consonant Sign + {0x0a9e5, 0x0a9e5}, // Myanmar Sign Shan Saw ..Myanmar Sign Shan Saw + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa7c, 0x0aa7c}, // Myanmar Sign Tai Laing T..Myanmar Sign Tai Laing T + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0aaec, 0x0aaed}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0aaf6, 0x0aaf6}, // Meetei Mayek Virama ..Meetei Mayek Virama + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe2f}, // Combining Ligature Left ..Combining Cyrillic Titlo + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x102e0, 0x102e0}, // Coptic Epact Thousands M..Coptic Epact Thousands M + {0x10376, 0x1037a}, // Combining Old Permic Let..Combining Old Permic Let + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x10ae5, 0x10ae6}, // Manichaean Abbreviation ..Manichaean Abbreviation + {0x10d24, 0x10d27}, // Hanifi Rohingya Sign Har..Hanifi Rohingya Sign Tas + {0x10eab, 0x10eac}, // (nil) ..(nil) + {0x10f46, 0x10f50}, // Sogdian Combining Dot Be..Sogdian Combining Stroke + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x1107f, 0x11081}, // Brahmi Number Joiner ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x11100, 0x11102}, // Chakma Sign Candrabindu ..Chakma Sign Visarga + {0x11127, 0x1112b}, // Chakma Vowel Sign A ..Chakma Vowel Sign Uu + {0x1112d, 0x11134}, // Chakma Vowel Sign Ai ..Chakma Maayyaa + {0x11173, 0x11173}, // Mahajani Sign Nukta ..Mahajani Sign Nukta + {0x11180, 0x11181}, // Sharada Sign Candrabindu..Sharada Sign Anusvara + {0x111b6, 0x111be}, // Sharada Vowel Sign U ..Sharada Vowel Sign O + {0x111c9, 0x111cc}, // Sharada Sandhi Mark ..Sharada Extra Short Vowe + {0x111cf, 0x111cf}, // (nil) ..(nil) + {0x1122f, 0x11231}, // Khojki Vowel Sign U ..Khojki Vowel Sign Ai + {0x11234, 0x11234}, // Khojki Sign Anusvara ..Khojki Sign Anusvara + {0x11236, 0x11237}, // Khojki Sign Nukta ..Khojki Sign Shadda + {0x1123e, 0x1123e}, // Khojki Sign Sukun ..Khojki Sign Sukun + {0x112df, 0x112df}, // Khudawadi Sign Anusvara ..Khudawadi Sign Anusvara + {0x112e3, 0x112ea}, // Khudawadi Vowel Sign U ..Khudawadi Sign Virama + {0x11300, 0x11301}, // Grantha Sign Combining A..Grantha Sign Candrabindu + {0x1133b, 0x1133c}, // Combining Bindu Below ..Grantha Sign Nukta + {0x11340, 0x11340}, // Grantha Vowel Sign Ii ..Grantha Vowel Sign Ii + {0x11366, 0x1136c}, // Combining Grantha Digit ..Combining Grantha Digit + {0x11370, 0x11374}, // Combining Grantha Letter..Combining Grantha Letter + {0x11438, 0x1143f}, // Newa Vowel Sign U ..Newa Vowel Sign Ai + {0x11442, 0x11444}, // Newa Sign Virama ..Newa Sign Anusvara + {0x11446, 0x11446}, // Newa Sign Nukta ..Newa Sign Nukta + {0x1145e, 0x1145e}, // Newa Sandhi Mark ..Newa Sandhi Mark + {0x114b3, 0x114b8}, // Tirhuta Vowel Sign U ..Tirhuta Vowel Sign Vocal + {0x114ba, 0x114ba}, // Tirhuta Vowel Sign Short..Tirhuta Vowel Sign Short + {0x114bf, 0x114c0}, // Tirhuta Sign Candrabindu..Tirhuta Sign Anusvara + {0x114c2, 0x114c3}, // Tirhuta Sign Virama ..Tirhuta Sign Nukta + {0x115b2, 0x115b5}, // Siddham Vowel Sign U ..Siddham Vowel Sign Vocal + {0x115bc, 0x115bd}, // Siddham Sign Candrabindu..Siddham Sign Anusvara + {0x115bf, 0x115c0}, // Siddham Sign Virama ..Siddham Sign Nukta + {0x115dc, 0x115dd}, // Siddham Vowel Sign Alter..Siddham Vowel Sign Alter + {0x11633, 0x1163a}, // Modi Vowel Sign U ..Modi Vowel Sign Ai + {0x1163d, 0x1163d}, // Modi Sign Anusvara ..Modi Sign Anusvara + {0x1163f, 0x11640}, // Modi Sign Virama ..Modi Sign Ardhacandra + {0x116ab, 0x116ab}, // Takri Sign Anusvara ..Takri Sign Anusvara + {0x116ad, 0x116ad}, // Takri Vowel Sign Aa ..Takri Vowel Sign Aa + {0x116b0, 0x116b5}, // Takri Vowel Sign U ..Takri Vowel Sign Au + {0x116b7, 0x116b7}, // Takri Sign Nukta ..Takri Sign Nukta + {0x1171d, 0x1171f}, // Ahom Consonant Sign Medi..Ahom Consonant Sign Medi + {0x11722, 0x11725}, // Ahom Vowel Sign I ..Ahom Vowel Sign Uu + {0x11727, 0x1172b}, // Ahom Vowel Sign Aw ..Ahom Sign Killer + {0x1182f, 0x11837}, // Dogra Vowel Sign U ..Dogra Sign Anusvara + {0x11839, 0x1183a}, // Dogra Sign Virama ..Dogra Sign Nukta + {0x1193b, 0x1193c}, // (nil) ..(nil) + {0x1193e, 0x1193e}, // (nil) ..(nil) + {0x11943, 0x11943}, // (nil) ..(nil) + {0x119d4, 0x119d7}, // Nandinagari Vowel Sign U..Nandinagari Vowel Sign V + {0x119da, 0x119db}, // Nandinagari Vowel Sign E..Nandinagari Vowel Sign A + {0x119e0, 0x119e0}, // Nandinagari Sign Virama ..Nandinagari Sign Virama + {0x11a01, 0x11a0a}, // Zanabazar Square Vowel S..Zanabazar Square Vowel L + {0x11a33, 0x11a38}, // Zanabazar Square Final C..Zanabazar Square Sign An + {0x11a3b, 0x11a3e}, // Zanabazar Square Cluster..Zanabazar Square Cluster + {0x11a47, 0x11a47}, // Zanabazar Square Subjoin..Zanabazar Square Subjoin + {0x11a51, 0x11a56}, // Soyombo Vowel Sign I ..Soyombo Vowel Sign Oe + {0x11a59, 0x11a5b}, // Soyombo Vowel Sign Vocal..Soyombo Vowel Length Mar + {0x11a8a, 0x11a96}, // Soyombo Final Consonant ..Soyombo Sign Anusvara + {0x11a98, 0x11a99}, // Soyombo Gemination Mark ..Soyombo Subjoiner + {0x11c30, 0x11c36}, // Bhaiksuki Vowel Sign I ..Bhaiksuki Vowel Sign Voc + {0x11c38, 0x11c3d}, // Bhaiksuki Vowel Sign E ..Bhaiksuki Sign Anusvara + {0x11c3f, 0x11c3f}, // Bhaiksuki Sign Virama ..Bhaiksuki Sign Virama + {0x11c92, 0x11ca7}, // Marchen Subjoined Letter..Marchen Subjoined Letter + {0x11caa, 0x11cb0}, // Marchen Subjoined Letter..Marchen Vowel Sign Aa + {0x11cb2, 0x11cb3}, // Marchen Vowel Sign U ..Marchen Vowel Sign E + {0x11cb5, 0x11cb6}, // Marchen Sign Anusvara ..Marchen Sign Candrabindu + {0x11d31, 0x11d36}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3a, 0x11d3a}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3c, 0x11d3d}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3f, 0x11d45}, // Masaram Gondi Vowel Sign..Masaram Gondi Virama + {0x11d47, 0x11d47}, // Masaram Gondi Ra-kara ..Masaram Gondi Ra-kara + {0x11d90, 0x11d91}, // Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign + {0x11d95, 0x11d95}, // Gunjala Gondi Sign Anusv..Gunjala Gondi Sign Anusv + {0x11d97, 0x11d97}, // Gunjala Gondi Virama ..Gunjala Gondi Virama + {0x11ef3, 0x11ef4}, // Makasar Vowel Sign I ..Makasar Vowel Sign U + {0x16af0, 0x16af4}, // Bassa Vah Combining High..Bassa Vah Combining High + {0x16b30, 0x16b36}, // Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta + {0x16f4f, 0x16f4f}, // Miao Sign Consonant Modi..Miao Sign Consonant Modi + {0x16f8f, 0x16f92}, // Miao Tone Right ..Miao Tone Below + {0x16fe4, 0x16fe4}, // (nil) ..(nil) + {0x1bc9d, 0x1bc9e}, // Duployan Thick Letter Se..Duployan Double Mark + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0x1da00, 0x1da36}, // Signwriting Head Rim ..Signwriting Air Sucking + {0x1da3b, 0x1da6c}, // Signwriting Mouth Closed..Signwriting Excitement + {0x1da75, 0x1da75}, // Signwriting Upper Body T..Signwriting Upper Body T + {0x1da84, 0x1da84}, // Signwriting Location Hea..Signwriting Location Hea + {0x1da9b, 0x1da9f}, // Signwriting Fill Modifie..Signwriting Fill Modifie + {0x1daa1, 0x1daaf}, // Signwriting Rotation Mod..Signwriting Rotation Mod + {0x1e000, 0x1e006}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e008, 0x1e018}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e01b, 0x1e021}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e023, 0x1e024}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e026, 0x1e02a}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e130, 0x1e136}, // Nyiakeng Puachue Hmong T..Nyiakeng Puachue Hmong T + {0x1e2ec, 0x1e2ef}, // Wancho Tone Tup ..Wancho Tone Koini + {0x1e8d0, 0x1e8d6}, // Mende Kikakui Combining ..Mende Kikakui Combining + {0x1e944, 0x1e94a}, // Adlam Alif Lengthener ..Adlam Nukta + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 +}; + +// https://github.com/jquast/wcwidth/blob/master/wcwidth/table_wide.py +// at commit b29897e5a1b403a0e36f7fc991614981cbc42475 (2020-07-14): +struct width_interval WIDE_EASTASIAN[] = { + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x0231a, 0x0231b}, // Watch ..Hourglass + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x023e9, 0x023ec}, // Black Right-pointing Dou..Black Down-pointing Doub + {0x023f0, 0x023f0}, // Alarm Clock ..Alarm Clock + {0x023f3, 0x023f3}, // Hourglass With Flowing S..Hourglass With Flowing S + {0x025fd, 0x025fe}, // White Medium Small Squar..Black Medium Small Squar + {0x02614, 0x02615}, // Umbrella With Rain Drops..Hot Beverage + {0x02648, 0x02653}, // Aries ..Pisces + {0x0267f, 0x0267f}, // Wheelchair Symbol ..Wheelchair Symbol + {0x02693, 0x02693}, // Anchor ..Anchor + {0x026a1, 0x026a1}, // High Voltage Sign ..High Voltage Sign + {0x026aa, 0x026ab}, // Medium White Circle ..Medium Black Circle + {0x026bd, 0x026be}, // Soccer Ball ..Baseball + {0x026c4, 0x026c5}, // Snowman Without Snow ..Sun Behind Cloud + {0x026ce, 0x026ce}, // Ophiuchus ..Ophiuchus + {0x026d4, 0x026d4}, // No Entry ..No Entry + {0x026ea, 0x026ea}, // Church ..Church + {0x026f2, 0x026f3}, // Fountain ..Flag In Hole + {0x026f5, 0x026f5}, // Sailboat ..Sailboat + {0x026fa, 0x026fa}, // Tent ..Tent + {0x026fd, 0x026fd}, // Fuel Pump ..Fuel Pump + {0x02705, 0x02705}, // White Heavy Check Mark ..White Heavy Check Mark + {0x0270a, 0x0270b}, // Raised Fist ..Raised Hand + {0x02728, 0x02728}, // Sparkles ..Sparkles + {0x0274c, 0x0274c}, // Cross Mark ..Cross Mark + {0x0274e, 0x0274e}, // Negative Squared Cross M..Negative Squared Cross M + {0x02753, 0x02755}, // Black Question Mark Orna..White Exclamation Mark O + {0x02757, 0x02757}, // Heavy Exclamation Mark S..Heavy Exclamation Mark S + {0x02795, 0x02797}, // Heavy Plus Sign ..Heavy Division Sign + {0x027b0, 0x027b0}, // Curly Loop ..Curly Loop + {0x027bf, 0x027bf}, // Double Curly Loop ..Double Curly Loop + {0x02b1b, 0x02b1c}, // Black Large Square ..White Large Square + {0x02b50, 0x02b50}, // White Medium Star ..White Medium Star + {0x02b55, 0x02b55}, // Heavy Large Circle ..Heavy Large Circle + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312f}, // Bopomofo Letter B ..Bopomofo Letter Nn + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031e3}, // Ideographic Annotation L..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x04dbf}, // Partnership Sign ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x16fe0, 0x16fe4}, // Tangut Iteration Mark ..(nil) + {0x16ff0, 0x16ff1}, // (nil) ..(nil) + {0x17000, 0x187f7}, // (nil) ..(nil) + {0x18800, 0x18cd5}, // Tangut Component-001 ..(nil) + {0x18d00, 0x18d08}, // (nil) ..(nil) + {0x1b000, 0x1b11e}, // Katakana Letter Archaic ..Hentaigana Letter N-mu-m + {0x1b150, 0x1b152}, // Hiragana Letter Small Wi..Hiragana Letter Small Wo + {0x1b164, 0x1b167}, // Katakana Letter Small Wi..Katakana Letter Small N + {0x1b170, 0x1b2fb}, // Nushu Character-1b170 ..Nushu Character-1b2fb + {0x1f004, 0x1f004}, // Mahjong Tile Red Dragon ..Mahjong Tile Red Dragon + {0x1f0cf, 0x1f0cf}, // Playing Card Black Joker..Playing Card Black Joker + {0x1f18e, 0x1f18e}, // Negative Squared Ab ..Negative Squared Ab + {0x1f191, 0x1f19a}, // Squared Cl ..Squared Vs + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23b}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x1f260, 0x1f265}, // Rounded Symbol For Fu ..Rounded Symbol For Cai + {0x1f300, 0x1f320}, // Cyclone ..Shooting Star + {0x1f32d, 0x1f335}, // Hot Dog ..Cactus + {0x1f337, 0x1f37c}, // Tulip ..Baby Bottle + {0x1f37e, 0x1f393}, // Bottle With Popping Cork..Graduation Cap + {0x1f3a0, 0x1f3ca}, // Carousel Horse ..Swimmer + {0x1f3cf, 0x1f3d3}, // Cricket Bat And Ball ..Table Tennis Paddle And + {0x1f3e0, 0x1f3f0}, // House Building ..European Castle + {0x1f3f4, 0x1f3f4}, // Waving Black Flag ..Waving Black Flag + {0x1f3f8, 0x1f43e}, // Badminton Racquet And Sh..Paw Prints + {0x1f440, 0x1f440}, // Eyes ..Eyes + {0x1f442, 0x1f4fc}, // Ear ..Videocassette + {0x1f4ff, 0x1f53d}, // Prayer Beads ..Down-pointing Small Red + {0x1f54b, 0x1f54e}, // Kaaba ..Menorah With Nine Branch + {0x1f550, 0x1f567}, // Clock Face One Oclock ..Clock Face Twelve-thirty + {0x1f57a, 0x1f57a}, // Man Dancing ..Man Dancing + {0x1f595, 0x1f596}, // Reversed Hand With Middl..Raised Hand With Part Be + {0x1f5a4, 0x1f5a4}, // Black Heart ..Black Heart + {0x1f5fb, 0x1f64f}, // Mount Fuji ..Person With Folded Hands + {0x1f680, 0x1f6c5}, // Rocket ..Left Luggage + {0x1f6cc, 0x1f6cc}, // Sleeping Accommodation ..Sleeping Accommodation + {0x1f6d0, 0x1f6d2}, // Place Of Worship ..Shopping Trolley + {0x1f6d5, 0x1f6d7}, // Hindu Temple ..(nil) + {0x1f6eb, 0x1f6ec}, // Airplane Departure ..Airplane Arriving + {0x1f6f4, 0x1f6fc}, // Scooter ..(nil) + {0x1f7e0, 0x1f7eb}, // Large Orange Circle ..Large Brown Square + {0x1f90c, 0x1f93a}, // (nil) ..Fencer + {0x1f93c, 0x1f945}, // Wrestlers ..Goal Net + {0x1f947, 0x1f978}, // First Place Medal ..(nil) + {0x1f97a, 0x1f9cb}, // Face With Pleading Eyes ..(nil) + {0x1f9cd, 0x1f9ff}, // Standing Person ..Nazar Amulet + {0x1fa70, 0x1fa74}, // Ballet Shoes ..(nil) + {0x1fa78, 0x1fa7a}, // Drop Of Blood ..Stethoscope + {0x1fa80, 0x1fa86}, // Yo-yo ..(nil) + {0x1fa90, 0x1faa8}, // Ringed Planet ..(nil) + {0x1fab0, 0x1fab6}, // (nil) ..(nil) + {0x1fac0, 0x1fac2}, // (nil) ..(nil) + {0x1fad0, 0x1fad6}, // (nil) ..(nil) + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) +}; + +bool intable(struct width_interval* table, int table_length, int c) { + // First quick check for Latin1 etc. characters. + if (c < table[0].start) return false; + + // Binary search in table. + int bot = 0; + int top = table_length - 1; + while (top >= bot) { + int mid = (bot + top) / 2; + if (table[mid].end < c) { + bot = mid + 1; + } else if (table[mid].start > c) { + top = mid - 1; + } else { + return true; + } + } + return false; +} + +} + +int wcwidth(wchar_t ucs) { + // NOTE: created by hand, there isn't anything identifiable other than + // general Cf category code to identify these, and some characters in Cf + // category code are of non-zero width. + if (ucs == 0 || ucs == 0x034F || (0x200B <= ucs && ucs <= 0x200F) || + ucs == 0x2028 || ucs == 0x2029 || (0x202A <= ucs && ucs <= 0x202E) || + (0x2060 <= ucs && ucs <= 0x2063)) { + return 0; + } + + // C0/C1 control characters. + if (ucs < 32 || (0x07F <= ucs && ucs < 0x0A0)) return -1; + + // Combining characters with zero width. + if (intable(ZERO_WIDTH, sizeof(ZERO_WIDTH) / sizeof(struct width_interval), ucs)) return 0; + + return intable(WIDE_EASTASIAN, sizeof(WIDE_EASTASIAN) / sizeof(struct width_interval), ucs) ? 2 : 1; +} + +int wcswidth(const wchar_t *wcs, size_t n) { + int ret = 0; + for(size_t i = 0; i < n && wcs[i]; i++) { + int cols = wcwidth(wcs[i]); + if (cols < 0) + return -1; + ret += cols; + } + + return ret; +} + +wchar_t *wcsdup(const wchar_t *s) { + size_t len = wcslen(s); + wchar_t *ret = (wchar_t *) malloc(sizeof(wchar_t) * (len + 1)); + if(!ret) + return NULL; + wmemcpy(ret, s, len + 1); + return ret; +} + +int wcsncasecmp(const wchar_t* s1, const wchar_t* s2, size_t n) { + for(size_t i = 0; i < n; i++) { + wint_t c1 = towlower(s1[i]); + wint_t c2 = towlower(s2[i]); + if(c1 == L'\0' && c2 == L'\0') + return 0; + if(c1 < c2) + return -1; + if(c1 > c2) + return 1; + } + return 0; +} + +int wcscasecmp(const wchar_t *, const wchar_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/ansi/generic/wctype.cpp b/lib/mlibc/options/ansi/generic/wctype.cpp new file mode 100644 index 0000000..57dcbc9 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/wctype.cpp @@ -0,0 +1,9 @@ + +#include +#include +#include +#include + +wctrans_t wctrans(const char *) MLIBC_STUB_BODY +wint_t towctrans(wint_t, wctrans_t) MLIBC_STUB_BODY + -- cgit v1.2.3