1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| | #include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
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);
}
|