• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <debug.h>
8 #include <platform.h>
9 #include <stdarg.h>
10 
unsigned_dec_print(char ** s,size_t n,size_t * chars_printed,unsigned int unum)11 static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed,
12 			       unsigned int unum)
13 {
14 	/* Enough for a 32-bit unsigned decimal integer (4294967295). */
15 	unsigned char num_buf[10];
16 	int i = 0, rem;
17 
18 	do {
19 		rem = unum % 10;
20 		num_buf[i++] = '0' + rem;
21 	} while (unum /= 10);
22 
23 	while (--i >= 0) {
24 		if (*chars_printed < n)
25 			*(*s)++ = num_buf[i];
26 		(*chars_printed)++;
27 	}
28 }
29 
30 /*******************************************************************
31  * Reduced snprintf to be used for Trusted firmware.
32  * The following type specifiers are supported:
33  *
34  * %d or %i - signed decimal format
35  * %u - unsigned decimal format
36  *
37  * The function panics on all other formats specifiers.
38  *
39  * It returns the number of characters that would be written if the
40  * buffer was big enough. If it returns a value lower than n, the
41  * whole string has been written.
42  *******************************************************************/
tf_snprintf(char * s,size_t n,const char * fmt,...)43 int tf_snprintf(char *s, size_t n, const char *fmt, ...)
44 {
45 	va_list args;
46 	int num;
47 	unsigned int unum;
48 	size_t chars_printed = 0;
49 
50 	if (n == 1) {
51 		/* Buffer is too small to actually write anything else. */
52 		*s = '\0';
53 		n = 0;
54 	} else if (n >= 2) {
55 		/* Reserve space for the terminator character. */
56 		n--;
57 	}
58 
59 	va_start(args, fmt);
60 	while (*fmt) {
61 
62 		if (*fmt == '%') {
63 			fmt++;
64 			/* Check the format specifier. */
65 			switch (*fmt) {
66 			case 'i':
67 			case 'd':
68 				num = va_arg(args, int);
69 
70 				if (num < 0) {
71 					if (chars_printed < n)
72 						*s++ = '-';
73 					chars_printed++;
74 
75 					unum = (unsigned int)-num;
76 				} else {
77 					unum = (unsigned int)num;
78 				}
79 
80 				unsigned_dec_print(&s, n, &chars_printed, unum);
81 				break;
82 			case 'u':
83 				unum = va_arg(args, unsigned int);
84 				unsigned_dec_print(&s, n, &chars_printed, unum);
85 				break;
86 			default:
87 				/* Panic on any other format specifier. */
88 				ERROR("tf_snprintf: specifier with ASCII code '%d' not supported.",
89 				      *fmt);
90 				plat_panic_handler();
91 			}
92 			fmt++;
93 			continue;
94 		}
95 
96 		if (chars_printed < n)
97 			*s++ = *fmt;
98 		fmt++;
99 		chars_printed++;
100 	}
101 
102 	va_end(args);
103 
104 	if (n > 0)
105 		*s = '\0';
106 
107 	return chars_printed;
108 }
109