1 /* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
2 *
3 * GNU Library General Public License (LGPL) version 2 or later.
4 *
5 * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
6 */
7
8 #include "_stdio.h"
9 #include <stdarg.h>
10
11 #ifdef __STDIO_BUFFERS
12 /* NB: we can still have __USE_OLD_VFPRINTF__ defined in this case! */
13
vsnprintf(char * __restrict buf,size_t size,const char * __restrict format,va_list arg)14 int vsnprintf(char *__restrict buf, size_t size,
15 const char * __restrict format, va_list arg)
16 {
17 FILE f;
18 int rv;
19
20 f.__filedes = __STDIO_STREAM_FAKE_VSNPRINTF_FILEDES;
21 f.__modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
22
23 #ifdef __UCLIBC_HAS_WCHAR__
24 f.__ungot_width[0] = 0;
25 #endif /* __UCLIBC_HAS_WCHAR__ */
26 #ifdef __STDIO_MBSTATE
27 __INIT_MBSTATE(&(f.__state));
28 #endif /* __STDIO_MBSTATE */
29
30 #if (defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__)) && defined(__UCLIBC_HAS_THREADS__)
31 f.__user_locking = 1; /* Set user locking. */
32 STDIO_INIT_MUTEX(f.__lock);
33 #endif
34 f.__nextopen = NULL;
35
36 if (size > SIZE_MAX - (size_t) buf) {
37 size = SIZE_MAX - (size_t) buf;
38 }
39
40 /* TODO: this comment seems to be wrong */
41 /* Set these last since __bufputc initialization depends on
42 * __user_locking and only gets set if user locking is on. */
43 f.__bufstart = (unsigned char *) buf;
44 f.__bufend = (unsigned char *) buf + size;
45 __STDIO_STREAM_INIT_BUFREAD_BUFPOS(&f);
46 __STDIO_STREAM_DISABLE_GETC(&f);
47 __STDIO_STREAM_ENABLE_PUTC(&f);
48
49 #ifdef __USE_OLD_VFPRINTF__
50 rv = vfprintf(&f, format, arg);
51 #else
52 rv = _vfprintf_internal(&f, format, arg);
53 #endif
54 if (size) {
55 if (f.__bufpos == f.__bufend) {
56 --f.__bufpos;
57 }
58 *f.__bufpos = 0;
59 }
60 return rv;
61 }
62 libc_hidden_def(vsnprintf)
63
64 #elif defined(__USE_OLD_VFPRINTF__)
65
66 typedef struct {
67 FILE f;
68 unsigned char *bufend; /* pointer to 1 past end of buffer */
69 unsigned char *bufpos;
70 } __FILE_vsnprintf;
71
72 int vsnprintf(char *__restrict buf, size_t size,
73 const char * __restrict format, va_list arg)
74 {
75 __FILE_vsnprintf f;
76 int rv;
77
78 f.bufpos = buf;
79
80 if (size > SIZE_MAX - (size_t) buf) {
81 size = SIZE_MAX - (size_t) buf;
82 }
83 f.bufend = buf + size;
84
85 f.f.__filedes = __STDIO_STREAM_FAKE_VSNPRINTF_FILEDES_NB;
86 f.f.__modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
87
88 #ifdef __UCLIBC_HAS_WCHAR__
89 f.f.__ungot_width[0] = 0;
90 #endif /* __UCLIBC_HAS_WCHAR__ */
91 #ifdef __STDIO_MBSTATE
92 __INIT_MBSTATE(&(f.f.__state));
93 #endif /* __STDIO_MBSTATE */
94
95 #ifdef __UCLIBC_HAS_THREADS__
96 f.f.__user_locking = 1; /* Set user locking. */
97 STDIO_INIT_MUTEX(f.f.__lock);
98 #endif
99 f.f.__nextopen = NULL;
100
101 rv = vfprintf((FILE *) &f, format, arg);
102 if (size) {
103 if (f.bufpos == f.bufend) {
104 --f.bufpos;
105 }
106 *f.bufpos = 0;
107 }
108 return rv;
109 }
110 libc_hidden_def(vsnprintf)
111
112 #elif defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)
113
114 typedef struct {
115 size_t pos;
116 size_t len;
117 char *buf;
118 FILE *fp;
119 } __snpf_cookie;
120
121 #define COOKIE ((__snpf_cookie *) cookie)
122
123 static ssize_t snpf_write(register void *cookie, const char *buf,
124 size_t bufsize)
125 {
126 size_t count;
127 register char *p;
128
129 /* Note: bufsize < SSIZE_MAX because of _stdio_WRITE. */
130
131 if (COOKIE->len > COOKIE->pos) {
132 count = COOKIE->len - COOKIE->pos - 1; /* Leave space for nul. */
133 if (count > bufsize) {
134 count = bufsize;
135 }
136
137 p = COOKIE->buf + COOKIE->pos;
138 while (count) {
139 *p++ = *buf++;
140 --count;
141 }
142 *p = 0;
143 }
144
145 COOKIE->pos += bufsize;
146
147 return bufsize;
148 }
149
150 #undef COOKIE
151
152 int vsnprintf(char *__restrict buf, size_t size,
153 const char * __restrict format, va_list arg)
154 {
155 _IO_cookie_file_t cf;
156 __snpf_cookie cookie;
157 int rv;
158
159 cookie.buf = buf;
160 cookie.len = size;
161 cookie.pos = 0;
162 cookie.fp = &cf.__fp;
163
164 cf.__cookie = &cookie;
165 cf.__gcs.write = snpf_write;
166 cf.__gcs.read = NULL;
167 cf.__gcs.seek = NULL;
168 cf.__gcs.close = NULL;
169
170 cf.__fp.__filedes = __STDIO_STREAM_GLIBC_CUSTOM_FILEDES;
171 cf.__fp.__modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
172
173 #ifdef __UCLIBC_HAS_WCHAR__
174 cf.__fp.__ungot_width[0] = 0;
175 #endif /* __UCLIBC_HAS_WCHAR__ */
176 #ifdef __STDIO_MBSTATE
177 __INIT_MBSTATE(&(cf.__fp.__state));
178 #endif /* __STDIO_MBSTATE */
179
180 cf.__fp.__nextopen = NULL;
181
182 rv = _vfprintf_internal(&cf.__fp, format, arg);
183
184 return rv;
185 }
186 libc_hidden_def(vsnprintf)
187
188 #else
189 #warning Skipping vsnprintf since no buffering, no custom streams, and not old vfprintf!
190 #ifdef __STDIO_HAS_VSNPRINTF
191 #error WHOA! __STDIO_HAS_VSNPRINTF is defined!
192 #endif
193 #endif
194