blob: a85634562f85d6bc73b348caa4fdc7cac61d57e0 [file] [log] [blame]
Soby Mathewafe7e2f2014-06-12 17:23:58 +01001/*
Maksims Svecovsbed55212023-05-09 12:03:31 +01002 * Copyright (c) 2014-2023, Arm Limited and Contributors. All rights reserved.
Soby Mathewafe7e2f2014-06-12 17:23:58 +01003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Soby Mathewafe7e2f2014-06-12 17:23:58 +01005 */
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00006
Soby Mathew0691d972016-05-05 12:34:41 +01007#include <assert.h>
Soby Mathewafe7e2f2014-06-12 17:23:58 +01008#include <stdarg.h>
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +01009#include <stdbool.h>
Jorge Troncosoa7538dc2022-09-27 17:35:54 -070010#include <stddef.h>
Soby Mathewafe7e2f2014-06-12 17:23:58 +010011#include <stdint.h>
Jorge Troncosoa7538dc2022-09-27 17:35:54 -070012#include <stdio.h>
Soby Mathewafe7e2f2014-06-12 17:23:58 +010013
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010014#define get_num_va_args(_args, _lcount) \
15 (((_lcount) > 1) ? va_arg(_args, long long int) : \
16 (((_lcount) == 1) ? va_arg(_args, long int) : \
17 va_arg(_args, int)))
Soby Mathewf62d5462016-03-22 17:38:00 +000018
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010019#define get_unum_va_args(_args, _lcount) \
20 (((_lcount) > 1) ? va_arg(_args, unsigned long long int) : \
21 (((_lcount) == 1) ? va_arg(_args, unsigned long int) : \
22 va_arg(_args, unsigned int)))
Soby Mathewf62d5462016-03-22 17:38:00 +000023
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +010024static int string_print(const char *str)
Soby Mathewf62d5462016-03-22 17:38:00 +000025{
Antonio Nino Diazf4407082018-08-15 16:52:32 +010026 int count = 0;
27
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010028 assert(str != NULL);
Soby Mathewf583a062017-09-04 11:45:52 +010029
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010030 for ( ; *str != '\0'; str++) {
31 (void)putchar(*str);
Antonio Nino Diazf4407082018-08-15 16:52:32 +010032 count++;
33 }
34
35 return count;
Soby Mathewf62d5462016-03-22 17:38:00 +000036}
37
Antonio Nino Diazf4407082018-08-15 16:52:32 +010038static int unsigned_num_print(unsigned long long int unum, unsigned int radix,
Matt Schulte50851f02023-07-13 11:10:32 -070039 char padc, int padn, bool uppercase)
Soby Mathewafe7e2f2014-06-12 17:23:58 +010040{
41 /* Just need enough space to store 64 bit decimal integer */
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010042 char num_buf[20];
43 int i = 0, count = 0;
44 unsigned int rem;
Soby Mathewafe7e2f2014-06-12 17:23:58 +010045
Claus Pedersen785e66c2022-09-12 22:42:58 +000046 /* num_buf is only large enough for radix >= 10 */
47 if (radix < 10) {
48 assert(0);
49 return 0;
50 }
51
Soby Mathewafe7e2f2014-06-12 17:23:58 +010052 do {
53 rem = unum % radix;
Matt Schulte50851f02023-07-13 11:10:32 -070054 if (rem < 0xa) {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010055 num_buf[i] = '0' + rem;
Matt Schulte50851f02023-07-13 11:10:32 -070056 } else if (uppercase) {
57 num_buf[i] = 'A' + (rem - 0xa);
58 } else {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010059 num_buf[i] = 'a' + (rem - 0xa);
Matt Schulte50851f02023-07-13 11:10:32 -070060 }
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010061 i++;
62 unum /= radix;
63 } while (unum > 0U);
Soby Mathewafe7e2f2014-06-12 17:23:58 +010064
Antonio Nino Diaz18c73532017-12-15 10:36:20 +000065 if (padn > 0) {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010066 while (i < padn) {
67 (void)putchar(padc);
Antonio Nino Diazf4407082018-08-15 16:52:32 +010068 count++;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010069 padn--;
Antonio Nino Diaz18c73532017-12-15 10:36:20 +000070 }
71 }
72
Antonio Nino Diazf4407082018-08-15 16:52:32 +010073 while (--i >= 0) {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010074 (void)putchar(num_buf[i]);
Antonio Nino Diazf4407082018-08-15 16:52:32 +010075 count++;
76 }
77
78 return count;
Soby Mathewafe7e2f2014-06-12 17:23:58 +010079}
80
Soby Mathewafe7e2f2014-06-12 17:23:58 +010081/*******************************************************************
82 * Reduced format print for Trusted firmware.
Soby Mathewf62d5462016-03-22 17:38:00 +000083 * The following type specifiers are supported by this print
84 * %x - hexadecimal format
Soby Mathewafe7e2f2014-06-12 17:23:58 +010085 * %s - string format
Soby Mathewf62d5462016-03-22 17:38:00 +000086 * %d or %i - signed decimal format
Maksims Svecovsbed55212023-05-09 12:03:31 +010087 * %c - character format
Soby Mathewf62d5462016-03-22 17:38:00 +000088 * %u - unsigned decimal format
Antonio Nino Diazb3a0a7b2016-02-02 12:03:38 +000089 * %p - pointer format
Soby Mathewf62d5462016-03-22 17:38:00 +000090 *
91 * The following length specifiers are supported by this print
92 * %l - long int (64-bit on AArch64)
93 * %ll - long long int (64-bit on AArch64)
94 * %z - size_t sized integer formats (64 bit on AArch64)
95 *
Antonio Nino Diaz18c73532017-12-15 10:36:20 +000096 * The following padding specifiers are supported by this print
97 * %0NN - Left-pad the number with 0s (NN is a decimal number)
Juan Pablo Conde746c0af2023-11-08 13:03:53 -060098 * %NN - Left-pad the number with spaces (NN is a decimal number)
Antonio Nino Diaz18c73532017-12-15 10:36:20 +000099 *
Soby Mathewf62d5462016-03-22 17:38:00 +0000100 * The print exits on all other formats specifiers other than valid
101 * combinations of the above specifiers.
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100102 *******************************************************************/
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +0100103int vprintf(const char *fmt, va_list args)
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100104{
Soby Mathewf62d5462016-03-22 17:38:00 +0000105 int l_count;
106 long long int num;
107 unsigned long long int unum;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100108 char *str;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100109 char padc = '\0'; /* Padding character */
Antonio Nino Diaz18c73532017-12-15 10:36:20 +0000110 int padn; /* Number of characters to pad */
Antonio Nino Diazf4407082018-08-15 16:52:32 +0100111 int count = 0; /* Number of printed characters */
Matt Schulte50851f02023-07-13 11:10:32 -0700112 bool uppercase; /* Print characters in uppercase */
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100113
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100114 while (*fmt != '\0') {
Matt Schulte50851f02023-07-13 11:10:32 -0700115 uppercase = false;
Soby Mathewf62d5462016-03-22 17:38:00 +0000116 l_count = 0;
Antonio Nino Diaz18c73532017-12-15 10:36:20 +0000117 padn = 0;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100118
119 if (*fmt == '%') {
120 fmt++;
121 /* Check the format specifier */
122loop:
123 switch (*fmt) {
Heyi Guoeb250ed2020-10-27 08:36:40 +0800124 case '%':
125 (void)putchar('%');
126 break;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100127 case 'i': /* Fall through to next one */
128 case 'd':
Soby Mathewf62d5462016-03-22 17:38:00 +0000129 num = get_num_va_args(args, l_count);
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100130 if (num < 0) {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100131 (void)putchar('-');
Soby Mathewf62d5462016-03-22 17:38:00 +0000132 unum = (unsigned long long int)-num;
Antonio Nino Diaz18c73532017-12-15 10:36:20 +0000133 padn--;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100134 } else
Soby Mathewf62d5462016-03-22 17:38:00 +0000135 unum = (unsigned long long int)num;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100136
Antonio Nino Diazf4407082018-08-15 16:52:32 +0100137 count += unsigned_num_print(unum, 10,
Matt Schulte50851f02023-07-13 11:10:32 -0700138 padc, padn, uppercase);
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100139 break;
Maksims Svecovsbed55212023-05-09 12:03:31 +0100140 case 'c':
141 (void)putchar(va_arg(args, int));
142 count++;
143 break;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100144 case 's':
145 str = va_arg(args, char *);
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +0100146 count += string_print(str);
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100147 break;
Antonio Nino Diazb3a0a7b2016-02-02 12:03:38 +0000148 case 'p':
Soby Mathewf62d5462016-03-22 17:38:00 +0000149 unum = (uintptr_t)va_arg(args, void *);
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100150 if (unum > 0U) {
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +0100151 count += string_print("0x");
Antonio Nino Diaz18c73532017-12-15 10:36:20 +0000152 padn -= 2;
153 }
Antonio Nino Diazb3a0a7b2016-02-02 12:03:38 +0000154
Antonio Nino Diazf4407082018-08-15 16:52:32 +0100155 count += unsigned_num_print(unum, 16,
Matt Schulte50851f02023-07-13 11:10:32 -0700156 padc, padn, uppercase);
Antonio Nino Diazb3a0a7b2016-02-02 12:03:38 +0000157 break;
Matt Schulte50851f02023-07-13 11:10:32 -0700158 case 'X':
159 uppercase = true;
160 // fall through
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100161 case 'x':
Soby Mathewf62d5462016-03-22 17:38:00 +0000162 unum = get_unum_va_args(args, l_count);
Antonio Nino Diazf4407082018-08-15 16:52:32 +0100163 count += unsigned_num_print(unum, 16,
Matt Schulte50851f02023-07-13 11:10:32 -0700164 padc, padn, uppercase);
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100165 break;
Scott Branden57bd75c2016-03-23 13:37:33 -0700166 case 'z':
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100167 if (sizeof(size_t) == 8U)
Soby Mathewf62d5462016-03-22 17:38:00 +0000168 l_count = 2;
169
Scott Branden57bd75c2016-03-23 13:37:33 -0700170 fmt++;
171 goto loop;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100172 case 'l':
Soby Mathewf62d5462016-03-22 17:38:00 +0000173 l_count++;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100174 fmt++;
175 goto loop;
176 case 'u':
Soby Mathewf62d5462016-03-22 17:38:00 +0000177 unum = get_unum_va_args(args, l_count);
Antonio Nino Diazf4407082018-08-15 16:52:32 +0100178 count += unsigned_num_print(unum, 10,
Matt Schulte50851f02023-07-13 11:10:32 -0700179 padc, padn, uppercase);
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100180 break;
Antonio Nino Diaz18c73532017-12-15 10:36:20 +0000181 case '0':
182 padc = '0';
183 padn = 0;
184 fmt++;
185
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100186 for (;;) {
Antonio Nino Diaz18c73532017-12-15 10:36:20 +0000187 char ch = *fmt;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100188 if ((ch < '0') || (ch > '9')) {
Antonio Nino Diaz18c73532017-12-15 10:36:20 +0000189 goto loop;
190 }
191 padn = (padn * 10) + (ch - '0');
192 fmt++;
193 }
Daniel Boulby8942a1b2018-06-22 14:16:03 +0100194 assert(0); /* Unreachable */
Juan Pablo Conde746c0af2023-11-08 13:03:53 -0600195 case '1':
196 case '2':
197 case '3':
198 case '4':
199 case '5':
200 case '6':
201 case '7':
202 case '8':
203 case '9':
204 padc = ' ';
205 padn = 0;
206
207 for (;;) {
208 char ch = *fmt;
209 if ((ch < '0') || (ch > '9')) {
210 goto loop;
211 }
212 padn = (padn * 10) + (ch - '0');
213 fmt++;
214 }
215 assert(0); /* Unreachable */
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100216 default:
217 /* Exit on any other format specifier */
Antonio Nino Diazf4407082018-08-15 16:52:32 +0100218 return -1;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100219 }
220 fmt++;
221 continue;
222 }
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100223 (void)putchar(*fmt);
224 fmt++;
Antonio Nino Diazf4407082018-08-15 16:52:32 +0100225 count++;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100226 }
Antonio Nino Diazf4407082018-08-15 16:52:32 +0100227
228 return count;
Soby Mathewf583a062017-09-04 11:45:52 +0100229}
230
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +0100231int printf(const char *fmt, ...)
Soby Mathewf583a062017-09-04 11:45:52 +0100232{
Antonio Nino Diazf4407082018-08-15 16:52:32 +0100233 int count;
Soby Mathewf583a062017-09-04 11:45:52 +0100234 va_list va;
235
236 va_start(va, fmt);
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +0100237 count = vprintf(fmt, va);
Soby Mathewf583a062017-09-04 11:45:52 +0100238 va_end(va);
Antonio Nino Diazf4407082018-08-15 16:52:32 +0100239
240 return count;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100241}