blob: 034d571caad03ba34dd45e2f63da1fca73cfd0f4 [file] [log] [blame]
/*
* Copyright (c) 2014, STMicroelectronics International N.V.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License Version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "adbg_int.h"
#include <stdlib.h>
#include <ctype.h>
/*************************************************************************
* 2. Definition of external constants and variables
************************************************************************/
/*************************************************************************
* 3. File scope types, constants and variables
************************************************************************/
/*************************************************************************
* 4. Declaration of file local functions
************************************************************************/
/*************************************************************************
* 5. Definition of external functions
************************************************************************/
/******************************************************************************/
/*! @fn void Do_ADBG_Log( void* This_p, char* Format, ...)
* @brief
* @param [in] This_p
* @param [in] Format
* @param [in] ...
* @return void
*/
/******************************************************************************/
void Do_ADBG_Log(const char *const Format, ...)
{
va_list ap;
char buf[ADBG_STRING_LENGTH_MAX];
va_start(ap, Format);
vsnprintf(buf, sizeof(buf), Format, ap);
va_end(ap);
printf("%s\n", buf);
}
void Do_ADBG_LogHeading(unsigned Level, const char *const Format, ...)
{
va_list List;
char String[ADBG_STRING_LENGTH_MAX];
char UnderLine;
char Numbers[10];
static int HeadingNumbers[3] = { 0, 0, 0 };
/* lint -save -e718 -e746 -e530 lint doesn't seem to know of va_start */
va_start(List, Format);
/* lint -restore */
(void)vsnprintf(String, sizeof(String), Format, List);
va_end(List);
switch (Level) {
case 0:
UnderLine = '#';
HeadingNumbers[0] = HeadingNumbers[1] = HeadingNumbers[2] = 0;
Numbers[0] = '\0';
break;
case 1:
UnderLine = '=';
HeadingNumbers[0]++;
HeadingNumbers[1] = HeadingNumbers[2] = 0;
(void)ADBG_snprintf(Numbers, sizeof(Numbers), "%d",
HeadingNumbers[0]);
break;
case 2:
UnderLine = '~';
HeadingNumbers[1]++;
HeadingNumbers[2] = 0;
#if 0 /* Stupid snprintf bug only taking first argument */
(void)ADBG_snprintf(Numbers, sizeof(Numbers), "%d.%d",
HeadingNumbers[0], HeadingNumbers[1]);
#else
(void)ADBG_snprintf(Numbers, sizeof(Numbers), "%d.",
HeadingNumbers[0]);
(void)ADBG_snprintf(Numbers + strlen(Numbers),
sizeof(Numbers) - strlen(Numbers),
"%d", HeadingNumbers[1]);
#endif
break;
case 3:
UnderLine = '-';
HeadingNumbers[2]++;
#if 0 /* Stupid snprintf bug only taking first argument */
(void)ADBG_snprintf(Numbers, sizeof(Numbers), "%d.%d.%d",
HeadingNumbers[0], HeadingNumbers[1],
HeadingNumbers[2]);
#else
(void)ADBG_snprintf(Numbers, sizeof(Numbers), "%d.",
HeadingNumbers[0]);
(void)ADBG_snprintf(Numbers + strlen(Numbers),
sizeof(Numbers) - strlen(Numbers),
"%d.", HeadingNumbers[1]);
(void)ADBG_snprintf(Numbers + strlen(Numbers),
sizeof(Numbers) - strlen(Numbers),
"%d", HeadingNumbers[2]);
#endif
break;
default:
UnderLine = '-';
Numbers[0] = '\0';
}
Do_ADBG_Log("%-5s %s", Numbers, String);
if (String[0] != '\0') {
size_t n;
for (n = 0; String[n] != '\0'; n++)
String[n] = UnderLine;
Do_ADBG_Log("%-5s %s", "", String);
if (Level == 0)
Do_ADBG_Log(" ");
}
}
void Do_ADBG_LogText(const char *const Text_p)
{
static const ADBG_LogTableShapes_t Shapes = { ' ', ' ', ' ' };
ADBG_LogTable_t LogTable[2] = { { 3, NULL }, { 74, NULL } };
LogTable[1].Text_p = Text_p;
Do_ADBG_LogTableShapes(&Shapes, LogTable, 2);
}
void Do_ADBG_LogHelp(
const ADBG_HelpTable_t *const HelpTable_p,
const size_t HelpTableLength
)
{
static const ADBG_LogTableShapes_t Shapes = { ' ', ' ', ' ' };
ADBG_LogTable_t Row[2] = { { 20, NULL }, { 50, NULL } };
size_t n;
for (n = 0; n < HelpTableLength; n++) {
Row[0].Text_p = HelpTable_p[n].Command_p;
Row[1].Text_p = HelpTable_p[n].Help_p;
Do_ADBG_LogTableShapes(&Shapes, Row, 2);
}
}
void Do_ADBG_HexLog(
const void *const Buf_p,
const size_t Size,
const size_t Cols
)
{
const uint8_t *Data_p = Buf_p;
size_t n;
for (n = 0; n < Size; n += Cols) {
char HexBuffer[ADBG_STRING_LENGTH_MAX];
char AsciiBuffer[ADBG_STRING_LENGTH_MAX / 3];
size_t m, NumCols;
(void)SecUtil_BufferToHex(Data_p + n, MIN(Cols, Size - n), NULL,
HexBuffer, sizeof(HexBuffer));
NumCols = MIN(MIN(Cols, Size - n), sizeof(AsciiBuffer) - 1);
for (m = 0; m < NumCols; m++) {
int ch = Data_p[n + m];
if (isprint(ch))
AsciiBuffer[m] = (char)ch;
else
AsciiBuffer[m] = '.';
}
AsciiBuffer[m] = '\0';
Do_ADBG_Log(" %-*s %s", (int)Cols * 3, HexBuffer, AsciiBuffer);
}
}
void Do_ADBG_LogTable(
const ADBG_LogTable_t *const TableRow_p,
const size_t NumColumns
)
{
const ADBG_LogTableShapes_t Shapes = { '+', '|', '-' };
Do_ADBG_LogTableShapes(&Shapes, TableRow_p, NumColumns);
}
void Do_ADBG_LogTableLine(
const ADBG_LogTable_t *const TableRow_p,
const size_t NumColumns
)
{
const ADBG_LogTableShapes_t Shapes = { '+', '|', '-' };
Do_ADBG_LogTableShapesLine(&Shapes, TableRow_p, NumColumns);
}
void Do_ADBG_LogTableShapes(
const ADBG_LogTableShapes_t *const Shapes,
const ADBG_LogTable_t *const TableRow_p,
const size_t NumColumns
)
{
char *Line_p;
size_t *LastPos_p;
size_t n;
size_t TableColumn;
size_t LinePosition;
size_t LineLength;
size_t NumColumnsLeft;
LineLength = 2; /* Starting and ending '|' */
for (n = 0; n < NumColumns; n++)
LineLength += TableRow_p[n].ColumnWidth + 1; /* One extra '|' */
Line_p = HEAP_UNTYPED_ALLOC(LineLength + 1);
LastPos_p = HEAP_UNTYPED_ALLOC(sizeof(size_t) * NumColumns);
if (Line_p == NULL || LastPos_p == NULL) {
Do_ADBG_Log("Do_ADBG_LogTableLine: Memory allocation failed");
goto CleanupReturn;
}
memset(LastPos_p, 0, sizeof(size_t) * NumColumns);
do {
NumColumnsLeft = NumColumns;
LinePosition = 0;
for (TableColumn = 0; TableColumn < NumColumns; TableColumn++) {
const ADBG_LogTable_t *Col_p = TableRow_p + TableColumn;
size_t TextLen = 0;
size_t ColumnPos;
if (Col_p->Text_p != NULL)
TextLen = strlen(Col_p->Text_p);
Line_p[LinePosition] = Shapes->Vertical;
LinePosition++;
if (Col_p->ColumnWidth <= 1) {
NumColumnsLeft--;
continue;
}
Line_p[LinePosition] = ' ';
LinePosition++;
if (Col_p->ColumnWidth <= 2) {
NumColumnsLeft--;
continue;
}
n = LastPos_p[TableColumn];
ColumnPos = 1;
while (n < TextLen && ColumnPos < Col_p->ColumnWidth) {
size_t WordLength;
size_t NewLine = 0;
/*
* We copy one complete word at a time.
* If the word is too long
* to fit in the column at all
* it's broken at the end of the
* column.
*/
/* Consume leading spaces */
while (n < TextLen && Col_p->Text_p[n] == ' ')
n++;
/* Find out the length of the word */
WordLength = 0;
while ((n + WordLength) < TextLen &&
Col_p->Text_p[n + WordLength] != ' ') {
if (Col_p->Text_p[n + WordLength] ==
'\n') {
NewLine = 1;
break;
}
/*
* The -1 for ColumnWidth is
* to make room for a final space
* before the '|'.
*/
if ((ColumnPos + WordLength) >=
(Col_p->ColumnWidth - 1)) {
if (ColumnPos != 1) {
/* Save this word
for the next line */
WordLength = 0;
}
break;
}
WordLength++;
}
/* Copy the word and update the positions */
memcpy(Line_p + LinePosition, Col_p->Text_p + n,
WordLength);
n += WordLength + NewLine;
LinePosition += WordLength;
ColumnPos += WordLength;
/* Now output all spaces */
if (WordLength == 0) {
/* The spaces will be added
in the outer loop */
break;
}
/*
* If there's spaces in the text at the
* current position
* and there's room for one, output one space.
* The rest of the spaces are consumed in
* the inner loop
* above. This will take an additional line if
* the spaces
* are at the end of the Text_p but you're not
* supposed end a Text_p with spaces any way.
*/
if (Col_p->Text_p[n] == ' ' && ColumnPos <
Col_p->ColumnWidth) {
Line_p[LinePosition] = ' ';
LinePosition++;
ColumnPos++;
n++;
}
}
LastPos_p[TableColumn] = n;
if (LastPos_p[TableColumn] == TextLen)
NumColumnsLeft--;
/* Output spaces until the end of the column */
while (ColumnPos < Col_p->ColumnWidth) {
Line_p[LinePosition] = ' ';
LinePosition++;
ColumnPos++;
}
}
Line_p[LinePosition] = Shapes->Vertical;
LinePosition++;
Line_p[LinePosition] = '\0';
Do_ADBG_Log("%s", Line_p);
} while (NumColumnsLeft > 0);
CleanupReturn:
HEAP_FREE(&Line_p);
HEAP_FREE(&LastPos_p);
}
void Do_ADBG_LogTableShapesLine(
const ADBG_LogTableShapes_t *const Shapes,
const ADBG_LogTable_t *const TableRow_p,
const size_t NumColumns
)
{
char *Line_p;
size_t n;
size_t TableColumn;
size_t LinePosition;
size_t LineLength;
LineLength = 2; /* Starting and ending '+' */
for (n = 0; n < NumColumns; n++)
LineLength += TableRow_p[n].ColumnWidth + 1; /* One extra '+' */
Line_p = HEAP_UNTYPED_ALLOC(LineLength + 1);
if (Line_p == NULL) {
Do_ADBG_Log("Do_ADBG_LogTableLine: Memory allocation failed");
goto CleanupReturn;
}
LinePosition = 0;
for (TableColumn = 0; TableColumn < NumColumns; TableColumn++) {
Line_p[LinePosition] = Shapes->Corner;
LinePosition++;
for (n = 0; n < TableRow_p[TableColumn].ColumnWidth; n++) {
Line_p[LinePosition] = Shapes->Horizontal;
LinePosition++;
}
}
Line_p[LinePosition] = Shapes->Corner;
LinePosition++;
Line_p[LinePosition] = '\0';
Do_ADBG_Log("%s", Line_p);
CleanupReturn:
HEAP_FREE(&Line_p);
}
/*************************************************************************
* 6. Definitions of internal functions
************************************************************************/