blob: 38ad1c71abb3fd5aa124d74612e1f4435c7beafe [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 <stdarg.h>
9
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010#include <common/debug.h>
11#include <plat/common/platform.h>
12
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010013static void string_print(char **s, size_t n, size_t *chars_printed,
14 const char *str)
15{
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010016 while (*str != '\0') {
17 if (*chars_printed < n) {
18 *(*s) = *str;
19 (*s)++;
20 }
21
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010022 (*chars_printed)++;
23 str++;
24 }
25}
26
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010027static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed,
28 unsigned int unum)
29{
30 /* Enough for a 32-bit unsigned decimal integer (4294967295). */
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010031 char num_buf[10];
32 int i = 0;
33 unsigned int rem;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010034
35 do {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010036 rem = unum % 10U;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010037 num_buf[i++] = '0' + rem;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010038 unum /= 10U;
39 } while (unum > 0U);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010040
41 while (--i >= 0) {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010042 if (*chars_printed < n) {
43 *(*s) = num_buf[i];
44 (*s)++;
45 }
46
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010047 (*chars_printed)++;
48 }
49}
50
51/*******************************************************************
52 * Reduced snprintf to be used for Trusted firmware.
53 * The following type specifiers are supported:
54 *
55 * %d or %i - signed decimal format
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010056 * %s - string format
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010057 * %u - unsigned decimal format
58 *
59 * The function panics on all other formats specifiers.
60 *
61 * It returns the number of characters that would be written if the
62 * buffer was big enough. If it returns a value lower than n, the
63 * whole string has been written.
64 *******************************************************************/
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +010065int snprintf(char *s, size_t n, const char *fmt, ...)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010066{
67 va_list args;
68 int num;
69 unsigned int unum;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010070 char *str;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010071 size_t chars_printed = 0U;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010072
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010073 if (n == 0U) {
74 /* There isn't space for anything. */
75 } else if (n == 1U) {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010076 /* Buffer is too small to actually write anything else. */
77 *s = '\0';
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010078 n = 0U;
79 } else {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010080 /* Reserve space for the terminator character. */
81 n--;
82 }
83
84 va_start(args, fmt);
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010085 while (*fmt != '\0') {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010086
87 if (*fmt == '%') {
88 fmt++;
89 /* Check the format specifier. */
90 switch (*fmt) {
91 case 'i':
92 case 'd':
93 num = va_arg(args, int);
94
95 if (num < 0) {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010096 if (chars_printed < n) {
97 *s = '-';
98 s++;
99 }
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100100 chars_printed++;
101
102 unum = (unsigned int)-num;
103 } else {
104 unum = (unsigned int)num;
105 }
106
107 unsigned_dec_print(&s, n, &chars_printed, unum);
108 break;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +0100109 case 's':
110 str = va_arg(args, char *);
111 string_print(&s, n, &chars_printed, str);
112 break;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100113 case 'u':
114 unum = va_arg(args, unsigned int);
115 unsigned_dec_print(&s, n, &chars_printed, unum);
116 break;
117 default:
118 /* Panic on any other format specifier. */
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +0100119 ERROR("snprintf: specifier with ASCII code '%d' not supported.",
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100120 *fmt);
121 plat_panic_handler();
Daniel Boulby8942a1b2018-06-22 14:16:03 +0100122 assert(0); /* Unreachable */
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100123 }
124 fmt++;
125 continue;
126 }
127
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100128 if (chars_printed < n) {
129 *s = *fmt;
130 s++;
131 }
132
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100133 fmt++;
134 chars_printed++;
135 }
136
137 va_end(args);
138
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100139 if (n > 0U)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100140 *s = '\0';
141
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100142 return (int)chars_printed;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100143}