xref: /minix3/external/bsd/bind/dist/lib/isc/print.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1 /*	$NetBSD: print.c,v 1.5 2015/07/08 17:28:59 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004-2008, 2010, 2014, 2015  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 1999-2001, 2003  Internet Software Consortium.
6  *
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.
10  *
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.
18  */
19 
20 /* Id: print.c,v 1.37 2010/10/18 23:47:08 tbox Exp  */
21 
22 /*! \file */
23 
24 #include <config.h>
25 
26 #include <ctype.h>
27 #include <stdio.h>		/* for sprintf() */
28 #include <string.h>		/* for strlen() */
29 
30 #define	ISC__PRINT_SOURCE	/* Used to get the isc_print_* prototypes. */
31 
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>
38 
39 int
isc_print_sprintf(char * str,const char * format,...)40 isc_print_sprintf(char *str, const char *format, ...) {
41 	va_list ap;
42 
43 	va_start(ap, format);
44 	vsprintf(str, format, ap);
45 	va_end(ap);
46 	return (strlen(str));
47 }
48 
49 /*!
50  * Return length of string that would have been written if not truncated.
51  */
52 
53 int
isc_print_snprintf(char * str,size_t size,const char * format,...)54 isc_print_snprintf(char *str, size_t size, const char *format, ...) {
55 	va_list ap;
56 	int ret;
57 
58 	va_start(ap, format);
59 	ret = vsnprintf(str, size, format, ap);
60 	va_end(ap);
61 	return (ret);
62 
63 }
64 
65 /*!
66  * Return length of string that would have been written if not truncated.
67  */
68 
69 int
isc_print_vsnprintf(char * str,size_t size,const char * format,va_list ap)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];
100 
101 	INSIST(str != NULL);
102 	INSIST(format != NULL);
103 
104 	while (*format != '\0') {
105 		if (*format != '%') {
106 			if (size > 1) {
107 				*str++ = *format;
108 				size--;
109 			}
110 			count++;
111 			format++;
112 			continue;
113 		}
114 		format++;
115 
116 		/*
117 		 * Reset flags.
118 		 */
119 		dot = neg = space = plus = left = zero = alt = h = l = q = 0;
120 		width = precision = 0;
121 		head = "";
122 		pad = zeropad = 0;
123 
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);
147 
148 		/*
149 		 * Width.
150 		 */
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;
158 		}
159 
160 		/*
161 		 * Precision.
162 		 */
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;
173 			}
174 		}
175 
176 		switch (*format) {
177 		case '\0':
178 			continue;
179 		case '%':
180 			if (size > 1) {
181 				*str++ = *format;
182 				size--;
183 			}
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++;
200 			}
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;
229 				}
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;
250 				}
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] = '\0';
266 					sprintf(buf + strlen(buf), "%lu", mid);
267 					sprintf(buf + strlen(buf), "%lu", lo);
268 				}
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);
299 				}
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] = '\0';
323 					sprintf(buf + strlen(buf), "%lu", mid);
324 					sprintf(buf + strlen(buf), "%lu", lo);
325 				}
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;
338 				}
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);
347 				}
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;
360 				}
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);
369 				}
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;
383 					}
384 				}
385 				count += strlen(head) + strlen(buf) + pad +
386 					 zeropad;
387 				if (!left) {
388 					while (pad > 0 && size > 1) {
389 						*str++ = ' ';
390 						size--;
391 						pad--;
392 					}
393 				}
394 				cp = head;
395 				while (*cp != '\0' && size > 1) {
396 					*str++ = *cp++;
397 					size--;
398 				}
399 				while (zeropad > 0 && size > 1) {
400 					*str++ = '0';
401 					size--;
402 					zeropad--;
403 				}
404 				cp = buf;
405 				while (*cp != '\0' && size > 1) {
406 					*str++ = *cp++;
407 					size--;
408 				}
409 				while (pad > 0 && size > 1) {
410 					*str++ = ' ';
411 					size--;
412 					pad--;
413 				}
414 				break;
415 			default:
416 				break;
417 			}
418 			break;
419 		case 's':
420 			cp = va_arg(ap, char *);
421 			REQUIRE(cp != NULL);
422 
423 			if (precision != 0) {
424 				/*
425 				 * cp need not be NULL terminated.
426 				 */
427 				const char *tp;
428 				unsigned long n;
429 
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);
437 			}
438 			if (width != 0) {
439 				pad = width - length;
440 				if (pad < 0)
441 					pad = 0;
442 			}
443 			count += pad + length;
444 			if (!left)
445 				while (pad > 0 && size > 1) {
446 					*str++ = ' ';
447 					size--;
448 					pad--;
449 				}
450 			if (precision != 0)
451 				while (precision > 0 && *cp != '\0' &&
452 				       size > 1) {
453 					*str++ = *cp++;
454 					size--;
455 					precision--;
456 				}
457 			else
458 				while (*cp != '\0' && size > 1) {
459 					*str++ = *cp++;
460 					size--;
461 				}
462 			while (pad > 0 && size > 1) {
463 				*str++ = ' ';
464 				size--;
465 				pad--;
466 			}
467 			break;
468 		case 'c':
469 			c = va_arg(ap, int);
470 			if (width > 0) {
471 				count += width;
472 				width--;
473 				if (left && size > 1) {
474 					*str++ = c;
475 					size--;
476 				}
477 				while (width-- > 0 && size > 1) {
478 					*str++ = ' ';
479 					size--;
480 				}
481 				if (!left && size > 1) {
482 					*str++ = c;
483 					size--;
484 				}
485 			} else {
486 				count++;
487 				if (size > 1) {
488 					*str++ = c;
489 					size--;
490 				}
491 			}
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;
503 			}
504 			count += length + pad + zeropad;
505 			if (!left)
506 				while (pad > 0 && size > 1) {
507 					*str++ = ' ';
508 					size--;
509 					pad--;
510 				}
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--;
517 				}
518 				if (size > 1) {
519 					*str++ = *cp++;
520 					size--;
521 				}
522 				while (zeropad > 0 && size > 1) {
523 					*str++ = '0';
524 					size--;
525 					zeropad--;
526 				}
527 			}
528 			while (*cp != '\0' && size > 1) {
529 				*str++ = *cp++;
530 				size--;
531 			}
532 			while (pad > 0 && size > 1) {
533 				*str++ = ' ';
534 				size--;
535 				pad--;
536 			}
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);
544 
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;
559 			/*
560 			 * IEEE floating point.
561 			 * MIN 2.2250738585072014E-308
562 			 * MAX 1.7976931348623157E+308
563 			 * VAX floating point has a smaller range than IEEE.
564 			 *
565 			 * precisions > 324 don't make much sense.
566 			 * if we cap the precision at 512 we will not
567 			 * overflow buf.
568 			 */
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
586 				{
587 					dbl = va_arg(ap, double);
588 					sprintf(buf, fmt, dbl);
589 				}
590 				length = strlen(buf);
591 				if (width > 0) {
592 					pad = width - length;
593 					if (pad < 0)
594 						pad = 0;
595 				}
596 				count += length + pad;
597 				if (!left)
598 					while (pad > 0 && size > 1) {
599 						*str++ = ' ';
600 						size--;
601 						pad--;
602 					}
603 				cp = buf;
604 				while (*cp != ' ' && size > 1) {
605 					*str++ = *cp++;
606 					size--;
607 				}
608 				while (pad > 0 && size > 1) {
609 					*str++ = ' ';
610 					size--;
611 					pad--;
612 				}
613 				break;
614 			default:
615 				continue;
616 			}
617 			break;
618 		default:
619 			continue;
620 		}
621 		format++;
622 	}
623 	if (size > 0)
624 		*str = '\0';
625 	return (count);
626 }
627