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