Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions inc/private/dmod_prf.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ extern "C" {
* - %X: hexadecimal (uppercase)
* - %p: pointer
* - %%: literal %
*
* Supported format modifiers:
* - Width: Minimum field width (e.g., %30s for 30 characters)
* - Left-align: '-' flag for left-justification (e.g., %-30s)
*/
extern int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list Args );

Expand Down
100 changes: 99 additions & 1 deletion src/system/if/dmod_prf.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
// HELPER FUNCTIONS
//==============================================================================

// Maximum field width to prevent integer overflow and unreasonable buffer usage
#define DMOD_PRINTF_MAX_WIDTH 1024

static int Dmod_StrLen( const char* Str )
{
int Len = 0;
Expand Down Expand Up @@ -68,6 +71,49 @@ static void Dmod_Print_String( char** Buffer, size_t* Pos, size_t Size, const ch
}
}

static void Dmod_Print_String_Width( char** Buffer, size_t* Pos, size_t Size, const char* Str, int Width, bool LeftAlign, int* Count )
{
if( Str == NULL ) Str = "(null)";

int StrLen = Dmod_StrLen( Str );
int PadLen = Width - StrLen;

// If string is longer than or equal to width, no padding needed
if( PadLen <= 0 )
{
while( *Str )
{
Dmod_Print_Char( Buffer, Pos, Size, *Str++, Count );
}
return;
}

// Left-aligned: print string first, then padding
if( LeftAlign )
{
while( *Str )
{
Dmod_Print_Char( Buffer, Pos, Size, *Str++, Count );
}
for( int i = 0; i < PadLen; i++ )
{
Dmod_Print_Char( Buffer, Pos, Size, ' ', Count );
}
}
// Right-aligned: print padding first, then string
else
{
for( int i = 0; i < PadLen; i++ )
{
Dmod_Print_Char( Buffer, Pos, Size, ' ', Count );
}
while( *Str )
{
Dmod_Print_Char( Buffer, Pos, Size, *Str++, Count );
}
}
}

static void Dmod_Print_Int( char** Buffer, size_t* Pos, size_t Size, int32_t Value, int* Count )
{
char Temp[12]; // Enough for -2147483648
Expand Down Expand Up @@ -197,6 +243,34 @@ int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list
{
Format++;

// Parse flags
bool LeftAlign = false;
if( *Format == '-' )
{
LeftAlign = true;
Format++;
}

// Parse width
int Width = 0;
while( *Format >= '0' && *Format <= '9' )
{
int NewWidth = Width * 10 + (*Format - '0');
// Prevent overflow by capping at maximum width
if( NewWidth > DMOD_PRINTF_MAX_WIDTH )
{
Width = DMOD_PRINTF_MAX_WIDTH;
// Skip remaining digits
while( *Format >= '0' && *Format <= '9' )
{
Format++;
}
break;
}
Width = NewWidth;
Format++;
}

// Handle format specifiers
switch( *Format )
{
Expand All @@ -210,7 +284,14 @@ int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list

case 's': {
const char* Str = va_arg( Args, const char* );
Dmod_Print_String( BufPtr, &Pos, Size, Str, &Count );
if( Width > 0 )
{
Dmod_Print_String_Width( BufPtr, &Pos, Size, Str, Width, LeftAlign, &Count );
}
else
{
Dmod_Print_String( BufPtr, &Pos, Size, Str, &Count );
}
break;
}

Expand Down Expand Up @@ -248,6 +329,23 @@ int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list
default:
// Unknown format specifier, just print it
Dmod_Print_Char( BufPtr, &Pos, Size, '%', &Count );
if( LeftAlign ) Dmod_Print_Char( BufPtr, &Pos, Size, '-', &Count );
// Print width digits if any
if( Width > 0 )
{
char WidthStr[12];
int i = 0;
int TempWidth = Width;
do
{
WidthStr[i++] = '0' + (TempWidth % 10);
TempWidth /= 10;
} while( TempWidth > 0 );
while( i > 0 )
{
Dmod_Print_Char( BufPtr, &Pos, Size, WidthStr[--i], &Count );
}
}
Dmod_Print_Char( BufPtr, &Pos, Size, *Format, &Count );
break;
}
Expand Down
89 changes: 89 additions & 0 deletions tests/system/if/tests_dmod_snprintf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,92 @@ TEST_F(DmodSnPrintfTest, SnPrintfZeroBuffer)
ASSERT_EQ(result, 5); // Should return the required size
ASSERT_EQ(buffer[0], 0); // Buffer should not be modified
}

/**
* @brief Test for Dmod_SnPrintf with left-aligned string (%-30s)
*
* The test checks if the function handles left-aligned strings with width.
*/
TEST_F(DmodSnPrintfTest, SnPrintfLeftAlignedString)
{
char buffer[64];
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%-30s", "test");

ASSERT_EQ(result, 30); // Should be padded to 30 characters
ASSERT_STREQ(buffer, "test ");
ASSERT_EQ(strlen(buffer), 30);
}

/**
* @brief Test for Dmod_SnPrintf with right-aligned string (%30s)
*
* The test checks if the function handles right-aligned strings with width.
*/
TEST_F(DmodSnPrintfTest, SnPrintfRightAlignedString)
{
char buffer[64];
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%30s", "test");

ASSERT_EQ(result, 30); // Should be padded to 30 characters
ASSERT_STREQ(buffer, " test");
ASSERT_EQ(strlen(buffer), 30);
}

/**
* @brief Test for Dmod_SnPrintf with multiple width-formatted strings
*
* The test checks if the function handles multiple width-formatted strings like in module list.
*/
TEST_F(DmodSnPrintfTest, SnPrintfMultipleWidthStrings)
{
char buffer[128];
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%-30s %-15s %-40s",
"Module Name", "Version", "Description");

ASSERT_EQ(result, 30 + 1 + 15 + 1 + 40); // 30 + space + 15 + space + 40 = 87
ASSERT_STREQ(buffer, "Module Name Version Description ");
}

/**
* @brief Test for Dmod_SnPrintf with string longer than width
*
* The test checks if the function handles strings longer than the specified width.
*/
TEST_F(DmodSnPrintfTest, SnPrintfStringLongerThanWidth)
{
char buffer[64];
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%-10s", "This is a long string");

ASSERT_EQ(result, 21); // String length is 21, no padding needed
ASSERT_STREQ(buffer, "This is a long string");
}

/**
* @brief Test for Dmod_SnPrintf with mixed format specifiers and widths
*
* The test checks if the function handles both width-formatted and regular specifiers.
*/
TEST_F(DmodSnPrintfTest, SnPrintfMixedWidthFormats)
{
char buffer[128];
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%-20s: %d", "Count", 42);

ASSERT_GT(result, 0);
ASSERT_STREQ(buffer, "Count : 42");
}

/**
* @brief Test for Dmod_SnPrintf with zero width (should work like normal)
*
* The test checks if the function handles zero width correctly.
*/
TEST_F(DmodSnPrintfTest, SnPrintfZeroWidth)
{
char buffer[64];
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%-0s", "test");

ASSERT_EQ(result, 4);
ASSERT_STREQ(buffer, "test");
}


Loading