blob: 9bc07b2cb4b4c224e3245632527a1b6c040f05d3 [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
7#include <debug.h>
8#include <platform.h>
9#include <stdarg.h>
10
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010011static void string_print(char **s, size_t n, size_t *chars_printed,
12 const char *str)
13{
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010014 while (*str != '\0') {
15 if (*chars_printed < n) {
16 *(*s) = *str;
17 (*s)++;
18 }
19
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010020 (*chars_printed)++;
21 str++;
22 }
23}
24
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010025static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed,
26 unsigned int unum)
27{
28 /* Enough for a 32-bit unsigned decimal integer (4294967295). */
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010029 char num_buf[10];
30 int i = 0;
31 unsigned int rem;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010032
33 do {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010034 rem = unum % 10U;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010035 num_buf[i++] = '0' + rem;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010036 unum /= 10U;
37 } while (unum > 0U);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010038
39 while (--i >= 0) {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010040 if (*chars_printed < n) {
41 *(*s) = num_buf[i];
42 (*s)++;
43 }
44
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010045 (*chars_printed)++;
46 }
47}
48
49/*******************************************************************
50 * Reduced snprintf to be used for Trusted firmware.
51 * The following type specifiers are supported:
52 *
53 * %d or %i - signed decimal format
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010054 * %s - string format
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010055 * %u - unsigned decimal format
56 *
57 * The function panics on all other formats specifiers.
58 *
59 * It returns the number of characters that would be written if the
60 * buffer was big enough. If it returns a value lower than n, the
61 * whole string has been written.
62 *******************************************************************/
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +010063int snprintf(char *s, size_t n, const char *fmt, ...)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010064{
65 va_list args;
66 int num;
67 unsigned int unum;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010068 char *str;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010069 size_t chars_printed = 0U;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010070
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010071 if (n == 0U) {
72 /* There isn't space for anything. */
73 } else if (n == 1U) {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010074 /* Buffer is too small to actually write anything else. */
75 *s = '\0';
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010076 n = 0U;
77 } else {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010078 /* Reserve space for the terminator character. */
79 n--;
80 }
81
82 va_start(args, fmt);
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010083 while (*fmt != '\0') {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010084
85 if (*fmt == '%') {
86 fmt++;
87 /* Check the format specifier. */
88 switch (*fmt) {
89 case 'i':
90 case 'd':
91 num = va_arg(args, int);
92
93 if (num < 0) {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010094 if (chars_printed < n) {
95 *s = '-';
96 s++;
97 }
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010098 chars_printed++;
99
100 unum = (unsigned int)-num;
101 } else {
102 unum = (unsigned int)num;
103 }
104
105 unsigned_dec_print(&s, n, &chars_printed, unum);
106 break;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +0100107 case 's':
108 str = va_arg(args, char *);
109 string_print(&s, n, &chars_printed, str);
110 break;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100111 case 'u':
112 unum = va_arg(args, unsigned int);
113 unsigned_dec_print(&s, n, &chars_printed, unum);
114 break;
115 default:
116 /* Panic on any other format specifier. */
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +0100117 ERROR("snprintf: specifier with ASCII code '%d' not supported.",
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100118 *fmt);
119 plat_panic_handler();
120 }
121 fmt++;
122 continue;
123 }
124
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100125 if (chars_printed < n) {
126 *s = *fmt;
127 s++;
128 }
129
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100130 fmt++;
131 chars_printed++;
132 }
133
134 va_end(args);
135
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100136 if (n > 0U)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100137 *s = '\0';
138
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100139 return (int)chars_printed;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100140}