diff options
author | Gabriel F. T. Gomes <gftg@linux.vnet.ibm.com> | 2016-06-28 17:30:42 -0300 |
---|---|---|
committer | Gabriel F. T. Gomes <gftg@linux.vnet.ibm.com> | 2016-10-25 17:03:54 -0200 |
commit | 6962682ffe5e5f0373047a0b894fee7a774be254 (patch) | |
tree | e8e3660cf706a62dc9c71972aa2acf165caf5c48 /stdlib | |
parent | 78b7adbaea643f2f213bb113e3ec933416a769a8 (diff) | |
download | glibc-6962682ffe5e5f0373047a0b894fee7a774be254.tar.gz |
Add strfromd, strfromf, and strfroml functions
ISO/IEC TS 18661-1 adds several functions in the strfrom family to stdlib.
This patch adds strfromd, strfromf, and strfroml. This is being done in
preparation for the new floating-point type, float128. The added functions
convert a floating-point value into a string, with configurable format.
Diffstat (limited to 'stdlib')
-rw-r--r-- | stdlib/Makefile | 7 | ||||
-rw-r--r-- | stdlib/Versions | 4 | ||||
-rw-r--r-- | stdlib/bits/stdlib-ldbl.h | 4 | ||||
-rw-r--r-- | stdlib/stdlib.h | 18 | ||||
-rw-r--r-- | stdlib/strfrom-skeleton.c | 149 | ||||
-rw-r--r-- | stdlib/strfromd.c | 22 | ||||
-rw-r--r-- | stdlib/strfromf.c | 22 | ||||
-rw-r--r-- | stdlib/strfroml.c | 22 |
8 files changed, 247 insertions, 1 deletions
diff --git a/stdlib/Makefile b/stdlib/Makefile index de3ecbbaa0..3cacb8b3f6 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -46,6 +46,7 @@ routines := \ drand48_r erand48_r lrand48_r nrand48_r mrand48_r jrand48_r \ srand48_r seed48_r lcong48_r \ drand48-iter \ + strfromf strfromd strfroml \ strtol strtoul strtoll strtoull \ strtol_l strtoul_l strtoll_l strtoull_l \ strtof strtod strtold \ @@ -122,6 +123,12 @@ CFLAGS-fmtmsg.c = -fexceptions CFLAGS-strfmon.c = $(libio-mtsafe) CFLAGS-strfmon_l.c = $(libio-mtsafe) +# The strfrom class of functions call __printf_fp in order to convert the +# floating-point value to characters. This requires the value of IO_MTSAFE_IO. +CFLAGS-strfromd.c = $(libio-mtsafe) +CFLAGS-strfromf.c = $(libio-mtsafe) +CFLAGS-strfroml.c = $(libio-mtsafe) + CFLAGS-tst-bsearch.c = $(stack-align-test-flags) CFLAGS-tst-qsort.c = $(stack-align-test-flags) CFLAGS-tst-makecontext.c += -funwind-tables diff --git a/stdlib/Versions b/stdlib/Versions index 9c06b43986..54416b7ea6 100644 --- a/stdlib/Versions +++ b/stdlib/Versions @@ -112,6 +112,10 @@ libc { GLIBC_2.24 { quick_exit; } + GLIBC_2.25 { + # s* + strfromd; strfromf; strfroml; + } GLIBC_PRIVATE { # functions which have an additional interface since they are # are cancelable. diff --git a/stdlib/bits/stdlib-ldbl.h b/stdlib/bits/stdlib-ldbl.h index acff499165..52fdc492d4 100644 --- a/stdlib/bits/stdlib-ldbl.h +++ b/stdlib/bits/stdlib-ldbl.h @@ -30,6 +30,10 @@ __END_NAMESPACE_C99 __LDBL_REDIR1_DECL (strtold_l, strtod_l) #endif +#if __GLIBC_USE (IEC_60559_BFP_EXT) +__LDBL_REDIR1_DECL (strfroml, strfromd) +#endif + #ifdef __USE_MISC __LDBL_REDIR1_DECL (qecvt, ecvt) __LDBL_REDIR1_DECL (qfcvt, fcvt) diff --git a/stdlib/stdlib.h b/stdlib/stdlib.h index f0dc951acf..48f9a9500e 100644 --- a/stdlib/stdlib.h +++ b/stdlib/stdlib.h @@ -21,7 +21,8 @@ #ifndef _STDLIB_H -#include <features.h> +#define __GLIBC_INTERNAL_STARTING_HEADER_IMPLEMENTATION +#include <bits/libc-header-start.h> /* Get size_t, wchar_t and NULL from <stddef.h>. */ #define __need_size_t @@ -178,6 +179,21 @@ extern unsigned long long int strtoull (const char *__restrict __nptr, __END_NAMESPACE_C99 #endif /* ISO C99 or use MISC. */ +/* Convert a floating-point number to a string. */ +#if __GLIBC_USE (IEC_60559_BFP_EXT) +extern int strfromd (char *__dest, size_t __size, const char *__format, + double __f) + __THROW __nonnull ((3)); + +extern int strfromf (char *__dest, size_t __size, const char *__format, + float __f) + __THROW __nonnull ((3)); + +extern int strfroml (char *__dest, size_t __size, const char *__format, + long double __f) + __THROW __nonnull ((3)); +#endif + #ifdef __USE_GNU /* The concept of one static locale per category is not very well diff --git a/stdlib/strfrom-skeleton.c b/stdlib/strfrom-skeleton.c new file mode 100644 index 0000000000..8fd1beb7aa --- /dev/null +++ b/stdlib/strfrom-skeleton.c @@ -0,0 +1,149 @@ +/* Convert a floating-point number to string. + Copyright (C) 2016 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* Generic implementation for strfrom functions. The implementation is generic + for several floating-point types (e.g.: float, double), so that each + function, such as strfromf and strfroml, share the same code, thus avoiding + code duplication. */ + +#include <ctype.h> +#include "../libio/libioP.h" +#include "../libio/strfile.h" +#include <printf.h> +#include <string.h> +#include <locale/localeinfo.h> + +#define UCHAR_T char +#define L_(Str) Str +#define ISDIGIT(Ch) isdigit (Ch) +#include "stdio-common/printf-parse.h" + +int +STRFROM (char *dest, size_t size, const char *format, FLOAT f) +{ + _IO_strnfile sfile; +#ifdef _IO_MTSAFE_IO + sfile.f._sbf._f._lock = NULL; +#endif + + int done; + + /* Single-precision values need to be stored in a double type, because + __printf_fp_l and __printf_fphex do not accept the float type. */ + union { + double flt; + FLOAT value; + } fpnum; + const void *fpptr; + fpptr = &fpnum; + + /* Variables to control the output format. */ + int precision = -1; /* printf_fp and printf_fphex treat this internally. */ + int specifier; + struct printf_info info; + + /* Single-precision values need to be converted into double-precision, + because __printf_fp and __printf_fphex only accept double and long double + as the floating-point argument. */ + if (__builtin_types_compatible_p (FLOAT, float)) + fpnum.flt = f; + else + fpnum.value = f; + + /* Check if the first character in the format string is indeed the '%' + character. Otherwise, abort. */ + if (*format == '%') + format++; + else + abort (); + + /* The optional precision specification always starts with a '.'. If such + character is present, read the precision. */ + if (*format == '.') + { + format++; + + /* Parse the precision. */ + if (ISDIGIT (*format)) + precision = read_int (&format); + /* If only the period is specified, the precision is taken as zero, as + described in ISO/IEC 9899:2011, section 7.21.6.1, 4th paragraph, 3rd + item. */ + else + precision = 0; + } + + /* Now there is only the conversion specifier to be read. */ + switch (*format) + { + case 'a': + case 'A': + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + specifier = *format; + break; + default: + abort (); + } + + /* The following code to prepare the virtual file has been adapted from the + function _IO_vsnprintf from libio. */ + + if (size == 0) + { + /* When size is zero, nothing is written and dest may be a null pointer. + This is specified for snprintf in ISO/IEC 9899:2011, Section 7.21.6.5, + in the second paragraph. Thus, if size is zero, prepare to use the + overflow buffer right from the start. */ + dest = sfile.overflow_buf; + size = sizeof (sfile.overflow_buf); + } + + /* Prepare the virtual string file. */ + _IO_no_init (&sfile.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL); + _IO_JUMPS (&sfile.f._sbf) = &_IO_strn_jumps; + _IO_str_init_static_internal (&sfile.f, dest, size - 1, dest); + + /* Prepare the format specification for printf_fp. */ + memset (&info, '\0', sizeof (info)); + + /* The functions strfromd and strfromf pass a floating-point number with + double precision to printf_fp, whereas strfroml passes a floating-point + number with long double precision. The following line informs printf_fp + which type of floating-point number is being passed. */ + info.is_long_double = __builtin_types_compatible_p (FLOAT, long double); + + /* Set info according to the format string. */ + info.prec = precision; + info.spec = specifier; + + if (info.spec != 'a' && info.spec != 'A') + done = __printf_fp_l (&sfile.f._sbf._f, _NL_CURRENT_LOCALE, &info, &fpptr); + else + done = __printf_fphex (&sfile.f._sbf._f, &info, &fpptr); + + /* Terminate the string. */ + if (sfile.f._sbf._f._IO_buf_base != sfile.overflow_buf) + *sfile.f._sbf._f._IO_write_ptr = '\0'; + + return done; +} diff --git a/stdlib/strfromd.c b/stdlib/strfromd.c new file mode 100644 index 0000000000..45a5790a1f --- /dev/null +++ b/stdlib/strfromd.c @@ -0,0 +1,22 @@ +/* Definitions for strfromd. Implementation in stdlib/strfrom-skeleton.c. + Copyright (C) 2016 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#define FLOAT double +#define STRFROM strfromd + +#include "strfrom-skeleton.c" diff --git a/stdlib/strfromf.c b/stdlib/strfromf.c new file mode 100644 index 0000000000..f0b085844c --- /dev/null +++ b/stdlib/strfromf.c @@ -0,0 +1,22 @@ +/* Definitions for strfromf. Implementation in stdlib/strfrom-skeleton.c. + Copyright (C) 2016 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#define FLOAT float +#define STRFROM strfromf + +#include "strfrom-skeleton.c" diff --git a/stdlib/strfroml.c b/stdlib/strfroml.c new file mode 100644 index 0000000000..8d5d15b0b9 --- /dev/null +++ b/stdlib/strfroml.c @@ -0,0 +1,22 @@ +/* Definitions for strfroml. Implementation in stdlib/strfrom-skeleton.c. + Copyright (C) 2016 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#define FLOAT long double +#define STRFROM strfroml + +#include "strfrom-skeleton.c" |