Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / ntp / dist / lib / isc / print.c
blob2db6875a213e665e5aa86c17b26c6ff303dbb579
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2001, 2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: print.c,v 1.35 2008/02/18 23:46:59 tbox Exp */
22 /*! \file */
24 #include <config.h>
26 #include <ctype.h>
27 #include <stdio.h> /* for sprintf() */
28 #include <string.h> /* for strlen() */
30 #define ISC__PRINT_SOURCE /* Used to get the isc_print_* prototypes. */
32 #include <isc/assertions.h>
33 #include <isc/int.h>
34 #include <isc/msgs.h>
35 #include <isc/print.h>
36 #include <isc/stdlib.h>
37 #include <isc/util.h>
39 int
40 isc_print_sprintf(char *str, const char *format, ...) {
41 va_list ap;
43 va_start(ap, format);
44 vsprintf(str, format, ap);
45 va_end(ap);
46 return (strlen(str));
49 /*!
50 * Return length of string that would have been written if not truncated.
53 int
54 isc_print_snprintf(char *str, size_t size, const char *format, ...) {
55 va_list ap;
56 int ret;
58 va_start(ap, format);
59 ret = vsnprintf(str, size, format, ap);
60 va_end(ap);
61 return (ret);
65 /*!
66 * Return length of string that would have been written if not truncated.
69 int
70 isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
71 int h;
72 int l;
73 int q;
74 int alt;
75 int zero;
76 int left;
77 int plus;
78 int space;
79 int neg;
80 isc_int64_t tmpi;
81 isc_uint64_t tmpui;
82 unsigned long width;
83 unsigned long precision;
84 unsigned int length;
85 char buf[1024];
86 char c;
87 void *v;
88 char *save = str;
89 const char *cp;
90 const char *head;
91 int count = 0;
92 int pad;
93 int zeropad;
94 int dot;
95 double dbl;
96 #ifdef HAVE_LONG_DOUBLE
97 long double ldbl;
98 #endif
99 char fmt[32];
101 INSIST(str != NULL);
102 INSIST(format != NULL);
104 while (*format != '\0') {
105 if (*format != '%') {
106 if (size > 1) {
107 *str++ = *format;
108 size--;
110 count++;
111 format++;
112 continue;
114 format++;
117 * Reset flags.
119 dot = neg = space = plus = left = zero = alt = h = l = q = 0;
120 width = precision = 0;
121 head = "";
122 length = pad = zeropad = 0;
124 do {
125 if (*format == '#') {
126 alt = 1;
127 format++;
128 } else if (*format == '-') {
129 left = 1;
130 zero = 0;
131 format++;
132 } else if (*format == ' ') {
133 if (!plus)
134 space = 1;
135 format++;
136 } else if (*format == '+') {
137 plus = 1;
138 space = 0;
139 format++;
140 } else if (*format == '0') {
141 if (!left)
142 zero = 1;
143 format++;
144 } else
145 break;
146 } while (1);
149 * Width.
151 if (*format == '*') {
152 width = va_arg(ap, int);
153 format++;
154 } else if (isdigit((unsigned char)*format)) {
155 char *e;
156 width = strtoul(format, &e, 10);
157 format = e;
161 * Precision.
163 if (*format == '.') {
164 format++;
165 dot = 1;
166 if (*format == '*') {
167 precision = va_arg(ap, int);
168 format++;
169 } else if (isdigit((unsigned char)*format)) {
170 char *e;
171 precision = strtoul(format, &e, 10);
172 format = e;
176 switch (*format) {
177 case '\0':
178 continue;
179 case '%':
180 if (size > 1) {
181 *str++ = *format;
182 size--;
184 count++;
185 break;
186 case 'q':
187 q = 1;
188 format++;
189 goto doint;
190 case 'h':
191 h = 1;
192 format++;
193 goto doint;
194 case 'l':
195 l = 1;
196 format++;
197 if (*format == 'l') {
198 q = 1;
199 format++;
201 goto doint;
202 case 'n':
203 case 'i':
204 case 'd':
205 case 'o':
206 case 'u':
207 case 'x':
208 case 'X':
209 doint:
210 if (precision != 0)
211 zero = 0;
212 switch (*format) {
213 case 'n':
214 if (h) {
215 short int *p;
216 p = va_arg(ap, short *);
217 REQUIRE(p != NULL);
218 *p = str - save;
219 } else if (l) {
220 long int *p;
221 p = va_arg(ap, long *);
222 REQUIRE(p != NULL);
223 *p = str - save;
224 } else {
225 int *p;
226 p = va_arg(ap, int *);
227 REQUIRE(p != NULL);
228 *p = str - save;
230 break;
231 case 'i':
232 case 'd':
233 if (q)
234 tmpi = va_arg(ap, isc_int64_t);
235 else if (l)
236 tmpi = va_arg(ap, long int);
237 else
238 tmpi = va_arg(ap, int);
239 if (tmpi < 0) {
240 head = "-";
241 tmpui = -tmpi;
242 } else {
243 if (plus)
244 head = "+";
245 else if (space)
246 head = " ";
247 else
248 head = "";
249 tmpui = tmpi;
251 if (tmpui <= 0xffffffffU)
252 sprintf(buf, "%lu",
253 (unsigned long)tmpui);
254 else {
255 unsigned long mid;
256 unsigned long lo;
257 unsigned long hi;
258 lo = tmpui % 1000000000;
259 tmpui /= 1000000000;
260 mid = tmpui % 1000000000;
261 hi = tmpui / 1000000000;
262 if (hi != 0)
263 sprintf(buf, "%lu", hi);
264 else
265 buf[0] = '\n';
266 sprintf(buf + strlen(buf), "%lu", mid);
267 sprintf(buf + strlen(buf), "%lu", lo);
269 goto printint;
270 case 'o':
271 if (q)
272 tmpui = va_arg(ap, isc_uint64_t);
273 else if (l)
274 tmpui = va_arg(ap, long int);
275 else
276 tmpui = va_arg(ap, int);
277 if (tmpui <= 0xffffffffU)
278 sprintf(buf, alt ? "%#lo" : "%lo",
279 (unsigned long)tmpui);
280 else {
281 unsigned long mid;
282 unsigned long lo;
283 unsigned long hi;
284 lo = tmpui % 010000000000;
285 tmpui /= 010000000000;
286 mid = tmpui % 010000000000;
287 hi = tmpui / 010000000000;
288 if (hi != 0) {
289 sprintf(buf,
290 alt ? "%#lo" : "%lo",
291 hi);
292 sprintf(buf + strlen(buf),
293 "%lo", mid);
294 } else
295 sprintf(buf,
296 alt ? "%#lo" : "%lo",
297 mid);
298 sprintf(buf + strlen(buf), "%lo", lo);
300 goto printint;
301 case 'u':
302 if (q)
303 tmpui = va_arg(ap, isc_uint64_t);
304 else if (l)
305 tmpui = va_arg(ap, unsigned long int);
306 else
307 tmpui = va_arg(ap, unsigned int);
308 if (tmpui <= 0xffffffffU)
309 sprintf(buf, "%lu",
310 (unsigned long)tmpui);
311 else {
312 unsigned long mid;
313 unsigned long lo;
314 unsigned long hi;
315 lo = tmpui % 1000000000;
316 tmpui /= 1000000000;
317 mid = tmpui % 1000000000;
318 hi = tmpui / 1000000000;
319 if (hi != 0)
320 sprintf(buf, "%lu", hi);
321 else
322 buf[0] = '\n';
323 sprintf(buf + strlen(buf), "%lu", mid);
324 sprintf(buf + strlen(buf), "%lu", lo);
326 goto printint;
327 case 'x':
328 if (q)
329 tmpui = va_arg(ap, isc_uint64_t);
330 else if (l)
331 tmpui = va_arg(ap, unsigned long int);
332 else
333 tmpui = va_arg(ap, unsigned int);
334 if (alt) {
335 head = "0x";
336 if (precision > 2)
337 precision -= 2;
339 if (tmpui <= 0xffffffffU)
340 sprintf(buf, "%lx",
341 (unsigned long)tmpui);
342 else {
343 unsigned long hi = tmpui>>32;
344 unsigned long lo = tmpui & 0xffffffff;
345 sprintf(buf, "%lx", hi);
346 sprintf(buf + strlen(buf), "%lx", lo);
348 goto printint;
349 case 'X':
350 if (q)
351 tmpui = va_arg(ap, isc_uint64_t);
352 else if (l)
353 tmpui = va_arg(ap, unsigned long int);
354 else
355 tmpui = va_arg(ap, unsigned int);
356 if (alt) {
357 head = "0X";
358 if (precision > 2)
359 precision -= 2;
361 if (tmpui <= 0xffffffffU)
362 sprintf(buf, "%lX",
363 (unsigned long)tmpui);
364 else {
365 unsigned long hi = tmpui>>32;
366 unsigned long lo = tmpui & 0xffffffff;
367 sprintf(buf, "%lX", hi);
368 sprintf(buf + strlen(buf), "%lX", lo);
370 goto printint;
371 printint:
372 if (precision != 0 || width != 0) {
373 length = strlen(buf);
374 if (length < precision)
375 zeropad = precision - length;
376 else if (length < width && zero)
377 zeropad = width - length;
378 if (width != 0) {
379 pad = width - length -
380 zeropad - strlen(head);
381 if (pad < 0)
382 pad = 0;
385 count += strlen(head) + strlen(buf) + pad +
386 zeropad;
387 if (!left) {
388 while (pad > 0 && size > 1) {
389 *str++ = ' ';
390 size--;
391 pad--;
394 cp = head;
395 while (*cp != '\0' && size > 1) {
396 *str++ = *cp++;
397 size--;
399 while (zeropad > 0 && size > 1) {
400 *str++ = '0';
401 size--;
402 zeropad--;
404 cp = buf;
405 while (*cp != '\0' && size > 1) {
406 *str++ = *cp++;
407 size--;
409 while (pad > 0 && size > 1) {
410 *str++ = ' ';
411 size--;
412 pad--;
414 break;
415 default:
416 break;
418 break;
419 case 's':
420 cp = va_arg(ap, char *);
421 REQUIRE(cp != NULL);
423 if (precision != 0) {
425 * cp need not be NULL terminated.
427 const char *tp;
428 unsigned long n;
430 n = precision;
431 tp = cp;
432 while (n != 0 && *tp != '\0')
433 n--, tp++;
434 length = precision - n;
435 } else {
436 length = strlen(cp);
438 if (width != 0) {
439 pad = width - length;
440 if (pad < 0)
441 pad = 0;
443 count += pad + length;
444 if (!left)
445 while (pad > 0 && size > 1) {
446 *str++ = ' ';
447 size--;
448 pad--;
450 if (precision != 0)
451 while (precision > 0 && *cp != '\0' &&
452 size > 1) {
453 *str++ = *cp++;
454 size--;
455 precision--;
457 else
458 while (*cp != '\0' && size > 1) {
459 *str++ = *cp++;
460 size--;
462 while (pad > 0 && size > 1) {
463 *str++ = ' ';
464 size--;
465 pad--;
467 break;
468 case 'c':
469 c = va_arg(ap, int);
470 if (width > 0) {
471 count += width;
472 width--;
473 if (left) {
474 *str++ = c;
475 size--;
477 while (width-- > 0 && size > 1) {
478 *str++ = ' ';
479 size--;
481 if (!left && size > 1) {
482 *str++ = c;
483 size--;
485 } else {
486 count++;
487 if (size > 1) {
488 *str++ = c;
489 size--;
492 break;
493 case 'p':
494 v = va_arg(ap, void *);
495 sprintf(buf, "%p", v);
496 length = strlen(buf);
497 if (precision > length)
498 zeropad = precision - length;
499 if (width > 0) {
500 pad = width - length - zeropad;
501 if (pad < 0)
502 pad = 0;
504 count += length + pad + zeropad;
505 if (!left)
506 while (pad > 0 && size > 1) {
507 *str++ = ' ';
508 size--;
509 pad--;
511 cp = buf;
512 if (zeropad > 0 && buf[0] == '0' &&
513 (buf[1] == 'x' || buf[1] == 'X')) {
514 if (size > 1) {
515 *str++ = *cp++;
516 size--;
518 if (size > 1) {
519 *str++ = *cp++;
520 size--;
522 while (zeropad > 0 && size > 1) {
523 *str++ = '0';
524 size--;
525 zeropad--;
528 while (*cp != '\0' && size > 1) {
529 *str++ = *cp++;
530 size--;
532 while (pad > 0 && size > 1) {
533 *str++ = ' ';
534 size--;
535 pad--;
537 break;
538 case 'D': /*deprecated*/
539 INSIST("use %ld instead of %D" == NULL);
540 case 'O': /*deprecated*/
541 INSIST("use %lo instead of %O" == NULL);
542 case 'U': /*deprecated*/
543 INSIST("use %lu instead of %U" == NULL);
545 case 'L':
546 #ifdef HAVE_LONG_DOUBLE
547 l = 1;
548 #else
549 INSIST("long doubles are not supported" == NULL);
550 #endif
551 /*FALLTHROUGH*/
552 case 'e':
553 case 'E':
554 case 'f':
555 case 'g':
556 case 'G':
557 if (!dot)
558 precision = 6;
560 * IEEE floating point.
561 * MIN 2.2250738585072014E-308
562 * MAX 1.7976931348623157E+308
563 * VAX floating point has a smaller range than IEEE.
565 * precisions > 324 don't make much sense.
566 * if we cap the precision at 512 we will not
567 * overflow buf.
569 if (precision > 512)
570 precision = 512;
571 sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "",
572 plus ? "+" : space ? " " : "",
573 precision, l ? "L" : "", *format);
574 switch (*format) {
575 case 'e':
576 case 'E':
577 case 'f':
578 case 'g':
579 case 'G':
580 #ifdef HAVE_LONG_DOUBLE
581 if (l) {
582 ldbl = va_arg(ap, long double);
583 sprintf(buf, fmt, ldbl);
584 } else
585 #endif
587 dbl = va_arg(ap, double);
588 sprintf(buf, fmt, dbl);
590 length = strlen(buf);
591 if (width > 0) {
592 pad = width - length;
593 if (pad < 0)
594 pad = 0;
596 count += length + pad;
597 if (!left)
598 while (pad > 0 && size > 1) {
599 *str++ = ' ';
600 size--;
601 pad--;
603 cp = buf;
604 while (*cp != ' ' && size > 1) {
605 *str++ = *cp++;
606 size--;
608 while (pad > 0 && size > 1) {
609 *str++ = ' ';
610 size--;
611 pad--;
613 break;
614 default:
615 continue;
617 break;
618 default:
619 continue;
621 format++;
623 if (size > 0)
624 *str = '\0';
625 return (count);