From 28f540f45bbacd939bfd07f213bcad2bf730b1bf Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Sat, 18 Feb 1995 01:27:10 +0000 Subject: initial import --- stdlib/Makefile | 43 +++ stdlib/abs.c | 30 ++ stdlib/alloca.h | 44 +++ stdlib/atexit.c | 65 ++++ stdlib/atof.c | 30 ++ stdlib/atoi.c | 30 ++ stdlib/atol.c | 30 ++ stdlib/bsearch.c | 51 +++ stdlib/div.c | 92 +++++ stdlib/exit.c | 70 ++++ stdlib/exit.h | 44 +++ stdlib/labs.c | 31 ++ stdlib/ldiv.c | 92 +++++ stdlib/mblen.c | 31 ++ stdlib/mbstowcs.c | 78 ++++ stdlib/mbtowc.c | 84 +++++ stdlib/msort.c | 103 +++++ stdlib/on_exit.c | 37 ++ stdlib/qsort.c | 243 ++++++++++++ stdlib/rand.c | 30 ++ stdlib/random.c | 357 ++++++++++++++++++ stdlib/stdlib.h | 289 ++++++++++++++ stdlib/strtod.c | 1027 ++++++++++++++++++++++++++++++++++++++++++++++++++ stdlib/strtof.c | 12 + stdlib/strtol.c | 189 ++++++++++ stdlib/strtold.c | 12 + stdlib/strtoq.c | 22 ++ stdlib/strtoul.c | 21 ++ stdlib/strtouq.c | 22 ++ stdlib/testdiv.c | 33 ++ stdlib/testdiv.input | 2 + stdlib/testmb.c | 69 ++++ stdlib/testrand.c | 51 +++ stdlib/testsort.c | 38 ++ stdlib/tst-strtod.c | 94 +++++ stdlib/tst-strtol.c | 127 +++++++ stdlib/wcstombs.c | 77 ++++ stdlib/wctomb.c | 72 ++++ 38 files changed, 3772 insertions(+) create mode 100644 stdlib/Makefile create mode 100644 stdlib/abs.c create mode 100644 stdlib/alloca.h create mode 100644 stdlib/atexit.c create mode 100644 stdlib/atof.c create mode 100644 stdlib/atoi.c create mode 100644 stdlib/atol.c create mode 100644 stdlib/bsearch.c create mode 100644 stdlib/div.c create mode 100644 stdlib/exit.c create mode 100644 stdlib/exit.h create mode 100644 stdlib/labs.c create mode 100644 stdlib/ldiv.c create mode 100644 stdlib/mblen.c create mode 100644 stdlib/mbstowcs.c create mode 100644 stdlib/mbtowc.c create mode 100644 stdlib/msort.c create mode 100644 stdlib/on_exit.c create mode 100644 stdlib/qsort.c create mode 100644 stdlib/rand.c create mode 100644 stdlib/random.c create mode 100644 stdlib/stdlib.h create mode 100644 stdlib/strtod.c create mode 100644 stdlib/strtof.c create mode 100644 stdlib/strtol.c create mode 100644 stdlib/strtold.c create mode 100644 stdlib/strtoq.c create mode 100644 stdlib/strtoul.c create mode 100644 stdlib/strtouq.c create mode 100644 stdlib/testdiv.c create mode 100644 stdlib/testdiv.input create mode 100644 stdlib/testmb.c create mode 100644 stdlib/testrand.c create mode 100644 stdlib/testsort.c create mode 100644 stdlib/tst-strtod.c create mode 100644 stdlib/tst-strtol.c create mode 100644 stdlib/wcstombs.c create mode 100644 stdlib/wctomb.c (limited to 'stdlib') diff --git a/stdlib/Makefile b/stdlib/Makefile new file mode 100644 index 0000000000..1a1498c662 --- /dev/null +++ b/stdlib/Makefile @@ -0,0 +1,43 @@ +# Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. + +# You should have received a copy of the GNU Library General Public +# License along with the GNU C Library; see the file COPYING.LIB. If +# not, write to the Free Software Foundation, Inc., 675 Mass Ave, +# Cambridge, MA 02139, USA. + +# +# Makefile for stdlib routines +# +subdir := stdlib + +headers := stdlib.h alloca.h + +routines := \ + atof atoi atol \ + abort \ + bsearch qsort msort \ + getenv putenv setenv \ + exit on_exit atexit \ + abs labs \ + div ldiv \ + mblen mbstowcs mbtowc wcstombs wctomb \ + random rand \ + strtol strtoul strtoq strtouq \ + strtof strtod strtold \ + system + +distribute := exit.h +tests := tst-strtol tst-strtod testmb testrand testsort testdiv + +include ../Rules diff --git a/stdlib/abs.c b/stdlib/abs.c new file mode 100644 index 0000000000..b8db100b41 --- /dev/null +++ b/stdlib/abs.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include + +#undef abs + +/* Return the absolute value of I. */ +__CONSTVALUE +int +DEFUN(abs, (i), int i) +{ + return(i < 0 ? -i : i); +} diff --git a/stdlib/alloca.h b/stdlib/alloca.h new file mode 100644 index 0000000000..4e9de464a3 --- /dev/null +++ b/stdlib/alloca.h @@ -0,0 +1,44 @@ +/* Copyright (C) 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the, 1992 Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _ALLOCA_H +#define _ALLOCA_H 1 +#include + +#define __need_size_t +#include + +__BEGIN_DECLS + +/* Remove any previous definitions. */ +#undef __alloca +#undef alloca + +/* Allocate a block that will be freed when the calling function exits. */ +extern __ptr_t __alloca __P ((size_t __size)); +extern __ptr_t alloca __P ((size_t __size)); + +#ifdef __GNUC__ +#define __alloca(size) __builtin_alloca(size) +#endif /* GCC. */ + +#define alloca(size) __alloca(size) + +__END_DECLS + +#endif /* alloca.h */ diff --git a/stdlib/atexit.c b/stdlib/atexit.c new file mode 100644 index 0000000000..a2ab453576 --- /dev/null +++ b/stdlib/atexit.c @@ -0,0 +1,65 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include "exit.h" + + +/* Register FUNC to be executed by `exit'. */ +int +DEFUN(atexit, (func), void EXFUN((*func), (NOARGS))) +{ + struct exit_function *new = __new_exitfn(); + + if (new == NULL) + return -1; + + new->flavor = ef_at; + new->func.at = func; + return 0; +} + + +static struct exit_function_list fnlist = { NULL, 0, }; +struct exit_function_list *__exit_funcs = &fnlist; + +struct exit_function * +DEFUN_VOID(__new_exitfn) +{ + register struct exit_function_list *l; + + for (l = __exit_funcs; l != NULL; l = l->next) + { + register size_t i; + for (i = 0; i < l->idx; ++i) + if (l->fns[i].flavor == ef_free) + return &l->fns[i]; + if (l->idx < sizeof(l->fns) / sizeof(l->fns[0])) + return &l->fns[l->idx++]; + } + + l = (struct exit_function_list *) malloc(sizeof(struct exit_function_list)); + if (l == NULL) + return NULL; + l->next = __exit_funcs; + __exit_funcs = l; + + l->idx = 1; + return &l->fns[0]; +} diff --git a/stdlib/atof.c b/stdlib/atof.c new file mode 100644 index 0000000000..79585464d1 --- /dev/null +++ b/stdlib/atof.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include + +#undef atof + + +/* Convert a string to a double. */ +double +DEFUN(atof, (nptr), CONST char *nptr) +{ + return(strtod(nptr, (char **) NULL)); +} diff --git a/stdlib/atoi.c b/stdlib/atoi.c new file mode 100644 index 0000000000..9fe280cc3e --- /dev/null +++ b/stdlib/atoi.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include + +#undef atoi + + +/* Convert a string to an int. */ +int +DEFUN(atoi, (nptr), CONST char *nptr) +{ + return((int) strtol(nptr, (char **) NULL, 10)); +} diff --git a/stdlib/atol.c b/stdlib/atol.c new file mode 100644 index 0000000000..75f599c107 --- /dev/null +++ b/stdlib/atol.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include + +#undef atol + + +/* Convert a string to a long int. */ +long int +DEFUN(atol, (nptr), CONST char *nptr) +{ + return(strtol(nptr, (char **) NULL, 10)); +} diff --git a/stdlib/bsearch.c b/stdlib/bsearch.c new file mode 100644 index 0000000000..d798eabd2b --- /dev/null +++ b/stdlib/bsearch.c @@ -0,0 +1,51 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include + + +/* Perform a binary search for KEY in BASE which has NMEMB elements + of SIZE bytes each. The comparisons are done by (*COMPAR)(). */ +PTR +DEFUN(bsearch, (key, base, nmemb, size, compar), + register CONST PTR key AND register CONST PTR base AND + size_t nmemb AND register size_t size AND + register int EXFUN((*compar), (CONST PTR, CONST PTR))) +{ + register size_t l, u, idx; + register CONST PTR p; + register int comparison; + + l = 0; + u = nmemb; + while (l < u) + { + idx = (l + u) / 2; + p = (PTR) (((CONST char *) base) + (idx * size)); + comparison = (*compar)(key, p); + if (comparison < 0) + u = idx; + else if (comparison > 0) + l = idx + 1; + else + return (PTR) p; + } + + return NULL; +} diff --git a/stdlib/div.c b/stdlib/div.c new file mode 100644 index 0000000000..5a0ee7da38 --- /dev/null +++ b/stdlib/div.c @@ -0,0 +1,92 @@ +/* Copyright (C) 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* + * Copyright (c) 1990 Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#include +#include + + +/* Return the `div_t' representation of NUMER over DENOM. */ +__CONSTVALUE +div_t +DEFUN(div, (numer, denom), int numer AND int denom) +{ + div_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + /* The ANSI standard says that |QUOT| <= |NUMER / DENOM|, where + NUMER / DENOM is to be computed in infinite precision. In + other words, we should always truncate the quotient towards + zero, never -infinity. Machine division and remainer may + work either way when one or both of NUMER or DENOM is + negative. If only one is negative and QUOT has been + truncated towards -infinity, REM will have the same sign as + DENOM and the opposite sign of NUMER; if both are negative + and QUOT has been truncated towards -infinity, REM will be + positive (will have the opposite sign of NUMER). These are + considered `wrong'. If both are NUM and DENOM are positive, + RESULT will always be positive. This all boils down to: if + NUMER >= 0, but REM < 0, we got the wrong answer. In that + case, to get the right answer, add 1 to QUOT and subtract + DENOM from REM. */ + + if (numer >= 0 && result.rem < 0) + { + ++result.quot; + result.rem -= denom; + } + + return result; +} diff --git a/stdlib/exit.c b/stdlib/exit.c new file mode 100644 index 0000000000..4f33a25cc4 --- /dev/null +++ b/stdlib/exit.c @@ -0,0 +1,70 @@ +/* Copyright (C) 1991, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include "exit.h" + +#ifdef HAVE_GNU_LD +#include "set-hooks.h" +DEFINE_HOOK (__libc_atexit, (void)) +#endif + + +/* Call all functions registered with `atexit' and `on_exit', + in the reverse of the order in which they were registered + perform stdio cleanup, and terminate program execution with STATUS. */ +void +DEFUN(exit, (status), int status) +{ + register CONST struct exit_function_list *l; + + for (l = __exit_funcs; l != NULL; l = l->next) + { + register size_t i = l->idx; + while (i-- > 0) + { + CONST struct exit_function *CONST f = &l->fns[i]; + switch (f->flavor) + { + case ef_free: + break; + case ef_on: + (*f->func.on.fn)(status, f->func.on.arg); + break; + case ef_at: + (*f->func.at)(); + break; + } + } + } + +#ifdef HAVE_GNU_LD + RUN_HOOK (__libc_atexit, ()); +#else + { + extern void EXFUN(_cleanup, (NOARGS)); + _cleanup(); + } +#endif + + _exit(status); +} + diff --git a/stdlib/exit.h b/stdlib/exit.h new file mode 100644 index 0000000000..214217853e --- /dev/null +++ b/stdlib/exit.h @@ -0,0 +1,44 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _EXIT_H + +struct exit_function + { + enum { ef_free, ef_on, ef_at } flavor; /* `ef_free' MUST be zero! */ + union + { + void EXFUN((*at), (NOARGS)); + struct + { + void EXFUN((*fn), (int status, PTR arg)); + PTR arg; + } on; + } func; + }; +struct exit_function_list + { + struct exit_function_list *next; + size_t idx; + struct exit_function fns[32]; + }; +extern struct exit_function_list *__exit_funcs; + +extern struct exit_function *EXFUN(__new_exitfn, (NOARGS)); + +#endif /* exit.h */ diff --git a/stdlib/labs.c b/stdlib/labs.c new file mode 100644 index 0000000000..c54339f02b --- /dev/null +++ b/stdlib/labs.c @@ -0,0 +1,31 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include + +#undef labs + + +/* Return the absolute value of I. */ +__CONSTVALUE +long int +DEFUN(labs, (i), long int i) +{ + return(i < 0 ? -i : i); +} diff --git a/stdlib/ldiv.c b/stdlib/ldiv.c new file mode 100644 index 0000000000..661f1bdbcd --- /dev/null +++ b/stdlib/ldiv.c @@ -0,0 +1,92 @@ +/* Copyright (C) 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* + * Copyright (c) 1990 Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#include +#include + + +/* Return the `ldiv_t' representation of NUMER over DENOM. */ +__CONSTVALUE +ldiv_t +DEFUN(ldiv, (numer, denom), long int numer AND long int denom) +{ + ldiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + /* The ANSI standard says that |QUOT| <= |NUMER / DENOM|, where + NUMER / DENOM is to be computed in infinite precision. In + other words, we should always truncate the quotient towards + zero, never -infinity. Machine division and remainer may + work either way when one or both of NUMER or DENOM is + negative. If only one is negative and QUOT has been + truncated towards -infinity, REM will have the same sign as + DENOM and the opposite sign of NUMER; if both are negative + and QUOT has been truncated towards -infinity, REM will be + positive (will have the opposite sign of NUMER). These are + considered `wrong'. If both are NUM and DENOM are positive, + RESULT will always be positive. This all boils down to: if + NUMER >= 0, but REM < 0, we got the wrong answer. In that + case, to get the right answer, add 1 to QUOT and subtract + DENOM from REM. */ + + if (numer >= 0 && result.rem < 0) + { + ++result.quot; + result.rem -= denom; + } + + return result; +} diff --git a/stdlib/mblen.c b/stdlib/mblen.c new file mode 100644 index 0000000000..5393ce433c --- /dev/null +++ b/stdlib/mblen.c @@ -0,0 +1,31 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include + +#undef mblen + + +/* Return the length of the multibyte character (if there is one) + at S which is no longer than N characters. */ +int +DEFUN(mblen, (s, n), CONST char *s AND size_t n) +{ + return(mbtowc((wchar_t *) NULL, s, n)); +} diff --git a/stdlib/mbstowcs.c b/stdlib/mbstowcs.c new file mode 100644 index 0000000000..38c710279a --- /dev/null +++ b/stdlib/mbstowcs.c @@ -0,0 +1,78 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include + + +extern int _mb_shift; /* Defined in mbtowc.c. */ + +/* Convert the string of multibyte characters in S to `wchar_t's in + PWCS, writing no more than N. Return the number written, + or (size_t) -1 if an invalid multibyte character is encountered. */ +size_t +DEFUN(mbstowcs, (pwcs, s, n), + register wchar_t *pwcs AND register CONST char *s AND register size_t n) +{ + int save_shift; + register size_t written = 0; + + /* Save the shift state. */ + save_shift = _mb_shift; + /* Reset the shift state. */ + _mb_shift = 0; + + while (*s != '\0') + { + int len; + if (isascii (*s)) + { + *pwcs = (wchar_t) *s; + len = 1; + } + else + len = mbtowc (pwcs, s, n); + + if (len < 1) + { + /* Return an error. */ + written = (size_t) -1; + break; + } + else + { + /* Multibyte character converted. */ + ++pwcs; + ++written; + s += len; + n -= len; + } + } + + /* Terminate the string if it has space. */ + if (n > 0) + *pwcs = (wchar_t) 0; + + /* Restore the old shift state. */ + _mb_shift = save_shift; + + /* Return how many we wrote (or maybe an error). */ + return written; +} diff --git a/stdlib/mbtowc.c b/stdlib/mbtowc.c new file mode 100644 index 0000000000..62103407c0 --- /dev/null +++ b/stdlib/mbtowc.c @@ -0,0 +1,84 @@ +/* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include + + +long int _mb_shift = 0; + +/* Convert the multibyte character at S, which is no longer + than N characters, to its `wchar_t' representation, placing + this n *PWC and returning its length. */ +int +DEFUN(mbtowc, (pwc, s, n), wchar_t *pwc AND CONST char *s AND size_t n) +{ + register CONST mb_char *mb; + register wchar_t i; + + if (s == NULL) + return _mb_shift != 0; + + if (*s == '\0') + /* ANSI 4.10.7.2, line 19. */ + return 0; + + if (isascii (*s)) + { + /* A normal ASCII character translates to itself. */ + if (pwc != NULL) + *pwc = (wchar_t) *s; + return 1; + } + + if (_ctype_info->mbchar == NULL || + _ctype_info->mbchar->mb_chars == NULL) + return -1; + + if (n > MB_CUR_MAX) + n = MB_CUR_MAX; + + for (i = 0; i < WCHAR_MAX; ++i) + { + mb = &_ctype_info->mbchar->mb_chars[i]; + /* EOF and NUL aren't MB chars. */ + if (i == (wchar_t) EOF || i == (wchar_t) '\0') + continue; + /* Normal ASCII values can't start MB chars. */ + else if (isascii(i)) + continue; + else if (mb->string == NULL || mb->len == 0) + continue; + else if (mb->len > n) + continue; + else if (!strncmp(mb->string, s, mb->len)) + { + _mb_shift += mb->shift; + if (pwc != NULL) + *pwc = i; + return mb->len; + } + } + + return -1; +} diff --git a/stdlib/msort.c b/stdlib/msort.c new file mode 100644 index 0000000000..92ba5182ed --- /dev/null +++ b/stdlib/msort.c @@ -0,0 +1,103 @@ +/* msort -- an alternative to qsort, with an identical interface. + Copyright (C) 1992 Free Software Foundation, Inc. + Written by Mike Haertel, September 1988. + +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include + +#define MEMCPY(dst, src, s) \ + ((s) == sizeof (int) \ + ? (*(int *) (dst) = *(int *) (src), (dst)) \ + : memcpy (dst, src, s)) + +static void +DEFUN(msort_with_tmp, (b, n, s, cmp, t), + PTR b AND size_t n AND size_t s AND __compar_fn_t cmp AND char *t) +{ + char *tmp; + char *b1, *b2; + size_t n1, n2; + + if (n <= 1) + return; + + n1 = n / 2; + n2 = n - n1; + b1 = b; + b2 = (char *) b + (n1 * s); + + msort_with_tmp (b1, n1, s, cmp, t); + msort_with_tmp (b2, n2, s, cmp, t); + + tmp = t; + + while (n1 > 0 && n2 > 0) + { + if ((*cmp) (b1, b2) <= 0) + { + MEMCPY (tmp, b1, s); + b1 += s; + --n1; + } + else + { + MEMCPY (tmp, b2, s); + b2 += s; + --n2; + } + tmp += s; + } + if (n1 > 0) + memcpy (tmp, b1, n1 * s); + memcpy (b, t, (n - n2) * s); +} + +void +DEFUN(qsort, (b, n, s, cmp), + PTR b AND size_t n AND size_t s AND __compar_fn_t cmp) +{ + CONST size_t size = n * s; + + if (size < 1024) + /* The temporary array is small, so put it on the stack. */ + msort_with_tmp (b, n, s, cmp, __alloca (size)); + else + { + /* It's somewhat large, so malloc it. */ + int save = errno; + char *tmp = malloc (size); + if (tmp == NULL) + { + /* Couldn't get space, so use the slower algorithm + that doesn't need a temporary array. */ + extern void EXFUN(_quicksort, (PTR __base, + size_t __nmemb, size_t __size, + __compar_fn_t __compar)); + _quicksort (b, n, s, cmp); + } + else + { + msort_with_tmp (b, n, s, cmp, tmp); + free (tmp); + } + errno = save; + } +} diff --git a/stdlib/on_exit.c b/stdlib/on_exit.c new file mode 100644 index 0000000000..bd100be895 --- /dev/null +++ b/stdlib/on_exit.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include "exit.h" + +/* Register a function to be called by exit. */ +int +DEFUN(on_exit, (func, arg), + void EXFUN((*func), (int status, PTR arg)) AND PTR arg) +{ + struct exit_function *new = __new_exitfn(); + + if (new == NULL) + return -1; + + new->flavor = ef_on; + new->func.on.fn = func; + new->func.on.arg = arg; + return 0; +} diff --git a/stdlib/qsort.c b/stdlib/qsort.c new file mode 100644 index 0000000000..bc8d171b79 --- /dev/null +++ b/stdlib/qsort.c @@ -0,0 +1,243 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. +Written by Douglas C. Schmidt (schmidt@ics.uci.edu). + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include + +/* Byte-wise swap two items of size SIZE. */ +#define SWAP(a, b, size) \ + do \ + { \ + register size_t __size = (size); \ + register char *__a = (a), *__b = (b); \ + do \ + { \ + char __tmp = *__a; \ + *__a++ = *__b; \ + *__b++ = __tmp; \ + } while (--__size > 0); \ + } while (0) + +/* Discontinue quicksort algorithm when partition gets below this size. + This particular magic number was chosen to work best on a Sun 4/260. */ +#define MAX_THRESH 4 + +/* Stack node declarations used to store unfulfilled partition obligations. */ +typedef struct + { + char *lo; + char *hi; + } stack_node; + +/* The next 4 #defines implement a very fast in-line stack abstraction. */ +#define STACK_SIZE (8 * sizeof(unsigned long int)) +#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top)) +#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi))) +#define STACK_NOT_EMPTY (stack < top) + + +/* Order size using quicksort. This implementation incorporates + four optimizations discussed in Sedgewick: + + 1. Non-recursive, using an explicit stack of pointer that store the + next array partition to sort. To save time, this maximum amount + of space required to store an array of MAX_INT is allocated on the + stack. Assuming a 32-bit integer, this needs only 32 * + sizeof(stack_node) == 136 bits. Pretty cheap, actually. + + 2. Chose the pivot element using a median-of-three decision tree. + This reduces the probability of selecting a bad pivot value and + eliminates certain extraneous comparisons. + + 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving + insertion sort to order the MAX_THRESH items within each partition. + This is a big win, since insertion sort is faster for small, mostly + sorted array segements. + + 4. The larger of the two sub-partitions is always pushed onto the + stack first, with the algorithm then concentrating on the + smaller partition. This *guarantees* no more than log (n) + stack size is needed (actually O(1) in this case)! */ + +void +DEFUN(_quicksort, (pbase, total_elems, size, cmp), + PTR CONST pbase AND size_t total_elems AND size_t size AND + int EXFUN((*cmp), (CONST PTR, CONST PTR))) +{ + register char *base_ptr = (char *) pbase; + + /* Allocating SIZE bytes for a pivot buffer facilitates a better + algorithm below since we can do comparisons directly on the pivot. */ + char *pivot_buffer = (char *) __alloca (size); + CONST size_t max_thresh = MAX_THRESH * size; + + if (total_elems == 0) + /* Avoid lossage with unsigned arithmetic below. */ + return; + + if (total_elems > MAX_THRESH) + { + char *lo = base_ptr; + char *hi = &lo[size * (total_elems - 1)]; + /* Largest size needed for 32-bit int!!! */ + stack_node stack[STACK_SIZE]; + stack_node *top = stack + 1; + + while (STACK_NOT_EMPTY) + { + char *left_ptr; + char *right_ptr; + + char *pivot = pivot_buffer; + + /* Select median value from among LO, MID, and HI. Rearrange + LO and HI so the three values are sorted. This lowers the + probability of picking a pathological pivot value and + skips a comparison for both the LEFT_PTR and RIGHT_PTR. */ + + char *mid = lo + size * ((hi - lo) / size >> 1); + + if ((*cmp)((PTR) mid, (PTR) lo) < 0) + SWAP(mid, lo, size); + if ((*cmp)((PTR) hi, (PTR) mid) < 0) + SWAP(mid, hi, size); + else + goto jump_over; + if ((*cmp)((PTR) mid, (PTR) lo) < 0) + SWAP(mid, lo, size); + jump_over:; + memcpy(pivot, mid, size); + pivot = pivot_buffer; + + left_ptr = lo + size; + right_ptr = hi - size; + + /* Here's the famous ``collapse the walls'' section of quicksort. + Gotta like those tight inner loops! They are the main reason + that this algorithm runs much faster than others. */ + do + { + while ((*cmp)((PTR) left_ptr, (PTR) pivot) < 0) + left_ptr += size; + + while ((*cmp)((PTR) pivot, (PTR) right_ptr) < 0) + right_ptr -= size; + + if (left_ptr < right_ptr) + { + SWAP(left_ptr, right_ptr, size); + left_ptr += size; + right_ptr -= size; + } + else if (left_ptr == right_ptr) + { + left_ptr += size; + right_ptr -= size; + break; + } + } + while (left_ptr <= right_ptr); + + /* Set up pointers for next iteration. First determine whether + left and right partitions are below the threshold size. If so, + ignore one or both. Otherwise, push the larger partition's + bounds on the stack and continue sorting the smaller one. */ + + if ((size_t) (right_ptr - lo) <= max_thresh) + { + if ((size_t) (hi - left_ptr) <= max_thresh) + /* Ignore both small partitions. */ + POP(lo, hi); + else + /* Ignore small left partition. */ + lo = left_ptr; + } + else if ((size_t) (hi - left_ptr) <= max_thresh) + /* Ignore small right partition. */ + hi = right_ptr; + else if ((right_ptr - lo) > (hi - left_ptr)) + { + /* Push larger left partition indices. */ + PUSH(lo, right_ptr); + lo = left_ptr; + } + else + { + /* Push larger right partition indices. */ + PUSH(left_ptr, hi); + hi = right_ptr; + } + } + } + + /* Once the BASE_PTR array is partially sorted by quicksort the rest + is completely sorted using insertion sort, since this is efficient + for partitions below MAX_THRESH size. BASE_PTR points to the beginning + of the array to sort, and END_PTR points at the very last element in + the array (*not* one beyond it!). */ + +#define min(x, y) ((x) < (y) ? (x) : (y)) + + { + char *CONST end_ptr = &base_ptr[size * (total_elems - 1)]; + char *tmp_ptr = base_ptr; + char *thresh = min(end_ptr, base_ptr + max_thresh); + register char *run_ptr; + + /* Find smallest element in first threshold and place it at the + array's beginning. This is the smallest array element, + and the operation speeds up insertion sort's inner loop. */ + + for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size) + if ((*cmp)((PTR) run_ptr, (PTR) tmp_ptr) < 0) + tmp_ptr = run_ptr; + + if (tmp_ptr != base_ptr) + SWAP(tmp_ptr, base_ptr, size); + + /* Insertion sort, running from left-hand-side up to right-hand-side. */ + + run_ptr = base_ptr + size; + while ((run_ptr += size) <= end_ptr) + { + tmp_ptr = run_ptr - size; + while ((*cmp)((PTR) run_ptr, (PTR) tmp_ptr) < 0) + tmp_ptr -= size; + + tmp_ptr += size; + if (tmp_ptr != run_ptr) + { + char *trav; + + trav = run_ptr + size; + while (--trav >= run_ptr) + { + char c = *trav; + char *hi, *lo; + + for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo) + *hi = *lo; + *hi = c; + } + } + } + } +} + diff --git a/stdlib/rand.c b/stdlib/rand.c new file mode 100644 index 0000000000..1353432850 --- /dev/null +++ b/stdlib/rand.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include + +#undef rand + + +/* Return a random integer between 0 and RAND_MAX. */ +int +DEFUN_VOID(rand) +{ + return (int) __random(); +} diff --git a/stdlib/random.c b/stdlib/random.c new file mode 100644 index 0000000000..fb32b36b87 --- /dev/null +++ b/stdlib/random.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * This is derived from the Berkeley source: + * @(#)random.c 5.5 (Berkeley) 7/6/88 + * It was reworked for the GNU C Library by Roland McGrath. + */ + +#include +#include +#include +#include +#include + + +/* An improved random number generation package. In addition to the standard + rand()/srand() like interface, this package also has a special state info + interface. The initstate() routine is called with a seed, an array of + bytes, and a count of how many bytes are being passed in; this array is + then initialized to contain information for random number generation with + that much state information. Good sizes for the amount of state + information are 32, 64, 128, and 256 bytes. The state can be switched by + calling the setstate() function with the same array as was initiallized + with initstate(). By default, the package runs with 128 bytes of state + information and generates far better random numbers than a linear + congruential generator. If the amount of state information is less than + 32 bytes, a simple linear congruential R.N.G. is used. Internally, the + state information is treated as an array of longs; the zeroeth element of + the array is the type of R.N.G. being used (small integer); the remainder + of the array is the state information for the R.N.G. Thus, 32 bytes of + state information will give 7 longs worth of state information, which will + allow a degree seven polynomial. (Note: The zeroeth word of state + information also has some other information stored in it; see setstate + for details). The random number generation technique is a linear feedback + shift register approach, employing trinomials (since there are fewer terms + to sum up that way). In this approach, the least significant bit of all + the numbers in the state table will act as a linear feedback shift register, + and will have period 2^deg - 1 (where deg is the degree of the polynomial + being used, assuming that the polynomial is irreducible and primitive). + The higher order bits will have longer periods, since their values are + also influenced by pseudo-random carries out of the lower bits. The + total period of the generator is approximately deg*(2**deg - 1); thus + doubling the amount of state information has a vast influence on the + period of the generator. Note: The deg*(2**deg - 1) is an approximation + only good for large deg, when the period of the shift register is the + dominant factor. With deg equal to seven, the period is actually much + longer than the 7*(2**7 - 1) predicted by this formula. */ + + + +/* For each of the currently supported random number generators, we have a + break value on the amount of state information (you need at least thi + bytes of state info to support this random number generator), a degree for + the polynomial (actually a trinomial) that the R.N.G. is based on, and + separation between the two lower order coefficients of the trinomial. */ + +/* Linear congruential. */ +#define TYPE_0 0 +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +/* x**7 + x**3 + 1. */ +#define TYPE_1 1 +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +/* x**15 + x + 1. */ +#define TYPE_2 2 +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +/* x**31 + x**3 + 1. */ +#define TYPE_3 3 +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +/* x**63 + x + 1. */ +#define TYPE_4 4 +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + + +/* Array versions of the above information to make code run faster. + Relies on fact that TYPE_i == i. */ + +#define MAX_TYPES 5 /* Max number of types above. */ + +static int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; +static int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; + + + +/* Initially, everything is set up as if from: + initstate(1, randtbl, 128); + Note that this initialization takes advantage of the fact that srandom + advances the front and rear pointers 10*rand_deg times, and hence the + rear pointer which starts at 0 will also end up at zero; thus the zeroeth + element of the state information, which contains info about the current + position of the rear pointer is just + (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */ + +static long int randtbl[DEG_3 + 1] = + { + TYPE_3, + -851904987, -43806228, -2029755270, 1390239686, -1912102820, + -485608943, 1969813258, -1590463333, -1944053249, 455935928, 508023712, + -1714531963, 1800685987, -2015299881, 654595283, -1149023258, + -1470005550, -1143256056, -1325577603, -1568001885, 1275120390, + -607508183, -205999574, -1696891592, 1492211999, -1528267240, + -952028296, -189082757, 362343714, 1424981831, 2039449641, + }; + +/* FPTR and RPTR are two pointers into the state info, a front and a rear + pointer. These two pointers are always rand_sep places aparts, as they + cycle through the state information. (Yes, this does mean we could get + away with just one pointer, but the code for random is more efficient + this way). The pointers are left positioned as they would be from the call: + initstate(1, randtbl, 128); + (The position of the rear pointer, rptr, is really 0 (as explained above + in the initialization of randtbl) because the state table pointer is set + to point to randtbl[1] (as explained below).) */ + +static long int *fptr = &randtbl[SEP_3 + 1]; +static long int *rptr = &randtbl[1]; + + + +/* The following things are the pointer to the state information table, + the type of the current generator, the degree of the current polynomial + being used, and the separation between the two pointers. + Note that for efficiency of random, we remember the first location of + the state information, not the zeroeth. Hence it is valid to access + state[-1], which is used to store the type of the R.N.G. + Also, we remember the last location, since this is more efficient than + indexing every time to find the address of the last element to see if + the front and rear pointers have wrapped. */ + +static long int *state = &randtbl[1]; + +static int rand_type = TYPE_3; +static int rand_deg = DEG_3; +static int rand_sep = SEP_3; + +static long int *end_ptr = &randtbl[sizeof(randtbl) / sizeof(randtbl[0])]; + +/* Initialize the random number generator based on the given seed. If the + type is the trivial no-state-information type, just remember the seed. + Otherwise, initializes state[] based on the given "seed" via a linear + congruential generator. Then, the pointers are set to known locations + that are exactly rand_sep places apart. Lastly, it cycles the state + information a given number of times to get rid of any initial dependencies + introduced by the L.C.R.N.G. Note that the initialization of randtbl[] + for default usage relies on values produced by this routine. */ +void +DEFUN(__srandom, (x), unsigned int x) +{ + state[0] = x; + if (rand_type != TYPE_0) + { + register long int i; + for (i = 1; i < rand_deg; ++i) + state[i] = (1103515145 * state[i - 1]) + 12345; + fptr = &state[rand_sep]; + rptr = &state[0]; + for (i = 0; i < 10 * rand_deg; ++i) + (void) __random(); + } +} + +weak_alias (__srandom, srandom) +weak_alias (__srandom, srand) + +/* Initialize the state information in the given array of N bytes for + future random number generation. Based on the number of bytes we + are given, and the break values for the different R.N.G.'s, we choose + the best (largest) one we can and set things up for it. srandom is + then called to initialize the state information. Note that on return + from srandom, we set state[-1] to be the type multiplexed with the current + value of the rear pointer; this is so successive calls to initstate won't + lose this information and will be able to restart with setstate. + Note: The first thing we do is save the current state, if any, just like + setstate so that it doesn't matter when initstate is called. + Returns a pointer to the old state. */ +PTR +DEFUN(__initstate, (seed, arg_state, n), + unsigned int seed AND PTR arg_state AND size_t n) +{ + PTR ostate = (PTR) &state[-1]; + + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; + if (n < BREAK_1) + { + if (n < BREAK_0) + { + errno = EINVAL; + return NULL; + } + rand_type = TYPE_0; + rand_deg = DEG_0; + rand_sep = SEP_0; + } + else if (n < BREAK_2) + { + rand_type = TYPE_1; + rand_deg = DEG_1; + rand_sep = SEP_1; + } + else if (n < BREAK_3) + { + rand_type = TYPE_2; + rand_deg = DEG_2; + rand_sep = SEP_2; + } + else if (n < BREAK_4) + { + rand_type = TYPE_3; + rand_deg = DEG_3; + rand_sep = SEP_3; + } + else + { + rand_type = TYPE_4; + rand_deg = DEG_4; + rand_sep = SEP_4; + } + + state = &((long int *) arg_state)[1]; /* First location. */ + /* Must set END_PTR before srandom. */ + end_ptr = &state[rand_deg]; + __srandom(seed); + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; + + return ostate; +} + +weak_alias (__initstate, initstate) + +/* Restore the state from the given state array. + Note: It is important that we also remember the locations of the pointers + in the current state information, and restore the locations of the pointers + from the old state information. This is done by multiplexing the pointer + location into the zeroeth word of the state information. Note that due + to the order in which things are done, it is OK to call setstate with the + same state as the current state + Returns a pointer to the old state information. */ +PTR +DEFUN(__setstate, (arg_state), PTR arg_state) +{ + register long int *new_state = (long int *) arg_state; + register int type = new_state[0] % MAX_TYPES; + register int rear = new_state[0] / MAX_TYPES; + PTR ostate = (PTR) &state[-1]; + + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; + + switch (type) + { + case TYPE_0: + case TYPE_1: + case TYPE_2: + case TYPE_3: + case TYPE_4: + rand_type = type; + rand_deg = degrees[type]; + rand_sep = seps[type]; + break; + default: + /* State info munged. */ + errno = EINVAL; + return NULL; + } + + state = &new_state[1]; + if (rand_type != TYPE_0) + { + rptr = &state[rear]; + fptr = &state[(rear + rand_sep) % rand_deg]; + } + /* Set end_ptr too. */ + end_ptr = &state[rand_deg]; + + return ostate; +} + +weak_alias (__setstate, setstate) + +/* If we are using the trivial TYPE_0 R.N.G., just do the old linear + congruential bit. Otherwise, we do our fancy trinomial stuff, which is the + same in all ther other cases due to all the global variables that have been + set up. The basic operation is to add the number at the rear pointer into + the one at the front pointer. Then both pointers are advanced to the next + location cyclically in the table. The value returned is the sum generated, + reduced to 31 bits by throwing away the "least random" low bit. + Note: The code takes advantage of the fact that both the front and + rear pointers can't wrap on the same call by not testing the rear + pointer if the front one has wrapped. Returns a 31-bit random number. */ + +long int +DEFUN_VOID(__random) +{ + if (rand_type == TYPE_0) + { + state[0] = ((state[0] * 1103515245) + 12345) & LONG_MAX; + return state[0]; + } + else + { + long int i; + *fptr += *rptr; + /* Chucking least random bit. */ + i = (*fptr >> 1) & LONG_MAX; + ++fptr; + if (fptr >= end_ptr) + { + fptr = state; + ++rptr; + } + else + { + ++rptr; + if (rptr >= end_ptr) + rptr = state; + } + return i; + } +} + +weak_alias (__random, random) diff --git a/stdlib/stdlib.h b/stdlib/stdlib.h new file mode 100644 index 0000000000..d64a2ffb7c --- /dev/null +++ b/stdlib/stdlib.h @@ -0,0 +1,289 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the, 1992 Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* + * ANSI Standard: 4.10 GENERAL UTILITIES + */ + +#ifndef _STDLIB_H + +#define _STDLIB_H 1 +#include + +/* Get size_t, wchar_t and NULL from . */ +#define __need_size_t +#define __need_wchar_t +#define __need_NULL +#include + +#define __need_Emath +#include + +__BEGIN_DECLS + +/* Returned by `div'. */ +typedef struct + { + int quot; /* Quotient. */ + int rem; /* Remainder. */ + } div_t; + +/* Returned by `ldiv'. */ +typedef struct + { + long int quot; /* Quotient. */ + long int rem; /* Remainder. */ + } ldiv_t; + + +/* The largest number rand will return (same as INT_MAX). */ +#define RAND_MAX 2147483647 + + +/* We define these the same for all machines. + Changes from this to the outside world should be done in `_exit'. */ +#define EXIT_FAILURE 1 /* Failing exit status. */ +#define EXIT_SUCCESS 0 /* Successful exit status. */ + + +/* Maximum length of a multibyte character in the current locale. + This is just one until the fancy locale support is finished. */ +#define MB_CUR_MAX 1 + + +/* Convert a string to a floating-point number. */ +extern double atof __P ((__const char *__nptr)); +/* Convert a string to an integer. */ +extern int atoi __P ((__const char *__nptr)); +/* Convert a string to a long integer. */ +extern long int atol __P ((__const char *__nptr)); + +/* Convert a string to a floating-point number. */ +extern double strtod __P ((__const char *__nptr, char **__endptr)); + +#ifdef __USE_GNU +/* Likewise for `float' and `long double' sizes of floating-point numbers. */ +extern float __strtof __P ((__const char *__nptr, char **__endptr)); +extern float strtof __P ((__const char *__nptr, char **__endptr)); +extern __long_double_t __strtold __P ((__const char *__nptr, char **__endptr)); +extern __long_double_t strtold __P ((__const char *__nptr, char **__endptr)); +#endif + +/* Convert a string to a long integer. */ +extern long int strtol __P ((__const char *__nptr, char **__endptr, + int __base)); +/* Convert a string to an unsigned long integer. */ +extern unsigned long int strtoul __P ((__const char *__nptr, + char **__endptr, int __base)); + +#if defined (__GNUC__) && defined (__USE_BSD) +/* Convert a string to a quadword integer. */ +extern long long int strtoq __P ((__const char *__nptr, char **__endptr, + int __base)); +/* Convert a string to an unsigned quadword integer. */ +extern unsigned long long int strtouq __P ((__const char *__nptr, + char **__endptr, int __base)); +#endif /* GCC and use BSD. */ + +#if defined (__OPTIMIZE__) && __GNUC__ >= 2 +extern __inline double atof (__const char *__nptr) +{ return strtod(__nptr, (char **) NULL); } +extern __inline int atoi (__const char *__nptr) +{ return (int) strtol (__nptr, (char **) NULL, 10); } +extern __inline long int atol (__const char *__nptr) +{ return strtol (__nptr, (char **) NULL, 10); } +#endif /* Optimizing GCC >=2. */ + + +/* Return a random integer between 0 and RAND_MAX inclusive. */ +extern int rand __P ((void)); +/* Seed the random number generator with the given number. */ +extern void srand __P ((unsigned int __seed)); + +/* These are the functions that actually do things. The `random', `srandom', + `initstate' and `setstate' functions are those from BSD Unices. + The `rand' and `srand' functions are required by the ANSI standard. + We provide both interfaces to the same random number generator. */ +/* Return a random long integer between 0 and RAND_MAX inclusive. */ +extern long int __random __P ((void)); +/* Seed the random number generator with the given number. */ +extern void __srandom __P ((unsigned int __seed)); + +/* Initialize the random number generator to use state buffer STATEBUF, + of length STATELEN, and seed it with SEED. Optimal lengths are 8, 16, + 32, 64, 128 and 256, the bigger the better; values less than 8 will + cause an error and values greater than 256 will be rounded down. */ +extern __ptr_t __initstate __P ((unsigned int __seed, __ptr_t __statebuf, + size_t __statelen)); +/* Switch the random number generator to state buffer STATEBUF, + which should have been previously initialized by `initstate'. */ +extern __ptr_t __setstate __P ((__ptr_t __statebuf)); + +#ifdef __USE_BSD +extern long int random __P ((void)); +extern void srandom __P ((unsigned int __seed)); +extern __ptr_t initstate __P ((unsigned int __seed, __ptr_t __statebuf, + size_t __statelen)); +extern __ptr_t setstate __P ((__ptr_t __statebuf)); + +#if defined (__OPTIMIZE__) && __GNUC__ >= 2 +extern __inline long int random (void) +{ return __random(); } +extern __inline void srandom (unsigned int __seed) +{ __srandom(__seed); } +extern __inline __ptr_t initstate (unsigned int __seed, + __ptr_t __statebuf, size_t __statelen) +{ return __initstate (__seed, __statebuf, __statelen); } +extern __inline __ptr_t setstate (__ptr_t __statebuf) +{ return __setstate (__statebuf); } +#endif /* Optimizing GCC >=2. */ +#endif /* Use BSD. */ + + +/* Allocate SIZE bytes of memory. */ +extern __ptr_t malloc __P ((size_t __size)); +/* Re-allocate the previously allocated block + in __ptr_t, making the new block SIZE bytes long. */ +extern __ptr_t realloc __P ((__ptr_t __ptr, size_t __size)); +/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ +extern __ptr_t calloc __P ((size_t __nmemb, size_t __size)); +/* Free a block allocated by `malloc', `realloc' or `calloc'. */ +extern void free __P ((__ptr_t __ptr)); + +#ifdef __USE_MISC +/* Free a block. An alias for `free'. (Sun Unices). */ +extern void cfree __P ((__ptr_t __ptr)); +#endif /* Use misc. */ + +#if defined(__USE_GNU) || defined(__USE_BSD) || defined(__USE_MISC) +#include +#endif /* Use GNU, BSD, or misc. */ + +#ifdef __USE_BSD +/* Allocate SIZE bytes on a page boundary. The storage cannot be freed. */ +extern __ptr_t valloc __P ((size_t __size)); +#endif + + +/* Abort execution and generate a core-dump. */ +extern void abort __P ((void)) __attribute__ ((__noreturn__)); + + +/* Register a function to be called when `exit' is called. */ +extern int atexit __P ((void (*__func) (void))); + +#ifdef __USE_MISC +/* Register a function to be called with the status + given to `exit' and the given argument. */ +extern int on_exit __P ((void (*__func) (int __status, __ptr_t __arg), + __ptr_t __arg)); +#endif + +/* Call all functions registered with `atexit' and `on_exit', + in the reverse of the order in which they were registered + perform stdio cleanup, and terminate program execution with STATUS. */ +extern void exit __P ((int __status)) __attribute__ ((__noreturn__)); + + +/* Return the value of envariable NAME, or NULL if it doesn't exist. */ +extern char *getenv __P ((__const char *__name)); + +#ifdef __USE_SVID +/* The SVID says this is in , but this seems a better place. */ +/* Put STRING, which is of the form "NAME=VALUE", in the environment. + If there is no `=', remove NAME from the environment. */ +extern int putenv __P ((__const char *__string)); +#endif + +#ifdef __USE_BSD +/* Set NAME to VALUE in the environment. + If REPLACE is nonzero, overwrite an existing value. */ +extern int setenv __P ((__const char *__name, __const char *__value, + int __replace)); +#endif + +/* Execute the given line as a shell command. */ +extern int system __P ((__const char *__command)); + + +/* Shorthand for type of comparison functions. */ +typedef int (*__compar_fn_t) __P ((__const __ptr_t, __const __ptr_t)); + +#ifdef __USE_GNU +typedef __compar_fn_t comparison_fn_t; +#endif + +/* Do a binary search for KEY in BASE, which consists of NMEMB elements + of SIZE bytes each, using COMPAR to perform the comparisons. */ +extern __ptr_t bsearch __P ((__const __ptr_t __key, __const __ptr_t __base, + size_t __nmemb, size_t __size, + __compar_fn_t __compar)); + +/* Sort NMEMB elements of BASE, of SIZE bytes each, + using COMPAR to perform the comparisons. */ +extern void qsort __P ((__ptr_t __base, size_t __nmemb, size_t __size, + __compar_fn_t __compar)); + + +#ifndef __CONSTVALUE +#ifdef __GNUC__ +/* The `const' keyword tells GCC that a function's return value is + based solely on its arguments, and there are no side-effects. */ +#define __CONSTVALUE __const +#else +#define __CONSTVALUE +#endif /* GCC. */ +#endif /* __CONSTVALUE not defined. */ + +/* Return the absolute value of X. */ +extern __CONSTVALUE int abs __P ((int __x)); +extern __CONSTVALUE long int labs __P ((long int __x)); + + +/* Return the `div_t' or `ldiv_t' representation + of the value of NUMER over DENOM. */ +/* GCC may have built-ins for these someday. */ +extern __CONSTVALUE div_t div __P ((int __numer, int __denom)); +extern __CONSTVALUE ldiv_t ldiv __P ((long int __numer, long int __denom)); + + +/* Return the length of the multibyte character + in S, which is no longer than N. */ +extern int mblen __P ((__const char *__s, size_t __n)); +/* Return the length of the given multibyte character, + putting its `wchar_t' representation in *PWC. */ +extern int mbtowc __P ((wchar_t * __pwc, __const char *__s, size_t __n)); +/* Put the multibyte character represented + by WCHAR in S, returning its length. */ +extern int wctomb __P ((char *__s, wchar_t __wchar)); + +#if defined (__OPTIMIZE__) && __GNUC__ >= 2 +extern __inline int mblen (__const char *__s, size_t __n) +{ return mbtowc ((wchar_t *) NULL, __s, __n); } +#endif /* Optimizing GCC >=2. */ + + +/* Convert a multibyte string to a wide char string. */ +extern size_t mbstowcs __P ((wchar_t * __pwcs, __const char *__s, size_t __n)); +/* Convert a wide char string to multibyte string. */ +extern size_t wcstombs __P ((char *__s, __const wchar_t * __pwcs, size_t __n)); + + +__END_DECLS + +#endif /* stdlib.h */ diff --git a/stdlib/strtod.c b/stdlib/strtod.c new file mode 100644 index 0000000000..d647753e79 --- /dev/null +++ b/stdlib/strtod.c @@ -0,0 +1,1027 @@ +/* Read decimal floating point numbers. +Copyright (C) 1995 Free Software Foundation, Inc. +Contributed by Ulrich Drepper. + +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* Configuration part. These macros are defined by `strtold.c' and `strtof.c' + to produce the `long double' and `float' versions of the reader. */ +#ifndef FLOAT +#define FLOAT double +#define FLT DBL +#define STRTOF strtod +#define MPN2FLOAT __mpn_construct_double +#define FLOAT_HUGE_VAL HUGE_VAL +#endif +/* End of configuration part. */ + +#include +#include +#include +#include +#include +#include +#include "../stdio/gmp.h" +#include "../stdio/gmp-impl.h" +#include +#include "../stdio/longlong.h" +#include "../stdio/fpioconst.h" + +/* #define NDEBUG 1 */ +#include + + +/* Constants we need from float.h; select the set for the FLOAT precision. */ +#define MANT_DIG FLT##_MANT_DIG +#define MAX_EXP FLT##_MAX_EXP +#define MIN_EXP FLT##_MIN_EXP +#define MAX_10_EXP FLT##_MAX_10_EXP +#define MIN_10_EXP FLT##_MIN_10_EXP +#define MAX_10_EXP_LOG FLT##_MAX_10_EXP_LOG + + +/* Function to construct a floating point number from an MP integer + containing the fraction bits, a base 2 exponent, and a sign flag. */ +extern FLOAT MPN2FLOAT (mp_srcptr mpn, int exponent, int negative); + +/* Definitions according to limb size used. */ +#if BITS_PER_MP_LIMB == 32 +# define MAX_DIG_PER_LIMB 9 +# define MAX_FAC_PER_LIMB 1000000000L +#elif BITS_PER_MP_LIMB == 64 +# define MAX_DIG_PER_LIMB 19 +# define MAX_FAC_PER_LIMB 10000000000000000000L +#else +# error "mp_limb size " BITS_PER_MP_LIMB "not accounted for" +#endif + + +/* Local data structure. */ +static const mp_limb _tens_in_limb[MAX_DIG_PER_LIMB] = +{ 0, 10, 100, + 1000, 10000, 100000, + 1000000, 10000000, 100000000 +#if BITS_PER_MP_LIMB > 32 + , 1000000000, 10000000000, 100000000000, + 1000000000000, 10000000000000, 100000000000000, + 1000000000000000, 10000000000000000, 100000000000000000, + 1000000000000000000 +#endif +#if BITS_PER_MP_LIMB > 64 + #error "Need to expand tens_in_limb table to" MAX_DIG_PER_LIMB +#endif +}; + +#ifndef howmany +#define howmany(x,y) (((x)+((y)-1))/(y)) +#endif +#define SWAP(x, y) ({ typeof(x) _tmp = x; x = y; y = _tmp; }) + +#define NDIG (MAX_10_EXP - MIN_10_EXP + 2 * MANT_DIG) +#define RETURN_LIMB_SIZE howmany (MANT_DIG, BITS_PER_MP_LIMB) + +#define RETURN(val,end) \ + do { if (endptr != 0) *endptr = (char *) end; return val; } while (0) + +/* Maximum size necessary for mpn integers to hold floating point numbers. */ +#define MPNSIZE (howmany (MAX_EXP + MANT_DIG, BITS_PER_MP_LIMB) + 1) +/* Declare an mpn integer variable that big. */ +#define MPN_VAR(name) mp_limb name[MPNSIZE]; mp_size_t name##size +/* Copy an mpn integer value. */ +#define MPN_ASSIGN(dst, src) \ + memcpy (dst, src, (dst##size = src##size) * sizeof (mp_limb)) + + +/* Return a floating point number of the needed type according to the given + multi-precision number after possible rounding. */ +static inline FLOAT +round_and_return (mp_limb *retval, int exponent, int negative, + mp_limb round_limb, mp_size_t round_bit, int more_bits) +{ + if (exponent < MIN_EXP) + { + mp_size_t shift = MIN_EXP - 1 - exponent; + + if (shift >= MANT_DIG) + { + errno = EDOM; + return 0.0; + } + + more_bits |= (round_limb & ((1 << round_bit) - 1)) != 0; + if (shift >= BITS_PER_MP_LIMB) + { + round_limb = retval[(shift - 1) / BITS_PER_MP_LIMB]; + round_bit = (shift - 1) % BITS_PER_MP_LIMB; +#if RETURN_LIMB_SIZE <= 2 + assert (RETURN_LIMB_SIZE == 2); + more_bits |= retval[0] != 0; + retval[0] = retval[1]; + retval[1] = 0; +#else + int disp = shift / BITS_PER_MP_LIMB; + int i = 0; + while (retval[i] == 0 && i < disp) + ++i; + more_bits |= i < disp; + for (i = disp; i < RETURN_LIMB_SIZE; ++i) + retval[i - disp] = retval[i]; + MPN_ZERO (&retval[RETURN_LIMB_SIZE - disp], disp); +#endif + shift %= BITS_PER_MP_LIMB; + } + else + { + round_limb = retval[0]; + round_bit = shift - 1; + } + (void) __mpn_rshift (retval, retval, RETURN_LIMB_SIZE, shift); + exponent = MIN_EXP - 2; + } + + if ((round_limb & (1 << round_bit)) != 0 && + (more_bits || (retval[0] & 1) != 0 || + (round_limb & ((1 << round_bit) - 1)) != 0)) + { + mp_limb cy = __mpn_add_1 (retval, retval, RETURN_LIMB_SIZE, 1); + if (cy || (retval[RETURN_LIMB_SIZE - 1] + & (1 << (MANT_DIG % BITS_PER_MP_LIMB))) != 0) + { + ++exponent; + (void) __mpn_rshift (retval, retval, RETURN_LIMB_SIZE, 1); + retval[RETURN_LIMB_SIZE - 1] |= 1 << (MANT_DIG % BITS_PER_MP_LIMB); + } + } + + if (exponent > MAX_EXP) + return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL; + + return MPN2FLOAT (retval, exponent, negative); +} + + +/* Read a multi-precision integer starting at STR with exactly DIGCNT digits + into N. Return the size of the number limbs in NSIZE at the first + character od the string that is not part of the integer as the function + value. If the EXPONENT is small enough to be taken as an additional + factor for the resulting number (see code) multiply by it. */ +static inline const char * +str_to_mpn (const char *str, int digcnt, mp_limb *n, mp_size_t *nsize, + int *exponent) +{ + /* Number of digits for actual limb. */ + int cnt = 0; + mp_limb low = 0; + mp_limb base; + + *nsize = 0; + assert (digcnt > 0); + do + { + if (cnt == MAX_DIG_PER_LIMB) + { + if (*nsize == 0) + n[0] = low; + else + { + mp_limb cy; + cy = __mpn_mul_1 (n, n, *nsize, MAX_FAC_PER_LIMB); + cy += __mpn_add_1 (n, n, *nsize, low); + if (cy != 0) + n[*nsize] = cy; + } + ++(*nsize); + cnt = 0; + low = 0; + } + + /* There might be thousands separators or radix characters in the string. + But these all can be ignored because we know the format of the number + is correct and we have an exact number of characters to read. */ + while (!isdigit (*str)) + ++str; + low = low * 10 + *str++ - '0'; + ++cnt; + } + while (--digcnt > 0); + + if (*exponent > 0 && cnt + *exponent <= MAX_DIG_PER_LIMB) + { + low *= _tens_in_limb[*exponent]; + base = _tens_in_limb[cnt + *exponent]; + *exponent = 0; + } + else + base = _tens_in_limb[cnt]; + + if (*nsize == 0) + { + n[0] = low; + *nsize = 1; + } + else + { + mp_limb cy; + cy = __mpn_mul_1 (n, n, *nsize, base); + cy += __mpn_add_1 (n, n, *nsize, low); + if (cy != 0) + n[(*nsize)++] = cy; + } + return str; +} + + +/* Shift {PTR, SIZE} COUNT bits to the left, and fill the vacated bits + with the COUNT most significant bits of LIMB. + + Tege doesn't like this function so I have to write it here myself. :) + --drepper */ +static inline void +__mpn_lshift_1 (mp_limb *ptr, mp_size_t size, unsigned int count, mp_limb limb) +{ + if (count == BITS_PER_MP_LIMB) + { + /* Optimize the case of shifting by exactly a word: + just copy words, with no actual bit-shifting. */ + mp_size_t i; + for (i = size - 1; i > 0; --i) + ptr[i] = ptr[i - 1]; + ptr[0] = limb; + } + else + { + (void) __mpn_lshift (ptr, ptr, size, count); + ptr[0] |= limb >> (BITS_PER_MP_LIMB - count); + } +} + + +/* Return a floating point number with the value of the given string NPTR. + Set *ENDPTR to the character after the last used one. If the number is + smaller than the smallest representable number, set `errno' to ERANGE and + return 0.0. If the number is too big to be represented, set `errno' to + ERANGE and return HUGE_VAL with the approriate sign. */ +FLOAT +STRTOF (nptr, endptr) + const char *nptr; + char **endptr; +{ + int negative; /* The sign of the number. */ + MPN_VAR (num); /* MP representation of the number. */ + int exponent; /* Exponent of the number. */ + + /* When we have to compute fractional digits we form a fraction with a + second multi-precision number (and we sometimes need a second for + temporary results). */ + MPN_VAR (den); + + /* Representation for the return value. */ + mp_limb retval[RETURN_LIMB_SIZE]; + /* Number of bits currently in result value. */ + int bits; + + /* Running pointer after the last character processed in the string. */ + const char *cp; + /* Start of significant part of the number. */ + const char *startp; + /* Points at the character following the integer and fractional digits. */ + const char *expp; + /* Total number of digit and number of digits in integer part. */ + int dig_no, int_no; + /* Contains the last character read. */ + char c; + + /* The radix character of the current locale. */ + wchar_t decimal; +#ifdef USE_GROUPING + /* The thousands character of the current locale. */ + wchar_t thousands; + /* The numeric grouping specification of the current locale, + in the format described in . */ + const char *grouping; + + /* Check the grouping of the integer part at [BEGIN,END). + Return zero iff a separator is found out of place. */ + int grouping_ok (const char *begin, const char *end) + { + if (grouping) + while (end > begin) + { + const char *p = end; + do + --p; + while (*p != thousands && p > begin); + if (end - 1 - p != *grouping++) + return 0; /* Wrong number of digits in this group. */ + end = p; /* Correct group; trim it off the end. */ + + if (*grouping == 0) + --grouping; /* Same grouping repeats in next iteration. */ + else if (*grouping == CHAR_MAX || *grouping < 0) + { + /* No further grouping allowed. */ + while (end > begin) + if (*--end == thousands) + return 0; + } + } + return 1; + } + /* Return with no conversion if the grouping of [STARTP,CP) is bad. */ +#define CHECK_GROUPING if (! grouping_ok (startp, cp)) RETURN (0.0, nptr); else + + grouping = _numeric_info->grouping; /* Cache the grouping info array. */ + if (*grouping <= 0 || *grouping == CHAR_MAX) + grouping = NULL; + else + { + /* Figure out the thousands seperator character. */ + if (mbtowc (&thousands_sep, _numeric_info->thousands_sep, + strlen (_numeric_info->thousands_sep)) <= 0) + thousands = (wchar_t) *_numeric_info->thousands_sep; + if (thousands == L'\0') + grouping = NULL; + } +#else +#define grouping NULL +#define thousands L'\0' +#define CHECK_GROUPING ((void) 0) +#endif + + /* Find the locale's decimal point character. */ + if (mbtowc (&decimal, _numeric_info->decimal_point, + strlen (_numeric_info->decimal_point)) <= 0) + decimal = (wchar_t) *_numeric_info->decimal_point; + + + /* Prepare number representation. */ + exponent = 0; + negative = 0; + bits = 0; + + /* Parse string to get maximal legal prefix. We need the number of + characters of the interger part, the fractional part and the exponent. */ + cp = nptr - 1; + /* Ignore leading white space. */ + do + c = *++cp; + while (isspace (c)); + + /* Get sign of the result. */ + if (c == '-') + { + negative = 1; + c = *++cp; + } + else if (c == '+') + c = *++cp; + + /* Return 0.0 if no legal string is found. + No character is used even if a sign was found. */ + if (!isdigit (c)) + RETURN (0.0, nptr); + + /* Record the start of the digits, in case we will check their grouping. */ + startp = cp; + + /* Ignore leading zeroes. This helps us to avoid useless computations. */ + while (c == '0' || (thousands != L'\0' && c == thousands)) + c = *++cp; + + CHECK_GROUPING; + + /* If no other digit but a '0' is found the result is 0.0. + Return current read pointer. */ + if (!isdigit (c) && c != decimal) + RETURN (0.0, cp); + + /* Remember first significant digit and read following characters until the + decimal point, exponent character or any non-FP number character. */ + startp = cp; + dig_no = 0; + while (dig_no < NDIG || + /* If parsing grouping info, keep going past useful digits + so we can check all the grouping separators. */ + grouping) + { + if (isdigit (c)) + ++dig_no; + else if (thousands == L'\0' || c != thousands) + /* Not a digit or separator: end of the integer part. */ + break; + c = *++cp; + } + + CHECK_GROUPING; + + if (dig_no >= NDIG) + /* Too many digits to be representable. Assigning this to EXPONENT + allows us to read the full number but return HUGE_VAL after parsing. */ + exponent = MAX_10_EXP; + + /* We have the number digits in the integer part. Whether these are all or + any is really a fractional digit will be decided later. */ + int_no = dig_no; + + /* Read the fractional digits. */ + if (c == decimal) + { + if (isdigit (cp[1])) + { + ++cp; + do + { + ++dig_no; + c = *++cp; + } + while (isdigit (c)); + } + } + + /* Remember start of exponent (if any). */ + expp = cp; + + /* Read exponent. */ + if (tolower (c) == 'e') + { + int exp_negative = 0; + + c = *++cp; + if (c == '-') + { + exp_negative = 1; + c = *++cp; + } + else if (c == '+') + c = *++cp; + + if (isdigit (c)) + { + do + { + if ((!exp_negative && exponent * 10 + int_no > MAX_10_EXP) + || (exp_negative + && exponent * 10 + int_no > -MIN_10_EXP + MANT_DIG)) + /* The exponent is too large/small to represent a valid + number. */ + { + FLOAT retval; + + /* Overflow or underflow. */ + errno = ERANGE; + retval = (exp_negative ? 0.0 : + negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL); + + /* Accept all following digits as part of the exponent. */ + do + ++cp; + while (isdigit (*cp)); + + RETURN (retval, cp); + /* NOTREACHED */ + } + + exponent *= 10; + exponent += c - '0'; + c = *++cp; + } + while (isdigit (c)); + } + else + cp = expp; + + if (exp_negative) + exponent = -exponent; + } + + /* We don't want to have to work with trailing zeroes after the radix. */ + if (dig_no > int_no) + { + while (expp[-1] == '0') + { + --expp; + --dig_no; + } + assert (dig_no >= int_no); + } + + /* The whole string is parsed. Store the address of the next character. */ + if (endptr) + *endptr = (char *) cp; + + if (dig_no == 0) + return 0.0; + + /* Now we have the number of digits in total and the integer digits as well + as the exponent and its sign. We can decide whether the read digits are + really integer digits or belong to the fractional part; i.e. we normalize + 123e-2 to 1.23. */ + { + register int incr = exponent < 0 ? MAX (-int_no, exponent) + : MIN (dig_no - int_no, exponent); + int_no += incr; + exponent -= incr; + } + + if (int_no + exponent > MAX_10_EXP) + { + errno = ERANGE; + return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL; + } + + if (int_no - dig_no + exponent < MIN_10_EXP - MANT_DIG) + { + errno = ERANGE; + return 0.0; + } + + if (int_no > 0) + { + /* Read the integer part as a multi-precision number to NUM. */ + startp = str_to_mpn (startp, int_no, num, &numsize, &exponent); + + if (exponent > 0) + { + /* We now multiply the gained number by the given power of ten. */ + mp_limb *psrc = num; + mp_limb *pdest = den; + int expbit = 1; + const struct mp_power *ttab = &_fpioconst_pow10[0]; + + assert (exponent < (1 << (MAX_10_EXP_LOG + 1))); + do + { + if ((exponent & expbit) != 0) + { + mp_limb cy; + exponent ^= expbit; + + /* FIXME: not the whole multiplication has to be done. + If we have the needed number of bits we only need the + information whether more non-zero bits follow. */ + if (numsize >= ttab->arraysize - 2) + cy = __mpn_mul (pdest, psrc, numsize, + &ttab->array[2], ttab->arraysize - 2); + else + cy = __mpn_mul (pdest, &ttab->array[2], + ttab->arraysize - 2, + psrc, numsize); + numsize += ttab->arraysize - 2; + if (cy == 0) + --numsize; + SWAP (psrc, pdest); + } + expbit <<= 1; + ++ttab; + } + while (exponent != 0); + + if (psrc == den) + memcpy (num, den, numsize * sizeof (mp_limb)); + } + + /* Determine how many bits of the result we already have. */ + count_leading_zeros (bits, num[numsize - 1]); + bits = numsize * BITS_PER_MP_LIMB - bits; + + /* We have already the first BITS bits of the result. Together with + the information whether more non-zero bits follow this is enough + to determine the result. */ + if (bits > MANT_DIG) + { + const mp_size_t least_idx = (bits - MANT_DIG) / BITS_PER_MP_LIMB; + const mp_size_t least_bit = (bits - MANT_DIG) % BITS_PER_MP_LIMB; + const mp_size_t round_idx = least_bit == 0 ? least_idx - 1 + : least_idx; + const mp_size_t round_bit = least_bit == 0 ? BITS_PER_MP_LIMB - 1 + : least_idx - 1; + int i; + + if (least_bit == 0) + memcpy (retval, &num[least_idx], + RETURN_LIMB_SIZE * sizeof (mp_limb)); + else + (void) __mpn_rshift (retval, &num[least_idx], + numsize - least_idx + 1, least_bit); + + /* Check whether any limb beside the ones in RETVAL are non-zero. */ + for (i = 0; num[i] == 0; ++i) + ; + + return round_and_return (retval, bits - 1, negative, + num[round_idx], round_bit, + int_no < dig_no || i < round_idx); + /* NOTREACHED */ + } + else if (dig_no == int_no) + { + const mp_size_t target_bit = (MANT_DIG - 1) % BITS_PER_MP_LIMB; + const mp_size_t is_bit = (bits - 1) % BITS_PER_MP_LIMB; + + if (target_bit == is_bit) + { + memcpy (&retval[RETURN_LIMB_SIZE - numsize], num, + numsize * sizeof (mp_limb)); + /* FIXME: the following loop can be avoided if we assume a + maximal MANT_DIG value. */ + MPN_ZERO (retval, RETURN_LIMB_SIZE - numsize); + } + else if (target_bit > is_bit) + { + (void) __mpn_lshift (&retval[RETURN_LIMB_SIZE - numsize], + num, numsize, target_bit - is_bit); + /* FIXME: the following loop can be avoided if we assume a + maximal MANT_DIG value. */ + MPN_ZERO (retval, RETURN_LIMB_SIZE - numsize); + } + else + { + mp_limb cy; + assert (numsize < RETURN_LIMB_SIZE); + + cy = __mpn_rshift (&retval[RETURN_LIMB_SIZE - numsize], + num, numsize, is_bit - target_bit); + retval[RETURN_LIMB_SIZE - numsize - 1] = cy; + /* FIXME: the following loop can be avoided if we assume a + maximal MANT_DIG value. */ + MPN_ZERO (retval, RETURN_LIMB_SIZE - numsize - 1); + } + + return round_and_return (retval, bits - 1, negative, 0, 0, 0); + /* NOTREACHED */ + } + + /* Store the bits we already have. */ + memcpy (retval, num, numsize * sizeof (mp_limb)); +#if RETURN_LIMB_SIZE > 1 + if (numsize < RETURN_LIMB_SIZE) + retval[numsize] = 0; +#endif + } + + /* We have to compute at least some of the fractional digits. */ + { + /* We construct a fraction and the result of the division gives us + the needed digits. The denominator is 1.0 multiplied by the + exponent of the lowest digit; i.e. 0.123 gives 123 / 1000 and + 123e6 gives 123 / 1000000. */ + + int expbit; + int cnt; + mp_limb cy; + mp_limb *psrc = den; + mp_limb *pdest = num; + int neg_exp = dig_no - int_no - exponent; + const struct mp_power *ttab = &_fpioconst_pow10[0]; + + assert (dig_no > int_no && exponent <= 0); + + /* Construct the denominator. */ + densize = 0; + expbit = 1; + do + { + if ((neg_exp & expbit) != 0) + { + mp_limb cy; + neg_exp ^= expbit; + + if (densize == 0) + memcpy (psrc, &ttab->array[2], + (densize = ttab->arraysize - 2) * sizeof (mp_limb)); + else + { + cy = __mpn_mul (pdest, &ttab->array[2], ttab->arraysize - 2, + psrc, densize); + densize += ttab->arraysize - 2; + if (cy == 0) + --densize; + SWAP (psrc, pdest); + } + } + expbit <<= 1; + ++ttab; + } + while (neg_exp != 0); + + if (psrc == num) + memcpy (den, num, densize * sizeof (mp_limb)); + + /* Read the fractional digits from the string. */ + (void) str_to_mpn (startp, dig_no - int_no, num, &numsize, &exponent); + + + /* We now have to shift both numbers so that the highest bit in the + denominator is set. In the same process we copy the numerator to + a high place in the array so that the division constructs the wanted + digits. This is done by a "quasi fix point" number representation. + + num: ddddddddddd . 0000000000000000000000 + |--- m ---| + den: ddddddddddd n >= m + |--- n ---| + */ + + count_leading_zeros (cnt, den[densize - 1]); + + (void) __mpn_lshift (den, den, densize, cnt); + cy = __mpn_lshift (num, num, numsize, cnt); + if (cy != 0) + num[numsize++] = cy; + + /* Now we are ready for the division. But it is not necessary to + do a full multi-precision division because we only need a small + number of bits for the result. So we do not use __mpn_divmod + here but instead do the division here by hand and stop whenever + the needed number of bits is reached. The code itself comes + from the GNU MP Library by Torbj\"orn Granlund. */ + + exponent = bits; + + switch (densize) + { + case 1: + { + mp_limb d, n, quot; + int used = 0; + + n = num[0]; + d = den[0]; + assert (numsize == 1 && n < d); + + do + { + udiv_qrnnd (quot, n, n, 0, d); + +#define got_limb \ + if (bits == 0) \ + { \ + register int cnt; \ + if (quot == 0) \ + cnt = BITS_PER_MP_LIMB; \ + else \ + count_leading_zeros (cnt, quot); \ + exponent -= cnt; \ + if (BITS_PER_MP_LIMB - cnt > MANT_DIG) \ + { \ + used = cnt + MANT_DIG; \ + retval[0] = quot >> (BITS_PER_MP_LIMB - used); \ + bits -= BITS_PER_MP_LIMB - used; \ + } \ + else \ + { \ + /* Note that we only clear the second element. */ \ + retval[1] = 0; \ + retval[0] = quot; \ + bits -= cnt; \ + } \ + } \ + else if (bits + BITS_PER_MP_LIMB <= MANT_DIG) \ + __mpn_lshift_1 (retval, RETURN_LIMB_SIZE, BITS_PER_MP_LIMB, \ + quot); \ + else \ + { \ + used = MANT_DIG - bits; \ + if (used > 0) \ + __mpn_lshift_1 (retval, RETURN_LIMB_SIZE, used, quot); \ + } \ + bits += BITS_PER_MP_LIMB + + got_limb; + } + while (bits <= MANT_DIG); + + return round_and_return (retval, exponent - 1, negative, + quot, BITS_PER_MP_LIMB - 1 - used, + n != 0); + } + case 2: + { + mp_limb d0, d1, n0, n1; + mp_limb quot = 0; + int used = 0; + + d0 = den[0]; + d1 = den[1]; + + if (numsize < densize) + { + if (bits <= 0) + exponent -= BITS_PER_MP_LIMB; + else + { + if (bits + BITS_PER_MP_LIMB <= MANT_DIG) + __mpn_lshift_1 (retval, RETURN_LIMB_SIZE, + BITS_PER_MP_LIMB, 0); + else + { + used = MANT_DIG - bits; + if (used > 0) + __mpn_lshift_1 (retval, RETURN_LIMB_SIZE, used, 0); + } + bits += BITS_PER_MP_LIMB; + } + n1 = num[0]; + n0 = 0; + } + else + { + n1 = num[1]; + n0 = num[0]; + } + + while (bits <= MANT_DIG) + { + mp_limb r; + + if (n1 == d1) + { + /* QUOT should be either 111..111 or 111..110. We need + special treatment of this rare case as normal division + would give overflow. */ + quot = ~(mp_limb) 0; + + r = n0 + d1; + if (r < d1) /* Carry in the addition? */ + { + add_ssaaaa (n1, n0, r - d0, 0, 0, d0); + goto have_quot; + } + n1 = d0 - (d0 != 0); + n0 = -d0; + } + else + { + udiv_qrnnd (quot, r, n1, n0, d1); + umul_ppmm (n1, n0, d0, quot); + } + + q_test: + if (n1 > r || (n1 == r && n0 > 0)) + { + /* The estimated QUOT was too large. */ + --quot; + + sub_ddmmss (n1, n0, n1, n0, 0, d0); + r += d1; + if (r >= d1) /* If not carry, test QUOT again. */ + goto q_test; + } + sub_ddmmss (n1, n0, r, 0, n1, n0); + + have_quot: + got_limb; + } + + return round_and_return (retval, exponent - 1, negative, + quot, BITS_PER_MP_LIMB - 1 - used, + n1 != 0 || n0 != 0); + } + default: + { + int i; + mp_limb cy, dX, d1, n0, n1; + mp_limb quot = 0; + int used = 0; + + dX = den[densize - 1]; + d1 = den[densize - 2]; + + /* The division does not work if the upper limb of the two-limb + numerator is greater than the denominator. */ + if (num[numsize - 1] > dX) + num[numsize++] = 0; + + if (numsize < densize) + { + mp_size_t empty = densize - numsize; + + if (bits <= 0) + { + register int i; + for (i = numsize; i > 0; --i) + num[i + empty] = num[i - 1]; + MPN_ZERO (num, empty + 1); + exponent -= empty * BITS_PER_MP_LIMB; + } + else + { + if (bits + empty * BITS_PER_MP_LIMB <= MANT_DIG) + { + /* We make a difference here because the compiler + cannot optimize the `else' case that good and + this reflects all currently used FLOAT types + and GMP implementations. */ + register int i; +#if RETURN_LIMB_SIZE <= 2 + assert (empty == 1); + __mpn_lshift_1 (retval, RETURN_LIMB_SIZE, + BITS_PER_MP_LIMB, 0); +#else + for (i = RETURN_LIMB_SIZE; i > empty; --i) + retval[i] = retval[i - empty]; +#endif + retval[1] = 0; + for (i = numsize; i > 0; --i) + num[i + empty] = num[i - 1]; + MPN_ZERO (num, empty + 1); + } + else + { + used = MANT_DIG - bits; + if (used >= BITS_PER_MP_LIMB) + { + register int i; + (void) __mpn_lshift (&retval[used + / BITS_PER_MP_LIMB], + retval, RETURN_LIMB_SIZE, + used % BITS_PER_MP_LIMB); + for (i = used / BITS_PER_MP_LIMB; i >= 0; --i) + retval[i] = 0; + } + else if (used > 0) + __mpn_lshift_1 (retval, RETURN_LIMB_SIZE, used, 0); + } + bits += empty * BITS_PER_MP_LIMB; + } + } + else + { + int i; + assert (numsize == densize); + for (i = numsize; i > 0; --i) + num[i] = num[i - 1]; + } + + den[densize] = 0; + n0 = num[densize]; + + while (bits <= MANT_DIG) + { + if (n0 == dX) + /* This might over-estimate QUOT, but it's probably not + worth the extra code here to find out. */ + quot = ~(mp_limb) 0; + else + { + mp_limb r; + + udiv_qrnnd (quot, r, n0, num[densize - 1], dX); + umul_ppmm (n1, n0, d1, quot); + + while (n1 > r || (n1 == r && n0 > num[densize - 2])) + { + --quot; + r += dX; + if (r < dX) /* I.e. "carry in previous addition?" */ + break; + n1 -= n0 < d1; + n0 -= d1; + } + } + + /* Possible optimization: We already have (q * n0) and (1 * n1) + after the calculation of QUOT. Taking advantage of this, we + could make this loop make two iterations less. */ + + cy = __mpn_submul_1 (num, den, densize + 1, quot); + + if (num[densize] != cy) + { + cy = __mpn_add_n (num, num, den, densize); + assert (cy != 0); + --quot; + } + n0 = num[densize] = num[densize - 1]; + for (i = densize - 1; i > 0; --i) + num[i] = num[i - 1]; + + got_limb; + } + + for (i = densize - 1; num[i] != 0 && i >= 0; --i) + ; + return round_and_return (retval, exponent - 1, negative, + quot, BITS_PER_MP_LIMB - 1 - used, + i >= 0); + } + } + } + + /* NOTREACHED */ +} diff --git a/stdlib/strtof.c b/stdlib/strtof.c new file mode 100644 index 0000000000..bf1349b108 --- /dev/null +++ b/stdlib/strtof.c @@ -0,0 +1,12 @@ +/* The actual implementation for all floating point sizes is in strtod.c. + These macros tell it to produce the `float' version, `strtof'. */ + +#define FLOAT float +#define FLT FLT +#define STRTOF __strtof +#define MPN2FLOAT __mpn_construct_float +#define FLOAT_HUGE_VAL HUGE_VALf + +#include "strtod.c" + +weak_alias (__strtof, strtof) diff --git a/stdlib/strtol.c b/stdlib/strtol.c new file mode 100644 index 0000000000..888a94e4d7 --- /dev/null +++ b/stdlib/strtol.c @@ -0,0 +1,189 @@ +/* Copyright (C) 1991, 1992, 1994, 1995 Free Software Foundation, Inc. + +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include + +/* Nonzero if we are defining `strtoul' or `strtouq', operating on unsigned + integers. */ +#ifndef UNSIGNED +#define UNSIGNED 0 +#endif + +/* If QUAD is defined, we are defining `strtoq' or `strtouq', + operating on `long long int's. */ +#ifdef QUAD +#if UNSIGNED +#define strtoul strtouq +#else +#define strtol strtoq +#endif +#define LONG long long +#undef LONG_MIN +#define LONG_MIN LONG_LONG_MIN +#undef LONG_MAX +#define LONG_MAX LONG_LONG_MAX +#undef ULONG_MAX +#define ULONG_MAX ULONG_LONG_MAX +#if __GNUC__ == 2 && __GNUC_MINOR__ < 7 +/* Work around gcc bug with using this constant. */ +static const unsigned long long int maxquad = ULONG_LONG_MAX; +#undef ULONG_MAX +#define ULONG_MAX maxquad +#endif +#else +#define LONG long +#endif + +/* Convert NPTR to an `unsigned long int' or `long int' in base BASE. + If BASE is 0 the base is determined by the presence of a leading + zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal. + If BASE is < 2 or > 36, it is reset to 10. + If ENDPTR is not NULL, a pointer to the character after the last + one converted is stored in *ENDPTR. */ +#if UNSIGNED +unsigned LONG int +#define strtol strtoul +#else +LONG int +#endif +strtol (nptr, endptr, base) + const char *nptr; + char **endptr; + int base; +{ + int negative; + register unsigned LONG int cutoff; + register unsigned int cutlim; + register unsigned LONG int i; + register const char *s; + register unsigned char c; + const char *save; + int overflow; + + if (base < 0 || base == 1 || base > 36) + base = 10; + + s = nptr; + + /* Skip white space. */ + while (isspace (*s)) + ++s; + if (*s == '\0') + goto noconv; + + /* Check for a sign. */ + if (*s == '-') + { + negative = 1; + ++s; + } + else if (*s == '+') + { + negative = 0; + ++s; + } + else + negative = 0; + + if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X') + s += 2; + + /* If BASE is zero, figure it out ourselves. */ + if (base == 0) + if (*s == '0') + { + if (toupper (s[1]) == 'X') + { + s += 2; + base = 16; + } + else + base = 8; + } + else + base = 10; + + /* Save the pointer so we can check later if anything happened. */ + save = s; + + cutoff = ULONG_MAX / (unsigned LONG int) base; + cutlim = ULONG_MAX % (unsigned LONG int) base; + + overflow = 0; + i = 0; + for (c = *s; c != '\0'; c = *++s) + { + if (isdigit (c)) + c -= '0'; + else if (isalpha (c)) + c = toupper (c) - 'A' + 10; + else + break; + if (c >= base) + break; + /* Check for overflow. */ + if (i > cutoff || (i == cutoff && c > cutlim)) + overflow = 1; + else + { + i *= (unsigned LONG int) base; + i += c; + } + } + + /* Check if anything actually happened. */ + if (s == save) + goto noconv; + + /* Store in ENDPTR the address of one character + past the last character we converted. */ + if (endptr != NULL) + *endptr = (char *) s; + +#if !UNSIGNED + /* Check for a value that is within the range of + `unsigned LONG int', but outside the range of `LONG int'. */ + if (i > (negative ? + -(unsigned LONG int) LONG_MIN : (unsigned LONG int) LONG_MAX)) + overflow = 1; +#endif + + if (overflow) + { + errno = ERANGE; +#if UNSIGNED + return ULONG_MAX; +#else + return negative ? LONG_MIN : LONG_MAX; +#endif + } + + /* Return the result of the appropriate sign. */ + return (negative ? -i : i); + +noconv: + /* There was no number to convert. */ + if (endptr != NULL) + *endptr = (char *) nptr; + return 0L; +} diff --git a/stdlib/strtold.c b/stdlib/strtold.c new file mode 100644 index 0000000000..2595725add --- /dev/null +++ b/stdlib/strtold.c @@ -0,0 +1,12 @@ +/* The actual implementation for all floating point sizes is in strtod.c. + These macros tell it to produce the `long double' version, `strtold'. */ + +#define FLOAT long double +#define FLT LDBL +#define STRTOF __strtold +#define MPN2FLOAT __mpn_construct_long_double +#define FLOAT_HUGE_VAL HUGE_VALl + +#include "strtod.c" + +weak_alias (__strtold, strtold) diff --git a/stdlib/strtoq.c b/stdlib/strtoq.c new file mode 100644 index 0000000000..be1f723b13 --- /dev/null +++ b/stdlib/strtoq.c @@ -0,0 +1,22 @@ +/* strtoq -- Function to parse a `long long int' from text. +Copyright (C) 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#define QUAD 1 + +#include diff --git a/stdlib/strtoul.c b/stdlib/strtoul.c new file mode 100644 index 0000000000..386cc7a357 --- /dev/null +++ b/stdlib/strtoul.c @@ -0,0 +1,21 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#define UNSIGNED 1 + +#include diff --git a/stdlib/strtouq.c b/stdlib/strtouq.c new file mode 100644 index 0000000000..4eea0b22ee --- /dev/null +++ b/stdlib/strtouq.c @@ -0,0 +1,22 @@ +/* strtouq -- Function to parse an `unsigned long long int' from text. +Copyright (C) 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#define QUAD 1 + +#include diff --git a/stdlib/testdiv.c b/stdlib/testdiv.c new file mode 100644 index 0000000000..b86a58d42c --- /dev/null +++ b/stdlib/testdiv.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include + +int +DEFUN_VOID(main) +{ + int i, j; + while (scanf ("%d %d\n", &i, &j) == 2) + { + div_t d = div (i, j); + printf ("%d / %d = %d + %d/%d\n", i, j, d.quot, d.rem, j); + } + return 0; +} diff --git a/stdlib/testdiv.input b/stdlib/testdiv.input new file mode 100644 index 0000000000..415b7b4f54 --- /dev/null +++ b/stdlib/testdiv.input @@ -0,0 +1,2 @@ +10 3 +-10 3 diff --git a/stdlib/testmb.c b/stdlib/testmb.c new file mode 100644 index 0000000000..c840ce195b --- /dev/null +++ b/stdlib/testmb.c @@ -0,0 +1,69 @@ +#include +#include + +int +main () +{ + wchar_t w[10]; + char c[10]; + int i; + int lose = 0; + + i = mbstowcs (w, "bar", 4); + if (!(i == 3 && w[1] == 'a')) + { + puts ("mbstowcs FAILED!"); + lose = 1; + } + + mbstowcs (w, "blah", 5); + i = wcstombs (c, w, 10); + if (i != 4) + { + puts ("wcstombs FAILED!"); + lose = 1; + } + + if (mblen ("foobar", 7) != 1) + { + puts ("mblen 1 FAILED!"); + lose = 1; + } + + if (mblen ("", 1) != 0) + { + puts ("mblen 2 FAILED!"); + lose = 1; + } + + { + int r; + char c = 'x'; + wchar_t wc; + char *mbc; + + mbc = (char *) malloc (MB_CUR_MAX); + mbc[0] = c; + mbc[1] = '\0'; + + if ((r = mbtowc (&wc, &c, MB_CUR_MAX)) <= 0) + { + printf ("conversion to wide failed, result: %d\n", r); + lose = 1; + } + else + { + printf ("wide value: 0x%04x\n", (unsigned long) wc); + mbc[0] = '\0'; + if ((r = wctomb (mbc, wc)) <= 0) + { + printf ("conversion to multibyte failed, result: %d\n", r); + lose = 1; + } + } + + } + + puts (lose ? "Test FAILED!" : "Test succeeded."); + return lose; +} diff --git a/stdlib/testrand.c b/stdlib/testrand.c new file mode 100644 index 0000000000..b66dca9899 --- /dev/null +++ b/stdlib/testrand.c @@ -0,0 +1,51 @@ +/* Copyright (C) 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include + +int +DEFUN_VOID(main) +{ + int i1, i2; + int j1, j2; + + /* The C standard says that "If rand is called before any calls to + srand have been made, the same sequence shall be generated as + when srand is first called with a seed value of 1." */ + i1 = rand(); + i2 = rand(); + srand (1); + j1 = rand(); + j2 = rand(); + if (j1 == i1 && j2 == i2) + { + puts ("Test succeeded."); + return 0; + } + else + { + if (j1 != i1) + printf ("%d != %d\n", j1, i1); + if (j2 != i2) + printf ("%d != %d\n", j2, i2); + puts ("Test FAILED!"); + return 1; + } +} diff --git a/stdlib/testsort.c b/stdlib/testsort.c new file mode 100644 index 0000000000..a171a62130 --- /dev/null +++ b/stdlib/testsort.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include + +int +DEFUN(compare, (a, b), CONST PTR a AND CONST PTR b) +{ + return strcmp (*(char **) a, *(char **) b); +} + + +int +DEFUN_VOID(main) +{ + char bufs[500][20]; + char *lines[500]; + size_t lens[500]; + size_t i, j; + + srandom (1); + + for (i = 0; i < 500; ++i) + { + lens[i] = random() % 19; + lines[i] = bufs[i]; + for (j = 0; j < lens[i]; ++j) + lines[i][j] = random() % 26 + 'a'; + lines[i][j] = '\0'; + } + + qsort (lines, 500, sizeof (char *), compare); + + for (i = 0; i < 500 && lines[i] != NULL; ++i) + puts (lines[i]); + + return 0; +} diff --git a/stdlib/tst-strtod.c b/stdlib/tst-strtod.c new file mode 100644 index 0000000000..a38ff4a74b --- /dev/null +++ b/stdlib/tst-strtod.c @@ -0,0 +1,94 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include + +struct ltest + { + CONST char *str; /* Convert this. */ + double expect; /* To get this. */ + char left; /* With this left over. */ + int err; /* And this in errno. */ + }; +static CONST struct ltest tests[] = + { + { "12.345", 12.345, '\0', 0 }, + { "12.345e19", 12.345e19, '\0', 0 }, + { "-.1e+9", -.1e+9, '\0', 0 }, + { ".125", .125, '\0', 0 }, + { "1e20", 1e20, '\0', 0 }, + { NULL, 0, '\0', 0 } + }; + +static void EXFUN(expand, (char *dst, int c)); + +int +DEFUN_VOID(main) +{ + register CONST struct ltest *lt; + char *ep; + int status = 0; + + for (lt = tests; lt->str != NULL; ++lt) + { + double d; + + errno = 0; + d = strtod(lt->str, &ep); + printf("strtod(\"%s\") test %u", + lt->str, (unsigned int) (lt - tests)); + if (d == lt->expect && *ep == lt->left && errno == lt->err) + puts("\tOK"); + else + { + puts("\tBAD"); + if (d != lt->expect) + printf(" returns %.60g, expected %.60g\n", d, lt->expect); + if (lt->left != *ep) + { + char exp1[5], exp2[5]; + expand(exp1, *ep); + expand(exp2, lt->left); + printf(" leaves '%s', expected '%s'\n", exp1, exp2); + } + if (errno != lt->err) + printf(" errno %d (%s) instead of %d (%s)\n", + errno, strerror(errno), lt->err, strerror(lt->err)); + status = 1; + } + } + + exit(status ? EXIT_FAILURE : EXIT_SUCCESS); +} + +static void +DEFUN(expand, (dst, c), register char *dst AND register int c) +{ + if (isprint(c)) + { + dst[0] = c; + dst[1] = '\0'; + } + else + (void) sprintf(dst, "%#.3o", (unsigned int) c); +} diff --git a/stdlib/tst-strtol.c b/stdlib/tst-strtol.c new file mode 100644 index 0000000000..0682da3f09 --- /dev/null +++ b/stdlib/tst-strtol.c @@ -0,0 +1,127 @@ +/* My bet is this was written by Chris Torek. + I reformatted and ansidecl-ized it, and tweaked it a little. */ + +#include +#include +#include +#include +#include +#include + +struct ltest + { + CONST char *str; /* Convert this. */ + unsigned long int expect; /* To get this. */ + int base; /* Use this base. */ + char left; /* With this left over. */ + int err; /* And this in errno. */ + }; +static CONST struct ltest tests[] = + { + /* First, signed numbers. */ + { " -17", -17, 0, 0, 0 }, + { " +0x123fg", 0x123f, 0, 'g', 0 }, + { "2147483647", 2147483647, 0, 0, 0 }, + { "2147483648", 2147483647, 0, 0, ERANGE }, + { "214748364888", 2147483647, 0, 0, ERANGE }, + { "2147483650", 2147483647, 0, 0, ERANGE }, + { "-2147483649", -2147483648, 0, 0, ERANGE }, + { "-2147483648", -2147483648, 0, 0, 0 }, + { "0123", 0123, 0, 0, 0 }, + { "0x1122334455z", 2147483647, 16, 'z', ERANGE }, + { "0x0xc", 0, 0, 'x', 0 }, + { "yz!", 34*36+35, 36, '!', 0 }, + { NULL, 0, 0, 0, 0 }, + + /* Then unsigned. */ + { " 0", 0, 0, 0, 0 }, + { "0xffffffffg", 0xffffffff, 0, 'g', 0 }, + { "0xf1f2f3f4f5", 0xffffffff, 0, 0, ERANGE }, + { "-0x123456789", 0xffffffff, 0, 0, ERANGE }, + { "-0xfedcba98", -0xfedcba98, 0, 0, 0 }, + { NULL, 0, 0, 0, 0 }, + }; + +static void EXFUN(expand, (char *dst, int c)); + +int +DEFUN_VOID(main) +{ + register CONST struct ltest *lt; + char *ep; + int status = 0; + + for (lt = tests; lt->str != NULL; ++lt) + { + register long int l; + + errno = 0; + l = strtol(lt->str, &ep, lt->base); + printf("strtol(\"%s\", , %d) test %u", + lt->str, lt->base, (unsigned int) (lt - tests)); + if (l == (long int) lt->expect && *ep == lt->left && errno == lt->err) + puts("\tOK"); + else + { + puts("\tBAD"); + if (l != (long int) lt->expect) + printf(" returns %ld, expected %ld\n", + l, (long int) lt->expect); + if (lt->left != *ep) + { + char exp1[5], exp2[5]; + expand(exp1, *ep); + expand(exp2, lt->left); + printf(" leaves '%s', expected '%s'\n", exp1, exp2); + } + if (errno != lt->err) + printf(" errno %d (%s) instead of %d (%s)\n", + errno, strerror(errno), lt->err, strerror(lt->err)); + status = 1; + } + } + + for (++lt; lt->str != NULL; lt++) + { + register unsigned long int ul; + + errno = 0; + ul = strtoul(lt->str, &ep, lt->base); + printf("strtoul(\"%s\", , %d) test %u", + lt->str, lt->base, (unsigned int) (lt - tests)); + if (ul == lt->expect && *ep == lt->left && errno == lt->err) + puts("\tOK"); + else + { + puts("\tBAD"); + if (ul != lt->expect) + printf(" returns %lu, expected %lu\n", + ul, lt->expect); + if (lt->left != *ep) + { + char exp1[5], exp2[5]; + expand(exp1, *ep); + expand(exp2, lt->left); + printf(" leaves '%s', expected '%s'\n", exp1, exp2); + } + if (errno != lt->err) + printf(" errno %d (%s) instead of %d (%s)\n", + errno, strerror(errno), lt->err, strerror(lt->err)); + status = 1; + } + } + + exit(status ? EXIT_FAILURE : EXIT_SUCCESS); +} + +static void +DEFUN(expand, (dst, c), register char *dst AND register int c) +{ + if (isprint(c)) + { + dst[0] = c; + dst[1] = '\0'; + } + else + (void) sprintf(dst, "%#.3o", (unsigned int) c); +} diff --git a/stdlib/wcstombs.c b/stdlib/wcstombs.c new file mode 100644 index 0000000000..acaf15a94e --- /dev/null +++ b/stdlib/wcstombs.c @@ -0,0 +1,77 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include + + +/* Convert the `wchar_t' string in PWCS to a multibyte character string + in S, writing no more than N characters. Return the number of bytes + written, or (size_t) -1 if an invalid `wchar_t' was found. */ +size_t +DEFUN(wcstombs, (s, pwcs, n), + register char *s AND register CONST wchar_t *pwcs AND register size_t n) +{ + register CONST mb_char *mb; + register int shift = 0; + + register size_t written = 0; + register wchar_t w; + + while ((w = *pwcs++) != (wchar_t) '\0') + { + if (isascii (w)) + { + /* A normal character. */ + *s++ = (unsigned char) w; + --n; + ++written; + } + else + { + mb = &_ctype_info->mbchar->mb_chars[w + shift]; + if (mb->string == NULL || mb->len == 0) + { + written = (size_t) -1; + break; + } + else if (mb->len > n) + break; + else + { + memcpy ((PTR) s, (CONST PTR) mb->string, mb->len); + s += mb->len; + n -= mb->len; + written += mb->len; + shift += mb->shift; + } + } + } + + /* Terminate the string if it has space. */ + if (n > 0) + *s = '\0'; + + /* Return the number of characters written (or maybe an error). */ + return written; +} diff --git a/stdlib/wctomb.c b/stdlib/wctomb.c new file mode 100644 index 0000000000..53f1cef3fc --- /dev/null +++ b/stdlib/wctomb.c @@ -0,0 +1,72 @@ +/* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include + + +extern long int _mb_shift; /* Defined in mbtowc.c. */ + +/* Convert WCHAR into its multibyte character representation, + putting this in S and returning its length. */ +int +DEFUN(wctomb, (s, wchar), register char *s AND wchar_t wchar) +{ + register CONST mb_char *mb; + + if (_ctype_info->mbchar == NULL) + mb = NULL; + else + mb = _ctype_info->mbchar->mb_chars; + + /* If S is NULL, just say if we're shifted or not. */ + if (s == NULL) + return _mb_shift != 0; + + if (wchar == (wchar_t) '\0') + { + _mb_shift = 0; + /* See ANSI 4.4.1.1, line 21. */ + if (s != NULL) + *s = '\0'; + return 1; + } + else if (mb == NULL) + { + if ((wchar_t) (char) wchar == wchar && isascii ((char) wchar)) + { + /* A normal ASCII character translates to itself. */ + if (s != NULL) + *s = (char) wchar; + return 1; + } + return -1; + } + + mb += wchar + _mb_shift; + if (mb->string == NULL || mb->len == 0) + return -1; + memcpy((PTR) s, (CONST PTR) mb->string, mb->len + 1); + _mb_shift += mb->shift; + return mb->len; +} -- cgit v1.2.3