PageRenderTime 37ms CodeModel.GetById 9ms app.highlight 22ms RepoModel.GetById 2ms app.codeStats 0ms

/contrib/bind9/lib/lwres/print.c

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