1 /*
2 * snprintf functions for CUPS.
3 *
4 * Copyright 2007-2013 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products.
6 *
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * missing or damaged, see the license at "http://www.cups.org/".
12 *
13 * This file is subject to the Apple OS-Developed Software exception.
14 */
15
16 /*
17 * Include necessary headers...
18 */
19
20 #include "string-private.h"
21
22
23 #ifndef HAVE_VSNPRINTF
24 /*
25 * '_cups_vsnprintf()' - Format a string into a fixed size buffer.
26 */
27
28 int /* O - Number of bytes formatted */
_cups_vsnprintf(char * buffer,size_t bufsize,const char * format,va_list ap)29 _cups_vsnprintf(char *buffer, /* O - Output buffer */
30 size_t bufsize, /* O - Size of output buffer */
31 const char *format, /* I - printf-style format string */
32 va_list ap) /* I - Pointer to additional arguments */
33 {
34 char *bufptr, /* Pointer to position in buffer */
35 *bufend, /* Pointer to end of buffer */
36 sign, /* Sign of format width */
37 size, /* Size character (h, l, L) */
38 type; /* Format type character */
39 int width, /* Width of field */
40 prec; /* Number of characters of precision */
41 char tformat[100], /* Temporary format string for sprintf() */
42 *tptr, /* Pointer into temporary format */
43 temp[1024]; /* Buffer for formatted numbers */
44 size_t templen; /* Length of "temp" */
45 char *s; /* Pointer to string */
46 int slen; /* Length of string */
47 int bytes; /* Total number of bytes needed */
48
49
50 /*
51 * Loop through the format string, formatting as needed...
52 */
53
54 bufptr = buffer;
55 bufend = buffer + bufsize - 1;
56 bytes = 0;
57
58 while (*format)
59 {
60 if (*format == '%')
61 {
62 tptr = tformat;
63 *tptr++ = *format++;
64
65 if (*format == '%')
66 {
67 if (bufptr && bufptr < bufend) *bufptr++ = *format;
68 bytes ++;
69 format ++;
70 continue;
71 }
72 else if (strchr(" -+#\'", *format))
73 {
74 *tptr++ = *format;
75 sign = *format++;
76 }
77 else
78 sign = 0;
79
80 if (*format == '*')
81 {
82 /*
83 * Get width from argument...
84 */
85
86 format ++;
87 width = va_arg(ap, int);
88
89 snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
90 tptr += strlen(tptr);
91 }
92 else
93 {
94 width = 0;
95
96 while (isdigit(*format & 255))
97 {
98 if (tptr < (tformat + sizeof(tformat) - 1))
99 *tptr++ = *format;
100
101 width = width * 10 + *format++ - '0';
102 }
103 }
104
105 if (*format == '.')
106 {
107 if (tptr < (tformat + sizeof(tformat) - 1))
108 *tptr++ = *format;
109
110 format ++;
111
112 if (*format == '*')
113 {
114 /*
115 * Get precision from argument...
116 */
117
118 format ++;
119 prec = va_arg(ap, int);
120
121 snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
122 tptr += strlen(tptr);
123 }
124 else
125 {
126 prec = 0;
127
128 while (isdigit(*format & 255))
129 {
130 if (tptr < (tformat + sizeof(tformat) - 1))
131 *tptr++ = *format;
132
133 prec = prec * 10 + *format++ - '0';
134 }
135 }
136 }
137 else
138 prec = -1;
139
140 if (*format == 'l' && format[1] == 'l')
141 {
142 size = 'L';
143
144 if (tptr < (tformat + sizeof(tformat) - 2))
145 {
146 *tptr++ = 'l';
147 *tptr++ = 'l';
148 }
149
150 format += 2;
151 }
152 else if (*format == 'h' || *format == 'l' || *format == 'L')
153 {
154 if (tptr < (tformat + sizeof(tformat) - 1))
155 *tptr++ = *format;
156
157 size = *format++;
158 }
159
160 if (!*format)
161 break;
162
163 if (tptr < (tformat + sizeof(tformat) - 1))
164 *tptr++ = *format;
165
166 type = *format++;
167 *tptr = '\0';
168
169 switch (type)
170 {
171 case 'E' : /* Floating point formats */
172 case 'G' :
173 case 'e' :
174 case 'f' :
175 case 'g' :
176 if ((width + 2) > sizeof(temp))
177 break;
178
179 sprintf(temp, tformat, va_arg(ap, double));
180 templen = strlen(temp):
181
182 bytes += (int)templen;
183
184 if (bufptr)
185 {
186 if ((bufptr + templen) > bufend)
187 {
188 strlcpy(bufptr, temp, (size_t)(bufend - bufptr));
189 bufptr = bufend;
190 }
191 else
192 {
193 memcpy(bufptr, temp, templen + 1);
194 bufptr += templen;
195 }
196 }
197 break;
198
199 case 'B' : /* Integer formats */
200 case 'X' :
201 case 'b' :
202 case 'd' :
203 case 'i' :
204 case 'o' :
205 case 'u' :
206 case 'x' :
207 if ((width + 2) > sizeof(temp))
208 break;
209
210 sprintf(temp, tformat, va_arg(ap, int));
211 templen = strlen(temp):
212
213 bytes += (int)templen;
214
215 if (bufptr)
216 {
217 if ((bufptr + templen) > bufend)
218 {
219 strlcpy(bufptr, temp, (size_t)(bufend - bufptr));
220 bufptr = bufend;
221 }
222 else
223 {
224 memcpy(bufptr, temp, templen + 1);
225 bufptr += templen;
226 }
227 }
228 break;
229
230 case 'p' : /* Pointer value */
231 if ((width + 2) > sizeof(temp))
232 break;
233
234 sprintf(temp, tformat, va_arg(ap, void *));
235 templen = strlen(temp):
236
237 bytes += (int)templen;
238
239 if (bufptr)
240 {
241 if ((bufptr + templen) > bufend)
242 {
243 strlcpy(bufptr, temp, (size_t)(bufend - bufptr));
244 bufptr = bufend;
245 }
246 else
247 {
248 memcpy(bufptr, temp, templen + 1);
249 bufptr += templen;
250 }
251 }
252 break;
253
254 case 'c' : /* Character or character array */
255 bytes += width;
256
257 if (bufptr)
258 {
259 if (width <= 1)
260 *bufptr++ = va_arg(ap, int);
261 else
262 {
263 if ((bufptr + width) > bufend)
264 width = (int)(bufend - bufptr);
265
266 memcpy(bufptr, va_arg(ap, char *), (size_t)width);
267 bufptr += width;
268 }
269 }
270 break;
271
272 case 's' : /* String */
273 if ((s = va_arg(ap, char *)) == NULL)
274 s = "(null)";
275
276 slen = (int)strlen(s);
277 if (slen > width && prec != width)
278 width = slen;
279
280 bytes += width;
281
282 if (bufptr)
283 {
284 if ((bufptr + width) > bufend)
285 width = (int)(bufend - bufptr);
286
287 if (slen > width)
288 slen = width;
289
290 if (sign == '-')
291 {
292 memcpy(bufptr, s, (size_t)slen);
293 memset(bufptr + slen, ' ', (size_t)(width - slen));
294 }
295 else
296 {
297 memset(bufptr, ' ', (size_t)(width - slen));
298 memcpy(bufptr + width - slen, s, (size_t)slen);
299 }
300
301 bufptr += width;
302 }
303 break;
304
305 case 'n' : /* Output number of chars so far */
306 *(va_arg(ap, int *)) = bytes;
307 break;
308 }
309 }
310 else
311 {
312 bytes ++;
313
314 if (bufptr && bufptr < bufend)
315 *bufptr++ = *format;
316
317 format ++;
318 }
319 }
320
321 /*
322 * Nul-terminate the string and return the number of characters needed.
323 */
324
325 *bufptr = '\0';
326
327 return (bytes);
328 }
329 #endif /* !HAVE_VSNPRINT */
330
331
332 #ifndef HAVE_SNPRINTF
333 /*
334 * '_cups_snprintf()' - Format a string into a fixed size buffer.
335 */
336
337 int /* O - Number of bytes formatted */
_cups_snprintf(char * buffer,size_t bufsize,const char * format,...)338 _cups_snprintf(char *buffer, /* O - Output buffer */
339 size_t bufsize, /* O - Size of output buffer */
340 const char *format, /* I - printf-style format string */
341 ...) /* I - Additional arguments as needed */
342 {
343 int bytes; /* Number of bytes formatted */
344 va_list ap; /* Pointer to additional arguments */
345
346
347 va_start(ap, format);
348 bytes = vsnprintf(buffer, bufsize, format, ap);
349 va_end(ap);
350
351 return (bytes);
352 }
353 #endif /* !HAVE_SNPRINTF */
354