xref: /aosp_15_r20/external/coreboot/payloads/libpayload/libc/printf.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*
2  *
3  * It has originally been taken from the HelenOS project
4  * (http://www.helenos.eu), and slightly modified for our purposes.
5  *
6  * Copyright (C) 2001-2004 Jakub Jermar
7  * Copyright (C) 2006 Josef Cejka
8  * Copyright (C) 2008 Uwe Hermann <[email protected]>
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * - Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * - Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in the
19  *   documentation and/or other materials provided with the distribution.
20  * - The name of the author may not be used to endorse or promote products
21  *   derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <libpayload.h>
36 #include <ctype.h>
37 
38 static struct _FILE {
39 } _stdout, _stdin, _stderr;
40 
41 FILE *stdout = &_stdout;
42 FILE *stdin = &_stdin;
43 FILE *stderr = &_stderr;
44 
45 /** Structure for specifying output methods for different printf clones. */
46 struct printf_spec {
47 	/* Output function, returns count of printed characters or EOF. */
48 	int (*write) (const char *, size_t, void *);
49 	/* Support data - output stream specification, its state, locks, ... */
50 	void *data;
51 };
52 
53 /** Show prefixes 0x or 0. */
54 #define __PRINTF_FLAG_PREFIX		0x00000001
55 /** Signed / unsigned number. */
56 #define __PRINTF_FLAG_SIGNED		0x00000002
57 /** Print leading zeroes. */
58 #define __PRINTF_FLAG_ZEROPADDED	0x00000004
59 /** Align to left. */
60 #define __PRINTF_FLAG_LEFTALIGNED	0x00000010
61 /** Always show + sign. */
62 #define __PRINTF_FLAG_SHOWPLUS		0x00000020
63 /** Print space instead of plus. */
64 #define __PRINTF_FLAG_SPACESIGN		0x00000040
65 /** Show big characters. */
66 #define __PRINTF_FLAG_BIGCHARS		0x00000080
67 /** Number has - sign. */
68 #define __PRINTF_FLAG_NEGATIVE		0x00000100
69 
70 /**
71  * Buffer big enough for 64-bit number printed in base 2, sign, and prefix.
72  * Add some more to support sane amounts of zero-padding.
73  */
74 #define PRINT_BUFFER_SIZE		(64 + 1 + 2 + 13)
75 
76 /** Enumeration of possible arguments types. */
77 typedef enum {
78 	PrintfQualifierByte = 0,
79 	PrintfQualifierShort,
80 	PrintfQualifierInt,
81 	PrintfQualifierLong,
82 	PrintfQualifierLongLong,
83 	PrintfQualifierPointer,
84 } qualifier_t;
85 
86 static const char digits_small[] = "0123456789abcdef";
87 static const char digits_big[] = "0123456789ABCDEF";
88 
89 /**
90  * Print one or more characters without adding newline.
91  *
92  * @param buf	Buffer of >= count bytesi size. NULL pointer is not allowed!
93  * @param count	Number of characters to print.
94  * @param ps	Output method and its data.
95  * @return	Number of characters printed.
96  */
printf_putnchars(const char * buf,size_t count,struct printf_spec * ps)97 static int printf_putnchars(const char *buf, size_t count,
98 			    struct printf_spec *ps)
99 {
100 	return ps->write(buf, count, ps->data);
101 }
102 
103 /**
104  * Print a string without adding a newline.
105  *
106  * @param str	String to print.
107  * @param ps	Write function specification and support data.
108  * @return	Number of characters printed.
109  */
printf_putstr(const char * str,struct printf_spec * ps)110 static inline int printf_putstr(const char *str, struct printf_spec *ps)
111 {
112 	return printf_putnchars(str, strlen(str), ps);
113 }
114 
115 /**
116  * Print one character.
117  *
118  * @param c	Character to be printed.
119  * @param ps	Output method.
120  * @return	Number of characters printed.
121  */
printf_putchar(int c,struct printf_spec * ps)122 static int printf_putchar(int c, struct printf_spec *ps)
123 {
124 	char ch = c;
125 
126 	return ps->write(&ch, 1, ps->data);
127 }
128 
129 /* Print spaces for padding. Ignores negative counts. */
print_spaces(int count,struct printf_spec * ps)130 static int print_spaces(int count, struct printf_spec *ps)
131 {
132 	int tmp, ret;
133 	char buffer[PRINT_BUFFER_SIZE];
134 
135 	if (count <= 0)
136 		return 0;
137 
138 	memset(buffer, ' ', MIN(PRINT_BUFFER_SIZE, count));
139 	for (tmp = count; tmp > PRINT_BUFFER_SIZE; tmp -= PRINT_BUFFER_SIZE)
140 		if ((ret = printf_putnchars(buffer, PRINT_BUFFER_SIZE, ps)) < 0)
141 			return ret;
142 
143 	if ((ret = printf_putnchars(buffer, tmp, ps)) < 0)
144 		return ret;
145 
146 	return count;
147 }
148 
149 /**
150  * Print one formatted character.
151  *
152  * @param c	Character to print.
153  * @param width	Width modifier.
154  * @param flags	Flags that change the way the character is printed.
155  * @param ps	Output methods spec for different printf clones.
156  * @return	Number of characters printed, negative value on failure.
157  */
print_char(char c,int width,uint64_t flags,struct printf_spec * ps)158 static int print_char(char c, int width, uint64_t flags, struct printf_spec *ps)
159 {
160 	int retval;
161 	int counter = 1;
162 
163 	if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
164 		if ((retval = print_spaces(width - 1, ps)) < 0)
165 			return retval;
166 		else
167 			counter += retval;
168 	}
169 
170 	if ((retval = printf_putchar(c, ps)) < 0)
171 		return retval;
172 
173 	if (flags & __PRINTF_FLAG_LEFTALIGNED) {
174 		if ((retval = print_spaces(width - 1, ps)) < 0)
175 			return retval;
176 		else
177 			counter += retval;
178 	}
179 
180 	return counter;
181 }
182 
183 /**
184  * Print string.
185  *
186  * @param s		String to be printed.
187  * @param width		Width modifier.
188  * @param precision	Precision modifier.
189  * @param flags		Flags that modify the way the string is printed.
190  * @param ps		Output methods spec for different printf clones.
191  * @return		Number of characters printed, negative value on	failure.
192  */
193 /** Structure for specifying output methods for different printf clones. */
print_string(char * s,int width,unsigned int precision,uint64_t flags,struct printf_spec * ps)194 static int print_string(char *s, int width, unsigned int precision,
195 			uint64_t flags, struct printf_spec *ps)
196 {
197 	int counter = 0, retval;
198 	size_t size;
199 
200 	if (s == NULL)
201 		return printf_putstr("(NULL)", ps);
202 	size = strlen(s);
203 	/* Print leading spaces. */
204 	if (precision == 0)
205 		precision = size;
206 	width -= precision;
207 
208 	if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
209 		if ((retval = print_spaces(width, ps)) < 0)
210 			return retval;
211 		else
212 			counter += retval;
213 	}
214 
215 	if ((retval = printf_putnchars(s, MIN(size, precision), ps)) < 0)
216 		return retval;
217 	counter += retval;
218 
219 	if (flags & __PRINTF_FLAG_LEFTALIGNED) {
220 		if ((retval = print_spaces(width, ps)) < 0)
221 			return retval;
222 		else
223 			counter += retval;
224 	}
225 
226 	return counter;
227 }
228 
229 /**
230  * Print a number in a given base.
231  *
232  * Print significant digits of a number in given base.
233  *
234  * @param num		Number to print.
235  * @param width		Width modifier.
236  * @param precision	Precision modifier.
237  * @param base		Base to print the number in (must be between 2 and 16).
238  * @param flags		Flags that modify the way the number is printed.
239  * @param ps		Output methods spec for different printf clones.
240  * @return		Number of characters printed.
241  */
print_number(uint64_t num,int width,int precision,int base,uint64_t flags,struct printf_spec * ps)242 static int print_number(uint64_t num, int width, int precision, int base,
243 			uint64_t flags, struct printf_spec *ps)
244 {
245 	const char *digits = digits_small;
246 	char d[PRINT_BUFFER_SIZE];
247 	char *ptr = &d[PRINT_BUFFER_SIZE];
248 	int size = 0;			/* Size of the string in ptr */
249 	int counter = 0;		/* Amount of actually printed bytes. */
250 	char sgn;
251 	int retval;
252 
253 	if (flags & __PRINTF_FLAG_BIGCHARS)
254 		digits = digits_big;
255 
256 	if (num == 0) {
257 		*--ptr = '0';
258 		size++;
259 	} else {
260 		do {
261 			*--ptr = digits[num % base];
262 			size++;
263 		} while (num /= base);
264 	}
265 
266 	/* Both precision and LEFTALIGNED overrule ZEROPADDED. */
267 	if ((flags & __PRINTF_FLAG_LEFTALIGNED) || precision)
268 		flags &= ~__PRINTF_FLAG_ZEROPADDED;
269 
270 	/* Fix precision now since it doesn't count prefixes/signs. */
271 	precision -= size;
272 
273 	/* Reserve size for prefixes/signs before filling up padding. */
274 	sgn = 0;
275 	if (flags & __PRINTF_FLAG_SIGNED) {
276 		if (flags & __PRINTF_FLAG_NEGATIVE) {
277 			sgn = '-';
278 			size++;
279 		} else if (flags & __PRINTF_FLAG_SHOWPLUS) {
280 			sgn = '+';
281 			size++;
282 		} else if (flags & __PRINTF_FLAG_SPACESIGN) {
283 			sgn = ' ';
284 			size++;
285 		}
286 	}
287 	if (flags & __PRINTF_FLAG_PREFIX) {
288 		switch (base) {
289 		case 2:	/* Binary formating is not standard, but useful. */
290 			size += 2;
291 			break;
292 		case 8:
293 			size++;
294 			break;
295 		case 16:
296 			size += 2;
297 			break;
298 		}
299 	}
300 
301 	/* If this is still set we didn't have a precision, so repurpose it */
302 	if (flags & __PRINTF_FLAG_ZEROPADDED)
303 		precision = width - size;
304 
305 	/* Pad smaller numbers with 0 (larger numbers lead to precision < 0). */
306 	if (precision > 0) {
307 		precision = MIN(precision, PRINT_BUFFER_SIZE - size);
308 		ptr -= precision;
309 		size += precision;
310 		memset(ptr, '0', precision);
311 	}
312 
313 	/* Add sign and prefix (we adjusted size for this beforehand). */
314 	if (flags & __PRINTF_FLAG_PREFIX) {
315 		switch (base) {
316 		case 2:	/* Binary formating is not standard, but useful. */
317 			*--ptr = (flags & __PRINTF_FLAG_BIGCHARS) ? 'B' : 'b';
318 			*--ptr = '0';
319 			break;
320 		case 8:
321 			*--ptr = '0';
322 			break;
323 		case 16:
324 			*--ptr = (flags & __PRINTF_FLAG_BIGCHARS) ? 'X' : 'x';
325 			*--ptr = '0';
326 			break;
327 		}
328 	}
329 	if (sgn)
330 		*--ptr = sgn;
331 
332 	/* Pad with spaces up to width, try to avoid extra putnchar if we can */
333 	width -= size;
334 	if (width > 0 && !(flags & __PRINTF_FLAG_LEFTALIGNED)) {
335 		int tmp = MIN(width, PRINT_BUFFER_SIZE - size);
336 		ptr -= tmp;
337 		size += tmp;
338 		memset(ptr, ' ', tmp);
339 		if ((retval = print_spaces(width - tmp, ps)) < 0)
340 			return retval;
341 		else
342 			counter += retval;
343 	}
344 
345 	/* Now print the whole thing at once. */
346 	if ((retval = printf_putnchars(ptr, size, ps)) < 0)
347 		return retval;
348 	counter += retval;
349 
350 	/* Edge case: left-aligned with width (should be rare). */
351 	if (flags & __PRINTF_FLAG_LEFTALIGNED) {
352 		if ((retval = print_spaces(width, ps)) < 0)
353 			return retval;
354 		else
355 			counter += retval;
356 	}
357 
358 	return counter;
359 }
360 
361 /**
362  * Print formatted string.
363  *
364  * Print string formatted according to the fmt parameter and variadic arguments.
365  * Each formatting directive must have the following form:
366  *
367  * 	\% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
368  *
369  * FLAGS:@n
370  * 	- "#"	Force to print prefix.For \%o conversion, the prefix is 0, for
371  *		\%x and \%X prefixes are 0x and	0X and for conversion \%b the
372  *		prefix is 0b.
373  *
374  * 	- "-"	Align to left.
375  *
376  * 	- "+"	Print positive sign just as negative.
377  *
378  * 	- " "	If the printed number is positive and "+" flag is not set,
379  *		print space in place of sign.
380  *
381  * 	- "0"	Print 0 as padding instead of spaces. Zeroes are placed between
382  *		sign and the rest of the number. This flag is ignored if "-"
383  *		flag is specified.
384  *
385  * WIDTH:@n
386  * 	- Specify the minimal width of a printed argument. If it is bigger,
387  *	width is ignored. If width is specified with a "*" character instead of
388  *	number, width is taken from parameter list. And integer parameter is
389  *	expected before parameter for processed conversion specification. If
390  *	this value is negative its absolute value is taken and the "-" flag is
391  *	set.
392  *
393  * PRECISION:@n
394  * 	- Value precision. For numbers it specifies minimum valid numbers.
395  *	Smaller numbers are printed with leading zeroes. Bigger numbers are not
396  *	affected. Strings with more than precision characters are cut off. Just
397  *	as with width, an "*" can be used used instead of a number. An integer
398  *	value is then expected in parameters. When both width and precision are
399  *	specified using "*", the first parameter is used for width and the
400  *	second one for precision.
401  *
402  * TYPE:@n
403  * 	- "hh"	Signed or unsigned char.@n
404  * 	- "h"	Signed or unsigned short.@n
405  * 	- ""	Signed or unsigned int (default value).@n
406  * 	- "l"	Signed or unsigned long int.@n
407  * 	- "ll"	Signed or unsigned long long int.@n
408  *
409  *
410  * CONVERSION:@n
411  * 	- %	Print percentile character itself.
412  *
413  * 	- c	Print single character.
414  *
415  * 	- s	Print zero terminated string. If a NULL value is passed as
416  *		value, "(NULL)" is printed instead.
417  *
418  * 	- P, p	Print value of a pointer. Void * value is expected and it is
419  *		printed in hexadecimal notation with prefix (as with \%#X / \%#x
420  *		for 32-bit or \%#X / \%#x for 64-bit long pointers).
421  *
422  * 	- b	Print value as unsigned binary number. Prefix is not printed by
423  *		default. (Nonstandard extension.)
424  *
425  * 	- o	Print value as unsigned octal number. Prefix is not printed by
426  *		default.
427  *
428  * 	- d, i	Print signed decimal number. There is no difference between d
429  *		and i conversion.
430  *
431  * 	- u	Print unsigned decimal number.
432  *
433  * 	- X, x	Print hexadecimal number with upper- or lower-case. Prefix is
434  *		not printed by default.
435  *
436  * All other characters from fmt except the formatting directives are printed in
437  * verbatim.
438  *
439  * @param fmt	Formatting NULL terminated string.
440  * @param ps	TODO.
441  * @param ap	TODO.
442  * @return	Number of characters printed, negative value on failure.
443  */
printf_core(const char * fmt,struct printf_spec * ps,va_list ap)444 static int printf_core(const char *fmt, struct printf_spec *ps, va_list ap)
445 {
446 	int i = 0;		/* Index of the currently processed char from fmt */
447 	int j = 0;		/* Index to the first not printed nonformating character */
448 	int end;
449 	int counter;		/* Counter of printed characters */
450 	int retval;		/* Used to store return values from called functions */
451 	char c;
452 	qualifier_t qualifier;	/* Type of argument */
453 	int base;		/* Base in which a numeric parameter will be printed */
454 	uint64_t number;	/* Argument value */
455 	size_t size;		/* Byte size of integer parameter */
456 	int width, precision;
457 	uint64_t flags;
458 
459 	counter = 0;
460 
461 	while ((c = fmt[i])) {
462 		/* Control character. */
463 		if (c == '%') {
464 			/* Print common characters if any processed. */
465 			if (i > j) {
466 				if ((retval = printf_putnchars(&fmt[j],
467 				    (size_t) (i - j), ps)) < 0)
468 				    	return retval;
469 				counter += retval;
470 			}
471 
472 			j = i;
473 			/* Parse modifiers. */
474 			flags = 0;
475 			end = 0;
476 
477 			do {
478 				++i;
479 				switch (c = fmt[i]) {
480 				case '#':
481 					flags |= __PRINTF_FLAG_PREFIX;
482 					break;
483 				case '-':
484 					flags |= __PRINTF_FLAG_LEFTALIGNED;
485 					break;
486 				case '+':
487 					flags |= __PRINTF_FLAG_SHOWPLUS;
488 					break;
489 				case ' ':
490 					flags |= __PRINTF_FLAG_SPACESIGN;
491 					break;
492 				case '0':
493 					flags |= __PRINTF_FLAG_ZEROPADDED;
494 					break;
495 				default:
496 					end = 1;
497 				};
498 
499 			} while (end == 0);
500 
501 			/* Width & '*' operator. */
502 			width = 0;
503 			if (isdigit(fmt[i])) {
504 				while (isdigit(fmt[i])) {
505 					width *= 10;
506 					width += fmt[i++] - '0';
507 				}
508 			} else if (fmt[i] == '*') {
509 				/* Get width value from argument list. */
510 				i++;
511 				width = (int)va_arg(ap, int);
512 				if (width < 0) {
513 					/* Negative width sets '-' flag. */
514 					width *= -1;
515 					flags |= __PRINTF_FLAG_LEFTALIGNED;
516 				}
517 			}
518 
519 			/* Precision and '*' operator. */
520 			precision = 0;
521 			if (fmt[i] == '.') {
522 				++i;
523 				if (isdigit(fmt[i])) {
524 					while (isdigit(fmt[i])) {
525 						precision *= 10;
526 						precision += fmt[i++] - '0';
527 					}
528 				} else if (fmt[i] == '*') {
529 					/* Get precision from argument list. */
530 					i++;
531 					precision = (int)va_arg(ap, int);
532 					/* Ignore negative precision. */
533 					if (precision < 0)
534 						precision = 0;
535 				}
536 			}
537 
538 			switch (fmt[i++]) {
539 			/** @todo unimplemented qualifiers:
540 			 * t ptrdiff_t - ISO C 99
541 			 */
542 			case 'h':	/* char or short */
543 				qualifier = PrintfQualifierShort;
544 				if (fmt[i] == 'h') {
545 					i++;
546 					qualifier = PrintfQualifierByte;
547 				}
548 				break;
549 			case 'z':	/* size_t or ssize_t */
550 				qualifier = PrintfQualifierLong;
551 				break;
552 			case 'l':	/* long or long long */
553 				qualifier = PrintfQualifierLong;
554 				if (fmt[i] == 'l') {
555 					i++;
556 					qualifier = PrintfQualifierLongLong;
557 				}
558 				break;
559 			default:
560 				/* default type */
561 				qualifier = PrintfQualifierInt;
562 				--i;
563 			}
564 
565 			base = 10;
566 
567 			switch (c = fmt[i]) {
568 			/* String and character conversions */
569 			case 's':
570 				if ((retval = print_string(va_arg(ap, char *),
571 				    width, precision, flags, ps)) < 0)
572 				    	return retval;
573 				counter += retval;
574 				j = i + 1;
575 				goto next_char;
576 			case 'c':
577 				c = va_arg(ap, unsigned int);
578 				if ((retval = print_char(c, width, flags, ps)) < 0)
579 					return retval;
580 				counter += retval;
581 				j = i + 1;
582 				goto next_char;
583 
584 			/* Integer values */
585 			case 'P':	/* pointer */
586 				flags |= __PRINTF_FLAG_BIGCHARS;
587 				__fallthrough;
588 			case 'p':
589 				flags |= __PRINTF_FLAG_PREFIX;
590 				base = 16;
591 				qualifier = PrintfQualifierPointer;
592 				break;
593 			case 'b':
594 				base = 2;
595 				break;
596 			case 'o':
597 				base = 8;
598 				break;
599 			case 'd':
600 			case 'i':
601 				flags |= __PRINTF_FLAG_SIGNED;
602 				break;
603 			case 'u':
604 				break;
605 			case 'X':
606 				flags |= __PRINTF_FLAG_BIGCHARS;
607 				__fallthrough;
608 			case 'x':
609 				base = 16;
610 				break;
611 			case '%': /* percentile itself */
612 				j = i;
613 				goto next_char;
614 			default: /* Bad formatting */
615 				/*
616 				 * Unknown format. Now, j is the index of '%'
617 				 * so we will print whole bad format sequence.
618 				 */
619 				goto next_char;
620 			}
621 
622 			/* Print integers. */
623 			/* Print number. */
624 			switch (qualifier) {
625 			case PrintfQualifierByte:
626 				size = sizeof(unsigned char);
627 				number = (uint64_t) va_arg(ap, unsigned int);
628 				break;
629 			case PrintfQualifierShort:
630 				size = sizeof(unsigned short);
631 				number = (uint64_t) va_arg(ap, unsigned int);
632 				break;
633 			case PrintfQualifierInt:
634 				size = sizeof(unsigned int);
635 				number = (uint64_t) va_arg(ap, unsigned int);
636 				break;
637 			case PrintfQualifierLong:
638 				size = sizeof(unsigned long);
639 				number = (uint64_t) va_arg(ap, unsigned long);
640 				break;
641 			case PrintfQualifierLongLong:
642 				size = sizeof(unsigned long long);
643 				number = (uint64_t) va_arg(ap, unsigned long long);
644 				break;
645 			case PrintfQualifierPointer:
646 				size = sizeof(void *);
647 				number = (uint64_t) (unsigned long)va_arg(ap, void *);
648 				break;
649 			}
650 
651 			if (flags & __PRINTF_FLAG_SIGNED) {
652 				if (number & (0x1ULL << (size * 8 - 1))) {
653 					flags |= __PRINTF_FLAG_NEGATIVE;
654 
655 					if (size == sizeof(uint64_t)) {
656 						number = -((int64_t) number);
657 					} else {
658 						number = ~number;
659 						number &= ~(0xFFFFFFFFFFFFFFFFll << (size * 8));
660 						number++;
661 					}
662 				}
663 			}
664 
665 			if ((retval = print_number(number, width, precision,
666 						   base, flags, ps)) < 0)
667 				return retval;
668 
669 			counter += retval;
670 			j = i + 1;
671 		}
672 next_char:
673 		++i;
674 	}
675 
676 	if (i > j) {
677 		if ((retval = printf_putnchars(&fmt[j],
678 		    (u64) (i - j), ps)) < 0)
679 		    	return retval;
680 		counter += retval;
681 	}
682 
683 	return counter;
684 }
685 
snprintf(char * str,size_t size,const char * fmt,...)686 int snprintf(char *str, size_t size, const char *fmt, ...)
687 {
688 	int ret;
689 	va_list args;
690 
691 	va_start(args, fmt);
692 	ret = vsnprintf(str, size, fmt, args);
693 	va_end(args);
694 
695 	return ret;
696 }
697 
sprintf(char * str,const char * fmt,...)698 int sprintf(char *str, const char *fmt, ...)
699 {
700 	int ret;
701 	va_list args;
702 
703 	va_start(args, fmt);
704 	ret = vsprintf(str, fmt, args);
705 	va_end(args);
706 
707 	return ret;
708 }
709 
fprintf(FILE * file,const char * fmt,...)710 int fprintf(FILE *file, const char *fmt, ...)
711 {
712 	int ret;
713 	if ((file == stdout) || (file == stderr)) {
714 		va_list args;
715 		va_start(args, fmt);
716 		ret = vprintf(fmt, args);
717 		va_end(args);
718 
719 		return ret;
720 	}
721 	return -1;
722 }
723 
724 struct vsnprintf_data {
725 	size_t size;		/* Total space for string */
726 	size_t len;		/* Count of currently used characters */
727 	char *string;		/* Destination string */
728 };
729 
730 /**
731  * Write string to given buffer.
732  *
733  * Write at most data->size characters including trailing zero. According to
734  * C99, snprintf() has to return number of characters that would have been
735  * written if enough space had been available. Hence the return value is not
736  * number of really printed characters but size of the input string.
737  * Number of really used characters is stored in data->len.
738  *
739  * @param str	Source string to print.
740  * @param count	Size of source string.
741  * @param _data	Structure with destination string, counter of used space
742  *              and total string size.
743  * @return Number of characters to print (not characters really printed!).
744  */
vsnprintf_write(const char * str,size_t count,void * _data)745 static int vsnprintf_write(const char *str, size_t count, void *_data)
746 {
747 	struct vsnprintf_data *data = _data;
748 	size_t i;
749 
750 	i = data->size - data->len;
751 	if (i == 0)
752 		return count;
753 
754 	/* We have only one free byte left in buffer => write trailing zero. */
755 	if (i == 1) {
756 		data->string[data->size - 1] = 0;
757 		data->len = data->size;
758 		return count;
759 	}
760 
761 	/*
762 	 * We have not enough space for whole string with the trailing
763 	 * zero => print only a part of string.
764 	 */
765 	if (i <= count) {
766 		memcpy((void *)(data->string + data->len), (void *)str, i - 1);
767 		data->string[data->size - 1] = 0;
768 		data->len = data->size;
769 		return count;
770 	}
771 
772 	/* Buffer is big enough to print whole string. */
773 	memcpy((void *)(data->string + data->len), (void *)str, count);
774 	data->len += count;
775 	/*
776 	 * Put trailing zero at end, but not count it into data->len so
777 	 * it could be rewritten next time.
778 	 */
779 	data->string[data->len] = 0;
780 
781 	return count;
782 }
783 
vsnprintf(char * str,size_t size,const char * fmt,va_list ap)784 int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
785 {
786 	struct vsnprintf_data data = { size, 0, str };
787 	struct printf_spec ps = { vsnprintf_write, &data };
788 
789 	/* Print 0 at end of string - fix case that nothing will be printed. */
790 	if (size > 0)
791 		str[0] = 0;
792 
793 	/* vsnprintf_write() ensures that str will be terminated by zero. */
794 	return printf_core(fmt, &ps, ap);
795 }
796 
vsprintf(char * str,const char * fmt,va_list ap)797 int vsprintf(char *str, const char *fmt, va_list ap)
798 {
799 	return vsnprintf(str, (size_t) - 1, fmt, ap);
800 }
801 
printf(const char * fmt,...)802 int printf(const char *fmt, ...)
803 {
804 	int ret;
805 	va_list args;
806 
807 	va_start(args, fmt);
808 	ret = vprintf(fmt, args);
809 	va_end(args);
810 
811 	return ret;
812 }
813 
vprintf_write(const char * str,size_t count,void * unused)814 static int vprintf_write(const char *str, size_t count, void *unused)
815 {
816 	console_write(str, count);
817 	return count;
818 }
819 
vprintf(const char * fmt,va_list ap)820 int vprintf(const char *fmt, va_list ap)
821 {
822 	struct printf_spec ps = { vprintf_write, NULL };
823 
824 	return printf_core(fmt, &ps, ap);
825 }
826