Program Listing for File printf_gadget.h
↰ Return to documentation for file (rcsw/stdio/printf_gadget.h
)
#pragma once
/*******************************************************************************
* Includes
******************************************************************************/
#include "rcsw/stdio/printf_config.h"
#include "rcsw/al/types.h"
#include "rcsw/stdio/stdio.h"
#include "rcsw/common/common.h"
/* \cond INTERNAL */
/*******************************************************************************
* Structure Definitions
******************************************************************************/
// wrapper (used as buffer) for output function type
//
// One of the following must hold:
// 1. max_chars is 0
// 2. buffer is non-null
// 3. function is non-null
//
// ... otherwise bad things will happen.
struct printf_output_gadget {
void (*cb)(int c, void* extra_arg);
void* extra_cb_arg;
char* buffer;
printf_size_t pos;
printf_size_t max_chars;
};
/*******************************************************************************
* API Functions
******************************************************************************/
BEGIN_C_DECLS
static inline struct printf_output_gadget gadget_init(void) {
struct printf_output_gadget gadget;
gadget.cb = NULL;
gadget.extra_cb_arg = NULL;
gadget.buffer = NULL;
gadget.pos = 0;
gadget.max_chars = 0;
return gadget;
}
static inline struct printf_output_gadget gadget_init_with_cb(
void (*cb)(int, void*),
void* extra_arg) {
struct printf_output_gadget result = gadget_init();
result.cb = cb;
result.extra_cb_arg = extra_arg;
result.max_chars = PRINTF_MAX_BUF_SIZE;
return result;
}
static inline struct printf_output_gadget gadget_init_with_buf(
char* buffer,
size_t buffer_size) {
printf_size_t usable_buffer_size = RCSW_MIN(buffer_size,
(size_t)PRINTF_MAX_BUF_SIZE);
struct printf_output_gadget result = gadget_init();
if (buffer != NULL) {
result.buffer = buffer;
result.max_chars = usable_buffer_size;
}
return result;
}
/*
* Note: This function currently assumes it is not passed a '\0' c, or
* alternatively, that '\0' can be passed to the function in the output
* gadget. The former assumption holds within the printf library. It also
* assumes that the output gadget has been properly initialized.
*/
static inline void gadget_putchar(struct printf_output_gadget* gadget, char c) {
printf_size_t write_pos = gadget->pos++;
// We're _always_ increasing pos, so as to count how may characters
// _would_ have been written if not for the max_chars limitation
if (write_pos >= gadget->max_chars) {
return;
}
if (gadget->cb != NULL) {
// No check for c == '\0' .
gadget->cb(c, gadget->extra_cb_arg);
} else {
// it must be the case that gadget->buffer != NULL , due to the constraint
// on struct printf_output_gadget ; and note we're relying on write_pos
// being non-negative.
gadget->buffer[write_pos] = c;
}
}
// Possibly-write the string-terminating '\0' character
static inline void gadget_append_termination(
struct printf_output_gadget* gadget) {
if (gadget->cb != NULL || gadget->max_chars == 0) {
return;
}
if (gadget->buffer == NULL) {
return;
}
printf_size_t null_char_pos = gadget->pos < gadget->max_chars ? gadget->pos : gadget->max_chars - 1;
gadget->buffer[null_char_pos] = '\0';
}
static inline void putchar_wrapper(int c, void* unused) {
(void) unused;
stdio_putchar(c);
}
static inline struct printf_output_gadget gadget_putchar_extern(void) {
return gadget_init_with_cb(putchar_wrapper, NULL);
}
/* \endcond */
END_C_DECLS