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