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