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