rework langinfo code for ABI compat and for use by time code
[musl] / src / stdio / vsnprintf.c
1 #include "stdio_impl.h"
2 #include <limits.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <stdint.h>
6
7 static size_t sn_write(FILE *f, const unsigned char *s, size_t l)
8 {
9         size_t k = f->wend - f->wpos;
10         if (k > l) k = l;
11         memcpy(f->wpos, s, k);
12         f->wpos += k;
13         /* pretend to succeed, but discard extra data */
14         return l;
15 }
16
17 int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap)
18 {
19         int r;
20         char b;
21         FILE f = { .lbf = EOF, .write = sn_write, .lock = -1 };
22
23         if (n-1 > INT_MAX-1) {
24                 if (n) {
25                         errno = EOVERFLOW;
26                         return -1;
27                 }
28                 s = &b;
29                 n = 1;
30         }
31
32         /* Ensure pointers don't wrap if "infinite" n is passed in */
33         if (n > (char *)0+SIZE_MAX-s-1) n = (char *)0+SIZE_MAX-s-1;
34         f.buf_size = n;
35         f.buf = f.wpos = (void *)s;
36         f.wbase = f.wend = (void *)(s+n);
37         r = vfprintf(&f, fmt, ap);
38
39         /* Null-terminate, overwriting last char if dest buffer is full */
40         if (n) f.wpos[-(f.wpos == f.wend)] = 0;
41         return r;
42 }