cs-midi/AH/PrintStream/PrintStream.cpp

282 lines
6.8 KiB
C++

// https://github.com/tttapa/Arduino-PrintStream/blob/6a9e0d365be0b3d84187daa2a8a7bda8d541472e/src/PrintStream.cpp
#include "PrintStream.hpp"
// LCOV_EXCL_START
#if not defined(ARDUINO_ARCH_ESP32) && not defined(ARDUINO_ARCH_SAM) && \
not defined(ARDUINO_API_VERSION) && not defined(ArduinoFake) && \
not defined(ARDUINO_ARCH_STM32)
#define FLUSH
#endif
BEGIN_AH_NAMESPACE
/* #define OCT 8 */
uint8_t formatPrintStream = DEC;
bool boolalphaPrintStream = false;
bool leadingZerosPrintStream = false;
uint8_t precisionPrintStream = 2;
char byteSeparatorPrintStream = '\0';
enum : char { LOWERCASE = 0x7F, UPPERCASE = 0x5F } casePrintStream = LOWERCASE;
bool showbasePrintStream = false;
template <class T>
Print &printIntegral(Print &printer, T i);
Print &endl(Print &printer) {
printer.println();
#ifdef FLUSH
printer.flush();
#endif
return printer;
}
Print &uppercase(Print &printer) {
casePrintStream = UPPERCASE;
return printer;
}
Print &nouppercase(Print &printer) {
casePrintStream = LOWERCASE;
return printer;
}
Print &showbase(Print &printer) {
showbasePrintStream = true;
return printer;
}
Print &noshowbase(Print &printer) {
showbasePrintStream = false;
return printer;
}
Print &flush(Print &printer) {
#ifdef FLUSH
printer.flush();
#endif
return printer;
}
Print &hex(Print &printer) {
formatPrintStream = HEX;
return printer;
}
/* Print &oct(Print &printer) {
formatPrintStream = OCT;
return printer;
} */
Print &bin(Print &printer) {
formatPrintStream = BIN;
return printer;
}
Print &dec(Print &printer) {
formatPrintStream = DEC;
return printer;
}
Print &boolalpha(Print &printer) {
boolalphaPrintStream = true;
return printer;
}
Print &noboolalpha(Print &printer) {
boolalphaPrintStream = false;
return printer;
}
Print &leadingzeros(Print &printer) {
leadingZerosPrintStream = true;
return printer;
}
Print &noleadingzeros(Print &printer) {
leadingZerosPrintStream = false;
return printer;
}
Print &operator<<(Print &printer, const __FlashStringHelper *s) {
printer.print(s);
return printer;
}
#ifdef ARDUINO
Print &operator<<(Print &printer, const String &s) {
printer.print(s);
return printer;
}
#endif
Print &operator<<(Print &printer, const char s[]) {
printer.print(s);
return printer;
}
Print &operator<<(Print &printer, char c) {
printer.print(c);
return printer;
}
Print &operator<<(Print &printer, unsigned char i) {
return printIntegral(printer, i);
}
Print &operator<<(Print &printer, int i) { return printIntegral(printer, i); }
Print &operator<<(Print &printer, unsigned int i) {
return printIntegral(printer, i);
}
Print &operator<<(Print &printer, int8_t i) {
return printIntegral(printer, i);
}
Print &operator<<(Print &printer, long i) { return printIntegral(printer, i); }
Print &operator<<(Print &printer, unsigned long i) {
return printIntegral(printer, i);
}
Print &operator<<(Print &printer, double d) {
printer.print(d, +precisionPrintStream);
return printer;
}
Print &operator<<(Print &printer, float f) {
return printer << static_cast<double>(f);
}
Print &operator<<(Print &printer, const Printable &p) {
printer.print(p);
return printer;
}
Print &operator<<(Print &printer, bool b) {
if (boolalphaPrintStream)
printer.print(b ? F("true") : F("false"));
else
printer.print(b);
return printer;
}
Print &operator<<(Print &printer, manipulator pf) { return pf(printer); }
Setbase setbase(uint8_t base) { return {base}; }
Print &operator<<(Print &printer, Setbase f) {
formatPrintStream = f.M_base;
return printer;
}
Setbytesep setbytesep(char bytesep) { return {bytesep}; }
Print &operator<<(Print &printer, Setbytesep f) {
byteSeparatorPrintStream = f.M_bytesep;
return printer;
}
Setprecision setprecision(int n) { return {n}; }
Print &operator<<(Print &printer, Setprecision f) {
precisionPrintStream = f.M_n;
return printer;
}
static char nibble_to_hex(
uint8_t nibble) { // convert a 4-bit nibble to a hexadecimal character
nibble &= 0xF;
return nibble > 9 ? nibble - 10 + ('a' & casePrintStream) : nibble + '0';
}
#if __BYTE_ORDER != __LITTLE_ENDIAN
#error "Byte order not supported"
#endif
template <class T>
void printHex(Print &printer, T val) {
if (showbasePrintStream)
printer.print("0x");
bool nonZero = false;
for (int i = sizeof(val) - 1; i >= 0; i--) {
uint8_t currByte = ((uint8_t *)&val)[i];
if (currByte != 0 || i == 0)
nonZero = true;
if (leadingZerosPrintStream || nonZero) {
printer.print(nibble_to_hex(currByte >> 4));
printer.print(nibble_to_hex(currByte));
if (byteSeparatorPrintStream && i)
printer.print(byteSeparatorPrintStream);
}
}
}
template <class T>
void printBin(Print &printer, T val) {
if (showbasePrintStream)
printer.print("0b");
bool nonZero = false;
for (int i = sizeof(val) - 1; i >= 0; i--) {
uint8_t currByte = ((uint8_t *)&val)[i];
for (int j = 7; j >= 0; j--) {
uint8_t currBit = currByte & 0x80;
if (currBit != 0 || (i == 0 && j == 0))
nonZero = true;
if (leadingZerosPrintStream || nonZero)
printer.print(currBit ? '1' : '0');
currByte <<= 1;
}
if (byteSeparatorPrintStream && i &&
(leadingZerosPrintStream || nonZero))
printer.print(byteSeparatorPrintStream);
}
}
/* template <class T>
void printOct(Print &printer, T val)
{
; // TODO
} */
template <class T>
Print &printIntegral(Print &printer, T i) {
switch (formatPrintStream) {
case DEC: printer.print(i); break;
case HEX: printHex(printer, i); break;
case BIN: printBin(printer, i); break;
/* case OCT:
printOct(printer, i);
break; */
default: break;
}
return printer;
}
Print &operator<<(Print &p, HexDump h) {
if (h.length == 0)
return p;
auto temp_case = casePrintStream;
casePrintStream = UPPERCASE;
while (h.length-- > 1) {
printHex(p, *h.data++);
p.print(' ');
}
printHex(p, *h.data++);
casePrintStream = temp_case;
return p;
}
#ifndef ARDUINO
std::ostream &operator<<(std::ostream &p, HexDump h) {
if (h.length == 0)
return p;
auto hex_nibble_to_char = [](uint8_t nibble) -> char {
nibble &= 0xF;
return nibble > 9 ? nibble - 10 + 'A' : nibble + '0';
};
auto printHex = [&](std::ostream &p, uint8_t b) {
p << hex_nibble_to_char(b >> 4) << hex_nibble_to_char(b);
};
while (h.length-- > 1) {
printHex(p, *h.data++);
p << ' ';
}
printHex(p, *h.data++);
return p;
}
#endif
END_AH_NAMESPACE
// LCOV_EXCL_STOP