| #include <stdio.h> |
| #include <ctype.h> |
| #include <stdarg.h> |
| #include <monetary.h> |
| #include <errno.h> |
| #include "locale_impl.h" |
| |
| static ssize_t vstrfmon_l(char* s, |
| size_t n, |
| locale_t loc, |
| const char* fmt, |
| va_list ap) { |
| size_t l; |
| double x; |
| int fill, nogrp, negpar, nosym, left, intl; |
| int lp, rp, w, fw; |
| char* s0 = s; |
| for (; n && *fmt;) { |
| if (*fmt != '%') { |
| literal: |
| *s++ = *fmt++; |
| n--; |
| continue; |
| } |
| fmt++; |
| if (*fmt == '%') |
| goto literal; |
| |
| fill = ' '; |
| nogrp = 0; |
| negpar = 0; |
| nosym = 0; |
| left = 0; |
| for (;; fmt++) { |
| switch (*fmt) { |
| case '=': |
| fill = *++fmt; |
| continue; |
| case '^': |
| nogrp = 1; |
| continue; |
| case '(': |
| negpar = 1; |
| case '+': |
| continue; |
| case '!': |
| nosym = 1; |
| continue; |
| case '-': |
| left = 1; |
| continue; |
| } |
| break; |
| } |
| |
| for (fw = 0; isdigit(*fmt); fmt++) |
| fw = 10 * fw + (*fmt - '0'); |
| lp = 0; |
| rp = 2; |
| if (*fmt == '#') |
| for (lp = 0, fmt++; isdigit(*fmt); fmt++) |
| lp = 10 * lp + (*fmt - '0'); |
| if (*fmt == '.') |
| for (rp = 0, fmt++; isdigit(*fmt); fmt++) |
| rp = 10 * rp + (*fmt - '0'); |
| |
| intl = *fmt++ == 'i'; |
| |
| w = lp + 1 + rp; |
| if (!left && fw > w) |
| w = fw; |
| |
| x = va_arg(ap, double); |
| l = snprintf(s, n, "%*.*f", w, rp, x); |
| if (l >= n) { |
| errno = E2BIG; |
| return -1; |
| } |
| s += l; |
| n -= l; |
| } |
| return s - s0; |
| } |
| |
| ssize_t strfmon_l(char* restrict s, |
| size_t n, |
| locale_t loc, |
| const char* restrict fmt, |
| ...) { |
| va_list ap; |
| ssize_t ret; |
| |
| va_start(ap, fmt); |
| ret = vstrfmon_l(s, n, loc, fmt, ap); |
| va_end(ap); |
| |
| return ret; |
| } |
| |
| ssize_t strfmon(char* restrict s, size_t n, const char* restrict fmt, ...) { |
| va_list ap; |
| ssize_t ret; |
| |
| va_start(ap, fmt); |
| ret = vstrfmon_l(s, n, CURRENT_LOCALE, fmt, ap); |
| va_end(ap); |
| |
| return ret; |
| } |