lib: os: cbprintf: Add function for converting package
Extend package copying functionality by adding function for converting a package. Function gets callback+context pair and converted package is part by part passed to that callback. Contrary to typical sprintf callback which works on chars, callback works with buffers. Existing cbprintf_package_copy function is implemented as static inline and uses new cbprintf_package_convert API. Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
parent
64ac44ad10
commit
07322b85c9
|
@ -11,6 +11,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <toolchain.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef CONFIG_CBPRINTF_LIBC_SUBSTS
|
||||
#include <stdio.h>
|
||||
|
@ -161,6 +162,16 @@ typedef int (*cbprintf_cb)(int c, void *ctx);
|
|||
typedef int (*cbprintf_cb)(/* int c, void *ctx */);
|
||||
#endif
|
||||
|
||||
/** @brief Signature for a cbprintf multibyte callback function.
|
||||
*
|
||||
* @param buf data.
|
||||
* @param len data length.
|
||||
* @param ctx a pointer to an object that provides context for the operation.
|
||||
*
|
||||
* return Amount of copied data or negative error code.
|
||||
*/
|
||||
typedef int (*cbprintf_convert_cb)(const void *buf, size_t len, void *ctx);
|
||||
|
||||
/** @brief Signature for a external formatter function identical to cbvprintf.
|
||||
*
|
||||
* This function expects the following parameters:
|
||||
|
@ -323,13 +334,75 @@ int cbvprintf_package(void *packaged,
|
|||
const char *format,
|
||||
va_list ap);
|
||||
|
||||
/** @brief Copy package with optional appending of strings.
|
||||
/** @brief Convert a package.
|
||||
*
|
||||
* Copying may include appending strings used in the package to the package body.
|
||||
* Converting may include appending strings used in the package to the package body.
|
||||
* If input package was created with @ref CBPRINTF_PACKAGE_ADD_RO_STR_POS or
|
||||
* @ref CBPRINTF_PACKAGE_ADD_RW_STR_POS, it contains information where strings
|
||||
* are located within the package. This information can be used to copy strings
|
||||
* into the output package.
|
||||
* during the conversion.
|
||||
*
|
||||
* @p cb is called with portions of the output package. At the end of the conversion
|
||||
* @p cb is called with null buffer.
|
||||
*
|
||||
* @param in_packaged Input package.
|
||||
*
|
||||
* @param in_len Input package length. If 0 package length will be retrieved
|
||||
* from the @p in_packaged
|
||||
*
|
||||
* @param cb callback called with portions of the converted package. If null only
|
||||
* length of the output package is calculated.
|
||||
*
|
||||
* @param ctx Context provided to the @p cb.
|
||||
*
|
||||
* @param flags Flags. See @ref CBPRINTF_PACKAGE_COPY_FLAGS.
|
||||
*
|
||||
* @param[in, out] strl if @p packaged is null, it is a pointer to the array where
|
||||
* @p strl_len first string lengths will is stored. If @p packaged is not null,
|
||||
* it contains lengths of first @p strl_len strings. It can be used to optimize
|
||||
* copying so that string length is calculated only once (at length calculation
|
||||
* phase when @p packaged is null.)
|
||||
*
|
||||
* @param strl_len Number of elements in @p strl array.
|
||||
*
|
||||
* @retval Positive output package size.
|
||||
* @retval -ENOSPC if @p packaged was not null and the space required to store
|
||||
* exceed @p len.
|
||||
*/
|
||||
int cbprintf_package_convert(void *in_packaged,
|
||||
size_t in_len,
|
||||
cbprintf_convert_cb cb,
|
||||
void *ctx,
|
||||
uint32_t flags,
|
||||
uint16_t *strl,
|
||||
size_t strl_len);
|
||||
|
||||
/* @interal Context used for package copying. */
|
||||
struct z_cbprintf_buf_desc {
|
||||
void *buf;
|
||||
size_t size;
|
||||
size_t off;
|
||||
};
|
||||
|
||||
/* @internal Function callback used for package copying. */
|
||||
static inline int z_cbprintf_cpy(const void *buf, size_t len, void *ctx)
|
||||
{
|
||||
struct z_cbprintf_buf_desc *desc = (struct z_cbprintf_buf_desc *)ctx;
|
||||
|
||||
if ((desc->size - desc->off) < len) {
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
memcpy(&((uint8_t *)desc->buf)[desc->off], (void *)buf, len);
|
||||
desc->off += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/** @brief Copy package with optional appending of strings.
|
||||
*
|
||||
* @ref cbprintf_package_convert is used to convert and store converted package
|
||||
* in the new location.
|
||||
*
|
||||
* @param in_packaged Input package.
|
||||
*
|
||||
|
@ -356,13 +429,23 @@ int cbvprintf_package(void *packaged,
|
|||
* @retval -ENOSPC if @p packaged was not null and the space required to store
|
||||
* exceed @p len.
|
||||
*/
|
||||
int cbprintf_package_copy(void *in_packaged,
|
||||
size_t in_len,
|
||||
void *packaged,
|
||||
size_t len,
|
||||
uint32_t flags,
|
||||
uint16_t *strl,
|
||||
size_t strl_len);
|
||||
static inline int cbprintf_package_copy(void *in_packaged,
|
||||
size_t in_len,
|
||||
void *packaged,
|
||||
size_t len,
|
||||
uint32_t flags,
|
||||
uint16_t *strl,
|
||||
size_t strl_len)
|
||||
{
|
||||
struct z_cbprintf_buf_desc buf_desc = {
|
||||
.buf = packaged,
|
||||
.size = len
|
||||
};
|
||||
|
||||
return cbprintf_package_convert(in_packaged, in_len,
|
||||
packaged ? z_cbprintf_cpy : NULL, &buf_desc,
|
||||
flags, strl, strl_len);
|
||||
}
|
||||
|
||||
/** @brief Convert package to fully self-contained (fsc) package.
|
||||
*
|
||||
|
|
|
@ -185,18 +185,6 @@ static int cbprintf_via_va_list(cbprintf_cb out,
|
|||
|
||||
#endif
|
||||
|
||||
static int z_strncpy(char *dst, const char *src, size_t num)
|
||||
{
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
dst[i] = src[i];
|
||||
if (src[i] == '\0') {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
static size_t get_package_len(void *packaged)
|
||||
{
|
||||
__ASSERT_NO_MSG(packaged != NULL);
|
||||
|
@ -224,21 +212,14 @@ static size_t get_package_len(void *packaged)
|
|||
return (size_t)(uintptr_t)(buf - start);
|
||||
}
|
||||
|
||||
static int append_string(void *dst, size_t max, const char *str, uint16_t strl)
|
||||
static int append_string(cbprintf_convert_cb cb, void *ctx, const char *str, uint16_t strl)
|
||||
{
|
||||
char *buf = dst;
|
||||
|
||||
if (dst == NULL) {
|
||||
if (cb == NULL) {
|
||||
return 1 + strlen(str);
|
||||
}
|
||||
|
||||
if (strl) {
|
||||
memcpy(dst, str, strl);
|
||||
|
||||
return strl;
|
||||
}
|
||||
|
||||
return z_strncpy(buf, str, max);
|
||||
strl = strl > 0 ? strl : strlen(str) + 1;
|
||||
return cb(str, strl, ctx);
|
||||
}
|
||||
|
||||
int cbvprintf_package(void *packaged, size_t len, uint32_t flags,
|
||||
|
@ -723,13 +704,13 @@ int cbpprintf_external(cbprintf_cb out,
|
|||
return cbprintf_via_va_list(out, formatter, ctx, fmt, buf);
|
||||
}
|
||||
|
||||
int cbprintf_package_copy(void *in_packaged,
|
||||
size_t in_len,
|
||||
void *packaged,
|
||||
size_t len,
|
||||
uint32_t flags,
|
||||
uint16_t *strl,
|
||||
size_t strl_len)
|
||||
int cbprintf_package_convert(void *in_packaged,
|
||||
size_t in_len,
|
||||
cbprintf_convert_cb cb,
|
||||
void *ctx,
|
||||
uint32_t flags,
|
||||
uint16_t *strl,
|
||||
size_t strl_len)
|
||||
{
|
||||
__ASSERT_NO_MSG(in_packaged != NULL);
|
||||
|
||||
|
@ -738,31 +719,31 @@ int cbprintf_package_copy(void *in_packaged,
|
|||
unsigned int args_size, ros_nbr, rws_nbr;
|
||||
bool rw_cpy;
|
||||
bool ro_cpy;
|
||||
struct z_cbprintf_desc *in_desc = in_packaged;
|
||||
|
||||
in_len != 0 ? in_len : get_package_len(in_packaged);
|
||||
|
||||
/* Get number of RO string indexes in the package and check if copying
|
||||
* includes appending those strings.
|
||||
*/
|
||||
ros_nbr = buf[2];
|
||||
ros_nbr = in_desc->ro_str_cnt;
|
||||
ro_cpy = ros_nbr &&
|
||||
(flags & CBPRINTF_PACKAGE_COPY_RO_STR) == CBPRINTF_PACKAGE_COPY_RO_STR;
|
||||
|
||||
/* Get number of RW string indexes in the package and check if copying
|
||||
* includes appending those strings.
|
||||
*/
|
||||
rws_nbr = buf[3];
|
||||
rws_nbr = in_desc->rw_str_cnt;
|
||||
rw_cpy = rws_nbr > 0 &&
|
||||
(flags & CBPRINTF_PACKAGE_COPY_RW_STR) == CBPRINTF_PACKAGE_COPY_RW_STR;
|
||||
|
||||
|
||||
/* If flags are not set or appending request without rw string indexes
|
||||
* present is chosen, just do a simple copy (or length calculation).
|
||||
* Assuming that it is the most common case.
|
||||
*/
|
||||
if (!rw_cpy && !ro_cpy) {
|
||||
if (packaged) {
|
||||
memcpy(packaged, in_packaged, in_len);
|
||||
if (cb) {
|
||||
cb(in_packaged, in_len, ctx);
|
||||
}
|
||||
|
||||
return in_len;
|
||||
|
@ -772,9 +753,9 @@ int cbprintf_package_copy(void *in_packaged,
|
|||
* done with strings appending.
|
||||
* Retrieve the size of the arg list.
|
||||
*/
|
||||
args_size = buf[0] * sizeof(int);
|
||||
args_size = in_desc->len * sizeof(int);
|
||||
|
||||
size_t out_len = in_len;
|
||||
int out_len;
|
||||
|
||||
/* Pointer to array with string locations. Array starts with read-only
|
||||
* string locations.
|
||||
|
@ -783,11 +764,12 @@ int cbprintf_package_copy(void *in_packaged,
|
|||
size_t strl_cnt = 0;
|
||||
|
||||
/* If null destination, just calculate output length. */
|
||||
if (packaged == NULL) {
|
||||
if (cb == NULL) {
|
||||
out_len = (int)in_len;
|
||||
if (ro_cpy) {
|
||||
for (int i = 0; i < ros_nbr; i++) {
|
||||
const char *str = *(const char **)&buf32[*str_pos];
|
||||
int len = append_string(NULL, 0, str, 0);
|
||||
int len = append_string(cb, NULL, str, 0);
|
||||
|
||||
/* If possible store calculated string length. */
|
||||
if (strl && strl_cnt < strl_len) {
|
||||
|
@ -813,7 +795,7 @@ int cbprintf_package_copy(void *in_packaged,
|
|||
|
||||
if ((is_ro && flags & CBPRINTF_PACKAGE_COPY_RO_STR) ||
|
||||
(!is_ro && flags & CBPRINTF_PACKAGE_COPY_RW_STR)) {
|
||||
int len = append_string(NULL, 0, str, 0);
|
||||
int len = append_string(cb, NULL, str, 0);
|
||||
|
||||
/* If possible store calculated string length. */
|
||||
if (strl && strl_cnt < strl_len) {
|
||||
|
@ -835,37 +817,37 @@ int cbprintf_package_copy(void *in_packaged,
|
|||
return out_len;
|
||||
}
|
||||
|
||||
struct z_cbprintf_desc out_desc;
|
||||
/* At least one is copied in. */
|
||||
uint8_t cpy_str_pos[16];
|
||||
/* Up to one will be kept since if both types are kept it returns earlier. */
|
||||
uint8_t keep_str_pos[16];
|
||||
uint8_t scpy_cnt;
|
||||
uint8_t *dst = packaged;
|
||||
uint8_t *dst_hdr = packaged;
|
||||
|
||||
memcpy(dst, in_packaged, args_size);
|
||||
dst += args_size;
|
||||
|
||||
/* Pointer to the beginning of string locations in the destination package. */
|
||||
uint8_t *dst_str_loc = dst;
|
||||
uint8_t keep_cnt;
|
||||
uint8_t *dst;
|
||||
int rv;
|
||||
|
||||
/* If read-only strings shall be appended to the output package copy
|
||||
* their indexes to the local array, otherwise indicate that indexes
|
||||
* shall remain in the output package.
|
||||
*/
|
||||
if (ro_cpy) {
|
||||
memcpy(cpy_str_pos, str_pos, ros_nbr);
|
||||
scpy_cnt = ros_nbr;
|
||||
/* Read only string indexes removed from package. */
|
||||
dst_hdr[2] = 0;
|
||||
str_pos += ros_nbr;
|
||||
keep_cnt = 0;
|
||||
dst = cpy_str_pos;
|
||||
} else if (ros_nbr && flags & CBPRINTF_PACKAGE_COPY_KEEP_RO_STR) {
|
||||
scpy_cnt = 0;
|
||||
keep_cnt = ros_nbr;
|
||||
dst = keep_str_pos;
|
||||
} else {
|
||||
scpy_cnt = 0;
|
||||
if (ros_nbr && flags & CBPRINTF_PACKAGE_COPY_KEEP_RO_STR) {
|
||||
memcpy(dst, str_pos, ros_nbr);
|
||||
dst += ros_nbr;
|
||||
str_pos += ros_nbr;
|
||||
} else {
|
||||
dst_hdr[2] = 0;
|
||||
}
|
||||
keep_cnt = 0;
|
||||
dst = NULL;
|
||||
}
|
||||
if (dst) {
|
||||
memcpy(dst, str_pos, ros_nbr);
|
||||
}
|
||||
str_pos += ros_nbr;
|
||||
|
||||
/* Go through read-write strings and identify which shall be appended.
|
||||
* Note that there may be read-only strings there. Use address evaluation
|
||||
|
@ -877,66 +859,83 @@ int cbprintf_package_copy(void *in_packaged,
|
|||
|
||||
if (is_ro) {
|
||||
if (flags & CBPRINTF_PACKAGE_COPY_RO_STR) {
|
||||
__ASSERT_NO_MSG(scpy_cnt < sizeof(cpy_str_pos));
|
||||
cpy_str_pos[scpy_cnt++] = *str_pos;
|
||||
} else if (flags & CBPRINTF_PACKAGE_COPY_KEEP_RO_STR) {
|
||||
*dst++ = *str_pos;
|
||||
/* Increment amount of ro locations. */
|
||||
dst_hdr[2]++;
|
||||
__ASSERT_NO_MSG(keep_cnt < sizeof(keep_str_pos));
|
||||
keep_str_pos[keep_cnt++] = *str_pos;
|
||||
} else {
|
||||
/* Drop information about ro_str location. */
|
||||
}
|
||||
} else {
|
||||
if (flags & CBPRINTF_PACKAGE_COPY_RW_STR) {
|
||||
__ASSERT_NO_MSG(scpy_cnt < sizeof(cpy_str_pos));
|
||||
cpy_str_pos[scpy_cnt++] = *str_pos;
|
||||
} else {
|
||||
*dst++ = *str_pos;
|
||||
__ASSERT_NO_MSG(keep_cnt < sizeof(keep_str_pos));
|
||||
keep_str_pos[keep_cnt++] = *str_pos;
|
||||
}
|
||||
}
|
||||
str_pos++;
|
||||
}
|
||||
|
||||
/* Increment amount of strings appended to the package. */
|
||||
dst_hdr[1] += scpy_cnt;
|
||||
/* Update number of rw string locations in the package. */
|
||||
dst_hdr[3] = (uint8_t)(uintptr_t)(dst - dst_str_loc) - dst_hdr[2];
|
||||
/* Set amount of strings appended to the package. */
|
||||
out_desc.len = in_desc->len;
|
||||
out_desc.str_cnt = in_desc->str_cnt + scpy_cnt;
|
||||
out_desc.rw_str_cnt = (flags & CBPRINTF_PACKAGE_COPY_RW_STR) ? 0 : keep_cnt;
|
||||
out_desc.ro_str_cnt = (flags & CBPRINTF_PACKAGE_COPY_RO_STR) ? 0 :
|
||||
((flags & CBPRINTF_PACKAGE_COPY_KEEP_RO_STR) ? keep_cnt : 0);
|
||||
|
||||
/* Temporary overwrite input descriptor to allow bulk transfer */
|
||||
struct z_cbprintf_desc in_desc_backup = *in_desc;
|
||||
*in_desc = out_desc;
|
||||
|
||||
/* Copy package header and arguments. */
|
||||
rv = cb(in_packaged, args_size, ctx);
|
||||
if (rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
out_len = rv;
|
||||
/* Restore input descriptor. */
|
||||
*in_desc = in_desc_backup;
|
||||
|
||||
/* Copy string positions which are kept. */
|
||||
rv = cb(keep_str_pos, keep_cnt, ctx);
|
||||
if (rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
out_len += rv;
|
||||
|
||||
/* Copy appended strings from source package to destination. */
|
||||
size_t strs_len = in_len - (args_size + ros_nbr + rws_nbr);
|
||||
|
||||
memcpy(dst, str_pos, strs_len);
|
||||
|
||||
dst += strs_len;
|
||||
|
||||
if (scpy_cnt == 0) {
|
||||
return dst - dst_hdr;
|
||||
}
|
||||
|
||||
/* Calculate remaining space in the buffer. */
|
||||
size_t rem = len - ((size_t)(uintptr_t)(dst - dst_hdr));
|
||||
|
||||
if (rem <= scpy_cnt) {
|
||||
return -ENOSPC;
|
||||
rv = cb(str_pos, strs_len, ctx);
|
||||
if (rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
out_len += rv;
|
||||
|
||||
/* Append strings */
|
||||
for (int i = 0; i < scpy_cnt; i++) {
|
||||
uint8_t loc = cpy_str_pos[i];
|
||||
const char *str = *(const char **)&buf32[loc];
|
||||
int cpy_len;
|
||||
uint16_t str_len = strl ? strl[i] : 0;
|
||||
|
||||
*dst = loc;
|
||||
rem--;
|
||||
dst++;
|
||||
cpy_len = append_string(dst, rem, str, str_len);
|
||||
|
||||
if (cpy_len < 0) {
|
||||
return -ENOSPC;
|
||||
rv = cb(&loc, 1, ctx);
|
||||
if (rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
out_len += rv;
|
||||
|
||||
rem -= cpy_len;
|
||||
dst += cpy_len;
|
||||
rv = append_string(cb, ctx, str, str_len);
|
||||
if (rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
out_len += rv;
|
||||
}
|
||||
|
||||
return len - rem;
|
||||
/* Empty call (can be interpreted as flushing) */
|
||||
(void)cb(NULL, 0, ctx);
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue