aboutsummaryrefslogtreecommitdiff
path: root/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib')
-rw-r--r--stdlib/strfmon_l.c196
-rw-r--r--stdlib/strfrom-skeleton.c38
2 files changed, 83 insertions, 151 deletions
diff --git a/stdlib/strfmon_l.c b/stdlib/strfmon_l.c
index d9b2208..6dc36e0 100644
--- a/stdlib/strfmon_l.c
+++ b/stdlib/strfmon_l.c
@@ -29,33 +29,8 @@
#include <string.h>
#include "../locale/localeinfo.h"
#include <bits/floatn.h>
-
-
-#define out_char(Ch) \
- do { \
- if (dest >= s + maxsize - 1) \
- { \
- __set_errno (E2BIG); \
- va_end (ap); \
- return -1; \
- } \
- *dest++ = (Ch); \
- } while (0)
-
-#define out_string(String) \
- do { \
- const char *_s = (String); \
- while (*_s) \
- out_char (*_s++); \
- } while (0)
-
-#define out_nstring(String, N) \
- do { \
- int _n = (N); \
- const char *_s = (String); \
- while (_n-- > 0) \
- out_char (*_s++); \
- } while (0)
+#include <stdio-common/grouping_iterator.h>
+#include <printf_buffer.h>
#define to_digit(Ch) ((Ch) - '0')
@@ -75,21 +50,15 @@
some information in the LC_MONETARY category which should be used,
too. Some of the information contradicts the information which can
be specified in format string. */
-ssize_t
-__vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
- const char *format, va_list ap, unsigned int flags)
+static void
+__vstrfmon_l_buffer (struct __printf_buffer *buf, locale_t loc,
+ const char *fmt, va_list ap, unsigned int flags)
{
struct __locale_data *current = loc->__locales[LC_MONETARY];
- _IO_strfile f;
struct printf_info info;
- char *dest; /* Pointer so copy the output. */
- const char *fmt; /* Pointer that walks through format. */
-
- dest = s;
- fmt = format;
/* Loop through the format-string. */
- while (*fmt != '\0')
+ while (*fmt != '\0' && !__printf_buffer_has_failed (buf))
{
/* The floating-point value to output. */
union
@@ -122,11 +91,9 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
int other_cs_precedes;
const char *sign_string;
const char *other_sign_string;
- int done;
const char *currency_symbol;
size_t currency_symbol_len;
long int width;
- char *startp;
const void *ptr;
char space_char;
@@ -134,14 +101,14 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
specification. */
if (*fmt != '%')
{
- out_char (*fmt++);
+ __printf_buffer_putc (buf, *fmt++);
continue;
}
/* "%%" means a single '%' character. */
if (fmt[1] == '%')
{
- out_char (*++fmt);
+ __printf_buffer_putc (buf, *++fmt);
++fmt;
continue;
}
@@ -171,7 +138,8 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
{
/* Premature EOS. */
__set_errno (EINVAL);
- return -1;
+ __printf_buffer_mark_failed (buf);
+ return;
}
continue;
case '^': /* Don't group digits. */
@@ -181,7 +149,8 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
if (n_sign_posn != -2)
{
__set_errno (EINVAL);
- return -1;
+ __printf_buffer_mark_failed (buf);
+ return;
}
p_sign_posn = *_NL_CURRENT (LC_MONETARY, P_SIGN_POSN);
n_sign_posn = *_NL_CURRENT (LC_MONETARY, N_SIGN_POSN);
@@ -190,7 +159,8 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
if (n_sign_posn != -2)
{
__set_errno (EINVAL);
- return -1;
+ __printf_buffer_mark_failed (buf);
+ return;
}
p_sign_posn = 0;
n_sign_posn = 0;
@@ -220,19 +190,12 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|| (width == LONG_MAX && val > LONG_MAX % 10))
{
__set_errno (E2BIG);
- return -1;
+ __printf_buffer_mark_failed (buf);
+ return;
}
width = width * 10 + val;
}
-
- /* If we don't have enough room for the demanded width we
- can stop now and return an error. */
- if (width >= maxsize - (dest - s))
- {
- __set_errno (E2BIG);
- return -1;
- }
}
/* Recognize left precision. */
@@ -241,7 +204,8 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
if (!isdigit (*++fmt))
{
__set_errno (EINVAL);
- return -1;
+ __printf_buffer_mark_failed (buf);
+ return;
}
left_prec = to_digit (*fmt);
@@ -258,7 +222,8 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
if (!isdigit (*++fmt))
{
__set_errno (EINVAL);
- return -1;
+ __printf_buffer_mark_failed (buf);
+ return;
}
right_prec = to_digit (*fmt);
@@ -306,7 +271,8 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
break;
default: /* Any unrecognized format is an error. */
__set_errno (EINVAL);
- return -1;
+ __printf_buffer_mark_failed (buf);
+ return;
}
/* If not specified by the format string now find the values for
@@ -327,8 +293,11 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
/* If we have to print the digits grouped determine how many
extra characters this means. */
if (group && left_prec != -1)
- left_prec += __guess_grouping (left_prec,
- _NL_CURRENT (LC_MONETARY, MON_GROUPING));
+ {
+ struct grouping_iterator it;
+ __grouping_iterator_init (&it, LC_MONETARY, loc, left_prec);
+ left_prec += it.separators;
+ }
/* Now it's time to get the value. */
if (is_long_double == 1)
@@ -482,57 +451,46 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
#define left_paren '('
#define right_paren ')'
- startp = dest; /* Remember start so we can compute length. */
+ char *startp = buf->write_ptr;
- while (left_pad-- > 0)
- out_char (' ');
+ __printf_buffer_pad (buf, ' ', left_pad);
if (sign_posn == 0 && is_negative)
- out_char (left_paren);
+ __printf_buffer_putc (buf, left_paren);
if (cs_precedes)
{
if (sign_posn != 0 && sign_posn != 2 && sign_posn != 4
&& sign_posn != 5)
{
- out_string (sign_string);
+ __printf_buffer_puts (buf, sign_string);
if (sep_by_space == 2)
- out_char (' ');
+ __printf_buffer_putc (buf, ' ');
}
if (print_curr_symbol)
- out_string (currency_symbol);
+ __printf_buffer_puts (buf, currency_symbol);
if (sign_posn == 4)
{
if (print_curr_symbol && sep_by_space == 2)
- out_char (space_char);
- out_string (sign_string);
+ __printf_buffer_putc (buf, space_char);
+ __printf_buffer_puts (buf, sign_string);
if (sep_by_space == 1)
/* POSIX.2 and SUS are not clear on this case, but C99
says a space follows the adjacent-symbol-and-sign */
- out_char (' ');
+ __printf_buffer_putc (buf, ' ');
}
else
if (print_curr_symbol && sep_by_space == 1)
- out_char (space_char);
+ __printf_buffer_putc (buf, space_char);
}
else
if (sign_posn != 0 && sign_posn != 2 && sign_posn != 3
&& sign_posn != 4 && sign_posn != 5)
- out_string (sign_string);
+ __printf_buffer_puts (buf, sign_string);
/* Print the number. */
-#ifdef _IO_MTSAFE_IO
- f._sbf._f._lock = NULL;
-#endif
- _IO_init_internal (&f._sbf._f, 0);
- _IO_JUMPS (&f._sbf) = &_IO_str_jumps;
- _IO_str_init_static_internal (&f, dest, (s + maxsize) - dest, dest);
- /* We clear the last available byte so we can find out whether
- the numeric representation is too long. */
- s[maxsize - 1] = '\0';
-
memset (&info, '\0', sizeof (info));
info.prec = right_prec;
info.width = left_prec + (right_prec ? (right_prec + 1) : 0);
@@ -544,25 +502,17 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
info.extra = 1; /* This means use values from LC_MONETARY. */
ptr = &fpnum;
- done = __printf_fp_l (&f._sbf._f, loc, &info, &ptr);
- if (done < 0)
- return -1;
-
- if (s[maxsize - 1] != '\0')
- {
- __set_errno (E2BIG);
- return -1;
- }
-
- dest += done;
+ __printf_fp_l_buffer (buf, loc, &info, &ptr);
+ if (__printf_buffer_has_failed (buf))
+ return;
if (!cs_precedes)
{
if (sign_posn == 3)
{
if (sep_by_space == 1)
- out_char (' ');
- out_string (sign_string);
+ __printf_buffer_putc (buf, ' ');
+ __printf_buffer_puts (buf, sign_string);
}
if (print_curr_symbol)
@@ -572,55 +522,61 @@ __vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
|| (sign_posn == 2 && sep_by_space == 1)
|| (sign_posn == 1 && sep_by_space == 1)
|| (sign_posn == 0 && sep_by_space == 1))
- out_char (space_char);
- out_nstring (currency_symbol, currency_symbol_len);
+ __printf_buffer_putc (buf, space_char);
+ __printf_buffer_write (buf, currency_symbol,
+ __strnlen (currency_symbol,
+ currency_symbol_len));
}
if (sign_posn == 4)
{
if (sep_by_space == 2)
- out_char (' ');
- out_string (sign_string);
+ __printf_buffer_putc (buf, ' ');
+ __printf_buffer_puts (buf, sign_string);
}
}
if (sign_posn == 2)
{
if (sep_by_space == 2)
- out_char (' ');
- out_string (sign_string);
+ __printf_buffer_putc (buf, ' ');
+ __printf_buffer_puts (buf, sign_string);
}
if (sign_posn == 0 && is_negative)
- out_char (right_paren);
+ __printf_buffer_putc (buf, right_paren);
/* Now test whether the output width is filled. */
- if (dest - startp < width)
+ if (buf->write_ptr - startp < width)
{
- if (left)
- /* We simply have to fill using spaces. */
- do
- out_char (' ');
- while (dest - startp < width);
- else
+ size_t pad_width = width - (buf->write_ptr - startp);
+ __printf_buffer_pad (buf, ' ', pad_width);
+ if (__printf_buffer_has_failed (buf))
+ /* Implies length check. */
+ return;
+ /* Left padding is already in the correct position.
+ Otherwise move the field contents in place. */
+ if (!left)
{
- long int dist = width - (dest - startp);
- for (char *cp = dest - 1; cp >= startp; --cp)
- cp[dist] = cp[0];
-
- dest += dist;
-
- do
- startp[--dist] = ' ';
- while (dist > 0);
+ memmove (startp + pad_width, startp, buf->write_ptr - startp);
+ memset (startp, ' ', pad_width);
}
}
}
+}
- /* Terminate the string. */
- *dest = '\0';
-
- return dest - s;
+ssize_t
+__vstrfmon_l_internal (char *s, size_t maxsize, locale_t loc,
+ const char *format, va_list ap, unsigned int flags)
+{
+ struct __printf_buffer buf;
+ __printf_buffer_init (&buf, s, maxsize, __printf_buffer_mode_strfmon);
+ __vstrfmon_l_buffer (&buf, loc, format, ap, flags);
+ __printf_buffer_putc (&buf, '\0'); /* Terminate the string. */
+ if (__printf_buffer_has_failed (&buf))
+ return -1;
+ else
+ return buf.write_ptr - buf.write_base - 1; /* Exclude NUL byte. */
}
ssize_t
diff --git a/stdlib/strfrom-skeleton.c b/stdlib/strfrom-skeleton.c
index 36e9adc..810eb31 100644
--- a/stdlib/strfrom-skeleton.c
+++ b/stdlib/strfrom-skeleton.c
@@ -28,6 +28,7 @@
#include <string.h>
#include <locale/localeinfo.h>
#include <fix-float-double-convert-nan.h>
+#include <printf_buffer.h>
#define UCHAR_T char
#define L_(Str) Str
@@ -37,12 +38,7 @@
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;
+ struct __printf_buffer_snprintf buf;
/* Single-precision values need to be stored in a double type, because
__printf_fp_l and __printf_fphex do not accept the float type. */
@@ -106,23 +102,8 @@ STRFROM (char *dest, size_t size, const char *format, FLOAT f)
abort ();
}
- /* The following code to prepare the virtual file has been adapted from the
- function __vsnprintf_internal 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 string buffer. */
+ __printf_buffer_snprintf_init (&buf, dest, size);
/* Prepare the format specification for printf_fp. */
memset (&info, '\0', sizeof (info));
@@ -144,13 +125,8 @@ STRFROM (char *dest, size_t size, const char *format, FLOAT f)
info.spec = specifier;
if (info.spec != 'a' && info.spec != 'A')
- done = __printf_fp_l (&sfile.f._sbf._f, _NL_CURRENT_LOCALE, &info, &fpptr);
+ __printf_fp_l_buffer (&buf.base, _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;
+ __printf_fphex_l_buffer (&buf.base, _NL_CURRENT_LOCALE, &info, &fpptr);
+ return __printf_buffer_snprintf_done (&buf);
}