1135446Strhodes/*
2216175Sdougb * Copyright (C) 2004-2008, 2010  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1999-2001, 2003  Internet Software Consortium.
4135446Strhodes *
5186462Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id: print.c,v 1.37 2010/10/18 23:47:08 tbox Exp $ */
19135446Strhodes
20165071Sdougb/*! \file */
21165071Sdougb
22135446Strhodes#include <config.h>
23135446Strhodes
24135446Strhodes#include <ctype.h>
25165071Sdougb#include <stdio.h>		/* for sprintf() */
26165071Sdougb#include <string.h>		/* for strlen() */
27135446Strhodes
28135446Strhodes#define	ISC__PRINT_SOURCE	/* Used to get the isc_print_* prototypes. */
29135446Strhodes
30135446Strhodes#include <isc/assertions.h>
31135446Strhodes#include <isc/int.h>
32135446Strhodes#include <isc/msgs.h>
33135446Strhodes#include <isc/print.h>
34135446Strhodes#include <isc/stdlib.h>
35135446Strhodes#include <isc/util.h>
36135446Strhodes
37135446Strhodesint
38135446Strhodesisc_print_sprintf(char *str, const char *format, ...) {
39135446Strhodes	va_list ap;
40135446Strhodes
41135446Strhodes	va_start(ap, format);
42135446Strhodes	vsprintf(str, format, ap);
43135446Strhodes	va_end(ap);
44135446Strhodes	return (strlen(str));
45135446Strhodes}
46135446Strhodes
47165071Sdougb/*!
48135446Strhodes * Return length of string that would have been written if not truncated.
49135446Strhodes */
50135446Strhodes
51135446Strhodesint
52135446Strhodesisc_print_snprintf(char *str, size_t size, const char *format, ...) {
53135446Strhodes	va_list ap;
54135446Strhodes	int ret;
55135446Strhodes
56135446Strhodes	va_start(ap, format);
57135446Strhodes	ret = vsnprintf(str, size, format, ap);
58135446Strhodes	va_end(ap);
59135446Strhodes	return (ret);
60135446Strhodes
61135446Strhodes}
62135446Strhodes
63165071Sdougb/*!
64135446Strhodes * Return length of string that would have been written if not truncated.
65135446Strhodes */
66135446Strhodes
67135446Strhodesint
68135446Strhodesisc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
69135446Strhodes	int h;
70135446Strhodes	int l;
71135446Strhodes	int q;
72135446Strhodes	int alt;
73135446Strhodes	int zero;
74135446Strhodes	int left;
75135446Strhodes	int plus;
76135446Strhodes	int space;
77135446Strhodes	int neg;
78135446Strhodes	isc_int64_t tmpi;
79135446Strhodes	isc_uint64_t tmpui;
80135446Strhodes	unsigned long width;
81135446Strhodes	unsigned long precision;
82135446Strhodes	unsigned int length;
83135446Strhodes	char buf[1024];
84135446Strhodes	char c;
85135446Strhodes	void *v;
86135446Strhodes	char *save = str;
87135446Strhodes	const char *cp;
88135446Strhodes	const char *head;
89135446Strhodes	int count = 0;
90135446Strhodes	int pad;
91135446Strhodes	int zeropad;
92135446Strhodes	int dot;
93135446Strhodes	double dbl;
94135446Strhodes#ifdef HAVE_LONG_DOUBLE
95135446Strhodes	long double ldbl;
96135446Strhodes#endif
97135446Strhodes	char fmt[32];
98135446Strhodes
99135446Strhodes	INSIST(str != NULL);
100135446Strhodes	INSIST(format != NULL);
101135446Strhodes
102135446Strhodes	while (*format != '\0') {
103135446Strhodes		if (*format != '%') {
104135446Strhodes			if (size > 1) {
105135446Strhodes				*str++ = *format;
106135446Strhodes				size--;
107135446Strhodes			}
108135446Strhodes			count++;
109135446Strhodes			format++;
110135446Strhodes			continue;
111135446Strhodes		}
112135446Strhodes		format++;
113135446Strhodes
114135446Strhodes		/*
115135446Strhodes		 * Reset flags.
116135446Strhodes		 */
117135446Strhodes		dot = neg = space = plus = left = zero = alt = h = l = q = 0;
118135446Strhodes		width = precision = 0;
119135446Strhodes		head = "";
120135446Strhodes		length = pad = zeropad = 0;
121135446Strhodes
122135446Strhodes		do {
123135446Strhodes			if (*format == '#') {
124135446Strhodes				alt = 1;
125135446Strhodes				format++;
126135446Strhodes			} else if (*format == '-') {
127135446Strhodes				left = 1;
128135446Strhodes				zero = 0;
129135446Strhodes				format++;
130135446Strhodes			} else if (*format == ' ') {
131135446Strhodes				if (!plus)
132135446Strhodes					space = 1;
133135446Strhodes				format++;
134135446Strhodes			} else if (*format == '+') {
135135446Strhodes				plus = 1;
136135446Strhodes				space = 0;
137135446Strhodes				format++;
138135446Strhodes			} else if (*format == '0') {
139135446Strhodes				if (!left)
140135446Strhodes					zero = 1;
141135446Strhodes				format++;
142135446Strhodes			} else
143135446Strhodes				break;
144135446Strhodes		} while (1);
145135446Strhodes
146135446Strhodes		/*
147135446Strhodes		 * Width.
148135446Strhodes		 */
149135446Strhodes		if (*format == '*') {
150135446Strhodes			width = va_arg(ap, int);
151135446Strhodes			format++;
152135446Strhodes		} else if (isdigit((unsigned char)*format)) {
153135446Strhodes			char *e;
154135446Strhodes			width = strtoul(format, &e, 10);
155135446Strhodes			format = e;
156135446Strhodes		}
157135446Strhodes
158135446Strhodes		/*
159135446Strhodes		 * Precision.
160135446Strhodes		 */
161135446Strhodes		if (*format == '.') {
162135446Strhodes			format++;
163135446Strhodes			dot = 1;
164135446Strhodes			if (*format == '*') {
165135446Strhodes				precision = va_arg(ap, int);
166135446Strhodes				format++;
167135446Strhodes			} else if (isdigit((unsigned char)*format)) {
168135446Strhodes				char *e;
169135446Strhodes				precision = strtoul(format, &e, 10);
170135446Strhodes				format = e;
171135446Strhodes			}
172135446Strhodes		}
173135446Strhodes
174135446Strhodes		switch (*format) {
175135446Strhodes		case '\0':
176135446Strhodes			continue;
177135446Strhodes		case '%':
178135446Strhodes			if (size > 1) {
179135446Strhodes				*str++ = *format;
180135446Strhodes				size--;
181135446Strhodes			}
182135446Strhodes			count++;
183135446Strhodes			break;
184135446Strhodes		case 'q':
185135446Strhodes			q = 1;
186135446Strhodes			format++;
187135446Strhodes			goto doint;
188135446Strhodes		case 'h':
189135446Strhodes			h = 1;
190135446Strhodes			format++;
191135446Strhodes			goto doint;
192135446Strhodes		case 'l':
193135446Strhodes			l = 1;
194135446Strhodes			format++;
195135446Strhodes			if (*format == 'l') {
196135446Strhodes				q = 1;
197135446Strhodes				format++;
198135446Strhodes			}
199135446Strhodes			goto doint;
200135446Strhodes		case 'n':
201135446Strhodes		case 'i':
202135446Strhodes		case 'd':
203135446Strhodes		case 'o':
204135446Strhodes		case 'u':
205135446Strhodes		case 'x':
206135446Strhodes		case 'X':
207135446Strhodes		doint:
208135446Strhodes			if (precision != 0)
209135446Strhodes				zero = 0;
210135446Strhodes			switch (*format) {
211135446Strhodes			case 'n':
212135446Strhodes				if (h) {
213135446Strhodes					short int *p;
214135446Strhodes					p = va_arg(ap, short *);
215135446Strhodes					REQUIRE(p != NULL);
216135446Strhodes					*p = str - save;
217135446Strhodes				} else if (l) {
218135446Strhodes					long int *p;
219135446Strhodes					p = va_arg(ap, long *);
220135446Strhodes					REQUIRE(p != NULL);
221135446Strhodes					*p = str - save;
222135446Strhodes				} else {
223135446Strhodes					int *p;
224135446Strhodes					p = va_arg(ap, int *);
225135446Strhodes					REQUIRE(p != NULL);
226135446Strhodes					*p = str - save;
227135446Strhodes				}
228135446Strhodes				break;
229135446Strhodes			case 'i':
230135446Strhodes			case 'd':
231135446Strhodes				if (q)
232135446Strhodes					tmpi = va_arg(ap, isc_int64_t);
233135446Strhodes				else if (l)
234135446Strhodes					tmpi = va_arg(ap, long int);
235135446Strhodes				else
236135446Strhodes					tmpi = va_arg(ap, int);
237135446Strhodes				if (tmpi < 0) {
238135446Strhodes					head = "-";
239135446Strhodes					tmpui = -tmpi;
240135446Strhodes				} else {
241135446Strhodes					if (plus)
242135446Strhodes						head = "+";
243135446Strhodes					else if (space)
244135446Strhodes						head = " ";
245135446Strhodes					else
246135446Strhodes						head = "";
247135446Strhodes					tmpui = tmpi;
248135446Strhodes				}
249186462Sdougb				if (tmpui <= 0xffffffffU)
250186462Sdougb					sprintf(buf, "%lu",
251186462Sdougb						(unsigned long)tmpui);
252186462Sdougb				else {
253186462Sdougb					unsigned long mid;
254186462Sdougb					unsigned long lo;
255186462Sdougb					unsigned long hi;
256186462Sdougb					lo = tmpui % 1000000000;
257186462Sdougb					tmpui /= 1000000000;
258186462Sdougb					mid = tmpui % 1000000000;
259186462Sdougb					hi = tmpui / 1000000000;
260186462Sdougb					if (hi != 0)
261186462Sdougb						sprintf(buf, "%lu", hi);
262186462Sdougb					else
263186462Sdougb						buf[0] = '\n';
264186462Sdougb					sprintf(buf + strlen(buf), "%lu", mid);
265186462Sdougb					sprintf(buf + strlen(buf), "%lu", lo);
266186462Sdougb				}
267135446Strhodes				goto printint;
268135446Strhodes			case 'o':
269135446Strhodes				if (q)
270135446Strhodes					tmpui = va_arg(ap, isc_uint64_t);
271135446Strhodes				else if (l)
272135446Strhodes					tmpui = va_arg(ap, long int);
273135446Strhodes				else
274135446Strhodes					tmpui = va_arg(ap, int);
275186462Sdougb				if (tmpui <= 0xffffffffU)
276186462Sdougb					sprintf(buf, alt ?  "%#lo" : "%lo",
277186462Sdougb						(unsigned long)tmpui);
278186462Sdougb				else {
279186462Sdougb					unsigned long mid;
280186462Sdougb					unsigned long lo;
281186462Sdougb					unsigned long hi;
282186462Sdougb					lo = tmpui % 010000000000;
283186462Sdougb					tmpui /= 010000000000;
284186462Sdougb					mid = tmpui % 010000000000;
285186462Sdougb					hi = tmpui / 010000000000;
286186462Sdougb					if (hi != 0) {
287186462Sdougb						sprintf(buf,
288186462Sdougb							alt ?  "%#lo" : "%lo",
289186462Sdougb							hi);
290186462Sdougb						sprintf(buf + strlen(buf),
291186462Sdougb							"%lo", mid);
292186462Sdougb					} else
293186462Sdougb						sprintf(buf,
294186462Sdougb							alt ?  "%#lo" : "%lo",
295186462Sdougb							mid);
296186462Sdougb					sprintf(buf + strlen(buf), "%lo", lo);
297186462Sdougb				}
298135446Strhodes				goto printint;
299135446Strhodes			case 'u':
300135446Strhodes				if (q)
301135446Strhodes					tmpui = va_arg(ap, isc_uint64_t);
302135446Strhodes				else if (l)
303135446Strhodes					tmpui = va_arg(ap, unsigned long int);
304135446Strhodes				else
305135446Strhodes					tmpui = va_arg(ap, unsigned int);
306186462Sdougb				if (tmpui <= 0xffffffffU)
307186462Sdougb					sprintf(buf, "%lu",
308186462Sdougb						(unsigned long)tmpui);
309186462Sdougb				else {
310186462Sdougb					unsigned long mid;
311186462Sdougb					unsigned long lo;
312186462Sdougb					unsigned long hi;
313186462Sdougb					lo = tmpui % 1000000000;
314186462Sdougb					tmpui /= 1000000000;
315186462Sdougb					mid = tmpui % 1000000000;
316186462Sdougb					hi = tmpui / 1000000000;
317186462Sdougb					if (hi != 0)
318186462Sdougb						sprintf(buf, "%lu", hi);
319186462Sdougb					else
320186462Sdougb						buf[0] = '\n';
321186462Sdougb					sprintf(buf + strlen(buf), "%lu", mid);
322186462Sdougb					sprintf(buf + strlen(buf), "%lu", lo);
323186462Sdougb				}
324135446Strhodes				goto printint;
325135446Strhodes			case 'x':
326135446Strhodes				if (q)
327135446Strhodes					tmpui = va_arg(ap, isc_uint64_t);
328135446Strhodes				else if (l)
329135446Strhodes					tmpui = va_arg(ap, unsigned long int);
330135446Strhodes				else
331135446Strhodes					tmpui = va_arg(ap, unsigned int);
332135446Strhodes				if (alt) {
333135446Strhodes					head = "0x";
334135446Strhodes					if (precision > 2)
335135446Strhodes						precision -= 2;
336135446Strhodes				}
337186462Sdougb				if (tmpui <= 0xffffffffU)
338186462Sdougb					sprintf(buf, "%lx",
339186462Sdougb						(unsigned long)tmpui);
340186462Sdougb				else {
341186462Sdougb					unsigned long hi = tmpui>>32;
342186462Sdougb					unsigned long lo = tmpui & 0xffffffff;
343186462Sdougb					sprintf(buf, "%lx", hi);
344186462Sdougb					sprintf(buf + strlen(buf), "%lx", lo);
345186462Sdougb				}
346135446Strhodes				goto printint;
347135446Strhodes			case 'X':
348135446Strhodes				if (q)
349135446Strhodes					tmpui = va_arg(ap, isc_uint64_t);
350135446Strhodes				else if (l)
351135446Strhodes					tmpui = va_arg(ap, unsigned long int);
352135446Strhodes				else
353135446Strhodes					tmpui = va_arg(ap, unsigned int);
354135446Strhodes				if (alt) {
355135446Strhodes					head = "0X";
356135446Strhodes					if (precision > 2)
357135446Strhodes						precision -= 2;
358135446Strhodes				}
359186462Sdougb				if (tmpui <= 0xffffffffU)
360186462Sdougb					sprintf(buf, "%lX",
361186462Sdougb						(unsigned long)tmpui);
362186462Sdougb				else  {
363186462Sdougb					unsigned long hi = tmpui>>32;
364186462Sdougb					unsigned long lo = tmpui & 0xffffffff;
365186462Sdougb					sprintf(buf, "%lX", hi);
366186462Sdougb					sprintf(buf + strlen(buf), "%lX", lo);
367186462Sdougb				}
368135446Strhodes				goto printint;
369135446Strhodes			printint:
370135446Strhodes				if (precision != 0 || width != 0) {
371135446Strhodes					length = strlen(buf);
372135446Strhodes					if (length < precision)
373135446Strhodes						zeropad = precision - length;
374135446Strhodes					else if (length < width && zero)
375135446Strhodes						zeropad = width - length;
376135446Strhodes					if (width != 0) {
377135446Strhodes						pad = width - length -
378135446Strhodes						      zeropad - strlen(head);
379135446Strhodes						if (pad < 0)
380135446Strhodes							pad = 0;
381135446Strhodes					}
382135446Strhodes				}
383135446Strhodes				count += strlen(head) + strlen(buf) + pad +
384135446Strhodes					 zeropad;
385135446Strhodes				if (!left) {
386135446Strhodes					while (pad > 0 && size > 1) {
387135446Strhodes						*str++ = ' ';
388135446Strhodes						size--;
389135446Strhodes						pad--;
390135446Strhodes					}
391135446Strhodes				}
392135446Strhodes				cp = head;
393135446Strhodes				while (*cp != '\0' && size > 1) {
394135446Strhodes					*str++ = *cp++;
395135446Strhodes					size--;
396135446Strhodes				}
397135446Strhodes				while (zeropad > 0 && size > 1) {
398135446Strhodes					*str++ = '0';
399135446Strhodes					size--;
400135446Strhodes					zeropad--;
401135446Strhodes				}
402135446Strhodes				cp = buf;
403135446Strhodes				while (*cp != '\0' && size > 1) {
404135446Strhodes					*str++ = *cp++;
405135446Strhodes					size--;
406135446Strhodes				}
407135446Strhodes				while (pad > 0 && size > 1) {
408135446Strhodes					*str++ = ' ';
409135446Strhodes					size--;
410135446Strhodes					pad--;
411135446Strhodes				}
412135446Strhodes				break;
413135446Strhodes			default:
414135446Strhodes				break;
415135446Strhodes			}
416135446Strhodes			break;
417135446Strhodes		case 's':
418135446Strhodes			cp = va_arg(ap, char *);
419135446Strhodes			REQUIRE(cp != NULL);
420135446Strhodes
421135446Strhodes			if (precision != 0) {
422135446Strhodes				/*
423135446Strhodes				 * cp need not be NULL terminated.
424135446Strhodes				 */
425135446Strhodes				const char *tp;
426135446Strhodes				unsigned long n;
427135446Strhodes
428135446Strhodes				n = precision;
429135446Strhodes				tp = cp;
430135446Strhodes				while (n != 0 && *tp != '\0')
431135446Strhodes					n--, tp++;
432135446Strhodes				length = precision - n;
433135446Strhodes			} else {
434135446Strhodes				length = strlen(cp);
435135446Strhodes			}
436135446Strhodes			if (width != 0) {
437135446Strhodes				pad = width - length;
438135446Strhodes				if (pad < 0)
439135446Strhodes					pad = 0;
440135446Strhodes			}
441135446Strhodes			count += pad + length;
442135446Strhodes			if (!left)
443135446Strhodes				while (pad > 0 && size > 1) {
444135446Strhodes					*str++ = ' ';
445135446Strhodes					size--;
446135446Strhodes					pad--;
447135446Strhodes				}
448135446Strhodes			if (precision != 0)
449135446Strhodes				while (precision > 0 && *cp != '\0' &&
450135446Strhodes				       size > 1) {
451135446Strhodes					*str++ = *cp++;
452135446Strhodes					size--;
453135446Strhodes					precision--;
454135446Strhodes				}
455135446Strhodes			else
456135446Strhodes				while (*cp != '\0' && size > 1) {
457135446Strhodes					*str++ = *cp++;
458135446Strhodes					size--;
459135446Strhodes				}
460135446Strhodes			while (pad > 0 && size > 1) {
461135446Strhodes				*str++ = ' ';
462135446Strhodes				size--;
463135446Strhodes				pad--;
464135446Strhodes			}
465135446Strhodes			break;
466135446Strhodes		case 'c':
467135446Strhodes			c = va_arg(ap, int);
468135446Strhodes			if (width > 0) {
469135446Strhodes				count += width;
470135446Strhodes				width--;
471216175Sdougb				if (left && size > 1) {
472135446Strhodes					*str++ = c;
473135446Strhodes					size--;
474135446Strhodes				}
475135446Strhodes				while (width-- > 0 && size > 1) {
476135446Strhodes					*str++ = ' ';
477135446Strhodes					size--;
478135446Strhodes				}
479135446Strhodes				if (!left && size > 1) {
480135446Strhodes					*str++ = c;
481135446Strhodes					size--;
482135446Strhodes				}
483135446Strhodes			} else {
484135446Strhodes				count++;
485135446Strhodes				if (size > 1) {
486135446Strhodes					*str++ = c;
487135446Strhodes					size--;
488135446Strhodes				}
489135446Strhodes			}
490135446Strhodes			break;
491135446Strhodes		case 'p':
492135446Strhodes			v = va_arg(ap, void *);
493135446Strhodes			sprintf(buf, "%p", v);
494135446Strhodes			length = strlen(buf);
495135446Strhodes			if (precision > length)
496135446Strhodes				zeropad = precision - length;
497135446Strhodes			if (width > 0) {
498135446Strhodes				pad = width - length - zeropad;
499135446Strhodes				if (pad < 0)
500135446Strhodes					pad = 0;
501135446Strhodes			}
502135446Strhodes			count += length + pad + zeropad;
503135446Strhodes			if (!left)
504135446Strhodes				while (pad > 0 && size > 1) {
505135446Strhodes					*str++ = ' ';
506135446Strhodes					size--;
507135446Strhodes					pad--;
508135446Strhodes				}
509135446Strhodes			cp = buf;
510135446Strhodes			if (zeropad > 0 && buf[0] == '0' &&
511135446Strhodes			    (buf[1] == 'x' || buf[1] == 'X')) {
512135446Strhodes				if (size > 1) {
513135446Strhodes					*str++ = *cp++;
514135446Strhodes					size--;
515135446Strhodes				}
516135446Strhodes				if (size > 1) {
517135446Strhodes					*str++ = *cp++;
518135446Strhodes					size--;
519135446Strhodes				}
520135446Strhodes				while (zeropad > 0 && size > 1) {
521135446Strhodes					*str++ = '0';
522135446Strhodes					size--;
523135446Strhodes					zeropad--;
524135446Strhodes				}
525135446Strhodes			}
526135446Strhodes			while (*cp != '\0' && size > 1) {
527135446Strhodes				*str++ = *cp++;
528135446Strhodes				size--;
529135446Strhodes			}
530135446Strhodes			while (pad > 0 && size > 1) {
531135446Strhodes				*str++ = ' ';
532135446Strhodes				size--;
533135446Strhodes				pad--;
534135446Strhodes			}
535135446Strhodes			break;
536135446Strhodes		case 'D':	/*deprecated*/
537135446Strhodes			INSIST("use %ld instead of %D" == NULL);
538135446Strhodes		case 'O':	/*deprecated*/
539135446Strhodes			INSIST("use %lo instead of %O" == NULL);
540135446Strhodes		case 'U':	/*deprecated*/
541135446Strhodes			INSIST("use %lu instead of %U" == NULL);
542135446Strhodes
543135446Strhodes		case 'L':
544135446Strhodes#ifdef HAVE_LONG_DOUBLE
545135446Strhodes			l = 1;
546135446Strhodes#else
547135446Strhodes			INSIST("long doubles are not supported" == NULL);
548135446Strhodes#endif
549135446Strhodes			/*FALLTHROUGH*/
550135446Strhodes		case 'e':
551135446Strhodes		case 'E':
552135446Strhodes		case 'f':
553135446Strhodes		case 'g':
554135446Strhodes		case 'G':
555135446Strhodes			if (!dot)
556135446Strhodes				precision = 6;
557135446Strhodes			/*
558135446Strhodes			 * IEEE floating point.
559135446Strhodes			 * MIN 2.2250738585072014E-308
560135446Strhodes			 * MAX 1.7976931348623157E+308
561135446Strhodes			 * VAX floating point has a smaller range than IEEE.
562135446Strhodes			 *
563135446Strhodes			 * precisions > 324 don't make much sense.
564135446Strhodes			 * if we cap the precision at 512 we will not
565135446Strhodes			 * overflow buf.
566135446Strhodes			 */
567135446Strhodes			if (precision > 512)
568135446Strhodes				precision = 512;
569135446Strhodes			sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "",
570135446Strhodes				plus ? "+" : space ? " " : "",
571135446Strhodes				precision, l ? "L" : "", *format);
572135446Strhodes			switch (*format) {
573135446Strhodes			case 'e':
574135446Strhodes			case 'E':
575135446Strhodes			case 'f':
576135446Strhodes			case 'g':
577135446Strhodes			case 'G':
578135446Strhodes#ifdef HAVE_LONG_DOUBLE
579135446Strhodes				if (l) {
580135446Strhodes					ldbl = va_arg(ap, long double);
581135446Strhodes					sprintf(buf, fmt, ldbl);
582135446Strhodes				} else
583135446Strhodes#endif
584135446Strhodes				{
585135446Strhodes					dbl = va_arg(ap, double);
586135446Strhodes					sprintf(buf, fmt, dbl);
587135446Strhodes				}
588135446Strhodes				length = strlen(buf);
589135446Strhodes				if (width > 0) {
590135446Strhodes					pad = width - length;
591135446Strhodes					if (pad < 0)
592135446Strhodes						pad = 0;
593135446Strhodes				}
594135446Strhodes				count += length + pad;
595135446Strhodes				if (!left)
596135446Strhodes					while (pad > 0 && size > 1) {
597135446Strhodes						*str++ = ' ';
598135446Strhodes						size--;
599135446Strhodes						pad--;
600135446Strhodes					}
601135446Strhodes				cp = buf;
602135446Strhodes				while (*cp != ' ' && size > 1) {
603135446Strhodes					*str++ = *cp++;
604135446Strhodes					size--;
605135446Strhodes				}
606135446Strhodes				while (pad > 0 && size > 1) {
607135446Strhodes					*str++ = ' ';
608135446Strhodes					size--;
609135446Strhodes					pad--;
610135446Strhodes				}
611135446Strhodes				break;
612135446Strhodes			default:
613135446Strhodes				continue;
614135446Strhodes			}
615135446Strhodes			break;
616135446Strhodes		default:
617135446Strhodes			continue;
618135446Strhodes		}
619135446Strhodes		format++;
620135446Strhodes	}
621135446Strhodes	if (size > 0)
622135446Strhodes		*str = '\0';
623135446Strhodes	return (count);
624135446Strhodes}
625