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