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
1 change: 1 addition & 0 deletions inc/private/dmod_prf.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ extern "C" {
* Supported format modifiers:
* - Width: Minimum field width (e.g., %30s for 30 characters)
* - Left-align: '-' flag for left-justification (e.g., %-30s)
* - Length modifier 'll': long long (64-bit) for d, i, u, x, X (e.g., %lld, %llu, %llx, %llX)
*/
extern int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list Args );

Expand Down
146 changes: 138 additions & 8 deletions src/system/if/dmod_prf.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,90 @@ static void Dmod_Print_Pointer( char** Buffer, size_t* Pos, size_t Size, void* P
}
}

static void Dmod_Print_LongLong( char** Buffer, size_t* Pos, size_t Size, int64_t Value, int* Count )
{
char Temp[21]; // Enough for -9223372036854775808
int i = 0;
bool IsNegative = false;
uint64_t UValue;

if( Value < 0 )
{
IsNegative = true;
// Handle most negative int64_t value specially to avoid overflow
if( Value == (int64_t)0x8000000000000000LL )
{
UValue = 0x8000000000000000ULL;
}
else
{
UValue = (uint64_t)(-Value);
}
}
else
{
UValue = (uint64_t)Value;
}

// Convert to string (reversed)
do
{
Temp[i++] = '0' + (UValue % 10);
UValue /= 10;
} while( UValue > 0 );

// Add sign
if( IsNegative )
{
Dmod_Print_Char( Buffer, Pos, Size, '-', Count );
}

// Print in correct order
while( i > 0 )
{
Dmod_Print_Char( Buffer, Pos, Size, Temp[--i], Count );
}
}

static void Dmod_Print_ULongLong( char** Buffer, size_t* Pos, size_t Size, uint64_t Value, int* Count )
{
char Temp[21]; // Enough for 18446744073709551615
int i = 0;

// Convert to string (reversed)
do
{
Temp[i++] = '0' + (Value % 10);
Value /= 10;
} while( Value > 0 );

// Print in correct order
while( i > 0 )
{
Dmod_Print_Char( Buffer, Pos, Size, Temp[--i], Count );
}
}

static void Dmod_Print_Hex64( char** Buffer, size_t* Pos, size_t Size, uint64_t Value, bool Uppercase, int* Count )
{
char Temp[17]; // Enough for 16 hex digits
int i = 0;
const char* HexDigits = Uppercase ? "0123456789ABCDEF" : "0123456789abcdef";

// Convert to hex string (reversed)
do
{
Temp[i++] = HexDigits[Value & 0xF];
Value >>= 4;
} while( Value > 0 );

// Print in correct order
while( i > 0 )
{
Dmod_Print_Char( Buffer, Pos, Size, Temp[--i], Count );
}
}

//==============================================================================
// PUBLIC FUNCTIONS
//==============================================================================
Expand Down Expand Up @@ -271,6 +355,14 @@ int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list
Format++;
}

// Parse length modifier
bool IsLongLong = false;
if( *Format == 'l' && *(Format + 1) == 'l' )
{
IsLongLong = true;
Format += 2;
}

// Handle format specifiers
switch( *Format )
{
Expand All @@ -297,26 +389,58 @@ int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list

case 'd':
case 'i': {
int32_t Value = va_arg( Args, int32_t );
Dmod_Print_Int( BufPtr, &Pos, Size, Value, &Count );
if( IsLongLong )
{
int64_t Value = va_arg( Args, int64_t );
Dmod_Print_LongLong( BufPtr, &Pos, Size, Value, &Count );
}
else
{
int32_t Value = va_arg( Args, int32_t );
Dmod_Print_Int( BufPtr, &Pos, Size, Value, &Count );
}
break;
}

case 'u': {
uint32_t Value = va_arg( Args, uint32_t );
Dmod_Print_UInt( BufPtr, &Pos, Size, Value, &Count );
if( IsLongLong )
{
uint64_t Value = va_arg( Args, uint64_t );
Dmod_Print_ULongLong( BufPtr, &Pos, Size, Value, &Count );
}
else
{
uint32_t Value = va_arg( Args, uint32_t );
Dmod_Print_UInt( BufPtr, &Pos, Size, Value, &Count );
}
break;
}

case 'x': {
uint32_t Value = va_arg( Args, uint32_t );
Dmod_Print_Hex( BufPtr, &Pos, Size, Value, false, &Count );
if( IsLongLong )
{
uint64_t Value = va_arg( Args, uint64_t );
Dmod_Print_Hex64( BufPtr, &Pos, Size, Value, false, &Count );
}
else
{
uint32_t Value = va_arg( Args, uint32_t );
Dmod_Print_Hex( BufPtr, &Pos, Size, Value, false, &Count );
}
break;
}

case 'X': {
uint32_t Value = va_arg( Args, uint32_t );
Dmod_Print_Hex( BufPtr, &Pos, Size, Value, true, &Count );
if( IsLongLong )
{
uint64_t Value = va_arg( Args, uint64_t );
Dmod_Print_Hex64( BufPtr, &Pos, Size, Value, true, &Count );
}
else
{
uint32_t Value = va_arg( Args, uint32_t );
Dmod_Print_Hex( BufPtr, &Pos, Size, Value, true, &Count );
}
break;
}

Expand Down Expand Up @@ -346,6 +470,12 @@ int Dmod_VSnPrintf_Impl( char* Buffer, size_t Size, const char* Format, va_list
Dmod_Print_Char( BufPtr, &Pos, Size, WidthStr[--i], &Count );
}
}
// Print length modifier if present
if( IsLongLong )
{
Dmod_Print_Char( BufPtr, &Pos, Size, 'l', &Count );
Dmod_Print_Char( BufPtr, &Pos, Size, 'l', &Count );
}
Dmod_Print_Char( BufPtr, &Pos, Size, *Format, &Count );
break;
}
Expand Down
153 changes: 153 additions & 0 deletions tests/system/if/tests_dmod_snprintf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,157 @@ TEST_F(DmodSnPrintfTest, SnPrintfZeroWidth)
ASSERT_STREQ(buffer, "test");
}

/**
* @brief Test for Dmod_SnPrintf with %llu (unsigned long long)
*
* The test checks if the function handles unsigned long long format specifier.
*/
TEST_F(DmodSnPrintfTest, SnPrintfUnsignedLongLong)
{
char buffer[64];
uint64_t value = 18446744073709551615ULL; // Max uint64_t
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%llu", value);

ASSERT_GT(result, 0);
ASSERT_STREQ(buffer, "18446744073709551615");
}

/**
* @brief Test for Dmod_SnPrintf with %lld (signed long long)
*
* The test checks if the function handles signed long long format specifier.
*/
TEST_F(DmodSnPrintfTest, SnPrintfSignedLongLong)
{
char buffer[64];
int64_t value = -9223372036854775807LL - 1LL; // Min int64_t
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%lld", value);

ASSERT_GT(result, 0);
ASSERT_STREQ(buffer, "-9223372036854775808");
}

/**
* @brief Test for Dmod_SnPrintf with positive %lld
*
* The test checks if the function handles positive signed long long values.
*/
TEST_F(DmodSnPrintfTest, SnPrintfPositiveLongLong)
{
char buffer[64];
int64_t value = 9223372036854775807LL; // Max int64_t
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%lld", value);

ASSERT_GT(result, 0);
ASSERT_STREQ(buffer, "9223372036854775807");
}

/**
* @brief Test for Dmod_SnPrintf with %llx (long long hex lowercase)
*
* The test checks if the function handles long long hexadecimal format specifier.
*/
TEST_F(DmodSnPrintfTest, SnPrintfLongLongHexLowercase)
{
char buffer[64];
uint64_t value = 0xFEDCBA9876543210ULL;
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%llx", value);

ASSERT_GT(result, 0);
ASSERT_STREQ(buffer, "fedcba9876543210");
}

/**
* @brief Test for Dmod_SnPrintf with %llX (long long hex uppercase)
*
* The test checks if the function handles long long hexadecimal uppercase format specifier.
*/
TEST_F(DmodSnPrintfTest, SnPrintfLongLongHexUppercase)
{
char buffer[64];
uint64_t value = 0xFEDCBA9876543210ULL;
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%llX", value);

ASSERT_GT(result, 0);
ASSERT_STREQ(buffer, "FEDCBA9876543210");
}

/**
* @brief Test for Dmod_SnPrintf with small %llu value
*
* The test checks if the function handles small unsigned long long values correctly.
*/
TEST_F(DmodSnPrintfTest, SnPrintfSmallUnsignedLongLong)
{
char buffer[64];
uint64_t value = 42ULL;
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%llu", value);

ASSERT_EQ(result, 2);
ASSERT_STREQ(buffer, "42");
}

/**
* @brief Test for Dmod_SnPrintf with zero %llu value
*
* The test checks if the function handles zero unsigned long long value.
*/
TEST_F(DmodSnPrintfTest, SnPrintfZeroLongLong)
{
char buffer[64];
uint64_t value = 0ULL;
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%llu", value);

ASSERT_EQ(result, 1);
ASSERT_STREQ(buffer, "0");
}

/**
* @brief Test for Dmod_SnPrintf with mixed format specifiers including %llu
*
* The test checks if the function handles multiple format specifiers including long long.
*/
TEST_F(DmodSnPrintfTest, SnPrintfMixedWithLongLong)
{
char buffer[128];
uint64_t big_value = 1234567890123456789ULL;
int small_value = 42;
int result = Dmod_SnPrintf(buffer, sizeof(buffer),
"Small: %d, Big: %llu, Hex: %llx",
small_value, big_value, big_value);

ASSERT_GT(result, 0);
ASSERT_STREQ(buffer, "Small: 42, Big: 1234567890123456789, Hex: 112210f47de98115");
}

/**
* @brief Test for Dmod_SnPrintf with negative zero %lld
*
* The test checks if the function handles zero signed long long value.
*/
TEST_F(DmodSnPrintfTest, SnPrintfNegativeZeroLongLong)
{
char buffer[64];
int64_t value = 0LL;
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%lld", value);

ASSERT_EQ(result, 1);
ASSERT_STREQ(buffer, "0");
}

/**
* @brief Test for Dmod_SnPrintf with %lli (signed long long, 'i' variant)
*
* The test checks if the function handles %lli format specifier.
*/
TEST_F(DmodSnPrintfTest, SnPrintfSignedLongLongI)
{
char buffer[64];
int64_t value = -1234567890123456789LL;
int result = Dmod_SnPrintf(buffer, sizeof(buffer), "%lli", value);

ASSERT_GT(result, 0);
ASSERT_STREQ(buffer, "-1234567890123456789");
}


Loading