CloverBootloader/Include/Library/printf_lite.h

298 lines
13 KiB
C
Raw Normal View History

//
// printf_lite.hpp
//
// Created by jief the 04 Apr 2019.
// Imported in CLover the 24 Feb 2020
//
#ifndef __PRINTF_LITE_H__
#define __PRINTF_LITE_H__
#include <stdarg.h>
#include <stddef.h> // for size_t
2020-03-26 13:59:20 +01:00
#include <printf_lite-conf.h>
#if defined(__cplusplus)
extern "C"
{
#endif
#ifdef DEBUG
#define DEFINE_SECTIONS 0
#endif
// To be able to compile on a platform where there are already std function snprintf, we need to change the name
#ifndef PRINTF_CFUNCTION_PREFIX
#define PRINTF_CFUNCTION_PREFIX
#endif
#ifndef PRINTF_CFUNCTION_SUFFIX
#define PRINTF_CFUNCTION_SUFFIX fl
#endif
#define PRINTF_MAKE_FN_NAME(prefix, root, suffix) prefix##root##suffix
#define PRINTF_FUNCTION_NAME(prefix, root, suffix) PRINTF_MAKE_FN_NAME(prefix, root, suffix)
#ifndef PRINTF_UTF8_INPUT_SUPPORT
#define PRINTF_UTF8_INPUT_SUPPORT 1
#endif
#ifndef PRINTF_UNICODE_INPUT_SUPPORT
#define PRINTF_UNICODE_INPUT_SUPPORT 1 // enable %ls. %ls = UTF16 or UTF32 string, depending of the size of wchar_t
#endif
#ifndef PRINTF_UTF8_OUTPUT_SUPPORT
#define PRINTF_UTF8_OUTPUT_SUPPORT 1
#endif
#ifndef PRINTF_UNICODE_OUTPUT_SUPPORT
#define PRINTF_UNICODE_OUTPUT_SUPPORT 1 // UTF16 or UTF32 depending of the size of wchar_t
#endif
#if PRINTF_UTF8_OUTPUT_SUPPORT == 0 && PRINTF_UNICODE_OUTPUT_SUPPORT == 0
#error no output format supported.
#endif
#ifndef PRINTF_LITE_SNPRINTF_SUPPORT
#define PRINTF_LITE_SNPRINTF_SUPPORT 1
#endif
#ifndef VSNWPRINTF_RETURN_MINUS1_ON_OVERFLOW
#define VSNWPRINTF_RETURN_MINUS1_ON_OVERFLOW 0
#endif
#ifndef PRINTF_CHECK_UNSUPPORTED_STRING_FORMAT
#define PRINTF_CHECK_UNSUPPORTED_STRING_FORMAT 0
#endif
/*
* A buffer is not needed. On some case it could be faster. For example when using semihosting
* It's 255 max, because of bufIdx of type uint8_t. It's possible to change it to int if bigger buffer needed.
* This buffer isn't statically allocated so it won't use permanent RAM.
* Not more than int because of cast in transmitBufXXX functions.
* 2017/08/31 : Save 22 bytes + bufsize of my STM32F103
*/
#ifndef PRINTF_LITE_BUF_SIZE
# define PRINTF_LITE_BUF_SIZE 200
#else
# if PRINTF_LITE_BUF_SIZE > 255
# error PRINTF_LITE_BUF_SIZE > 255
# endif
#endif
/*
* Fallback on something close if specifier isn't supported.
* Unsupported specifier are ignored.
* if 0, any unsupported modifier or specifier will be seen as unknown.
*/
#ifndef PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED
#define PRINTF_LITE_FALLBACK_FOR_UNSUPPORTED 0
#endif
#ifndef PRINTF_LITE_FLOAT_SUPPORT
#define PRINTF_LITE_FLOAT_SUPPORT 1
#endif
/*
* The int part of the float (or double) will be printed if PRINTF_LITE_FLOAT_SUPPORT is enabled
* June 2017, avr-gcc 4.9.2-atmel3.5.4-arduino2 :
* Float support increase 828 bytes of text and 16 bytes of data
*/
#ifndef PRINTF_LITE_FLOAT_AS_INT_SUPPORT
#define PRINTF_LITE_FLOAT_AS_INT_SUPPORT 1 // if float not supported, an int will be print instead.
#endif
/*
* Disabling LONG LONG support has an effect on printing double. If long int is disabled, the int part of the double has to be < ULONG_MAX
*/
#ifndef PRINTF_LITE_LONGLONGINT_SUPPORT
#define PRINTF_LITE_LONGLONGINT_SUPPORT 1 // 1712 bytes
#endif
/*
* Disabling LONG support automatically disable LONG LONG support whatever the value of PRINTF_LITE_LONGLONGINT_SUPPORT.
* Disabling LONG support has an effect on printing double. The int part of the double has to be < UINT_MAX max
*/
#ifndef PRINTF_LITE_LONGINT_SUPPORT
#define PRINTF_LITE_LONGINT_SUPPORT 1 // 1712 bytes
#endif
2020-04-17 14:27:38 +02:00
#ifndef PRINTF_LITE_SHORTINT_SUPPORT
#define PRINTF_LITE_SHORTINT_SUPPORT 1
#endif
#ifndef PRINTF_LITE_SHORTSHORTINT_SUPPORT
#define PRINTF_LITE_SHORTSHORTINT_SUPPORT 1
#endif
#ifndef PRINTF_LITE_TIMESTAMP_SUPPORT
#define PRINTF_LITE_TIMESTAMP_SUPPORT 1 // 240 bytes
#endif
#ifndef PRINTF_LITE_TIMESTAMP_CUSTOM_FUNCTION
#define PRINTF_LITE_TIMESTAMP_CUSTOM_FUNCTION 0
#endif
#ifndef PRINTF_LITE_FIELDWIDTH_SUPPORT
#define PRINTF_LITE_FIELDWIDTH_SUPPORT 1 // 107 bytes
#endif
#ifndef PRINTF_LITE_FIELDPRECISION_SUPPORT
#define PRINTF_LITE_FIELDPRECISION_SUPPORT 1 // bytes
#endif
#ifndef PRINTF_LITE_PADCHAR_SUPPORT
#define PRINTF_LITE_PADCHAR_SUPPORT 1 // bytes
#endif
#ifndef PRINTF_LITE_ZSPECIFIER_SUPPORT
#define PRINTF_LITE_ZSPECIFIER_SUPPORT 1 // 230 bytes. If not supported, z modifier become llu
#endif
#ifndef PRINTF_LITE_XSPECIFIER_SUPPORT
#define PRINTF_LITE_XSPECIFIER_SUPPORT 1 // 96 bytes. If not supported, x specifier become u
#endif
#ifndef PRINTF_LITE_USPECIFIER_SUPPORT
#define PRINTF_LITE_USPECIFIER_SUPPORT 1 // 96 bytes. If not supported, u specifier become d
#endif
#ifndef PRINTF_EMIT_CR_SUPPORT
#define PRINTF_EMIT_CR_SUPPORT 0
#endif
/*===================================================== Private definition ============================================*/
#if PRINTF_UTF8_OUTPUT_SUPPORT == 1
typedef void (*transmitBufCallBackType)(const char* buf, unsigned int nbchar, void* context);
#endif
#if PRINTF_UNICODE_OUTPUT_SUPPORT == 1
typedef void (*transmitWBufCallBackType)(const wchar_t* buf, unsigned int nbchar, void* context);
#endif
typedef union {
#if PRINTF_UTF8_OUTPUT_SUPPORT == 1
transmitBufCallBackType transmitBufCallBack;
#endif
#if PRINTF_UNICODE_OUTPUT_SUPPORT == 1
transmitWBufCallBackType transmitWBufCallBack;
#endif
} printf_callback_t;
// I need to pass a va_list by reference, NOT value, because va_list is "incremented" in printf_handle_format_char
// On macOS, the builtin va_list type seems to already be a pointer
#ifdef __APPLE__
#define VALIST_PARAM_TYPE va_list
#define VALIST_PARAM(valist) valist
#define VALIST_ACCESS(valist) valist
#else
#define VALIST_PARAM_TYPE va_list*
#define VALIST_PARAM(valist) &valist
#define VALIST_ACCESS(valist) (*valist)
#endif
//void printf_handle_format_char(char c, VALIST_PARAM_TYPE valist, PrintfParams* printfParams);
/*===================================================== User function ============================================*/
// I tried to inline this in printf_lite.h, but GCC seems to not accept that an inline function could call another inline function.
#if PRINTF_LITE_TIMESTAMP_SUPPORT == 1
# if PRINTF_EMIT_CR_SUPPORT == 1
void vprintf_with_callback_timestamp_emitcr(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context, int* newline, int timestamp, int emitCr); // emitCr is a boolean flag
void vprintf_with_callback_timestamp(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context, int* newline, int timestamp);
// inline void vprintf_with_callback_timestamp(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context, int* newline, int timestamp) {
// vprintf_with_callback_timestamp_emitcr(format, valist, transmitBufCallBack, context, newline, timestamp, 0);
// }
void vprintf_with_callback_emitcr(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context, int emitCr);
// inline void vprintf_with_callback_emitcr(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context, int emitCr) {
// vprintf_with_callback_timestamp_emitcr(format, valist, transmitBufCallBack, context, NULL, 0, emitCr);
// }
void vprintf_with_callback(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context);
// inline void vprintf_with_callback(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context) {
// vprintf_with_callback_timestamp_emitcr(format, valist, transmitBufCallBack, context, NULL, 0, 0);
// }
# else
void vprintf_with_callback_timestamp(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context, int* newline, int timestamp);
void vprintf_with_callback(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context);
// inline void vprintf_with_callback(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context) {
// vprintf_with_callback_timestamp(format, valist, transmitBufCallBack, context, NULL, 0);
// }
# endif
#else
# if PRINTF_EMIT_CR_SUPPORT == 1
void vprintf_with_callback_emitcr(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context, int emitCr);
void vprintf_with_callback(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context);
// inline void vprintf_with_callback(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context) {
// vprintf_with_callback_emitcr(format, valist, transmitBufCallBack, context, 0);
// }
# else
void vprintf_with_callback(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context);
# endif
#endif
#if PRINTF_LITE_TIMESTAMP_SUPPORT == 1
# if PRINTF_EMIT_CR_SUPPORT == 1
void printf_with_callback_timestamp_emitcr(const char* format, transmitBufCallBackType transmitBufCallBack, void* context, int* newline, int timestamp, int emitCr, ...);
inline void printf_with_callback_timestamp(const char* format, transmitBufCallBackType transmitBufCallBack, void* context, int* newline, int timestamp, ...) {
va_list va;
va_start(va, timestamp);
vprintf_with_callback_timestamp(format, va, transmitBufCallBack, context, newline, timestamp);
va_end(va);
}
inline void printf_with_callback__emitcr(const char* format, transmitBufCallBackType transmitBufCallBack, void* context, int emitCr, ...) {
va_list va;
va_start(va, emitCr);
vprintf_with_callback_emitcr(format, va, transmitBufCallBack, context, emitCr);
va_end(va);
}
inline void printf_with_callback(const char* format, transmitBufCallBackType transmitBufCallBack, void* context, ...) {
va_list va;
va_start(va, context);
vprintf_with_callback(format, va, transmitBufCallBack, context);
va_end(va);
}
# else
void printf_with_callback_timestamp(const char* format, transmitBufCallBackType transmitBufCallBack, void* context, int* newline, int timestamp, ...);
inline void printf_with_callback(const char* format, transmitBufCallBackType transmitBufCallBack, void* context, ...) {
va_list va;
va_start(va, context);
vprintf_with_callback_timestamp(format, va, transmitBufCallBack, context, NULL, 0);
va_end(va);
}
# endif
#else
# if PRINTF_EMIT_CR_SUPPORT == 1
void printf_with_callback_emitcr(const char* format, transmitBufCallBackType transmitBufCallBack, void* context, bool emitCr, ...);
# else
void printf_with_callback(const char* format, transmitBufCallBackType transmitBufCallBack, void* context, ...);
# endif
#endif
#if PRINTF_LITE_TIMESTAMP_SUPPORT == 1
void vwprintf_with_callback_timestamp(const char* format, va_list valist, transmitWBufCallBackType transmitBufCallBack, void* context, int* newline, int timestamp);
inline void vwprintf_with_callback(const char* format, va_list valist, transmitWBufCallBackType transmitWBufCallBack, void* context) {
vwprintf_with_callback_timestamp(format, valist, transmitWBufCallBack, context, NULL, 0);
}
#else
void vwprintf_with_callback(const char* format, va_list valist, transmitWBufCallBackType transmitWBufCallBack, void* context);
#endif
#if PRINTF_LITE_SNPRINTF_SUPPORT == 1
#if PRINTF_UTF8_OUTPUT_SUPPORT == 1
int PRINTF_FUNCTION_NAME(PRINTF_CFUNCTION_PREFIX, vsnprint, PRINTF_CFUNCTION_SUFFIX)(char*, size_t, const char *__restrict, va_list valist);
// gcc-4.9.2-atmel3.5.4-arduino2 report snprintf to undefined. Change the name and it'll work. Strange isn't it ?
int PRINTF_FUNCTION_NAME(PRINTF_CFUNCTION_PREFIX, snprint, PRINTF_CFUNCTION_SUFFIX)(char*, size_t len, const char *__restrict format, ...) __attribute__((__format__ (__printf__, 3, 4)));
#endif
#if PRINTF_UNICODE_OUTPUT_SUPPORT == 1
// ATTENTION : len is the number of wchar_t, NOT the number of bytes.
int PRINTF_FUNCTION_NAME(PRINTF_CFUNCTION_PREFIX, vsnwprint, PRINTF_CFUNCTION_SUFFIX)(wchar_t*, size_t len, const char *__restrict, va_list valist);
int PRINTF_FUNCTION_NAME(PRINTF_CFUNCTION_PREFIX, snwprint, PRINTF_CFUNCTION_SUFFIX)(wchar_t*, size_t len, const char *__restrict format, ...) __attribute__((__format__ (__printf__, 3, 4)));
#endif
#endif
#if defined(__cplusplus)
}
#endif
//#if defined(__cplusplus) && PRINTF_LITE_TIMESTAMP_SUPPORT == 1
// void vprintf_with_callback(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context){
// vprintf_with_callback(format, valist, transmitBufCallBack, NULL, 0, context);
// }
//#endif
//#if defined(__cplusplus) && PRINTF_LITE_TIMESTAMP_SUPPORT == 1
// void printf_with_callback(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context){
// printf_with_callback(format, valist, transmitBufCallBack, NULL, 0, context);
// }
//#endif
//#if defined(__cplusplus) && PRINTF_UNICODE_OUTPUT_SUPPORT == 1 && PRINTF_LITE_TIMESTAMP_SUPPORT == 1
// void vwprintf_with_callback(const char* format, va_list valist, transmitBufCallBackType transmitBufCallBack, void* context){
// vwprintf_with_callback(format, valist, transmitBufCallBack, NULL, 0, context);
// }
//#endif
#endif // __PRINTF_LITE_H__