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