309 lines
7.3 KiB
C
309 lines
7.3 KiB
C
/*************************************************************************************************/
|
|
/*!
|
|
* \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;
|
|
}
|