]>
Commit | Line | Data |
---|---|---|
5d0ff7ea DH |
1 | /* |
2 | * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") | |
3 | * Copyright (C) 1999-2001, 2003 Internet Software Consortium. | |
4 | * | |
5 | * Permission to use, copy, modify, and distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH | |
10 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |
11 | * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, | |
12 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | |
13 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | |
14 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
15 | * PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
18 | /* $Id: iscprint.c,v 1.2 2005/03/17 20:30:41 dhankins Exp $ */ | |
19 | ||
20 | #include "dhcpd.h" | |
21 | ||
22 | #ifdef NO_SNPRINTF | |
23 | ||
24 | #ifndef LINT | |
25 | static char copyright[] = | |
26 | "$Id: iscprint.c,v 1.2 2005/03/17 20:30:41 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium, Inc. All rights reserved."; | |
27 | #endif | |
28 | ||
29 | #define INSIST(cond) REQUIRE(cond) | |
30 | #define REQUIRE(cond) if (!(cond)) { return 0; } | |
31 | ||
32 | /* | |
33 | * Return length of string that would have been written if not truncated. | |
34 | */ | |
35 | ||
36 | int | |
37 | isc_print_snprintf(char *str, size_t size, const char *format, ...) { | |
38 | va_list ap; | |
39 | int ret; | |
40 | ||
41 | va_start(ap, format); | |
42 | ret = vsnprintf(str, size, format, ap); | |
43 | va_end(ap); | |
44 | return (ret); | |
45 | } | |
46 | ||
47 | /* | |
48 | * Return length of string that would have been written if not truncated. | |
49 | */ | |
50 | ||
51 | int | |
52 | isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) { | |
53 | int h; | |
54 | int l; | |
55 | int q; | |
56 | int alt; | |
57 | int zero; | |
58 | int left; | |
59 | int plus; | |
60 | int space; | |
61 | int neg; | |
62 | isc_int64_t tmpi; | |
63 | isc_uint64_t tmpui; | |
64 | unsigned long width; | |
65 | unsigned long precision; | |
66 | unsigned int length; | |
67 | char buf[1024]; | |
68 | char c; | |
69 | void *v; | |
70 | char *save = str; | |
71 | const char *cp; | |
72 | const char *head; | |
73 | int count = 0; | |
74 | int pad; | |
75 | int zeropad; | |
76 | int dot; | |
77 | double dbl; | |
78 | #ifdef HAVE_LONG_DOUBLE | |
79 | long double ldbl; | |
80 | #endif | |
81 | char fmt[32]; | |
82 | ||
83 | INSIST(str != NULL); | |
84 | INSIST(format != NULL); | |
85 | ||
86 | while (*format != '\0') { | |
87 | if (*format != '%') { | |
88 | if (size > 1) { | |
89 | *str++ = *format; | |
90 | size--; | |
91 | } | |
92 | count++; | |
93 | format++; | |
94 | continue; | |
95 | } | |
96 | format++; | |
97 | ||
98 | /* | |
99 | * Reset flags. | |
100 | */ | |
101 | dot = neg = space = plus = left = zero = alt = h = l = q = 0; | |
102 | width = precision = 0; | |
103 | head = ""; | |
104 | length = pad = zeropad = 0; | |
105 | ||
106 | do { | |
107 | if (*format == '#') { | |
108 | alt = 1; | |
109 | format++; | |
110 | } else if (*format == '-') { | |
111 | left = 1; | |
112 | zero = 0; | |
113 | format++; | |
114 | } else if (*format == ' ') { | |
115 | if (!plus) | |
116 | space = 1; | |
117 | format++; | |
118 | } else if (*format == '+') { | |
119 | plus = 1; | |
120 | space = 0; | |
121 | format++; | |
122 | } else if (*format == '0') { | |
123 | if (!left) | |
124 | zero = 1; | |
125 | format++; | |
126 | } else | |
127 | break; | |
128 | } while (1); | |
129 | ||
130 | /* | |
131 | * Width. | |
132 | */ | |
133 | if (*format == '*') { | |
134 | width = va_arg(ap, int); | |
135 | format++; | |
136 | } else if (isdigit((unsigned char)*format)) { | |
137 | char *e; | |
138 | width = strtoul(format, &e, 10); | |
139 | format = e; | |
140 | } | |
141 | ||
142 | /* | |
143 | * Precision. | |
144 | */ | |
145 | if (*format == '.') { | |
146 | format++; | |
147 | dot = 1; | |
148 | if (*format == '*') { | |
149 | precision = va_arg(ap, int); | |
150 | format++; | |
151 | } else if (isdigit((unsigned char)*format)) { | |
152 | char *e; | |
153 | precision = strtoul(format, &e, 10); | |
154 | format = e; | |
155 | } | |
156 | } | |
157 | ||
158 | switch (*format) { | |
159 | case '\0': | |
160 | continue; | |
161 | case '%': | |
162 | if (size > 1) { | |
163 | *str++ = *format; | |
164 | size--; | |
165 | } | |
166 | count++; | |
167 | break; | |
168 | case 'q': | |
169 | q = 1; | |
170 | format++; | |
171 | goto doint; | |
172 | case 'h': | |
173 | h = 1; | |
174 | format++; | |
175 | goto doint; | |
176 | case 'l': | |
177 | l = 1; | |
178 | format++; | |
179 | if (*format == 'l') { | |
180 | q = 1; | |
181 | format++; | |
182 | } | |
183 | goto doint; | |
184 | case 'n': | |
185 | case 'i': | |
186 | case 'd': | |
187 | case 'o': | |
188 | case 'u': | |
189 | case 'x': | |
190 | case 'X': | |
191 | doint: | |
192 | if (precision != 0) | |
193 | zero = 0; | |
194 | switch (*format) { | |
195 | case 'n': | |
196 | if (h) { | |
197 | short int *p; | |
198 | p = va_arg(ap, short *); | |
199 | REQUIRE(p != NULL); | |
200 | *p = str - save; | |
201 | } else if (l) { | |
202 | long int *p; | |
203 | p = va_arg(ap, long *); | |
204 | REQUIRE(p != NULL); | |
205 | *p = str - save; | |
206 | } else { | |
207 | int *p; | |
208 | p = va_arg(ap, int *); | |
209 | REQUIRE(p != NULL); | |
210 | *p = str - save; | |
211 | } | |
212 | break; | |
213 | case 'i': | |
214 | case 'd': | |
215 | if (q) | |
216 | tmpi = va_arg(ap, isc_int64_t); | |
217 | else if (l) | |
218 | tmpi = va_arg(ap, long int); | |
219 | else | |
220 | tmpi = va_arg(ap, int); | |
221 | if (tmpi < 0) { | |
222 | head = "-"; | |
223 | tmpui = -tmpi; | |
224 | } else { | |
225 | if (plus) | |
226 | head = "+"; | |
227 | else if (space) | |
228 | head = " "; | |
229 | else | |
230 | head = ""; | |
231 | tmpui = tmpi; | |
232 | } | |
233 | sprintf(buf, "%u", tmpui); | |
234 | goto printint; | |
235 | case 'o': | |
236 | if (q) | |
237 | tmpui = va_arg(ap, isc_uint64_t); | |
238 | else if (l) | |
239 | tmpui = va_arg(ap, long int); | |
240 | else | |
241 | tmpui = va_arg(ap, int); | |
242 | sprintf(buf, alt ? "%#o" | |
243 | : "%o", tmpui); | |
244 | goto printint; | |
245 | case 'u': | |
246 | if (q) | |
247 | tmpui = va_arg(ap, isc_uint64_t); | |
248 | else if (l) | |
249 | tmpui = va_arg(ap, unsigned long int); | |
250 | else | |
251 | tmpui = va_arg(ap, unsigned int); | |
252 | sprintf(buf, "%u", tmpui); | |
253 | goto printint; | |
254 | case 'x': | |
255 | if (q) | |
256 | tmpui = va_arg(ap, isc_uint64_t); | |
257 | else if (l) | |
258 | tmpui = va_arg(ap, unsigned long int); | |
259 | else | |
260 | tmpui = va_arg(ap, unsigned int); | |
261 | if (alt) { | |
262 | head = "0x"; | |
263 | if (precision > 2) | |
264 | precision -= 2; | |
265 | } | |
266 | sprintf(buf, "%x", tmpui); | |
267 | goto printint; | |
268 | case 'X': | |
269 | if (q) | |
270 | tmpui = va_arg(ap, isc_uint64_t); | |
271 | else if (l) | |
272 | tmpui = va_arg(ap, unsigned long int); | |
273 | else | |
274 | tmpui = va_arg(ap, unsigned int); | |
275 | if (alt) { | |
276 | head = "0X"; | |
277 | if (precision > 2) | |
278 | precision -= 2; | |
279 | } | |
280 | sprintf(buf, "%X", tmpui); | |
281 | goto printint; | |
282 | printint: | |
283 | if (precision != 0 || width != 0) { | |
284 | length = strlen(buf); | |
285 | if (length < precision) | |
286 | zeropad = precision - length; | |
287 | else if (length < width && zero) | |
288 | zeropad = width - length; | |
289 | if (width != 0) { | |
290 | pad = width - length - | |
291 | zeropad - strlen(head); | |
292 | if (pad < 0) | |
293 | pad = 0; | |
294 | } | |
295 | } | |
296 | count += strlen(head) + strlen(buf) + pad + | |
297 | zeropad; | |
298 | if (!left) { | |
299 | while (pad > 0 && size > 1) { | |
300 | *str++ = ' '; | |
301 | size--; | |
302 | pad--; | |
303 | } | |
304 | } | |
305 | cp = head; | |
306 | while (*cp != '\0' && size > 1) { | |
307 | *str++ = *cp++; | |
308 | size--; | |
309 | } | |
310 | while (zeropad > 0 && size > 1) { | |
311 | *str++ = '0'; | |
312 | size--; | |
313 | zeropad--; | |
314 | } | |
315 | cp = buf; | |
316 | while (*cp != '\0' && size > 1) { | |
317 | *str++ = *cp++; | |
318 | size--; | |
319 | } | |
320 | while (pad > 0 && size > 1) { | |
321 | *str++ = ' '; | |
322 | size--; | |
323 | pad--; | |
324 | } | |
325 | break; | |
326 | default: | |
327 | break; | |
328 | } | |
329 | break; | |
330 | case 's': | |
331 | cp = va_arg(ap, char *); | |
332 | REQUIRE(cp != NULL); | |
333 | ||
334 | if (precision != 0) { | |
335 | /* | |
336 | * cp need not be NULL terminated. | |
337 | */ | |
338 | const char *tp; | |
339 | unsigned long n; | |
340 | ||
341 | n = precision; | |
342 | tp = cp; | |
343 | while (n != 0 && *tp != '\0') | |
344 | n--, tp++; | |
345 | length = precision - n; | |
346 | } else { | |
347 | length = strlen(cp); | |
348 | } | |
349 | if (width != 0) { | |
350 | pad = width - length; | |
351 | if (pad < 0) | |
352 | pad = 0; | |
353 | } | |
354 | count += pad + length; | |
355 | if (!left) | |
356 | while (pad > 0 && size > 1) { | |
357 | *str++ = ' '; | |
358 | size--; | |
359 | pad--; | |
360 | } | |
361 | if (precision != 0) | |
362 | while (precision > 0 && *cp != '\0' && | |
363 | size > 1) { | |
364 | *str++ = *cp++; | |
365 | size--; | |
366 | precision--; | |
367 | } | |
368 | else | |
369 | while (*cp != '\0' && size > 1) { | |
370 | *str++ = *cp++; | |
371 | size--; | |
372 | } | |
373 | while (pad > 0 && size > 1) { | |
374 | *str++ = ' '; | |
375 | size--; | |
376 | pad--; | |
377 | } | |
378 | break; | |
379 | case 'c': | |
380 | c = va_arg(ap, int); | |
381 | if (width > 0) { | |
382 | count += width; | |
383 | width--; | |
384 | if (left) { | |
385 | *str++ = c; | |
386 | size--; | |
387 | } | |
388 | while (width-- > 0 && size > 1) { | |
389 | *str++ = ' '; | |
390 | size--; | |
391 | } | |
392 | if (!left && size > 1) { | |
393 | *str++ = c; | |
394 | size--; | |
395 | } | |
396 | } else { | |
397 | count++; | |
398 | if (size > 1) { | |
399 | *str++ = c; | |
400 | size--; | |
401 | } | |
402 | } | |
403 | break; | |
404 | case 'p': | |
405 | v = va_arg(ap, void *); | |
406 | sprintf(buf, "%p", v); | |
407 | length = strlen(buf); | |
408 | if (precision > length) | |
409 | zeropad = precision - length; | |
410 | if (width > 0) { | |
411 | pad = width - length - zeropad; | |
412 | if (pad < 0) | |
413 | pad = 0; | |
414 | } | |
415 | count += length + pad + zeropad; | |
416 | if (!left) | |
417 | while (pad > 0 && size > 1) { | |
418 | *str++ = ' '; | |
419 | size--; | |
420 | pad--; | |
421 | } | |
422 | cp = buf; | |
423 | if (zeropad > 0 && buf[0] == '0' && | |
424 | (buf[1] == 'x' || buf[1] == 'X')) { | |
425 | if (size > 1) { | |
426 | *str++ = *cp++; | |
427 | size--; | |
428 | } | |
429 | if (size > 1) { | |
430 | *str++ = *cp++; | |
431 | size--; | |
432 | } | |
433 | while (zeropad > 0 && size > 1) { | |
434 | *str++ = '0'; | |
435 | size--; | |
436 | zeropad--; | |
437 | } | |
438 | } | |
439 | while (*cp != '\0' && size > 1) { | |
440 | *str++ = *cp++; | |
441 | size--; | |
442 | } | |
443 | while (pad > 0 && size > 1) { | |
444 | *str++ = ' '; | |
445 | size--; | |
446 | pad--; | |
447 | } | |
448 | break; | |
449 | case 'D': /*deprecated*/ | |
450 | INSIST("use %ld instead of %D" == NULL); | |
451 | case 'O': /*deprecated*/ | |
452 | INSIST("use %lo instead of %O" == NULL); | |
453 | case 'U': /*deprecated*/ | |
454 | INSIST("use %lu instead of %U" == NULL); | |
455 | ||
456 | case 'L': | |
457 | #ifdef HAVE_LONG_DOUBLE | |
458 | l = 1; | |
459 | #else | |
460 | INSIST("long doubles are not supported" == NULL); | |
461 | #endif | |
462 | /*FALLTHROUGH*/ | |
463 | case 'e': | |
464 | case 'E': | |
465 | case 'f': | |
466 | case 'g': | |
467 | case 'G': | |
468 | if (!dot) | |
469 | precision = 6; | |
470 | /* | |
471 | * IEEE floating point. | |
472 | * MIN 2.2250738585072014E-308 | |
473 | * MAX 1.7976931348623157E+308 | |
474 | * VAX floating point has a smaller range than IEEE. | |
475 | * | |
476 | * precisions > 324 don't make much sense. | |
477 | * if we cap the precision at 512 we will not | |
478 | * overflow buf. | |
479 | */ | |
480 | if (precision > 512) | |
481 | precision = 512; | |
482 | sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "", | |
483 | plus ? "+" : space ? " " : "", | |
484 | precision, l ? "L" : "", *format); | |
485 | switch (*format) { | |
486 | case 'e': | |
487 | case 'E': | |
488 | case 'f': | |
489 | case 'g': | |
490 | case 'G': | |
491 | #ifdef HAVE_LONG_DOUBLE | |
492 | if (l) { | |
493 | ldbl = va_arg(ap, long double); | |
494 | sprintf(buf, fmt, ldbl); | |
495 | } else | |
496 | #endif | |
497 | { | |
498 | dbl = va_arg(ap, double); | |
499 | sprintf(buf, fmt, dbl); | |
500 | } | |
501 | length = strlen(buf); | |
502 | if (width > 0) { | |
503 | pad = width - length; | |
504 | if (pad < 0) | |
505 | pad = 0; | |
506 | } | |
507 | count += length + pad; | |
508 | if (!left) | |
509 | while (pad > 0 && size > 1) { | |
510 | *str++ = ' '; | |
511 | size--; | |
512 | pad--; | |
513 | } | |
514 | cp = buf; | |
515 | while (*cp != ' ' && size > 1) { | |
516 | *str++ = *cp++; | |
517 | size--; | |
518 | } | |
519 | while (pad > 0 && size > 1) { | |
520 | *str++ = ' '; | |
521 | size--; | |
522 | pad--; | |
523 | } | |
524 | break; | |
525 | default: | |
526 | continue; | |
527 | } | |
528 | break; | |
529 | default: | |
530 | continue; | |
531 | } | |
532 | format++; | |
533 | } | |
534 | if (size > 0) | |
535 | *str = '\0'; | |
536 | return (count); | |
537 | } | |
538 | ||
539 | #endif |