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
|
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <debug.h>
#include <platform.h>
#include <stdarg.h>
static void string_print(char **s, size_t n, size_t *chars_printed,
const char *str)
{
while (*str != '\0') {
if (*chars_printed < n) {
*(*s) = *str;
(*s)++;
}
(*chars_printed)++;
str++;
}
}
static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed,
unsigned int unum)
{
/* Enough for a 32-bit unsigned decimal integer (4294967295). */
char num_buf[10];
int i = 0;
unsigned int rem;
do {
rem = unum % 10U;
num_buf[i++] = '0' + rem;
unum /= 10U;
} while (unum > 0U);
while (--i >= 0) {
if (*chars_printed < n) {
*(*s) = num_buf[i];
(*s)++;
}
(*chars_printed)++;
}
}
/*******************************************************************
* Reduced snprintf to be used for Trusted firmware.
* The following type specifiers are supported:
*
* %d or %i - signed decimal format
* %s - string format
* %u - unsigned decimal format
*
* The function panics on all other formats specifiers.
*
* It returns the number of characters that would be written if the
* buffer was big enough. If it returns a value lower than n, the
* whole string has been written.
*******************************************************************/
int snprintf(char *s, size_t n, const char *fmt, ...)
{
va_list args;
int num;
unsigned int unum;
char *str;
size_t chars_printed = 0U;
if (n == 0U) {
/* There isn't space for anything. */
} else if (n == 1U) {
/* Buffer is too small to actually write anything else. */
*s = '\0';
n = 0U;
} else {
/* Reserve space for the terminator character. */
n--;
}
va_start(args, fmt);
while (*fmt != '\0') {
if (*fmt == '%') {
fmt++;
/* Check the format specifier. */
switch (*fmt) {
case 'i':
case 'd':
num = va_arg(args, int);
if (num < 0) {
if (chars_printed < n) {
*s = '-';
s++;
}
chars_printed++;
unum = (unsigned int)-num;
} else {
unum = (unsigned int)num;
}
unsigned_dec_print(&s, n, &chars_printed, unum);
break;
case 's':
str = va_arg(args, char *);
string_print(&s, n, &chars_printed, str);
break;
case 'u':
unum = va_arg(args, unsigned int);
unsigned_dec_print(&s, n, &chars_printed, unum);
break;
default:
/* Panic on any other format specifier. */
ERROR("snprintf: specifier with ASCII code '%d' not supported.",
*fmt);
plat_panic_handler();
assert(0); /* Unreachable */
}
fmt++;
continue;
}
if (chars_printed < n) {
*s = *fmt;
s++;
}
fmt++;
chars_printed++;
}
va_end(args);
if (n > 0U)
*s = '\0';
return (int)chars_printed;
}
|