blob: d479f8a01e37ea49ea2048873696606fead8d88c [file] [log] [blame]
DRC2ff39b82011-07-28 08:38:59 +00001/*
2 * "$Id: vsnprintf.c 7903 2010-11-28 21:06:39Z matt $"
3 *
4 * snprintf() and vsnprintf() functions for the Fast Light Tool Kit (FLTK).
5 *
6 * Copyright 1998-2010 by Bill Spitzak and others.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA.
22 *
23 * Please report all bugs and problems on the following page:
24 *
25 * http://www.fltk.org/str.php
26 */
27
28#include <stdio.h>
29#include "flstring.h"
30
31#ifdef HAVE_SYS_STDTYPES_H
32# include <sys/stdtypes.h>
33#endif /* HAVE_SYS_STDTYPES_H */
34
35#ifdef __cplusplus
36extern "C" {
37#endif
38
39int fl_vsnprintf(char* buffer, size_t bufsize, const char* format, va_list ap) {
40 char *bufptr, /* Pointer to position in buffer */
41 *bufend, /* Pointer to end of buffer */
42 sign, /* Sign of format width */
43 size, /* Size character (h, l, L) */
44 type; /* Format type character */
45 int width, /* Width of field */
46 prec; /* Number of characters of precision */
47 char tformat[100], /* Temporary format string for sprintf() */
48 *tptr, /* Pointer into temporary format */
49 temp[1024]; /* Buffer for formatted numbers */
50 char *s; /* Pointer to string */
51 int slen; /* Length of string */
52 int bytes; /* Total number of bytes needed */
53
54
55 /*
56 * Loop through the format string, formatting as needed...
57 */
58
59 bufptr = buffer;
60 bufend = buffer + bufsize - 1;
61 bytes = 0;
62
63 while (*format) {
64 if (*format == '%') {
65 tptr = tformat;
66 *tptr++ = *format++;
67
68 if (*format == '%') {
69 if (bufptr && bufptr < bufend) *bufptr++ = *format;
70 bytes ++;
71 format ++;
72 continue;
73 } else if (strchr(" -+#\'", *format)) {
74 *tptr++ = *format;
75 sign = *format++;
76 } else sign = 0;
77
78 if (*format == '*') {
79 /* Get width from argument... */
80 format ++;
81 width = va_arg(ap, int);
82 snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
83 tptr += strlen(tptr);
84 } else {
85 width = 0;
86 while (isdigit(*format & 255)) {
87 if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
88 width = width * 10 + *format++ - '0';
89 }
90 }
91
92 if (*format == '.') {
93 if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
94 format ++;
95
96 if (*format == '*') {
97 /* Get precision from argument... */
98 format ++;
99 prec = va_arg(ap, int);
100 snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
101 tptr += strlen(tptr);
102 } else {
103 prec = 0;
104 while (isdigit(*format & 255)) {
105 if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
106 prec = prec * 10 + *format++ - '0';
107 }
108 }
109 } else prec = -1;
110
111 size = '\0';
112
113 if (*format == 'l' && format[1] == 'l') {
114 size = 'L';
115 if (tptr < (tformat + sizeof(tformat) - 2)) {
116 *tptr++ = 'l';
117 *tptr++ = 'l';
118 }
119 format += 2;
120 } else if (*format == 'h' || *format == 'l' || *format == 'L') {
121 if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
122 size = *format++;
123 }
124
125 if (!*format) break;
126
127 if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
128 type = *format++;
129 *tptr = '\0';
130
131 switch (type) {
132 case 'E' : /* Floating point formats */
133 case 'G' :
134 case 'e' :
135 case 'f' :
136 case 'g' :
137 if ((width + 2) > sizeof(temp)) break;
138
139 sprintf(temp, tformat, va_arg(ap, double));
140
141 bytes += strlen(temp);
142
143 if (bufptr) {
144 if ((bufptr + strlen(temp)) > bufend) {
145 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
146 bufptr = bufend;
147 } else {
148 strcpy(bufptr, temp);
149 bufptr += strlen(temp);
150 }
151 }
152 break;
153
154 case 'B' : /* Integer formats */
155 case 'X' :
156 case 'b' :
157 case 'd' :
158 case 'i' :
159 case 'o' :
160 case 'u' :
161 case 'x' :
162 if ((width + 2) > sizeof(temp)) break;
163
164#ifdef HAVE_LONG_LONG
165 if (size == 'L')
166 sprintf(temp, tformat, va_arg(ap, long long));
167 else
168#endif /* HAVE_LONG_LONG */
169 if (size == 'l')
170 sprintf(temp, tformat, va_arg(ap, long));
171 else
172 sprintf(temp, tformat, va_arg(ap, int));
173
174 bytes += strlen(temp);
175
176 if (bufptr) {
177 if ((bufptr + strlen(temp)) > bufend) {
178 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
179 bufptr = bufend;
180 } else {
181 strcpy(bufptr, temp);
182 bufptr += strlen(temp);
183 }
184 }
185 break;
186
187 case 'p' : /* Pointer value */
188 if ((width + 2) > sizeof(temp)) break;
189
190 sprintf(temp, tformat, va_arg(ap, void *));
191
192 bytes += strlen(temp);
193
194 if (bufptr) {
195 if ((bufptr + strlen(temp)) > bufend) {
196 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
197 bufptr = bufend;
198 } else {
199 strcpy(bufptr, temp);
200 bufptr += strlen(temp);
201 }
202 }
203 break;
204
205 case 'c' : /* Character or character array */
206 bytes += width;
207
208 if (bufptr) {
209 if (width <= 1) *bufptr++ = va_arg(ap, int);
210 else {
211 if ((bufptr + width) > bufend) width = bufend - bufptr;
212
213 memcpy(bufptr, va_arg(ap, char *), (size_t)width);
214 bufptr += width;
215 }
216 }
217 break;
218
219 case 's' : /* String */
220 if ((s = va_arg(ap, char *)) == NULL) s = "(null)";
221
222 slen = strlen(s);
223 if (slen > width && prec != width) width = slen;
224
225 bytes += width;
226
227 if (bufptr) {
228 if ((bufptr + width) > bufend) width = bufend - bufptr;
229
230 if (slen > width) slen = width;
231
232 if (sign == '-') {
233 strncpy(bufptr, s, (size_t)slen);
234 memset(bufptr + slen, ' ', (size_t)(width - slen));
235 } else {
236 memset(bufptr, ' ', (size_t)(width - slen));
237 strncpy(bufptr + width - slen, s, (size_t)slen);
238 }
239
240 bufptr += width;
241 }
242 break;
243
244 case 'n' : /* Output number of chars so far */
245 *(va_arg(ap, int *)) = bytes;
246 break;
247 }
248 } else {
249 bytes ++;
250
251 if (bufptr && bufptr < bufend) *bufptr++ = *format;
252 format ++;
253 }
254 }
255
256 /*
257 * Nul-terminate the string and return the number of characters needed.
258 */
259
260 if (bufptr) *bufptr = '\0';
261
262 return (bytes);
263}
264
265int fl_snprintf(char* str, size_t size, const char* fmt, ...) {
266 int ret;
267 va_list ap;
268 va_start(ap, fmt);
269 ret = vsnprintf(str, size, fmt, ap);
270 va_end(ap);
271 return ret;
272}
273
274#ifdef __cplusplus
275}
276#endif
277
278/*
279 * End of "$Id: vsnprintf.c 7903 2010-11-28 21:06:39Z matt $".
280 */
281