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