1 /* 2 * Copyright (c) 2014-2023, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <stdarg.h> 9 #include <stdbool.h> 10 #include <stddef.h> 11 #include <stdint.h> 12 #include <stdio.h> 13 14 #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))) 18 19 #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))) 23 24 static int string_print(const char *str) 25 { 26 int count = 0; 27 28 assert(str != NULL); 29 30 for ( ; *str != '\0'; str++) { 31 (void)putchar(*str); 32 count++; 33 } 34 35 return count; 36 } 37 38 static int unsigned_num_print(unsigned long long int unum, unsigned int radix, 39 char padc, int padn, bool uppercase) 40 { 41 /* Just need enough space to store 64 bit decimal integer */ 42 char num_buf[20]; 43 int i = 0, count = 0; 44 unsigned int rem; 45 46 /* num_buf is only large enough for radix >= 10 */ 47 if (radix < 10) { 48 assert(0); 49 return 0; 50 } 51 52 do { 53 rem = unum % radix; 54 if (rem < 0xa) { 55 num_buf[i] = '0' + rem; 56 } else if (uppercase) { 57 num_buf[i] = 'A' + (rem - 0xa); 58 } else { 59 num_buf[i] = 'a' + (rem - 0xa); 60 } 61 i++; 62 unum /= radix; 63 } while (unum > 0U); 64 65 if (padn > 0) { 66 while (i < padn) { 67 (void)putchar(padc); 68 count++; 69 padn--; 70 } 71 } 72 73 while (--i >= 0) { 74 (void)putchar(num_buf[i]); 75 count++; 76 } 77 78 return count; 79 } 80 81 /******************************************************************* 82 * Reduced format print for Trusted firmware. 83 * The following type specifiers are supported by this print 84 * %x - hexadecimal format 85 * %s - string format 86 * %d or %i - signed decimal format 87 * %c - character format 88 * %u - unsigned decimal format 89 * %p - pointer format 90 * 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 * 96 * The following padding specifiers are supported by this print 97 * %0NN - Left-pad the number with 0s (NN is a decimal number) 98 * 99 * The print exits on all other formats specifiers other than valid 100 * combinations of the above specifiers. 101 *******************************************************************/ 102 int vprintf(const char *fmt, va_list args) 103 { 104 int l_count; 105 long long int num; 106 unsigned long long int unum; 107 char *str; 108 char padc = '\0'; /* Padding character */ 109 int padn; /* Number of characters to pad */ 110 int count = 0; /* Number of printed characters */ 111 bool uppercase; /* Print characters in uppercase */ 112 113 while (*fmt != '\0') { 114 uppercase = false; 115 l_count = 0; 116 padn = 0; 117 118 if (*fmt == '%') { 119 fmt++; 120 /* Check the format specifier */ 121 loop: 122 switch (*fmt) { 123 case '%': 124 (void)putchar('%'); 125 break; 126 case 'i': /* Fall through to next one */ 127 case 'd': 128 num = get_num_va_args(args, l_count); 129 if (num < 0) { 130 (void)putchar('-'); 131 unum = (unsigned long long int)-num; 132 padn--; 133 } else 134 unum = (unsigned long long int)num; 135 136 count += unsigned_num_print(unum, 10, 137 padc, padn, uppercase); 138 break; 139 case 'c': 140 (void)putchar(va_arg(args, int)); 141 count++; 142 break; 143 case 's': 144 str = va_arg(args, char *); 145 count += string_print(str); 146 break; 147 case 'p': 148 unum = (uintptr_t)va_arg(args, void *); 149 if (unum > 0U) { 150 count += string_print("0x"); 151 padn -= 2; 152 } 153 154 count += unsigned_num_print(unum, 16, 155 padc, padn, uppercase); 156 break; 157 case 'X': 158 uppercase = true; 159 // fall through 160 case 'x': 161 unum = get_unum_va_args(args, l_count); 162 count += unsigned_num_print(unum, 16, 163 padc, padn, uppercase); 164 break; 165 case 'z': 166 if (sizeof(size_t) == 8U) 167 l_count = 2; 168 169 fmt++; 170 goto loop; 171 case 'l': 172 l_count++; 173 fmt++; 174 goto loop; 175 case 'u': 176 unum = get_unum_va_args(args, l_count); 177 count += unsigned_num_print(unum, 10, 178 padc, padn, uppercase); 179 break; 180 case '0': 181 padc = '0'; 182 padn = 0; 183 fmt++; 184 185 for (;;) { 186 char ch = *fmt; 187 if ((ch < '0') || (ch > '9')) { 188 goto loop; 189 } 190 padn = (padn * 10) + (ch - '0'); 191 fmt++; 192 } 193 assert(0); /* Unreachable */ 194 default: 195 /* Exit on any other format specifier */ 196 return -1; 197 } 198 fmt++; 199 continue; 200 } 201 (void)putchar(*fmt); 202 fmt++; 203 count++; 204 } 205 206 return count; 207 } 208 209 int printf(const char *fmt, ...) 210 { 211 int count; 212 va_list va; 213 214 va_start(va, fmt); 215 count = vprintf(fmt, va); 216 va_end(va); 217 218 return count; 219 } 220