#include #include #include #include #include static size_t sanitize(const char*format) { size_t slen = format ? strlen(format) : 0; if (format[0] != '%' || (slen > 2 && format[1] != '.') || strchr(&format[1], '%') || (strspn(&format[slen-1], "aAeEfFgG") != 1)) return 0; else return slen; } int strfromd(char *restrict s, size_t n, const char *restrict format, double fp) { return sanitize(format) ? snprintf(s, n, format, fp) : -1; } int strfromf(char *restrict s, size_t n, const char *restrict format, float fp) { return sanitize(format) ? snprintf(s, n, format, fp) : -1; } int strfroml(char *restrict s, size_t n, const char *restrict format, long double fp) { enum { max_len = 1+sizeof "%.18446744073709551615Lg", }; char ff[max_len]; size_t slen = sanitize(format); if (!slen) return -1; if (slen < max_len-2) { memcpy(ff, format, slen-1); ff[slen-1] = 'L'; ff[slen] = format[slen-1]; ff[slen+1] = 0; } else { // If the precision is unreasonably long, fallback to // strtoull to parse it, and squeeze it into a // reasonable length, if possible. int eback = errno; unsigned long long prec = strtoull(format+2, NULL, 10); if (prec == ULLONG_MAX) errno = eback; snprintf(ff, max_len, "%%.%lldL%c", prec, format[slen-1]); } return snprintf(s, n, ff, fp); }