Support long and long long types in TEST_PRINTF

This change helps Unity parse and print correctly in cases where a long
or long long type is passed to TEST_PRINTF.

Example situations:

```C
// With %u:
TEST_PRINTF("%u %d\n", ((1ULL << 63) - 1), 5); //  --> prints 11982546 -1 (both arguments incorrect because only 4 of the 8 bytes were read out of the va_list)

// With %llu, UNITY_SUPPORT_64=0
TEST_PRINTF("%llu %d\n", ((1ULL << 63) - 1), 5); //  --> prints 4294967295 5 (first argument wrapped, second argument intact)

// With %llu, UNITY_SUPPORT_64=1
TEST_PRINTF("%llu %d\n", ((1ULL << 63) - 1), 5); //  --> prints 9223372036854775807 5 (both arguments correct)
```
This commit is contained in:
jonath.re@gmail.com
2022-07-27 02:39:14 +02:00
parent 3852926c00
commit 612aec09e8
2 changed files with 118 additions and 7 deletions

View File

@@ -240,7 +240,7 @@ _Example:_
Unity provides a simple (and very basic) printf-like string output implementation, which is able to print a string modified by the following format string modifiers: Unity provides a simple (and very basic) printf-like string output implementation, which is able to print a string modified by the following format string modifiers:
- __%d__ - signed value (decimal) - __%d__ - signed value (decimal)
- __%i__ - same as __%i__ - __%i__ - same as __%d__
- __%u__ - unsigned value (decimal) - __%u__ - unsigned value (decimal)
- __%f__ - float/Double (if float support is activated) - __%f__ - float/Double (if float support is activated)
- __%g__ - same as __%f__ - __%g__ - same as __%f__
@@ -252,6 +252,15 @@ Unity provides a simple (and very basic) printf-like string output implementatio
- __%s__ - a string (e.g. "string") - __%s__ - a string (e.g. "string")
- __%%__ - The "%" symbol (escaped) - __%%__ - The "%" symbol (escaped)
Length specifiers are also supported. If you are using long long types, make sure UNITY_SUPPORT_64 is true to ensure they are printed correctly.
- __%ld__ - signed long value (decimal)
- __%lld__ - signed long long value (decimal)
- __%lu__ - unsigned long value (decimal)
- __%llu__ - unsigned long long value (decimal)
- __%lx__ - unsigned long value (hexadecimal)
- __%llx__ - unsigned long long value (hexadecimal)
_Example:_ _Example:_
```C ```C
@@ -267,6 +276,7 @@ TEST_PRINTF("Pointer %p\n", &a);
TEST_PRINTF("Character %c\n", 'F'); TEST_PRINTF("Character %c\n", 'F');
TEST_PRINTF("String %s\n", "My string"); TEST_PRINTF("String %s\n", "My string");
TEST_PRINTF("Percent %%\n"); TEST_PRINTF("Percent %%\n");
TEST_PRINTF("Unsigned long long %llu\n", 922337203685477580);
TEST_PRINTF("Color Red \033[41mFAIL\033[0m\n"); TEST_PRINTF("Color Red \033[41mFAIL\033[0m\n");
TEST_PRINTF("\n"); TEST_PRINTF("\n");
TEST_PRINTF("Multiple (%d) (%i) (%u) (%x)\n", -100, 0, 200, 0x12345); TEST_PRINTF("Multiple (%d) (%i) (%u) (%x)\n", -100, 0, 200, 0x12345);

View File

@@ -1823,10 +1823,96 @@ UNITY_INTERNAL_PTR UnityDoubleToPtr(const double num)
} }
#endif #endif
#ifdef UNITY_INCLUDE_PRINT_FORMATTED
/*-----------------------------------------------
* printf length modifier helpers
*-----------------------------------------------*/
enum UnityLengthModifier {
UNITY_LENGTH_MODIFIER_NONE,
UNITY_LENGTH_MODIFIER_LONG_LONG,
UNITY_LENGTH_MODIFIER_LONG,
};
#define UNITY_EXTRACT_ARG(NUMBER_T, NUMBER, LENGTH_MOD, VA, ARG_T) \
do { \
switch (LENGTH_MOD) \
{ \
case UNITY_LENGTH_MODIFIER_LONG_LONG: \
{ \
NUMBER = (NUMBER_T)va_arg(VA, long long ARG_T); \
break; \
} \
case UNITY_LENGTH_MODIFIER_LONG: \
{ \
NUMBER = (NUMBER_T)va_arg(VA, long ARG_T); \
break; \
} \
case UNITY_LENGTH_MODIFIER_NONE: \
default: \
{ \
NUMBER = (NUMBER_T)va_arg(VA, ARG_T); \
break; \
} \
} \
} while (0)
static enum UnityLengthModifier UnityLengthModifierGet(const char *pch, int *length)
{
enum UnityLengthModifier length_mod;
switch (pch[0])
{
case 'l':
{
if (pch[1] == 'l')
{
*length = 2;
length_mod = UNITY_LENGTH_MODIFIER_LONG_LONG;
}
else
{
*length = 1;
length_mod = UNITY_LENGTH_MODIFIER_LONG;
}
break;
}
case 'h':
{
// short and char are converted to int
length_mod = UNITY_LENGTH_MODIFIER_NONE;
if (pch[1] == 'h')
{
*length = 2;
}
else
{
*length = 1;
}
break;
}
case 'j':
case 'z':
case 't':
case 'L':
{
// Not supported, but should gobble up the length specifier anyway
length_mod = UNITY_LENGTH_MODIFIER_NONE;
*length = 1;
break;
}
default:
{
length_mod = UNITY_LENGTH_MODIFIER_NONE;
*length = 0;
}
}
return length_mod;
}
/*----------------------------------------------- /*-----------------------------------------------
* printf helper function * printf helper function
*-----------------------------------------------*/ *-----------------------------------------------*/
#ifdef UNITY_INCLUDE_PRINT_FORMATTED
static void UnityPrintFVA(const char* format, va_list va) static void UnityPrintFVA(const char* format, va_list va)
{ {
const char* pch = format; const char* pch = format;
@@ -1841,12 +1927,17 @@ static void UnityPrintFVA(const char* format, va_list va)
if (pch != NULL) if (pch != NULL)
{ {
int length_mod_size;
enum UnityLengthModifier length_mod = UnityLengthModifierGet(pch, &length_mod_size);
pch += length_mod_size;
switch (*pch) switch (*pch)
{ {
case 'd': case 'd':
case 'i': case 'i':
{ {
const int number = va_arg(va, int); UNITY_INT number;
UNITY_EXTRACT_ARG(UNITY_INT, number, length_mod, va, int);
UnityPrintNumber((UNITY_INT)number); UnityPrintNumber((UNITY_INT)number);
break; break;
} }
@@ -1861,21 +1952,31 @@ static void UnityPrintFVA(const char* format, va_list va)
#endif #endif
case 'u': case 'u':
{ {
const unsigned int number = va_arg(va, unsigned int); UNITY_UINT number;
UnityPrintNumberUnsigned((UNITY_UINT)number); UNITY_EXTRACT_ARG(UNITY_UINT, number, length_mod, va, unsigned int);
UnityPrintNumberUnsigned(number);
break; break;
} }
case 'b': case 'b':
{ {
const unsigned int number = va_arg(va, unsigned int); UNITY_UINT number;
UNITY_EXTRACT_ARG(UNITY_UINT, number, length_mod, va, unsigned int);
const UNITY_UINT mask = (UNITY_UINT)0 - (UNITY_UINT)1; const UNITY_UINT mask = (UNITY_UINT)0 - (UNITY_UINT)1;
UNITY_OUTPUT_CHAR('0'); UNITY_OUTPUT_CHAR('0');
UNITY_OUTPUT_CHAR('b'); UNITY_OUTPUT_CHAR('b');
UnityPrintMask(mask, (UNITY_UINT)number); UnityPrintMask(mask, number);
break; break;
} }
case 'x': case 'x':
case 'X': case 'X':
{
UNITY_UINT number;
UNITY_EXTRACT_ARG(UNITY_UINT, number, length_mod, va, unsigned int);
UNITY_OUTPUT_CHAR('0');
UNITY_OUTPUT_CHAR('x');
UnityPrintNumberHex(number, 8);
break;
}
case 'p': case 'p':
{ {
const unsigned int number = va_arg(va, unsigned int); const unsigned int number = va_arg(va, unsigned int);