1290001Sglebius/*
2290001Sglebius * Copyright (C) 2004-2008, 2010  Internet Systems Consortium, Inc. ("ISC")
3290001Sglebius * Copyright (C) 1999-2001, 2003  Internet Software Consortium.
4290001Sglebius *
5290001Sglebius * Permission to use, copy, modify, and/or distribute this software for any
6290001Sglebius * purpose with or without fee is hereby granted, provided that the above
7290001Sglebius * copyright notice and this permission notice appear in all copies.
8290001Sglebius *
9290001Sglebius * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10290001Sglebius * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11290001Sglebius * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12290001Sglebius * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13290001Sglebius * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14290001Sglebius * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15290001Sglebius * PERFORMANCE OF THIS SOFTWARE.
16290001Sglebius */
17290001Sglebius
18290001Sglebius/* $Id: print.c,v 1.37 2010/10/18 23:47:08 tbox Exp $ */
19290001Sglebius
20290001Sglebius/*! \file */
21290001Sglebius
22290001Sglebius#include <config.h>
23290001Sglebius
24290001Sglebius#include <ctype.h>
25290001Sglebius#include <stdio.h>		/* for sprintf() */
26290001Sglebius#include <string.h>		/* for strlen() */
27290001Sglebius
28290001Sglebius#define	ISC__PRINT_SOURCE	/* Used to get the isc_print_* prototypes. */
29290001Sglebius
30290001Sglebius#include <isc/assertions.h>
31290001Sglebius#include <isc/int.h>
32290001Sglebius#include <isc/msgs.h>
33290001Sglebius#include <isc/print.h>
34290001Sglebius#include <isc/stdlib.h>
35290001Sglebius#include <isc/util.h>
36290001Sglebius
37290001Sglebiusint
38290001Sglebiusisc_print_sprintf(char *str, const char *format, ...) {
39290001Sglebius	va_list ap;
40290001Sglebius
41290001Sglebius	va_start(ap, format);
42290001Sglebius	vsprintf(str, format, ap);
43290001Sglebius	va_end(ap);
44290001Sglebius	return (strlen(str));
45290001Sglebius}
46290001Sglebius
47290001Sglebius/*!
48290001Sglebius * Return length of string that would have been written if not truncated.
49290001Sglebius */
50290001Sglebius
51290001Sglebiusint
52290001Sglebiusisc_print_snprintf(char *str, size_t size, const char *format, ...) {
53290001Sglebius	va_list ap;
54290001Sglebius	int ret;
55290001Sglebius
56290001Sglebius	va_start(ap, format);
57290001Sglebius	ret = vsnprintf(str, size, format, ap);
58290001Sglebius	va_end(ap);
59290001Sglebius	return (ret);
60290001Sglebius
61290001Sglebius}
62290001Sglebius
63290001Sglebius/*!
64290001Sglebius * Return length of string that would have been written if not truncated.
65290001Sglebius */
66290001Sglebius
67290001Sglebiusint
68290001Sglebiusisc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
69290001Sglebius	int h;
70290001Sglebius	int l;
71290001Sglebius	int q;
72290001Sglebius	int alt;
73290001Sglebius	int zero;
74290001Sglebius	int left;
75290001Sglebius	int plus;
76290001Sglebius	int space;
77290001Sglebius	int neg;
78290001Sglebius	isc_int64_t tmpi;
79290001Sglebius	isc_uint64_t tmpui;
80290001Sglebius	unsigned long width;
81290001Sglebius	unsigned long precision;
82290001Sglebius	unsigned int length;
83290001Sglebius	char buf[1024];
84290001Sglebius	char c;
85290001Sglebius	void *v;
86290001Sglebius	char *save = str;
87290001Sglebius	const char *cp;
88290001Sglebius	const char *head;
89290001Sglebius	int count = 0;
90290001Sglebius	int pad;
91290001Sglebius	int zeropad;
92290001Sglebius	int dot;
93290001Sglebius	double dbl;
94290001Sglebius#ifdef HAVE_LONG_DOUBLE
95290001Sglebius	long double ldbl;
96290001Sglebius#endif
97290001Sglebius	char fmt[32];
98290001Sglebius
99290001Sglebius	INSIST(str != NULL);
100290001Sglebius	INSIST(format != NULL);
101290001Sglebius
102290001Sglebius	while (*format != '\0') {
103290001Sglebius		if (*format != '%') {
104290001Sglebius			if (size > 1) {
105290001Sglebius				*str++ = *format;
106290001Sglebius				size--;
107290001Sglebius			}
108290001Sglebius			count++;
109290001Sglebius			format++;
110290001Sglebius			continue;
111290001Sglebius		}
112290001Sglebius		format++;
113290001Sglebius
114290001Sglebius		/*
115290001Sglebius		 * Reset flags.
116290001Sglebius		 */
117290001Sglebius		dot = neg = space = plus = left = zero = alt = h = l = q = 0;
118290001Sglebius		width = precision = 0;
119290001Sglebius		head = "";
120290001Sglebius		length = pad = zeropad = 0;
121290001Sglebius
122290001Sglebius		do {
123290001Sglebius			if (*format == '#') {
124290001Sglebius				alt = 1;
125290001Sglebius				format++;
126290001Sglebius			} else if (*format == '-') {
127290001Sglebius				left = 1;
128290001Sglebius				zero = 0;
129290001Sglebius				format++;
130290001Sglebius			} else if (*format == ' ') {
131290001Sglebius				if (!plus)
132290001Sglebius					space = 1;
133290001Sglebius				format++;
134290001Sglebius			} else if (*format == '+') {
135290001Sglebius				plus = 1;
136290001Sglebius				space = 0;
137290001Sglebius				format++;
138290001Sglebius			} else if (*format == '0') {
139290001Sglebius				if (!left)
140290001Sglebius					zero = 1;
141290001Sglebius				format++;
142290001Sglebius			} else
143290001Sglebius				break;
144290001Sglebius		} while (1);
145290001Sglebius
146290001Sglebius		/*
147290001Sglebius		 * Width.
148290001Sglebius		 */
149290001Sglebius		if (*format == '*') {
150290001Sglebius			width = va_arg(ap, int);
151290001Sglebius			format++;
152290001Sglebius		} else if (isdigit((unsigned char)*format)) {
153290001Sglebius			char *e;
154290001Sglebius			width = strtoul(format, &e, 10);
155290001Sglebius			format = e;
156290001Sglebius		}
157290001Sglebius
158290001Sglebius		/*
159290001Sglebius		 * Precision.
160290001Sglebius		 */
161290001Sglebius		if (*format == '.') {
162290001Sglebius			format++;
163290001Sglebius			dot = 1;
164290001Sglebius			if (*format == '*') {
165290001Sglebius				precision = va_arg(ap, int);
166290001Sglebius				format++;
167290001Sglebius			} else if (isdigit((unsigned char)*format)) {
168290001Sglebius				char *e;
169290001Sglebius				precision = strtoul(format, &e, 10);
170290001Sglebius				format = e;
171290001Sglebius			}
172290001Sglebius		}
173290001Sglebius
174290001Sglebius		switch (*format) {
175290001Sglebius		case '\0':
176290001Sglebius			continue;
177290001Sglebius		case '%':
178290001Sglebius			if (size > 1) {
179290001Sglebius				*str++ = *format;
180290001Sglebius				size--;
181290001Sglebius			}
182290001Sglebius			count++;
183290001Sglebius			break;
184290001Sglebius		case 'q':
185290001Sglebius			q = 1;
186290001Sglebius			format++;
187290001Sglebius			goto doint;
188290001Sglebius		case 'h':
189290001Sglebius			h = 1;
190290001Sglebius			format++;
191290001Sglebius			goto doint;
192290001Sglebius		case 'l':
193290001Sglebius			l = 1;
194290001Sglebius			format++;
195290001Sglebius			if (*format == 'l') {
196290001Sglebius				q = 1;
197290001Sglebius				format++;
198290001Sglebius			}
199290001Sglebius			goto doint;
200290001Sglebius		case 'n':
201290001Sglebius		case 'i':
202290001Sglebius		case 'd':
203290001Sglebius		case 'o':
204290001Sglebius		case 'u':
205290001Sglebius		case 'x':
206290001Sglebius		case 'X':
207290001Sglebius		doint:
208290001Sglebius			if (precision != 0)
209290001Sglebius				zero = 0;
210290001Sglebius			switch (*format) {
211290001Sglebius			case 'n':
212290001Sglebius				if (h) {
213290001Sglebius					short int *p;
214290001Sglebius					p = va_arg(ap, short *);
215290001Sglebius					REQUIRE(p != NULL);
216290001Sglebius					*p = str - save;
217290001Sglebius				} else if (l) {
218290001Sglebius					long int *p;
219290001Sglebius					p = va_arg(ap, long *);
220290001Sglebius					REQUIRE(p != NULL);
221290001Sglebius					*p = str - save;
222290001Sglebius				} else {
223290001Sglebius					int *p;
224290001Sglebius					p = va_arg(ap, int *);
225290001Sglebius					REQUIRE(p != NULL);
226290001Sglebius					*p = str - save;
227290001Sglebius				}
228290001Sglebius				break;
229290001Sglebius			case 'i':
230290001Sglebius			case 'd':
231290001Sglebius				if (q)
232290001Sglebius					tmpi = va_arg(ap, isc_int64_t);
233290001Sglebius				else if (l)
234290001Sglebius					tmpi = va_arg(ap, long int);
235290001Sglebius				else
236290001Sglebius					tmpi = va_arg(ap, int);
237290001Sglebius				if (tmpi < 0) {
238290001Sglebius					head = "-";
239290001Sglebius					tmpui = -tmpi;
240290001Sglebius				} else {
241290001Sglebius					if (plus)
242290001Sglebius						head = "+";
243290001Sglebius					else if (space)
244290001Sglebius						head = " ";
245290001Sglebius					else
246290001Sglebius						head = "";
247290001Sglebius					tmpui = tmpi;
248290001Sglebius				}
249290001Sglebius				if (tmpui <= 0xffffffffU)
250290001Sglebius					sprintf(buf, "%lu",
251290001Sglebius						(unsigned long)tmpui);
252290001Sglebius				else {
253290001Sglebius					unsigned long mid;
254290001Sglebius					unsigned long lo;
255290001Sglebius					unsigned long hi;
256290001Sglebius					lo = tmpui % 1000000000;
257290001Sglebius					tmpui /= 1000000000;
258290001Sglebius					mid = tmpui % 1000000000;
259290001Sglebius					hi = tmpui / 1000000000;
260290001Sglebius					if (hi != 0)
261290001Sglebius						sprintf(buf, "%lu", hi);
262290001Sglebius					else
263290001Sglebius						buf[0] = '\n';
264290001Sglebius					sprintf(buf + strlen(buf), "%lu", mid);
265290001Sglebius					sprintf(buf + strlen(buf), "%lu", lo);
266290001Sglebius				}
267290001Sglebius				goto printint;
268290001Sglebius			case 'o':
269290001Sglebius				if (q)
270290001Sglebius					tmpui = va_arg(ap, isc_uint64_t);
271290001Sglebius				else if (l)
272290001Sglebius					tmpui = va_arg(ap, long int);
273290001Sglebius				else
274290001Sglebius					tmpui = va_arg(ap, int);
275290001Sglebius				if (tmpui <= 0xffffffffU)
276290001Sglebius					sprintf(buf, alt ?  "%#lo" : "%lo",
277290001Sglebius						(unsigned long)tmpui);
278290001Sglebius				else {
279290001Sglebius					unsigned long mid;
280290001Sglebius					unsigned long lo;
281290001Sglebius					unsigned long hi;
282290001Sglebius					lo = tmpui % 010000000000;
283290001Sglebius					tmpui /= 010000000000;
284290001Sglebius					mid = tmpui % 010000000000;
285290001Sglebius					hi = tmpui / 010000000000;
286290001Sglebius					if (hi != 0) {
287290001Sglebius						sprintf(buf,
288290001Sglebius							alt ?  "%#lo" : "%lo",
289290001Sglebius							hi);
290290001Sglebius						sprintf(buf + strlen(buf),
291290001Sglebius							"%lo", mid);
292290001Sglebius					} else
293290001Sglebius						sprintf(buf,
294290001Sglebius							alt ?  "%#lo" : "%lo",
295290001Sglebius							mid);
296290001Sglebius					sprintf(buf + strlen(buf), "%lo", lo);
297290001Sglebius				}
298290001Sglebius				goto printint;
299290001Sglebius			case 'u':
300290001Sglebius				if (q)
301290001Sglebius					tmpui = va_arg(ap, isc_uint64_t);
302290001Sglebius				else if (l)
303290001Sglebius					tmpui = va_arg(ap, unsigned long int);
304290001Sglebius				else
305290001Sglebius					tmpui = va_arg(ap, unsigned int);
306290001Sglebius				if (tmpui <= 0xffffffffU)
307290001Sglebius					sprintf(buf, "%lu",
308290001Sglebius						(unsigned long)tmpui);
309290001Sglebius				else {
310290001Sglebius					unsigned long mid;
311290001Sglebius					unsigned long lo;
312290001Sglebius					unsigned long hi;
313290001Sglebius					lo = tmpui % 1000000000;
314290001Sglebius					tmpui /= 1000000000;
315290001Sglebius					mid = tmpui % 1000000000;
316290001Sglebius					hi = tmpui / 1000000000;
317290001Sglebius					if (hi != 0)
318290001Sglebius						sprintf(buf, "%lu", hi);
319290001Sglebius					else
320290001Sglebius						buf[0] = '\n';
321290001Sglebius					sprintf(buf + strlen(buf), "%lu", mid);
322290001Sglebius					sprintf(buf + strlen(buf), "%lu", lo);
323290001Sglebius				}
324290001Sglebius				goto printint;
325290001Sglebius			case 'x':
326290001Sglebius				if (q)
327290001Sglebius					tmpui = va_arg(ap, isc_uint64_t);
328290001Sglebius				else if (l)
329290001Sglebius					tmpui = va_arg(ap, unsigned long int);
330290001Sglebius				else
331290001Sglebius					tmpui = va_arg(ap, unsigned int);
332290001Sglebius				if (alt) {
333290001Sglebius					head = "0x";
334290001Sglebius					if (precision > 2)
335290001Sglebius						precision -= 2;
336290001Sglebius				}
337290001Sglebius				if (tmpui <= 0xffffffffU)
338290001Sglebius					sprintf(buf, "%lx",
339290001Sglebius						(unsigned long)tmpui);
340290001Sglebius				else {
341290001Sglebius					unsigned long hi = tmpui>>32;
342290001Sglebius					unsigned long lo = tmpui & 0xffffffff;
343290001Sglebius					sprintf(buf, "%lx", hi);
344290001Sglebius					sprintf(buf + strlen(buf), "%lx", lo);
345290001Sglebius				}
346290001Sglebius				goto printint;
347290001Sglebius			case 'X':
348290001Sglebius				if (q)
349290001Sglebius					tmpui = va_arg(ap, isc_uint64_t);
350290001Sglebius				else if (l)
351290001Sglebius					tmpui = va_arg(ap, unsigned long int);
352290001Sglebius				else
353290001Sglebius					tmpui = va_arg(ap, unsigned int);
354290001Sglebius				if (alt) {
355290001Sglebius					head = "0X";
356290001Sglebius					if (precision > 2)
357290001Sglebius						precision -= 2;
358290001Sglebius				}
359290001Sglebius				if (tmpui <= 0xffffffffU)
360290001Sglebius					sprintf(buf, "%lX",
361290001Sglebius						(unsigned long)tmpui);
362290001Sglebius				else  {
363290001Sglebius					unsigned long hi = tmpui>>32;
364290001Sglebius					unsigned long lo = tmpui & 0xffffffff;
365290001Sglebius					sprintf(buf, "%lX", hi);
366290001Sglebius					sprintf(buf + strlen(buf), "%lX", lo);
367290001Sglebius				}
368290001Sglebius				goto printint;
369290001Sglebius			printint:
370290001Sglebius				if (precision != 0 || width != 0) {
371290001Sglebius					length = strlen(buf);
372290001Sglebius					if (length < precision)
373290001Sglebius						zeropad = precision - length;
374290001Sglebius					else if (length < width && zero)
375290001Sglebius						zeropad = width - length;
376290001Sglebius					if (width != 0) {
377290001Sglebius						pad = width - length -
378290001Sglebius						      zeropad - strlen(head);
379290001Sglebius						if (pad < 0)
380290001Sglebius							pad = 0;
381290001Sglebius					}
382290001Sglebius				}
383290001Sglebius				count += strlen(head) + strlen(buf) + pad +
384290001Sglebius					 zeropad;
385290001Sglebius				if (!left) {
386290001Sglebius					while (pad > 0 && size > 1) {
387290001Sglebius						*str++ = ' ';
388290001Sglebius						size--;
389290001Sglebius						pad--;
390290001Sglebius					}
391290001Sglebius				}
392290001Sglebius				cp = head;
393290001Sglebius				while (*cp != '\0' && size > 1) {
394290001Sglebius					*str++ = *cp++;
395290001Sglebius					size--;
396290001Sglebius				}
397290001Sglebius				while (zeropad > 0 && size > 1) {
398290001Sglebius					*str++ = '0';
399290001Sglebius					size--;
400290001Sglebius					zeropad--;
401290001Sglebius				}
402290001Sglebius				cp = buf;
403290001Sglebius				while (*cp != '\0' && size > 1) {
404290001Sglebius					*str++ = *cp++;
405290001Sglebius					size--;
406290001Sglebius				}
407290001Sglebius				while (pad > 0 && size > 1) {
408290001Sglebius					*str++ = ' ';
409290001Sglebius					size--;
410290001Sglebius					pad--;
411290001Sglebius				}
412290001Sglebius				break;
413290001Sglebius			default:
414290001Sglebius				break;
415290001Sglebius			}
416290001Sglebius			break;
417290001Sglebius		case 's':
418290001Sglebius			cp = va_arg(ap, char *);
419290001Sglebius			REQUIRE(cp != NULL);
420290001Sglebius
421290001Sglebius			if (precision != 0) {
422290001Sglebius				/*
423290001Sglebius				 * cp need not be NULL terminated.
424290001Sglebius				 */
425290001Sglebius				const char *tp;
426290001Sglebius				unsigned long n;
427290001Sglebius
428290001Sglebius				n = precision;
429290001Sglebius				tp = cp;
430290001Sglebius				while (n != 0 && *tp != '\0')
431290001Sglebius					n--, tp++;
432290001Sglebius				length = precision - n;
433290001Sglebius			} else {
434290001Sglebius				length = strlen(cp);
435290001Sglebius			}
436290001Sglebius			if (width != 0) {
437290001Sglebius				pad = width - length;
438290001Sglebius				if (pad < 0)
439290001Sglebius					pad = 0;
440290001Sglebius			}
441290001Sglebius			count += pad + length;
442290001Sglebius			if (!left)
443290001Sglebius				while (pad > 0 && size > 1) {
444290001Sglebius					*str++ = ' ';
445290001Sglebius					size--;
446290001Sglebius					pad--;
447290001Sglebius				}
448290001Sglebius			if (precision != 0)
449290001Sglebius				while (precision > 0 && *cp != '\0' &&
450290001Sglebius				       size > 1) {
451290001Sglebius					*str++ = *cp++;
452290001Sglebius					size--;
453290001Sglebius					precision--;
454290001Sglebius				}
455290001Sglebius			else
456290001Sglebius				while (*cp != '\0' && size > 1) {
457290001Sglebius					*str++ = *cp++;
458290001Sglebius					size--;
459290001Sglebius				}
460290001Sglebius			while (pad > 0 && size > 1) {
461290001Sglebius				*str++ = ' ';
462290001Sglebius				size--;
463290001Sglebius				pad--;
464290001Sglebius			}
465290001Sglebius			break;
466290001Sglebius		case 'c':
467290001Sglebius			c = va_arg(ap, int);
468290001Sglebius			if (width > 0) {
469290001Sglebius				count += width;
470290001Sglebius				width--;
471290001Sglebius				if (left && size > 1) {
472290001Sglebius					*str++ = c;
473290001Sglebius					size--;
474290001Sglebius				}
475290001Sglebius				while (width-- > 0 && size > 1) {
476290001Sglebius					*str++ = ' ';
477290001Sglebius					size--;
478290001Sglebius				}
479290001Sglebius				if (!left && size > 1) {
480290001Sglebius					*str++ = c;
481290001Sglebius					size--;
482290001Sglebius				}
483290001Sglebius			} else {
484290001Sglebius				count++;
485290001Sglebius				if (size > 1) {
486290001Sglebius					*str++ = c;
487290001Sglebius					size--;
488290001Sglebius				}
489290001Sglebius			}
490290001Sglebius			break;
491290001Sglebius		case 'p':
492290001Sglebius			v = va_arg(ap, void *);
493290001Sglebius			sprintf(buf, "%p", v);
494290001Sglebius			length = strlen(buf);
495290001Sglebius			if (precision > length)
496290001Sglebius				zeropad = precision - length;
497290001Sglebius			if (width > 0) {
498290001Sglebius				pad = width - length - zeropad;
499290001Sglebius				if (pad < 0)
500290001Sglebius					pad = 0;
501290001Sglebius			}
502290001Sglebius			count += length + pad + zeropad;
503290001Sglebius			if (!left)
504290001Sglebius				while (pad > 0 && size > 1) {
505290001Sglebius					*str++ = ' ';
506290001Sglebius					size--;
507290001Sglebius					pad--;
508290001Sglebius				}
509290001Sglebius			cp = buf;
510290001Sglebius			if (zeropad > 0 && buf[0] == '0' &&
511290001Sglebius			    (buf[1] == 'x' || buf[1] == 'X')) {
512290001Sglebius				if (size > 1) {
513290001Sglebius					*str++ = *cp++;
514290001Sglebius					size--;
515290001Sglebius				}
516290001Sglebius				if (size > 1) {
517290001Sglebius					*str++ = *cp++;
518290001Sglebius					size--;
519290001Sglebius				}
520290001Sglebius				while (zeropad > 0 && size > 1) {
521290001Sglebius					*str++ = '0';
522290001Sglebius					size--;
523290001Sglebius					zeropad--;
524290001Sglebius				}
525290001Sglebius			}
526290001Sglebius			while (*cp != '\0' && size > 1) {
527290001Sglebius				*str++ = *cp++;
528290001Sglebius				size--;
529290001Sglebius			}
530290001Sglebius			while (pad > 0 && size > 1) {
531290001Sglebius				*str++ = ' ';
532290001Sglebius				size--;
533290001Sglebius				pad--;
534290001Sglebius			}
535290001Sglebius			break;
536290001Sglebius		case 'D':	/*deprecated*/
537290001Sglebius			INSIST("use %ld instead of %D" == NULL);
538290001Sglebius		case 'O':	/*deprecated*/
539290001Sglebius			INSIST("use %lo instead of %O" == NULL);
540290001Sglebius		case 'U':	/*deprecated*/
541290001Sglebius			INSIST("use %lu instead of %U" == NULL);
542290001Sglebius
543290001Sglebius		case 'L':
544290001Sglebius#ifdef HAVE_LONG_DOUBLE
545290001Sglebius			l = 1;
546290001Sglebius#else
547290001Sglebius			INSIST("long doubles are not supported" == NULL);
548290001Sglebius#endif
549290001Sglebius			/*FALLTHROUGH*/
550290001Sglebius		case 'e':
551290001Sglebius		case 'E':
552290001Sglebius		case 'f':
553290001Sglebius		case 'g':
554290001Sglebius		case 'G':
555290001Sglebius			if (!dot)
556290001Sglebius				precision = 6;
557290001Sglebius			/*
558290001Sglebius			 * IEEE floating point.
559290001Sglebius			 * MIN 2.2250738585072014E-308
560290001Sglebius			 * MAX 1.7976931348623157E+308
561290001Sglebius			 * VAX floating point has a smaller range than IEEE.
562290001Sglebius			 *
563290001Sglebius			 * precisions > 324 don't make much sense.
564290001Sglebius			 * if we cap the precision at 512 we will not
565290001Sglebius			 * overflow buf.
566290001Sglebius			 */
567290001Sglebius			if (precision > 512)
568290001Sglebius				precision = 512;
569290001Sglebius			sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "",
570290001Sglebius				plus ? "+" : space ? " " : "",
571290001Sglebius				precision, l ? "L" : "", *format);
572290001Sglebius			switch (*format) {
573290001Sglebius			case 'e':
574290001Sglebius			case 'E':
575290001Sglebius			case 'f':
576290001Sglebius			case 'g':
577290001Sglebius			case 'G':
578290001Sglebius#ifdef HAVE_LONG_DOUBLE
579290001Sglebius				if (l) {
580290001Sglebius					ldbl = va_arg(ap, long double);
581290001Sglebius					sprintf(buf, fmt, ldbl);
582290001Sglebius				} else
583290001Sglebius#endif
584290001Sglebius				{
585290001Sglebius					dbl = va_arg(ap, double);
586290001Sglebius					sprintf(buf, fmt, dbl);
587290001Sglebius				}
588290001Sglebius				length = strlen(buf);
589290001Sglebius				if (width > 0) {
590290001Sglebius					pad = width - length;
591290001Sglebius					if (pad < 0)
592290001Sglebius						pad = 0;
593290001Sglebius				}
594290001Sglebius				count += length + pad;
595290001Sglebius				if (!left)
596290001Sglebius					while (pad > 0 && size > 1) {
597290001Sglebius						*str++ = ' ';
598290001Sglebius						size--;
599290001Sglebius						pad--;
600290001Sglebius					}
601290001Sglebius				cp = buf;
602290001Sglebius				while (*cp != ' ' && size > 1) {
603290001Sglebius					*str++ = *cp++;
604290001Sglebius					size--;
605290001Sglebius				}
606290001Sglebius				while (pad > 0 && size > 1) {
607290001Sglebius					*str++ = ' ';
608290001Sglebius					size--;
609290001Sglebius					pad--;
610290001Sglebius				}
611290001Sglebius				break;
612290001Sglebius			default:
613290001Sglebius				continue;
614290001Sglebius			}
615290001Sglebius			break;
616290001Sglebius		default:
617290001Sglebius			continue;
618290001Sglebius		}
619290001Sglebius		format++;
620290001Sglebius	}
621290001Sglebius	if (size > 0)
622290001Sglebius		*str = '\0';
623290001Sglebius	return (count);
624290001Sglebius}
625