309 lines
7.3 KiB
C
Raw Normal View History

2022-10-23 23:45:43 -07:00
/*************************************************************************************************/
/*!
* \file print.c
*
* \brief Utility functions.
*
* $Date: 2016-03-29 14:55:12 -0700 (Tue, 29 Mar 2016) $
* $Revision: 6524 $
*
* Copyright (c) 2015-2017 ARM Ltd., all rights reserved.
* ARM confidential and proprietary.
*
* IMPORTANT. Your use of this file is governed by a Software License Agreement
* ("Agreement") that must be accepted in order to download or otherwise receive a
* copy of this file. You may not use or copy this file for any purpose other than
* as described in the Agreement. If you do not agree to all of the terms of the
* Agreement do not use this file and delete all copies in your possession or control;
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
* to any use, copying or further distribution of this software.
*/
/*************************************************************************************************/
#include <string.h>
#include "print.h"
/**************************************************************************************************
Macros
**************************************************************************************************/
/*! \brief Detect hexadecimal digits. */
#define PRINT_IS_XDIGIT(c) (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || \
((c >= 'A') && (c <= 'F')))
/*! \brief Convert hexadecimal digit to integer. */
#define PRINT_XDIGIT_TO_INT(c) (((c >= '0') && (c <= '9')) ? (uint8_t)(c - '0') : \
((c >= 'a') && (c <= 'f')) ? (uint8_t)(c - 'a' + 10u) : \
((c >= 'A') && (c <= 'F')) ? (uint8_t)(c - 'A' + 10u) : 0u)
/*************************************************************************************************/
/*!
* \fn printFmtInt
*
* \brief Format an integer.
*
* \param pStr Storage for formatted integer.
* \param maxLen Maximum number of characters to store.
* \param i Integer to format.
* \param base Integer base.
* \param sign TRUE if sign should be printed.
* \param width Width of field.
*
* \return Number of characters stored.
*/
/*************************************************************************************************/
static int printFmtInt(char *pStr, int maxLen, int i, uint8_t base, bool_t sign, int width)
{
char *s, *p = pStr;
unsigned int u = (unsigned int) i;
uint8_t use_width;
int t;
use_width = width;
if (i == 0)
{
s = "0\0";
width--;
goto almost;
}
if (sign && base == 10 && i < 0)
{
*pStr++ = '-';
u = (unsigned int)-i;
width--;
}
s = pStr + maxLen - 1;
*s = '\0';
while (u && (!use_width || (width > 0)))
{
t = (unsigned int)u % base;
if (t >= 10)
{
t += 'A' - '0' - 10;
}
*--s = (char)(t + '0');
u /= base;
width--;
}
almost:
while (width > 0)
{
*pStr++ = '0';
width--;
}
strcpy(pStr, s);
return strlen(p);
}
/*************************************************************************************************/
/*!
* \fn printParseInt
*
* \brief Parse an integer from a string.
*
* \param pStr String to parse.
* \param pInt Storage for parsed integer.
* \param base Integer base.
*
* \return Number of characters consumed.
*/
/*************************************************************************************************/
static int32_t printParseInt(const char *pStr, uint32_t *pInt, uint32_t base)
{
int32_t r = 0;
if (base == 0)
{
if (*pStr == '0')
{
if (((*(pStr + 1) == 'x') || (*(pStr + 1) == 'X')) && PRINT_IS_XDIGIT(*(pStr + 2)))
{
r += 2;
pStr += 2;
base = 16;
}
else
{
base = 8;
}
}
else
{
base = 10;
}
}
else if (base == 16)
{
if (*pStr == '0')
{
if (((*(pStr + 1) == 'x') || (*(pStr + 1) == 'X')) && PRINT_IS_XDIGIT(*(pStr + 2)))
{
r += 2;
pStr += 2;
}
}
}
/* One character is required; all characters must be consumed. */
*pInt = 0;
do
{
char c;
uint8_t t;
c = *pStr++;
if (!PRINT_IS_XDIGIT(c))
{
break;
}
t = PRINT_XDIGIT_TO_INT(c);
if (t >= base)
{
break;
}
*pInt *= base;
*pInt += t;
r++;
} while (*pStr != '\0');
return r;
}
/*************************************************************************************************/
/*!
* \fn PrintVsn
*
* \brief Print a trace message.
*
* \param pStr Storage for formatted string.
* \param size Maximum number of characters to store.
* \param pFmt Format string.
* \param ap Arguments.
*
* \return Number of characters stored.
*/
/*************************************************************************************************/
uint32_t PrintVsn(char *pStr, uint32_t size, const char *pFmt, va_list ap)
{
size_t len = 0;
*pStr = 0;
size--; /* Ensure we null-terminate within our buffer */
while ((*pFmt != '\0') && (len < size))
{
uint32_t width = 0;
/* normal */
if (*pFmt != '%')
{
*pStr++ = *pFmt++;
len++;
continue;
}
pFmt++;
if (*pFmt == '%')
{
*pStr++ = '%';
len++;
pFmt++;
continue;
}
/* width */
if (*pFmt == '0')
{
pFmt += printParseInt(pFmt, &width, 10u);
}
/* long (ignore) */
if (*pFmt == 'l')
{
pFmt++;
}
switch(*pFmt)
{
/* character */
case 'c':
{
char tmp = va_arg(ap, int);
*pStr++ = tmp;
len++;
break;
}
/* unsigned decimal integer */
case 'u':
{
unsigned int tmp = va_arg(ap, unsigned int);
uint8_t lenTmp = printFmtInt(pStr, size - len, tmp, 10, 0, width);
pStr += lenTmp;
len += lenTmp;
break;
}
/* signed decimal integer */
case 'd':
{
int tmp = va_arg(ap, int);
uint8_t lenTmp = printFmtInt(pStr, size - len, tmp, 10, 1, width);
pStr += lenTmp;
len += lenTmp;
break;
}
/* pointer */
case 'p':
{
unsigned long tmp = va_arg(ap, unsigned long);
uint8_t lenTmp = printFmtInt(pStr, size - len, tmp, 16, 1, 8u);
pStr += lenTmp;
len += lenTmp;
break;
}
/* unsigned hexadecimal integer */
case 'x':
case 'X':
{
unsigned int tmp = va_arg(ap, unsigned int);
uint8_t lenTmp = printFmtInt(pStr, size - len, tmp, 16, 0, width);
pStr += lenTmp;
len += lenTmp;
break;
}
/* string */
case 's':
{
char *tmp = va_arg(ap, char *);
while ((tmp != NULL) && (*tmp != '\0') && (len < size))
{
*pStr++ = *tmp++;
len++;
}
break;
}
default:
break;
}
pFmt++;
}
/* Null-terminate output. */
*pStr = 0;
if (len > size)
{
/* Compensate for -1 earlier. */
return size + 2;
}
return len;
}