blob: 66a2fa2f53122dd6152e9a3cf0c304d5425aee43 [file] [log] [blame]
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +01001/*
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +01002 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Daniel Boulby8942a1b2018-06-22 14:16:03 +01007#include <assert.h>
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +01008#include <debug.h>
9#include <platform.h>
10#include <stdarg.h>
11
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010012static void string_print(char **s, size_t n, size_t *chars_printed,
13 const char *str)
14{
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010015 while (*str != '\0') {
16 if (*chars_printed < n) {
17 *(*s) = *str;
18 (*s)++;
19 }
20
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010021 (*chars_printed)++;
22 str++;
23 }
24}
25
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010026static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed,
27 unsigned int unum)
28{
29 /* Enough for a 32-bit unsigned decimal integer (4294967295). */
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010030 char num_buf[10];
31 int i = 0;
32 unsigned int rem;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010033
34 do {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010035 rem = unum % 10U;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010036 num_buf[i++] = '0' + rem;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010037 unum /= 10U;
38 } while (unum > 0U);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010039
40 while (--i >= 0) {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010041 if (*chars_printed < n) {
42 *(*s) = num_buf[i];
43 (*s)++;
44 }
45
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010046 (*chars_printed)++;
47 }
48}
49
50/*******************************************************************
51 * Reduced snprintf to be used for Trusted firmware.
52 * The following type specifiers are supported:
53 *
54 * %d or %i - signed decimal format
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010055 * %s - string format
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010056 * %u - unsigned decimal format
57 *
58 * The function panics on all other formats specifiers.
59 *
60 * It returns the number of characters that would be written if the
61 * buffer was big enough. If it returns a value lower than n, the
62 * whole string has been written.
63 *******************************************************************/
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +010064int snprintf(char *s, size_t n, const char *fmt, ...)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010065{
66 va_list args;
67 int num;
68 unsigned int unum;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010069 char *str;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010070 size_t chars_printed = 0U;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010071
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010072 if (n == 0U) {
73 /* There isn't space for anything. */
74 } else if (n == 1U) {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010075 /* Buffer is too small to actually write anything else. */
76 *s = '\0';
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010077 n = 0U;
78 } else {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010079 /* Reserve space for the terminator character. */
80 n--;
81 }
82
83 va_start(args, fmt);
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010084 while (*fmt != '\0') {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010085
86 if (*fmt == '%') {
87 fmt++;
88 /* Check the format specifier. */
89 switch (*fmt) {
90 case 'i':
91 case 'd':
92 num = va_arg(args, int);
93
94 if (num < 0) {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010095 if (chars_printed < n) {
96 *s = '-';
97 s++;
98 }
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010099 chars_printed++;
100
101 unum = (unsigned int)-num;
102 } else {
103 unum = (unsigned int)num;
104 }
105
106 unsigned_dec_print(&s, n, &chars_printed, unum);
107 break;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +0100108 case 's':
109 str = va_arg(args, char *);
110 string_print(&s, n, &chars_printed, str);
111 break;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100112 case 'u':
113 unum = va_arg(args, unsigned int);
114 unsigned_dec_print(&s, n, &chars_printed, unum);
115 break;
116 default:
117 /* Panic on any other format specifier. */
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +0100118 ERROR("snprintf: specifier with ASCII code '%d' not supported.",
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100119 *fmt);
120 plat_panic_handler();
Daniel Boulby8942a1b2018-06-22 14:16:03 +0100121 assert(0); /* Unreachable */
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100122 }
123 fmt++;
124 continue;
125 }
126
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100127 if (chars_printed < n) {
128 *s = *fmt;
129 s++;
130 }
131
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100132 fmt++;
133 chars_printed++;
134 }
135
136 va_end(args);
137
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100138 if (n > 0U)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100139 *s = '\0';
140
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100141 return (int)chars_printed;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100142}