summaryrefslogtreecommitdiff
path: root/stdlib
diff options
context:
space:
mode:
authorGabriel F. T. Gomes <gftg@linux.vnet.ibm.com>2016-06-28 17:30:42 -0300
committerGabriel F. T. Gomes <gftg@linux.vnet.ibm.com>2016-10-25 17:03:54 -0200
commit6962682ffe5e5f0373047a0b894fee7a774be254 (patch)
treee8e3660cf706a62dc9c71972aa2acf165caf5c48 /stdlib
parent78b7adbaea643f2f213bb113e3ec933416a769a8 (diff)
downloadglibc-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/Makefile7
-rw-r--r--stdlib/Versions4
-rw-r--r--stdlib/bits/stdlib-ldbl.h4
-rw-r--r--stdlib/stdlib.h18
-rw-r--r--stdlib/strfrom-skeleton.c149
-rw-r--r--stdlib/strfromd.c22
-rw-r--r--stdlib/strfromf.c22
-rw-r--r--stdlib/strfroml.c22
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"