mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #20843 from benpicco/string_writer
sys/string_utils: add string_writer helper
This commit is contained in:
commit
243ca3114b
@ -64,6 +64,10 @@ extern "C" {
|
||||
*/
|
||||
#define IRQ_API_INLINED (1)
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#define HAS_FLASH_UTILS_ARCH 1
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -21,6 +21,7 @@
|
||||
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
/* if explicit_bzero() is provided by standard C lib, it may be defined in
|
||||
@ -29,6 +30,7 @@
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "flash_utils.h"
|
||||
#include "modules.h"
|
||||
|
||||
#ifndef STRING_UTILS_H
|
||||
@ -38,6 +40,80 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief String Writer structure.
|
||||
* Helper for writing multiple formatted strings to a buffer
|
||||
*/
|
||||
typedef struct {
|
||||
const char *start; /**< start of the target buffer */
|
||||
char *position; /**< current write pointer */
|
||||
size_t capacity; /**< remaining capacity of the buffer */
|
||||
} string_writer_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize a string writer structure
|
||||
*
|
||||
* @param[out] sw String Writer object to initialize
|
||||
* @param[in] buffer destination buffer
|
||||
* @param[in] len size of the destination buffer
|
||||
*/
|
||||
static inline void string_writer_init(string_writer_t *sw, void *buffer, size_t len)
|
||||
{
|
||||
assert(buffer && len);
|
||||
|
||||
sw->start = buffer;
|
||||
sw->position = buffer;
|
||||
sw->capacity = len;
|
||||
sw->position[0] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the size of the string contained by the string writer
|
||||
* @param[in] sw String Writer to query
|
||||
* @return size of the string
|
||||
*/
|
||||
static inline size_t string_writer_len(const string_writer_t *sw)
|
||||
{
|
||||
return sw->position - sw->start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the string contained by the string writer
|
||||
* @param[in] sw String Writer to query
|
||||
* @return the string assembled by string writer
|
||||
*/
|
||||
static inline const char *string_writer_str(const string_writer_t *sw)
|
||||
{
|
||||
return sw->start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief internal helper macro
|
||||
*/
|
||||
#if IS_ACTIVE(HAS_FLASH_UTILS_ARCH)
|
||||
#define __swprintf flash_swprintf
|
||||
#else
|
||||
#define __swprintf swprintf
|
||||
__attribute__ ((format (printf, 2, 3)))
|
||||
#endif
|
||||
/**
|
||||
* @brief Write a formatted string to a buffer
|
||||
* The string will be truncated if there is not enough space left in
|
||||
* the destination buffer.
|
||||
* A terminating `\0` character is always included.
|
||||
*
|
||||
* @param[in] sw String Writer to write to
|
||||
* @param[in] format format string to write
|
||||
*
|
||||
* @return number of bytes written on success
|
||||
* -E2BIG if the string was truncated
|
||||
*/
|
||||
int __swprintf(string_writer_t *sw, FLASH_ATTR const char *restrict format, ...);
|
||||
|
||||
#if IS_ACTIVE(HAS_FLASH_UTILS_ARCH)
|
||||
#define swprintf(sw, fmt, ...) flash_swprintf(sw, TO_FLASH(fmt), ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* explicit_bzero is provided if:
|
||||
* - glibc is used as C lib (only with board natvie)
|
||||
* - newlib is used and __BSD_VISIBILE is set
|
||||
|
@ -14,6 +14,8 @@
|
||||
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "string_utils.h"
|
||||
|
||||
@ -50,4 +52,32 @@ const void *memchk(const void *data, uint8_t c, size_t len)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int __swprintf(string_writer_t *sw, FLASH_ATTR const char *restrict format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int res;
|
||||
|
||||
va_start(args, format);
|
||||
#ifdef __clang__
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wformat-nonliteral\"") \
|
||||
res = flash_vsnprintf(sw->position, sw->capacity, format, args);
|
||||
_Pragma("clang diagnostic pop")
|
||||
#else
|
||||
res = flash_vsnprintf(sw->position, sw->capacity, format, args);
|
||||
#endif
|
||||
va_end(args);
|
||||
|
||||
if (res < (int)sw->capacity) {
|
||||
sw->capacity -= res;
|
||||
sw->position += res;
|
||||
} else {
|
||||
sw->position += sw->capacity;
|
||||
sw->capacity = 0;
|
||||
res = -E2BIG;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
@ -9,6 +9,9 @@ BOARD_BLACKLIST := arduino-duemilanove \
|
||||
atmega256rfr2-xpro \
|
||||
atmega328p \
|
||||
atmega328p-xplained-mini \
|
||||
atxmega-a1-xplained \
|
||||
atxmega-a1u-xpro \
|
||||
atxmega-a3bu-xplained \
|
||||
derfmega128 \
|
||||
derfmega256 \
|
||||
f4vi1 \
|
||||
|
@ -30,6 +30,41 @@ static void test_libc_strscpy(void)
|
||||
TEST_ASSERT_EQUAL_INT(strscpy(buffer, "empty", 0), -E2BIG);
|
||||
}
|
||||
|
||||
static void test_libc_swprintf(void)
|
||||
{
|
||||
string_writer_t sw;
|
||||
char buffer[32];
|
||||
int res;
|
||||
|
||||
string_writer_init(&sw, buffer, sizeof(buffer));
|
||||
|
||||
/* check that string can be written completely */
|
||||
res = swprintf(&sw, "Hello World!");
|
||||
TEST_ASSERT_EQUAL_INT(res, 12);
|
||||
TEST_ASSERT_EQUAL_INT(string_writer_len(&sw), 12);
|
||||
TEST_ASSERT_EQUAL_INT(strcmp("Hello World!", string_writer_str(&sw)), 0);
|
||||
|
||||
/* check that we can add to the string */
|
||||
/* Writing 10 characters, returns 10 bytes written */
|
||||
res = swprintf(&sw, "0123456789");
|
||||
TEST_ASSERT_EQUAL_INT(res, 10);
|
||||
TEST_ASSERT_EQUAL_INT(strcmp("Hello World!0123456789", string_writer_str(&sw)), 0);
|
||||
|
||||
/* The string does not fit completely into the buffer, so it gets truncated */
|
||||
res = swprintf(&sw, "01234567891");
|
||||
TEST_ASSERT_EQUAL_INT(res, -E2BIG);
|
||||
TEST_ASSERT_EQUAL_INT(strcmp("Hello World!0123456789012345678", string_writer_str(&sw)), 0);
|
||||
|
||||
/* You can't write to a full buffer */
|
||||
res = swprintf(&sw, "###");
|
||||
TEST_ASSERT_EQUAL_INT(res, -E2BIG);
|
||||
|
||||
/* check if string was truncated as expected */
|
||||
TEST_ASSERT_EQUAL_INT(string_writer_len(&sw), 32);
|
||||
TEST_ASSERT_EQUAL_INT(strcmp("Hello World!0123456789012345678",
|
||||
string_writer_str(&sw)), 0);
|
||||
}
|
||||
|
||||
static void test_libc_memchk(void)
|
||||
{
|
||||
char buffer[32];
|
||||
@ -101,6 +136,7 @@ Test *tests_libc_tests(void)
|
||||
{
|
||||
EMB_UNIT_TESTFIXTURES(fixtures) {
|
||||
new_TestFixture(test_libc_strscpy),
|
||||
new_TestFixture(test_libc_swprintf),
|
||||
new_TestFixture(test_libc_memchk),
|
||||
new_TestFixture(test_libc_endian),
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user