Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #79: Integrate @joshklod's format attribute addition #10

Merged
merged 2 commits into from
Jun 30, 2021
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
20 changes: 14 additions & 6 deletions printf.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ extern "C" {
#endif


#ifdef __GNUC__
# define ATTR_PRINTF(fmt, first_arg) \
__attribute__((format(__printf__, (fmt), (first_arg))))
#else
# define ATTR_PRINTF(fmt, first_arg) // Empty
#endif


/**
* Output a character to a custom device like UART, used by the printf() function
* This function is declared here only. You have to write your custom implementation somewhere
Expand All @@ -58,7 +66,7 @@ void _putchar(char character);
* \return The number of characters that are written into the array, not counting the terminating null character
*/
#define printf printf_
int printf_(const char* format, ...);
int printf_(const char* format, ...) ATTR_PRINTF(1, 2);


/**
Expand All @@ -69,7 +77,7 @@ int printf_(const char* format, ...);
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
*/
#define sprintf sprintf_
int sprintf_(char* buffer, const char* format, ...);
int sprintf_(char* buffer, const char* format, ...) ATTR_PRINTF(2, 3);


/**
Expand All @@ -84,8 +92,8 @@ int sprintf_(char* buffer, const char* format, ...);
*/
#define snprintf snprintf_
#define vsnprintf vsnprintf_
int snprintf_(char* buffer, size_t count, const char* format, ...);
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
int snprintf_(char* buffer, size_t count, const char* format, ...) ATTR_PRINTF(3, 4);
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va) ATTR_PRINTF(3, 0);


/**
Expand All @@ -95,7 +103,7 @@ int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
*/
#define vprintf vprintf_
int vprintf_(const char* format, va_list va);
int vprintf_(const char* format, va_list va) ATTR_PRINTF(1, 0);


/**
Expand All @@ -106,7 +114,7 @@ int vprintf_(const char* format, va_list va);
* \param format A string that specifies the format of the output
* \return The number of characters that are sent to the output function, not counting the terminating null character
*/
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...) ATTR_PRINTF(3, 4);


#ifdef __cplusplus
Expand Down
100 changes: 74 additions & 26 deletions test/test_suite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,6 @@ TEST_CASE("space flag", "[]" ) {
test::sprintf(buffer, "% 15.3f", 42.987);
REQUIRE(!strcmp(buffer, " 42.987"));

test::sprintf(buffer, "% s", "Hello testing");
REQUIRE(!strcmp(buffer, "Hello testing"));

test::sprintf(buffer, "% d", 1024);
REQUIRE(!strcmp(buffer, " 1024"));

Expand All @@ -179,6 +176,12 @@ TEST_CASE("space flag", "[]" ) {
test::sprintf(buffer, "% i", -1024);
REQUIRE(!strcmp(buffer, "-1024"));

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"

test::sprintf(buffer, "% s", "Hello testing");
REQUIRE(!strcmp(buffer, "Hello testing"));

test::sprintf(buffer, "% u", 1024);
REQUIRE(!strcmp(buffer, "1024"));

Expand All @@ -205,6 +208,8 @@ TEST_CASE("space flag", "[]" ) {

test::sprintf(buffer, "% c", 'x');
REQUIRE(!strcmp(buffer, "x"));

#pragma GCC diagnostic pop
}


Expand All @@ -229,9 +234,6 @@ TEST_CASE("+ flag", "[]" ) {
test::sprintf(buffer, "%+15d", -42);
REQUIRE(!strcmp(buffer, " -42"));

test::sprintf(buffer, "%+s", "Hello testing");
REQUIRE(!strcmp(buffer, "Hello testing"));

test::sprintf(buffer, "%+d", 1024);
REQUIRE(!strcmp(buffer, "+1024"));

Expand All @@ -244,6 +246,12 @@ TEST_CASE("+ flag", "[]" ) {
test::sprintf(buffer, "%+i", -1024);
REQUIRE(!strcmp(buffer, "-1024"));

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"

test::sprintf(buffer, "%+s", "Hello testing");
REQUIRE(!strcmp(buffer, "Hello testing"));

test::sprintf(buffer, "%+u", 1024);
REQUIRE(!strcmp(buffer, "1024"));

Expand Down Expand Up @@ -271,6 +279,8 @@ TEST_CASE("+ flag", "[]" ) {
test::sprintf(buffer, "%+c", 'x');
REQUIRE(!strcmp(buffer, "x"));

#pragma GCC diagnostic pop

test::sprintf(buffer, "%+.0d", 0);
REQUIRE(!strcmp(buffer, "+"));
}
Expand Down Expand Up @@ -332,6 +342,9 @@ TEST_CASE("- flag", "[]" ) {
test::sprintf(buffer, "%-15d", -42);
REQUIRE(!strcmp(buffer, "-42 "));

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"

test::sprintf(buffer, "%-0d", 42);
REQUIRE(!strcmp(buffer, "42"));

Expand Down Expand Up @@ -381,6 +394,8 @@ TEST_CASE("- flag", "[]" ) {
#else
REQUIRE(!strcmp(buffer, "g"));
#endif

#pragma GCC diagnostic pop
}


Expand All @@ -395,8 +410,15 @@ TEST_CASE("# flag", "[]" ) {
REQUIRE(!strcmp(buffer, ""));
test::sprintf(buffer, "%#.8x", 0x614e);
REQUIRE(!strcmp(buffer, "0x0000614e"));

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
#pragma GCC diagnostic ignored "-Wformat-extra-args"

test::sprintf(buffer,"%#b", 6);
REQUIRE(!strcmp(buffer, "0b110"));

#pragma GCC diagnostic pop
}


Expand Down Expand Up @@ -653,6 +675,9 @@ TEST_CASE("width -20", "[]" ) {
}


#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"

TEST_CASE("width 0-20", "[]" ) {
char buffer[100];

Expand Down Expand Up @@ -699,6 +724,8 @@ TEST_CASE("width 0-20", "[]" ) {
REQUIRE(!strcmp(buffer, "x "));
}

#pragma GCC diagnostic pop


TEST_CASE("padding 20", "[]" ) {
char buffer[100];
Expand Down Expand Up @@ -785,6 +812,9 @@ TEST_CASE("padding .20", "[]" ) {
TEST_CASE("padding #020", "[]" ) {
char buffer[100];

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"

test::sprintf(buffer, "%#020d", 1024);
REQUIRE(!strcmp(buffer, "00000000000000001024"));

Expand All @@ -803,6 +833,8 @@ TEST_CASE("padding #020", "[]" ) {
test::sprintf(buffer, "%#020u", 4294966272U);
REQUIRE(!strcmp(buffer, "00000000004294966272"));

#pragma GCC diagnostic pop

test::sprintf(buffer, "%#020o", 511);
REQUIRE(!strcmp(buffer, "00000000000000000777"));

Expand All @@ -826,6 +858,9 @@ TEST_CASE("padding #020", "[]" ) {
TEST_CASE("padding #20", "[]" ) {
char buffer[100];

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"

test::sprintf(buffer, "%#20d", 1024);
REQUIRE(!strcmp(buffer, " 1024"));

Expand All @@ -844,6 +879,8 @@ TEST_CASE("padding #20", "[]" ) {
test::sprintf(buffer, "%#20u", 4294966272U);
REQUIRE(!strcmp(buffer, " 4294966272"));

#pragma GCC diagnostic pop

test::sprintf(buffer, "%#20o", 511);
REQUIRE(!strcmp(buffer, " 0777"));

Expand Down Expand Up @@ -1067,11 +1104,16 @@ TEST_CASE("length", "[]" ) {
test::sprintf(buffer, "%20.X", 0U);
REQUIRE(!strcmp(buffer, " "));

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"

test::sprintf(buffer, "%02.0u", 0U);
REQUIRE(!strcmp(buffer, " "));

test::sprintf(buffer, "%02.0d", 0);
REQUIRE(!strcmp(buffer, " "));

#pragma GCC diagnostic pop
}


Expand Down Expand Up @@ -1284,27 +1326,27 @@ TEST_CASE("types", "[]" ) {
test::sprintf(buffer, "%llu", 18446744073709551615LLU);
REQUIRE(!strcmp(buffer, "18446744073709551615"));

test::sprintf(buffer, "%zu", 2147483647UL);
test::sprintf(buffer, "%zu", (size_t)2147483647UL);
REQUIRE(!strcmp(buffer, "2147483647"));

test::sprintf(buffer, "%zd", 2147483647UL);
test::sprintf(buffer, "%zd", (size_t)2147483647UL);
REQUIRE(!strcmp(buffer, "2147483647"));

if (sizeof(size_t) == sizeof(long)) {
test::sprintf(buffer, "%zi", -2147483647L);
REQUIRE(!strcmp(buffer, "-2147483647"));
}
else {
test::sprintf(buffer, "%zi", -2147483647LL);
REQUIRE(!strcmp(buffer, "-2147483647"));
}
test::sprintf(buffer, "%zi", (signed size_t)-2147483647L);
REQUIRE(!strcmp(buffer, "-2147483647"));

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
#pragma GCC diagnostic ignored "-Wformat-extra-args"

test::sprintf(buffer, "%b", 60000);
REQUIRE(!strcmp(buffer, "1110101001100000"));

test::sprintf(buffer, "%lb", 12345678L);
REQUIRE(!strcmp(buffer, "101111000110000101001110"));

#pragma GCC diagnostic pop

test::sprintf(buffer, "%o", 60000);
REQUIRE(!strcmp(buffer, "165140"));

Expand Down Expand Up @@ -1332,10 +1374,10 @@ TEST_CASE("types", "[]" ) {
test::sprintf(buffer, "%s", "A Test");
REQUIRE(!strcmp(buffer, "A Test"));

test::sprintf(buffer, "%hhu", 0xFFFFUL);
test::sprintf(buffer, "%hhu", 0xFFFFU);
REQUIRE(!strcmp(buffer, "255"));

test::sprintf(buffer, "%hu", 0x123456UL);
test::sprintf(buffer, "%hu", 0x123456U);
REQUIRE(!strcmp(buffer, "13398"));

test::sprintf(buffer, "%s%hhi %hu", "Test", 10000, 0xFFFFFFFF);
Expand All @@ -1345,14 +1387,8 @@ TEST_CASE("types", "[]" ) {
REQUIRE(!strcmp(buffer, "a"));

// TBD
if (sizeof(intmax_t) == sizeof(long)) {
test::sprintf(buffer, "%ji", -2147483647L);
REQUIRE(!strcmp(buffer, "-2147483647"));
}
else {
test::sprintf(buffer, "%ji", -2147483647LL);
REQUIRE(!strcmp(buffer, "-2147483647"));
}
test::sprintf(buffer, "%ji", (intmax_t)-2147483647L);
REQUIRE(!strcmp(buffer, "-2147483647"));
}


Expand Down Expand Up @@ -1394,13 +1430,19 @@ TEST_CASE("pointer", "[]" ) {
}


#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
#pragma GCC diagnostic ignored "-Wformat-extra-args"

TEST_CASE("unknown flag", "[]" ) {
char buffer[100];

test::sprintf(buffer, "%kmarco", 42, 37);
REQUIRE(!strcmp(buffer, "kmarco"));
}

#pragma GCC diagnostic pop


TEST_CASE("string length", "[]" ) {
char buffer[100];
Expand All @@ -1420,9 +1462,15 @@ TEST_CASE("string length", "[]" ) {
test::sprintf(buffer, "%.4s%.2s", "123456", "abcdef");
REQUIRE(!strcmp(buffer, "1234ab"));

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
#pragma GCC diagnostic ignored "-Wformat-extra-args"

test::sprintf(buffer, "%.4.2s", "123456");
REQUIRE(!strcmp(buffer, ".2s"));

#pragma GCC diagnostic pop

test::sprintf(buffer, "%.*s", 3, "123456");
REQUIRE(!strcmp(buffer, "123"));
}
Expand Down