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