xref: /haiku/src/system/kernel/lib/kernel_vsprintf.cpp (revision 3ce26345338e484601eb0a6598414d22cb73c9cc)
1bd185b41SIngo Weinhold /*
2*3ce26345SIngo Weinhold  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3bd185b41SIngo Weinhold  * Copyright 2003-2008, Axel Dörfler. All rights reserved.
4bd185b41SIngo Weinhold  * Distributed under the terms of the MIT license.
5bd185b41SIngo Weinhold  *
6bd185b41SIngo Weinhold  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
7bd185b41SIngo Weinhold  * Distributed under the terms of the NewOS License.
8bd185b41SIngo Weinhold  */
9bd185b41SIngo Weinhold 
10bd185b41SIngo Weinhold 
11bd185b41SIngo Weinhold #include <SupportDefs.h>
12bd185b41SIngo Weinhold 
13bd185b41SIngo Weinhold #include <ctype.h>
14*3ce26345SIngo Weinhold #include <stdarg.h>
15bd185b41SIngo Weinhold #include <stdio.h>
16*3ce26345SIngo Weinhold #include <string.h>
17*3ce26345SIngo Weinhold 
18*3ce26345SIngo Weinhold #include <algorithm>
19bd185b41SIngo Weinhold 
20bd185b41SIngo Weinhold 
21bd185b41SIngo Weinhold #define ZEROPAD	1		/* pad with zero */
22bd185b41SIngo Weinhold #define SIGN	2		/* unsigned/signed long */
23bd185b41SIngo Weinhold #define PLUS	4		/* show plus */
24bd185b41SIngo Weinhold #define SPACE	8		/* space if plus */
25bd185b41SIngo Weinhold #define LEFT	16		/* left justified */
26bd185b41SIngo Weinhold #define SPECIAL	32		/* 0x */
27bd185b41SIngo Weinhold #define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
28bd185b41SIngo Weinhold 
29bd185b41SIngo Weinhold #define FLOATING_SUPPORT
30bd185b41SIngo Weinhold 
31bd185b41SIngo Weinhold 
32*3ce26345SIngo Weinhold struct Buffer {
33*3ce26345SIngo Weinhold 	Buffer(char* buffer, size_t size)
34*3ce26345SIngo Weinhold 		:
35*3ce26345SIngo Weinhold 		fCurrent(buffer),
36*3ce26345SIngo Weinhold 		fSize(size),
37*3ce26345SIngo Weinhold 		fBytesWritten(0)
38*3ce26345SIngo Weinhold 	{
39*3ce26345SIngo Weinhold 	}
40*3ce26345SIngo Weinhold 
41*3ce26345SIngo Weinhold 	size_t BytesWritten() const
42*3ce26345SIngo Weinhold 	{
43*3ce26345SIngo Weinhold 		return fBytesWritten;
44*3ce26345SIngo Weinhold 	}
45*3ce26345SIngo Weinhold 
46*3ce26345SIngo Weinhold 	void PutCharacter(char c)
47*3ce26345SIngo Weinhold 	{
48*3ce26345SIngo Weinhold 		if (fBytesWritten < fSize) {
49*3ce26345SIngo Weinhold 			*fCurrent = c;
50*3ce26345SIngo Weinhold 			fCurrent++;
51*3ce26345SIngo Weinhold 		}
52*3ce26345SIngo Weinhold 
53*3ce26345SIngo Weinhold 		fBytesWritten++;
54*3ce26345SIngo Weinhold 	}
55*3ce26345SIngo Weinhold 
56*3ce26345SIngo Weinhold 	void PutPadding(int32 count)
57*3ce26345SIngo Weinhold 	{
58*3ce26345SIngo Weinhold 		if (count <= 0)
59*3ce26345SIngo Weinhold 			return;
60*3ce26345SIngo Weinhold 
61*3ce26345SIngo Weinhold 		if (fBytesWritten < fSize) {
62*3ce26345SIngo Weinhold 			int32 toWrite = std::min(fSize - fBytesWritten, (size_t)count);
63*3ce26345SIngo Weinhold 			while (--toWrite >= 0)
64*3ce26345SIngo Weinhold 				*fCurrent++ = ' ';
65*3ce26345SIngo Weinhold 		}
66*3ce26345SIngo Weinhold 
67*3ce26345SIngo Weinhold 		fBytesWritten += count;
68*3ce26345SIngo Weinhold 	}
69*3ce26345SIngo Weinhold 
70*3ce26345SIngo Weinhold 	void PutString(const char *source, int32 length)
71*3ce26345SIngo Weinhold 	{
72*3ce26345SIngo Weinhold 		if (length <= 0)
73*3ce26345SIngo Weinhold 			return;
74*3ce26345SIngo Weinhold 
75*3ce26345SIngo Weinhold 		if (fBytesWritten < fSize) {
76*3ce26345SIngo Weinhold 			int32 toWrite = std::min(fSize - fBytesWritten, (size_t)length);
77*3ce26345SIngo Weinhold 			memcpy(fCurrent, source, toWrite);
78*3ce26345SIngo Weinhold 			fCurrent += toWrite;
79*3ce26345SIngo Weinhold 		}
80*3ce26345SIngo Weinhold 
81*3ce26345SIngo Weinhold 		fBytesWritten += length;
82*3ce26345SIngo Weinhold 	}
83*3ce26345SIngo Weinhold 
84*3ce26345SIngo Weinhold 	void NullTerminate()
85*3ce26345SIngo Weinhold 	{
86*3ce26345SIngo Weinhold 		if (fBytesWritten < fSize)
87*3ce26345SIngo Weinhold 			*fCurrent = '\0';
88*3ce26345SIngo Weinhold 		else if (fSize > 0)
89*3ce26345SIngo Weinhold 			fCurrent[-1] = '\0';
90*3ce26345SIngo Weinhold 	}
91*3ce26345SIngo Weinhold 
92*3ce26345SIngo Weinhold private:
93*3ce26345SIngo Weinhold 	char*	fCurrent;
94*3ce26345SIngo Weinhold 	size_t	fSize;
95*3ce26345SIngo Weinhold 	size_t	fBytesWritten;
96*3ce26345SIngo Weinhold };
97*3ce26345SIngo Weinhold 
98*3ce26345SIngo Weinhold 
99bd185b41SIngo Weinhold static int
100bd185b41SIngo Weinhold skip_atoi(const char **s)
101bd185b41SIngo Weinhold {
102bd185b41SIngo Weinhold 	int i = 0;
103bd185b41SIngo Weinhold 
104bd185b41SIngo Weinhold 	while (isdigit(**s))
105bd185b41SIngo Weinhold 		i = i*10 + *((*s)++) - '0';
106bd185b41SIngo Weinhold 
107bd185b41SIngo Weinhold 	return i;
108bd185b41SIngo Weinhold }
109bd185b41SIngo Weinhold 
110bd185b41SIngo Weinhold 
111bd185b41SIngo Weinhold static uint64
112bd185b41SIngo Weinhold do_div(uint64 *_number, uint32 base)
113bd185b41SIngo Weinhold {
114bd185b41SIngo Weinhold 	uint64 result = *_number % (uint64)base;
115bd185b41SIngo Weinhold 	*_number = *_number / (uint64)base;
116bd185b41SIngo Weinhold 
117bd185b41SIngo Weinhold 	return result;
118bd185b41SIngo Weinhold }
119bd185b41SIngo Weinhold 
120bd185b41SIngo Weinhold 
121bd185b41SIngo Weinhold static char
122bd185b41SIngo Weinhold sign_symbol(int flags, bool negative)
123bd185b41SIngo Weinhold {
124bd185b41SIngo Weinhold 	if ((flags & SIGN) == 0)
125bd185b41SIngo Weinhold 		return '\0';
126bd185b41SIngo Weinhold 
127bd185b41SIngo Weinhold 	if (negative)
128bd185b41SIngo Weinhold 		return '-';
129bd185b41SIngo Weinhold 	else if ((flags & PLUS) != 0)
130bd185b41SIngo Weinhold 		return '+';
131bd185b41SIngo Weinhold 	else if ((flags & SPACE) != 0)
132bd185b41SIngo Weinhold 		return ' ';
133bd185b41SIngo Weinhold 
134bd185b41SIngo Weinhold 	return '\0';
135bd185b41SIngo Weinhold }
136bd185b41SIngo Weinhold 
137bd185b41SIngo Weinhold 
138bd185b41SIngo Weinhold static void
139*3ce26345SIngo Weinhold number(Buffer& outBuffer, uint64 num, uint32 base, int size,
140bd185b41SIngo Weinhold 	int precision, int flags)
141bd185b41SIngo Weinhold {
142bd185b41SIngo Weinhold 	const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
143bd185b41SIngo Weinhold 	char c, sign, tmp[66];
144bd185b41SIngo Weinhold 	int i;
145bd185b41SIngo Weinhold 
146bd185b41SIngo Weinhold 	if (flags & LARGE)
147bd185b41SIngo Weinhold 		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
148bd185b41SIngo Weinhold 	if (flags & LEFT)
149bd185b41SIngo Weinhold 		flags &= ~ZEROPAD;
150bd185b41SIngo Weinhold 	if (base < 2 || base > 36)
151bd185b41SIngo Weinhold 		return;
152bd185b41SIngo Weinhold 
153bd185b41SIngo Weinhold 	c = (flags & ZEROPAD) ? '0' : ' ';
154bd185b41SIngo Weinhold 
155bd185b41SIngo Weinhold 	if (flags & SIGN) {
156bd185b41SIngo Weinhold 		sign = sign_symbol(flags, (int64)num < 0);
157bd185b41SIngo Weinhold 		if ((int64)num < 0)
158bd185b41SIngo Weinhold 			num = -(int64)num;
159bd185b41SIngo Weinhold 		if (sign)
160bd185b41SIngo Weinhold 			size--;
161bd185b41SIngo Weinhold 	} else
162bd185b41SIngo Weinhold 		sign = 0;
163bd185b41SIngo Weinhold 
164bd185b41SIngo Weinhold 	if ((flags & SPECIAL) != 0) {
165bd185b41SIngo Weinhold 		if (base == 16)
166bd185b41SIngo Weinhold 			size -= 2;
167bd185b41SIngo Weinhold 		else if (base == 8)
168bd185b41SIngo Weinhold 			size--;
169bd185b41SIngo Weinhold 	}
170bd185b41SIngo Weinhold 
171bd185b41SIngo Weinhold 	i = 0;
172bd185b41SIngo Weinhold 	if (num == 0)
173bd185b41SIngo Weinhold 		tmp[i++] = '0';
174bd185b41SIngo Weinhold 	else while (num != 0)
175bd185b41SIngo Weinhold 		tmp[i++] = digits[do_div(&num, base)];
176bd185b41SIngo Weinhold 
177bd185b41SIngo Weinhold 	if (i > precision)
178bd185b41SIngo Weinhold 		precision = i;
179bd185b41SIngo Weinhold 	size -= precision;
180bd185b41SIngo Weinhold 
181bd185b41SIngo Weinhold 	if (!(flags & (ZEROPAD + LEFT))) {
182*3ce26345SIngo Weinhold 		outBuffer.PutPadding(size);
183bd185b41SIngo Weinhold 		size = 0;
184bd185b41SIngo Weinhold 	}
185bd185b41SIngo Weinhold 	if (sign)
186*3ce26345SIngo Weinhold 		outBuffer.PutCharacter(sign);
187bd185b41SIngo Weinhold 
188bd185b41SIngo Weinhold 	if ((flags & SPECIAL) != 0) {
189bd185b41SIngo Weinhold 		if (base == 8)
190*3ce26345SIngo Weinhold 			outBuffer.PutCharacter('0');
191bd185b41SIngo Weinhold 		else if (base == 16) {
192*3ce26345SIngo Weinhold 			outBuffer.PutCharacter('0');
193*3ce26345SIngo Weinhold 			outBuffer.PutCharacter(digits[33]);
194bd185b41SIngo Weinhold 		}
195bd185b41SIngo Weinhold 	}
196bd185b41SIngo Weinhold 
197bd185b41SIngo Weinhold 	if (!(flags & LEFT)) {
198bd185b41SIngo Weinhold 		while (size-- > 0)
199*3ce26345SIngo Weinhold 			outBuffer.PutCharacter(c);
200bd185b41SIngo Weinhold 	}
201bd185b41SIngo Weinhold 	while (i < precision--)
202*3ce26345SIngo Weinhold 		outBuffer.PutCharacter('0');
203bd185b41SIngo Weinhold 	while (i-- > 0)
204*3ce26345SIngo Weinhold 		outBuffer.PutCharacter(tmp[i]);
205bd185b41SIngo Weinhold 
206*3ce26345SIngo Weinhold 	outBuffer.PutPadding(size);
207bd185b41SIngo Weinhold }
208bd185b41SIngo Weinhold 
209bd185b41SIngo Weinhold 
210bd185b41SIngo Weinhold #ifdef FLOATING_SUPPORT
211bd185b41SIngo Weinhold /*!
212bd185b41SIngo Weinhold 	This is a very basic floating point to string conversion routine.
213bd185b41SIngo Weinhold 	It prints up to 3 fraction digits, and doesn't support any precision arguments.
214bd185b41SIngo Weinhold 	It's just here for your convenience so that you can use it for debug output.
215bd185b41SIngo Weinhold */
216*3ce26345SIngo Weinhold static void
217*3ce26345SIngo Weinhold floating(Buffer& outBuffer, double value, int fieldWidth, int flags)
218bd185b41SIngo Weinhold {
219bd185b41SIngo Weinhold 	char buffer[66];
220bd185b41SIngo Weinhold 	uint64 fraction;
221bd185b41SIngo Weinhold 	uint64 integer;
222bd185b41SIngo Weinhold 	int32 length = 0;
223bd185b41SIngo Weinhold 	char sign;
224bd185b41SIngo Weinhold 
225bd185b41SIngo Weinhold 	sign = sign_symbol(flags, value < 0.0);
226bd185b41SIngo Weinhold 	if (value < 0.0)
227bd185b41SIngo Weinhold 		value = -value;
228bd185b41SIngo Weinhold 
229bd185b41SIngo Weinhold 	fraction = (uint64)(value * 1000) % 1000;
230bd185b41SIngo Weinhold 	integer = (uint64)value;
231bd185b41SIngo Weinhold 
232bd185b41SIngo Weinhold 	// put fraction part, if any
233bd185b41SIngo Weinhold 
234bd185b41SIngo Weinhold 	if (fraction != 0) {
235bd185b41SIngo Weinhold 		bool first = true;
236bd185b41SIngo Weinhold 		while (fraction != 0) {
237bd185b41SIngo Weinhold 			int digit = do_div(&fraction, 10);
238bd185b41SIngo Weinhold 			if (!first || digit > 0) {
239bd185b41SIngo Weinhold 				buffer[length++] = '0' + digit;
240bd185b41SIngo Weinhold 				first = false;
241bd185b41SIngo Weinhold 			}
242bd185b41SIngo Weinhold 		}
243bd185b41SIngo Weinhold 
244bd185b41SIngo Weinhold 		buffer[length++] = '.';
245bd185b41SIngo Weinhold 	}
246bd185b41SIngo Weinhold 
247bd185b41SIngo Weinhold 	// put integer part
248bd185b41SIngo Weinhold 
249*3ce26345SIngo Weinhold 	if (integer == 0) {
250bd185b41SIngo Weinhold 		buffer[length++] = '0';
251*3ce26345SIngo Weinhold 	} else {
252*3ce26345SIngo Weinhold 		while (integer != 0)
253bd185b41SIngo Weinhold 			buffer[length++] = '0' + do_div(&integer, 10);
254bd185b41SIngo Weinhold 	}
255bd185b41SIngo Weinhold 
256bd185b41SIngo Weinhold 	// write back to string
257bd185b41SIngo Weinhold 
258*3ce26345SIngo Weinhold 	if (!(flags & LEFT))
259*3ce26345SIngo Weinhold 		outBuffer.PutPadding(fieldWidth);
260bd185b41SIngo Weinhold 
261*3ce26345SIngo Weinhold 	if (sign)
262*3ce26345SIngo Weinhold 		outBuffer.PutCharacter(sign);
263bd185b41SIngo Weinhold 
264*3ce26345SIngo Weinhold 	while (length-- > 0)
265*3ce26345SIngo Weinhold 		outBuffer.PutCharacter(buffer[length]);
266bd185b41SIngo Weinhold 
267*3ce26345SIngo Weinhold 	if ((flags & LEFT) != 0)
268*3ce26345SIngo Weinhold 		outBuffer.PutPadding(fieldWidth);
269bd185b41SIngo Weinhold }
270bd185b41SIngo Weinhold #endif	// FLOATING_SUPPORT
271bd185b41SIngo Weinhold 
272bd185b41SIngo Weinhold 
273bd185b41SIngo Weinhold int
274bd185b41SIngo Weinhold vsnprintf(char *buffer, size_t bufferSize, const char *format, va_list args)
275bd185b41SIngo Weinhold {
276bd185b41SIngo Weinhold 	uint64 num;
277bd185b41SIngo Weinhold 	int base;
278bd185b41SIngo Weinhold 	int flags;			/* flags to number() */
279bd185b41SIngo Weinhold 	int fieldWidth;	/* width of output field */
280bd185b41SIngo Weinhold 	int precision;
281bd185b41SIngo Weinhold 		/* min. # of digits for integers; max number of chars for from string */
282bd185b41SIngo Weinhold 	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
283bd185b41SIngo Weinhold 
284*3ce26345SIngo Weinhold 	Buffer outBuffer(buffer, bufferSize);
285bd185b41SIngo Weinhold 
286*3ce26345SIngo Weinhold 	for (; format[0]; format++) {
287bd185b41SIngo Weinhold 		if (format[0] != '%') {
288*3ce26345SIngo Weinhold 			outBuffer.PutCharacter(format[0]);
289bd185b41SIngo Weinhold 			continue;
290bd185b41SIngo Weinhold 		}
291bd185b41SIngo Weinhold 
292bd185b41SIngo Weinhold 		/* process flags */
293bd185b41SIngo Weinhold 
294bd185b41SIngo Weinhold 		flags = 0;
295bd185b41SIngo Weinhold 
296bd185b41SIngo Weinhold 	repeat:
297bd185b41SIngo Weinhold 		format++;
298bd185b41SIngo Weinhold 			/* this also skips first '%' */
299bd185b41SIngo Weinhold 		switch (format[0]) {
300bd185b41SIngo Weinhold 			case '-': flags |= LEFT; goto repeat;
301bd185b41SIngo Weinhold 			case '+': flags |= PLUS; goto repeat;
302bd185b41SIngo Weinhold 			case ' ': flags |= SPACE; goto repeat;
303bd185b41SIngo Weinhold 			case '#': flags |= SPECIAL; goto repeat;
304bd185b41SIngo Weinhold 			case '0': flags |= ZEROPAD; goto repeat;
305bd185b41SIngo Weinhold 
306bd185b41SIngo Weinhold 			case '%':
307*3ce26345SIngo Weinhold 				outBuffer.PutCharacter(format[0]);
308bd185b41SIngo Weinhold 				continue;
309bd185b41SIngo Weinhold 		}
310bd185b41SIngo Weinhold 
311bd185b41SIngo Weinhold 		/* get field width */
312bd185b41SIngo Weinhold 
313bd185b41SIngo Weinhold 		fieldWidth = -1;
314bd185b41SIngo Weinhold 		if (isdigit(*format))
315bd185b41SIngo Weinhold 			fieldWidth = skip_atoi(&format);
316bd185b41SIngo Weinhold 		else if (format[0] == '*') {
317bd185b41SIngo Weinhold 			format++;
318bd185b41SIngo Weinhold 			/* it's the next argument */
319bd185b41SIngo Weinhold 			fieldWidth = va_arg(args, int);
320bd185b41SIngo Weinhold 			if (fieldWidth < 0) {
321bd185b41SIngo Weinhold 				fieldWidth = -fieldWidth;
322bd185b41SIngo Weinhold 				flags |= LEFT;
323bd185b41SIngo Weinhold 			}
324bd185b41SIngo Weinhold 		}
325bd185b41SIngo Weinhold 
326bd185b41SIngo Weinhold 		/* get the precision */
327bd185b41SIngo Weinhold 
328bd185b41SIngo Weinhold 		precision = -1;
329bd185b41SIngo Weinhold 		if (format[0] == '.') {
330bd185b41SIngo Weinhold 			format++;
331bd185b41SIngo Weinhold 			if (isdigit(*format))
332bd185b41SIngo Weinhold 				precision = skip_atoi(&format);
333bd185b41SIngo Weinhold 			else if (format[0] == '*') {
334bd185b41SIngo Weinhold 				format++;
335bd185b41SIngo Weinhold 				/* it's the next argument */
336bd185b41SIngo Weinhold 				precision = va_arg(args, int);
337bd185b41SIngo Weinhold 			}
338bd185b41SIngo Weinhold 			if (precision < 0)
339bd185b41SIngo Weinhold 				precision = 0;
340bd185b41SIngo Weinhold 		}
341bd185b41SIngo Weinhold 
342bd185b41SIngo Weinhold 		/* get the conversion qualifier */
343bd185b41SIngo Weinhold 
344bd185b41SIngo Weinhold 		qualifier = -1;
345bd185b41SIngo Weinhold 		if (format[0] == 'h' || format[0] == 'L') {
346bd185b41SIngo Weinhold 			qualifier = *format++;
347bd185b41SIngo Weinhold 		} else if (format[0] == 'l')  {
348bd185b41SIngo Weinhold 			format++;
349bd185b41SIngo Weinhold 			if (format[0] == 'l') {
350bd185b41SIngo Weinhold 				qualifier = 'L';
351bd185b41SIngo Weinhold 				format++;
352bd185b41SIngo Weinhold 			} else
353bd185b41SIngo Weinhold 				qualifier = 'l';
354bd185b41SIngo Weinhold 		}
355bd185b41SIngo Weinhold 
356bd185b41SIngo Weinhold 		/* default base */
357bd185b41SIngo Weinhold 		base = 10;
358bd185b41SIngo Weinhold 
359bd185b41SIngo Weinhold 		switch (format[0]) {
360bd185b41SIngo Weinhold 			case 'c':
361*3ce26345SIngo Weinhold 				if (!(flags & LEFT))
362*3ce26345SIngo Weinhold 					outBuffer.PutPadding(fieldWidth - 1);
363bd185b41SIngo Weinhold 
364*3ce26345SIngo Weinhold 				outBuffer.PutCharacter((char)va_arg(args, int));
365bd185b41SIngo Weinhold 
366*3ce26345SIngo Weinhold 				if ((flags & LEFT) != 0)
367*3ce26345SIngo Weinhold 					outBuffer.PutPadding(fieldWidth - 1);
368bd185b41SIngo Weinhold 				continue;
369bd185b41SIngo Weinhold 
370bd185b41SIngo Weinhold 			case 's':
371bd185b41SIngo Weinhold 			{
372bd185b41SIngo Weinhold 				const char *argument = va_arg(args, char *);
373bd185b41SIngo Weinhold 				int32 length;
374bd185b41SIngo Weinhold 
375bd185b41SIngo Weinhold 				if (argument == NULL)
376bd185b41SIngo Weinhold 					argument = "<NULL>";
377bd185b41SIngo Weinhold 
378bd185b41SIngo Weinhold 				length = strnlen(argument, precision);
379bd185b41SIngo Weinhold 				fieldWidth -= length;
380bd185b41SIngo Weinhold 
381*3ce26345SIngo Weinhold 				if (!(flags & LEFT))
382*3ce26345SIngo Weinhold 					outBuffer.PutPadding(fieldWidth);
383bd185b41SIngo Weinhold 
384*3ce26345SIngo Weinhold 				outBuffer.PutString(argument, length);
385bd185b41SIngo Weinhold 
386*3ce26345SIngo Weinhold 				if ((flags & LEFT) != 0)
387*3ce26345SIngo Weinhold 					outBuffer.PutPadding(fieldWidth);
388bd185b41SIngo Weinhold 				continue;
389bd185b41SIngo Weinhold 			}
390bd185b41SIngo Weinhold 
391bd185b41SIngo Weinhold #ifdef FLOATING_SUPPORT
392bd185b41SIngo Weinhold 			case 'f':
393bd185b41SIngo Weinhold 			case 'F':
394bd185b41SIngo Weinhold 			case 'g':
395bd185b41SIngo Weinhold 			case 'G':
396bd185b41SIngo Weinhold 			{
397bd185b41SIngo Weinhold 				double value = va_arg(args, double);
398*3ce26345SIngo Weinhold 				floating(outBuffer, value, fieldWidth, flags | SIGN);
399bd185b41SIngo Weinhold 				continue;
400bd185b41SIngo Weinhold 			}
401bd185b41SIngo Weinhold #endif	// FLOATING_SUPPORT
402bd185b41SIngo Weinhold 
403bd185b41SIngo Weinhold 			case 'p':
404bd185b41SIngo Weinhold 				if (fieldWidth == -1) {
405bd185b41SIngo Weinhold 					fieldWidth = 2*sizeof(void *);
406bd185b41SIngo Weinhold 					flags |= ZEROPAD;
407bd185b41SIngo Weinhold 				}
408bd185b41SIngo Weinhold 
409*3ce26345SIngo Weinhold 				outBuffer.PutString("0x", 2);
410*3ce26345SIngo Weinhold 				number(outBuffer, (uint32)va_arg(args, void *), 16, fieldWidth,
411*3ce26345SIngo Weinhold 					precision, flags);
412bd185b41SIngo Weinhold 				continue;
413bd185b41SIngo Weinhold 
414bd185b41SIngo Weinhold 			case 'n':
415bd185b41SIngo Weinhold 				if (qualifier == 'l') {
416bd185b41SIngo Weinhold 					long *ip = va_arg(args, long *);
417*3ce26345SIngo Weinhold 					*ip = outBuffer.BytesWritten();
418bd185b41SIngo Weinhold 				} else {
419bd185b41SIngo Weinhold 					int *ip = va_arg(args, int *);
420*3ce26345SIngo Weinhold 					*ip = outBuffer.BytesWritten();
421bd185b41SIngo Weinhold 				}
422bd185b41SIngo Weinhold 				continue;
423bd185b41SIngo Weinhold 
424bd185b41SIngo Weinhold 			/* integer number formats - set up the flags and "break" */
425bd185b41SIngo Weinhold 			case 'o':
426bd185b41SIngo Weinhold 				base = 8;
427bd185b41SIngo Weinhold 				break;
428bd185b41SIngo Weinhold 
429bd185b41SIngo Weinhold 			case 'X':
430bd185b41SIngo Weinhold 				flags |= LARGE;
431bd185b41SIngo Weinhold 			case 'x':
432bd185b41SIngo Weinhold 				base = 16;
433bd185b41SIngo Weinhold 				break;
434bd185b41SIngo Weinhold 
435bd185b41SIngo Weinhold 			case 'd':
436bd185b41SIngo Weinhold 			case 'i':
437bd185b41SIngo Weinhold 				flags |= SIGN;
438bd185b41SIngo Weinhold 			case 'u':
439bd185b41SIngo Weinhold 				break;
440bd185b41SIngo Weinhold 
441bd185b41SIngo Weinhold 			default:
442bd185b41SIngo Weinhold 				if (format[0] != '%')
443*3ce26345SIngo Weinhold 					outBuffer.PutCharacter('%');
444bd185b41SIngo Weinhold 
445bd185b41SIngo Weinhold 				if (!format[0])
446bd185b41SIngo Weinhold 					goto out;
447bd185b41SIngo Weinhold 
448*3ce26345SIngo Weinhold 				outBuffer.PutCharacter(format[0]);
449bd185b41SIngo Weinhold 				continue;
450bd185b41SIngo Weinhold 		}
451bd185b41SIngo Weinhold 
452bd185b41SIngo Weinhold 		if (qualifier == 'L')
453bd185b41SIngo Weinhold 			num = va_arg(args, uint64);
454bd185b41SIngo Weinhold 		else if (qualifier == 'l') {
455bd185b41SIngo Weinhold 			num = va_arg(args, uint32);
456bd185b41SIngo Weinhold 			if (flags & SIGN)
457bd185b41SIngo Weinhold 				num = (long)num;
458bd185b41SIngo Weinhold 		} else if (qualifier == 'h') {
459bd185b41SIngo Weinhold 			num = (unsigned short)va_arg(args, int);
460bd185b41SIngo Weinhold 			if (flags & SIGN)
461bd185b41SIngo Weinhold 				num = (short)num;
462bd185b41SIngo Weinhold 		} else if (flags & SIGN)
463bd185b41SIngo Weinhold 			num = va_arg(args, int);
464bd185b41SIngo Weinhold 		else
465bd185b41SIngo Weinhold 			num = va_arg(args, unsigned int);
466bd185b41SIngo Weinhold 
467*3ce26345SIngo Weinhold 		number(outBuffer, num, base, fieldWidth, precision, flags);
468bd185b41SIngo Weinhold 	}
469bd185b41SIngo Weinhold 
470bd185b41SIngo Weinhold out:
471*3ce26345SIngo Weinhold 	outBuffer.NullTerminate();
472*3ce26345SIngo Weinhold 	return outBuffer.BytesWritten();
473bd185b41SIngo Weinhold }
474bd185b41SIngo Weinhold 
475bd185b41SIngo Weinhold 
476bd185b41SIngo Weinhold int
477bd185b41SIngo Weinhold vsprintf(char *buffer, const char *format, va_list args)
478bd185b41SIngo Weinhold {
479bd185b41SIngo Weinhold 	return vsnprintf(buffer, ~0UL, format, args);
480bd185b41SIngo Weinhold }
481bd185b41SIngo Weinhold 
482bd185b41SIngo Weinhold 
483bd185b41SIngo Weinhold int
484bd185b41SIngo Weinhold snprintf(char *buffer, size_t bufferSize, const char *format, ...)
485bd185b41SIngo Weinhold {
486bd185b41SIngo Weinhold 	va_list args;
487bd185b41SIngo Weinhold 	int i;
488bd185b41SIngo Weinhold 
489bd185b41SIngo Weinhold 	va_start(args, format);
490bd185b41SIngo Weinhold 	i = vsnprintf(buffer, bufferSize, format, args);
491bd185b41SIngo Weinhold 	va_end(args);
492bd185b41SIngo Weinhold 
493bd185b41SIngo Weinhold 	return i;
494bd185b41SIngo Weinhold }
495bd185b41SIngo Weinhold 
496bd185b41SIngo Weinhold 
497bd185b41SIngo Weinhold int
498bd185b41SIngo Weinhold sprintf(char *buffer, const char *format, ...)
499bd185b41SIngo Weinhold {
500bd185b41SIngo Weinhold 	va_list args;
501bd185b41SIngo Weinhold 	int i;
502bd185b41SIngo Weinhold 
503bd185b41SIngo Weinhold 	va_start(args, format);
504bd185b41SIngo Weinhold 	i = vsnprintf(buffer, ~0UL, format, args);
505bd185b41SIngo Weinhold 	va_end(args);
506bd185b41SIngo Weinhold 
507bd185b41SIngo Weinhold 	return i;
508bd185b41SIngo Weinhold }
509bd185b41SIngo Weinhold 
510