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