diff options
Diffstat (limited to 'stdlib')
-rw-r--r-- | stdlib/strfmon_l.c | 196 | ||||
-rw-r--r-- | stdlib/strfrom-skeleton.c | 38 |
2 files changed, 83 insertions, 151 deletions
diff --git a/stdlib/strfmon_l.c b/stdlib/strfmon_l.c index d9b22088c7..6dc36e07cc 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 36e9adcad5..810eb315d0 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); } |