1#include "stdio_impl.h"
2#include <limits.h>
3#include <string.h>
4#include <errno.h>
5#include <stdint.h>
6#include <pthread.h>
7
8struct cookie {
9	char *s;
10	size_t n;
11};
12
13#define MIN(a, b) ((a) < (b) ? (a) : (b))
14
15static size_t sn_write(FILE *f, const unsigned char *s, size_t l)
16{
17	struct cookie *c = f->cookie;
18	size_t k = MIN(c->n, f->wpos - f->wbase);
19	if (k) {
20		memcpy(c->s, f->wbase, k);
21		c->s += k;
22		c->n -= k;
23	}
24	k = MIN(c->n, l);
25	if (k) {
26		memcpy(c->s, s, k);
27		c->s += k;
28		c->n -= k;
29	}
30	*c->s = 0;
31	f->wpos = f->wbase = f->buf;
32	/* pretend to succeed, even if we discarded extra data */
33	return l;
34}
35
36int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap)
37{
38	unsigned char buf[1];
39	char dummy[1];
40	struct cookie c = { .s = n ? s : dummy, .n = n ? n-1 : 0 };
41	pthread_mutex_t locallock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
42	FILE f = {
43		.lbf = EOF,
44		.write = sn_write,
45		.lock = &locallock,
46		.buf = buf,
47		.cookie = &c,
48	};
49
50	if (n > INT_MAX) {
51		errno = EOVERFLOW;
52		return -1;
53	}
54
55	*c.s = 0;
56	return vfprintf(&f, fmt, ap);
57}
58