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