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) 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 57 num_buf[i] = 'a' + (rem - 0xa); 58 i++; 59 unum /= radix; 60 } while (unum > 0U); 61 62 if (padn > 0) { 63 while (i < padn) { 64 (void)putchar(padc); 65 count++; 66 padn--; 67 } 68 } 69 70 while (--i >= 0) { 71 (void)putchar(num_buf[i]); 72 count++; 73 } 74 75 return count; 76 } 77 78 /******************************************************************* 79 * Reduced format print for Trusted firmware. 80 * The following type specifiers are supported by this print 81 * %x - hexadecimal format 82 * %s - string format 83 * %d or %i - signed decimal format 84 * %c - character format 85 * %u - unsigned decimal format 86 * %p - pointer format 87 * 88 * The following length specifiers are supported by this print 89 * %l - long int (64-bit on AArch64) 90 * %ll - long long int (64-bit on AArch64) 91 * %z - size_t sized integer formats (64 bit on AArch64) 92 * 93 * The following padding specifiers are supported by this print 94 * %0NN - Left-pad the number with 0s (NN is a decimal number) 95 * 96 * The print exits on all other formats specifiers other than valid 97 * combinations of the above specifiers. 98 *******************************************************************/ 99 int vprintf(const char *fmt, va_list args) 100 { 101 int l_count; 102 long long int num; 103 unsigned long long int unum; 104 char *str; 105 char padc = '\0'; /* Padding character */ 106 int padn; /* Number of characters to pad */ 107 int count = 0; /* Number of printed characters */ 108 109 while (*fmt != '\0') { 110 l_count = 0; 111 padn = 0; 112 113 if (*fmt == '%') { 114 fmt++; 115 /* Check the format specifier */ 116 loop: 117 switch (*fmt) { 118 case '%': 119 (void)putchar('%'); 120 break; 121 case 'i': /* Fall through to next one */ 122 case 'd': 123 num = get_num_va_args(args, l_count); 124 if (num < 0) { 125 (void)putchar('-'); 126 unum = (unsigned long long int)-num; 127 padn--; 128 } else 129 unum = (unsigned long long int)num; 130 131 count += unsigned_num_print(unum, 10, 132 padc, padn); 133 break; 134 case 'c': 135 (void)putchar(va_arg(args, int)); 136 count++; 137 break; 138 case 's': 139 str = va_arg(args, char *); 140 count += string_print(str); 141 break; 142 case 'p': 143 unum = (uintptr_t)va_arg(args, void *); 144 if (unum > 0U) { 145 count += string_print("0x"); 146 padn -= 2; 147 } 148 149 count += unsigned_num_print(unum, 16, 150 padc, padn); 151 break; 152 case 'x': 153 unum = get_unum_va_args(args, l_count); 154 count += unsigned_num_print(unum, 16, 155 padc, padn); 156 break; 157 case 'z': 158 if (sizeof(size_t) == 8U) 159 l_count = 2; 160 161 fmt++; 162 goto loop; 163 case 'l': 164 l_count++; 165 fmt++; 166 goto loop; 167 case 'u': 168 unum = get_unum_va_args(args, l_count); 169 count += unsigned_num_print(unum, 10, 170 padc, padn); 171 break; 172 case '0': 173 padc = '0'; 174 padn = 0; 175 fmt++; 176 177 for (;;) { 178 char ch = *fmt; 179 if ((ch < '0') || (ch > '9')) { 180 goto loop; 181 } 182 padn = (padn * 10) + (ch - '0'); 183 fmt++; 184 } 185 assert(0); /* Unreachable */ 186 default: 187 /* Exit on any other format specifier */ 188 return -1; 189 } 190 fmt++; 191 continue; 192 } 193 (void)putchar(*fmt); 194 fmt++; 195 count++; 196 } 197 198 return count; 199 } 200 201 int printf(const char *fmt, ...) 202 { 203 int count; 204 va_list va; 205 206 va_start(va, fmt); 207 count = vprintf(fmt, va); 208 va_end(va); 209 210 return count; 211 } 212