PropWare  3.0.0.229
C++ objects and CMake build system for Parallax Propeller
printer.h
Go to the documentation of this file.
1 
26 #pragma once
27 
28 #include <PropWare/PropWare.h>
31 
32 namespace PropWare {
33 
34 #ifndef S_ISNAN
35 #define S_ISNAN(x) (x != x)
36 #endif /* !defined(S_ISNAN) */
37 
38 #ifndef S_ISINF
39 #define S_ISINF(x) (x != 0.0 && x + x == x)
40 #endif /* !defined(S_ISINF) */
41 
42 #ifndef isdigit
43 #define isdigit(x) ('0' <= x && x <= '9')
44 #endif
45 
76 class Printer {
77  public:
78  static const uint16_t DEFAULT_WIDTH = 0;
79  static const uint16_t DEFAULT_PRECISION = 6;
80  static const uint8_t DEFAULT_RADIX = 10;
81  static const char DEFAULT_FILL_CHAR = ' ';
82 
87  struct Format {
94  uint16_t width;
98  uint16_t precision;
103  uint8_t radix;
111  char fillChar;
112 
113  Format (const uint16_t width = DEFAULT_WIDTH, const char fillChar = DEFAULT_FILL_CHAR,
114  const uint8_t radix = DEFAULT_RADIX, const uint16_t precision = DEFAULT_PRECISION)
115  : width(width),
117  radix(radix),
118  fillChar(fillChar) {
119  }
120  };
121 
122  static const Format DEFAULT_FORMAT;
123 
124  public:
133  Printer (PrintCapable &printCapable, const bool cooked = true)
134  : m_printCapable(&printCapable),
135  m_cooked(cooked) {
136  }
137 
150  void set_cooked (const bool cooked) {
151  this->m_cooked = cooked;
152  }
153 
166  bool get_cooked () const {
167  return this->m_cooked;
168  }
169 
175  void put_char (const char c) const {
176  if (this->m_cooked && '\n' == c)
177  this->m_printCapable->put_char('\r');
178  this->m_printCapable->put_char(c);
179  }
180 
188  void puts (const char string[]) const {
189  if (this->m_cooked)
190  for (const char *s = string; *s; ++s)
191  this->put_char(*s);
192  else
193  this->m_printCapable->puts(string);
194  }
195 
205  void put_int (int x, const uint8_t radix = 10, uint16_t width = 0,
206  const char fillChar = DEFAULT_FILL_CHAR) const {
207  if (0 > x)
208  this->put_char('-');
209 
210  this->put_uint((uint32_t) abs(x), radix, width, fillChar);
211  }
212 
222  void put_uint (unsigned int x, const uint8_t radix = 10, uint16_t width = 0,
223  const char fillChar = DEFAULT_FILL_CHAR) const {
224  char buf[sizeof(x) * 8]; // Max size would be a single character for each bit - aka, bytes * 8
225  uint_fast8_t i = 0;
226 
227  // Create a character array in reverse order, starting with the
228  // tens digit and working toward the largest digit
229  do {
230  const unsigned int digit = x % radix;
231  buf[i] = static_cast<char>(digit > 9 ? digit + 'A' - 10 : digit + '0');
232  x /= radix;
233  ++i;
234  } while (x);
235 
236  if (width && width > i) {
237  width -= i;
238  while (width--)
239  this->put_char(fillChar);
240  }
241 
242  // Reverse the character array
243  for (unsigned int j = 0; j < i; ++j)
244  this->put_char(buf[i - j - 1]);
245  }
246 
256  void put_ll (long long x, const uint8_t radix = 10, uint16_t width = 0,
257  const char fillChar = DEFAULT_FILL_CHAR) const {
258  if (0 > x)
259  this->put_char('-');
260 
261  this->put_ull((unsigned long long) llabs(x), radix, width, fillChar);
262  }
263 
273  void put_ull (unsigned long long x, const uint8_t radix = 10, uint16_t width = 0,
274  const char fillChar = DEFAULT_FILL_CHAR) const {
275  char buf[sizeof(x) * 8]; // Max size would be a single character for each bit - aka, bytes * 8
276  uint_fast8_t i = 0;
277 
278  // Create a character array in reverse order, starting with the
279  // tens digit and working toward the largest digit
280  do {
281  const uint_fast8_t digit = static_cast<uint_fast8_t>(x % radix);
282  buf[i] = static_cast<char>(digit > 9 ? digit + 'A' - 10 : digit + '0');
283  x /= radix;
284  ++i;
285  } while (x);
286 
287  if (width && width > i) {
288  width -= i;
289  while (width--)
290  this->put_char(fillChar);
291  }
292 
293  // Reverse the character array
294  for (unsigned int j = 0; j < i; ++j)
295  this->put_char(buf[i - j - 1]);
296  }
297 
310  void put_float (double f, uint16_t width = 0, uint16_t precision = 6,
311  const char fillChar = DEFAULT_FILL_CHAR) const {
313  // Code taken straight from Parallax's floatToString! Thank you!!!
315 
316  char buffer[32];
317  char *s = buffer;
318  union convert {
319  float v;
320  int w;
321  } fval;
322 
323  int m = 0;
324  int k = 0;
325 
326  int j = 0;
327  int sign = 0;
328  int g = 0;
329 
330  int reps = 0;
331  float scale;
332  int ctr = 0;
333 
334  int offset;
335  int p;
336  int q;
337  int n;
338 
339  if (S_ISNAN(f)) {
340  this->puts("nan");
341  }
342  if (S_ISINF(f)) {
343  if (((int) f) & 0x80000000)
344  this->puts("-inf");
345  else
346  this->puts("inf");
347  }
348 
349  /* clamp the digits. */
350  int clamp = 6; /* a buffer must be at least clamp + 4 digits */
351  precision = (precision > clamp) ? clamp : precision;
352 
353  if (f < 0.0) {
354  sign = 1;
355  f = -f;
356  }
357 
358  if (sign) {
359  s[j++] = '-';
360  }
361 
362  /* Find reasonable starting value for scale.
363  // Using 2^10x has similar values to 10^3x. */
364  fval.v = f;
365  g = fval.w;
366 
367  g >>= 23;
368  g &= 0xFF;
369  g -= 127;
370 
371  reps = (g / 10);
372  scale = 1.0;
373  for (ctr = 0; ctr <= reps; ctr++) {
374  scale *= 1000.0;
375  }
376 
377  /* If integer is zero, 0 */
378  if (f < 1.0) {
379  s[j++] = '0';
380  }
381  else {
382  char c;
383  for (; scale >= 1.0; scale /= 10.0) {
384  if (f >= scale) {
385  break;
386  }
387  }
388  for (; scale >= 1.0; scale /= 10.0) {
389  c = (char) (f / scale);
390  f -= ((float) c * scale);
391  c += 48;
392  s[j++] = c;
393  }
394  }
395 
396  /* If width > current size, move right, then pad with spaces */
397  offset = width - j - precision - 1;
398  if (precision == 0)
399  offset++;
400 
401  p = j + offset;
402  q = j;
403  n = p;
404 
405  if (offset > 0) {
406  for (; j >= 0;) {
407  s[n--] = s[j--];
408  }
409  for (; n >= 0;) {
410  s[n--] = fillChar;
411  }
412  j = p;
413  }
414  else
415  j = q;
416 
417  /* Append with fractional */
418  if (precision > 0)
419  s[j++] = '.';
420 
421  k = j;
422  k += precision;
423  for (; j <= k;) {
424  f *= 10.0;
425  s[j++] = (char) f + '0';
426  f -= ((int) f);
427  }
428 
429  m = j - 1;
430  j--;
431  if (s[j] >= '5') {
432  j--;
433  for (; (j >= 0); j--)
434  if (!(s[j] < '0' || s[j] > '9')) {
435  if (s[j] < '9') {
436  s[j]++;
437  break;
438  } else
439  s[j] = '0';
440  }
441  }
442 
443  s[m] = 0;
444 
445  this->puts(s);
446  }
447 
496  template<typename T, typename... Targs>
497  void printf (const char fmt[], const T first, const Targs... remaining) const {
498  const char *s = fmt;
499  char c;
500  Format format;
501 
502  while (*s) {
503  c = *s;
504 
505  if ('%' == c) {
506  c = *(++s);
507  if ('%' == c)
508  this->put_char(c);
509  else {
510  if (c == '0')
511  format.fillChar = '0';
512  else
513  format.fillChar = DEFAULT_FILL_CHAR;
514 
515  format.width = 0;
516  while (c && isdigit(c)) {
517  format.width = (uint16_t) (10 * format.width + (c - '0'));
518  c = *(++s);
519  }
520 
521  if (c == '.') {
522  format.precision = 0;
523  c = *(++s);
524  while (c && isdigit(c)) {
525  format.precision = (uint16_t) (10 * format.precision + (c - '0'));
526  c = *(++s);
527  }
528  }
529 
530  ++s;
531 
532  switch (c) {
533  case 'i':
534  case 'd':
535  this->print((int) first, format);
536  break;
537  case 'X':
538  case 'b':
539  format.radix = static_cast<uint8_t>('b' == c ? 2 : 16);
540  // No "break;" after 'X' - let it flow into 'u'
541  case 'u':
542  this->print((unsigned int) first, format);
543  break;
544  case 'f':
545  case 's':
546  case 'c':
547  this->print(first, format);
548  break;
549  default:
550  this->put_char(DEFAULT_FILL_CHAR);
551  break;
552  }
553  if (0 == sizeof...(remaining))
554  this->puts(s);
555  else {
556  this->printf(s, remaining...);
557  }
558  return;
559  }
560  } else
561  this->put_char(*s);
562 
563  ++s;
564  }
565  }
566 
570  void printf (const char fmt[]) const {
571  this->puts(fmt);
572  }
573 
580  void print (const char c, const Format &format = DEFAULT_FORMAT) const {
581  this->put_char(c);
582  }
583 
590  void print (const char string[], const Format &format = DEFAULT_FORMAT) const {
591  this->puts(string);
592  }
593 
599  void println (const char string[]) const {
600  this->puts(string);
601  this->put_char('\n');
602  }
603 
607  void println () const {
608  this->put_char('\n');
609  }
610 
617  void print (const bool b, const Format &format = DEFAULT_FORMAT) const {
618  this->puts(Utility::to_string(b));
619  }
620 
627  void print (const unsigned int x, const Format &format = DEFAULT_FORMAT) const {
628  this->put_uint(x, format.radix, format.width, format.fillChar);
629  }
630 
637  void print (const int x, const Format &format = DEFAULT_FORMAT) const {
638  this->put_int(x, format.radix, format.width, format.fillChar);
639  }
640 
647  void print (const unsigned long long x, const Format &format = DEFAULT_FORMAT) const {
648  this->put_uint(x, format.radix, format.width, format.fillChar);
649  }
650 
657  void print (const long long x, const Format &format = DEFAULT_FORMAT) const {
658  this->put_int(x, format.radix, format.width, format.fillChar);
659  }
660 
667  void print (const double f, const Format &format = DEFAULT_FORMAT) const {
668  this->put_float(f, format.width, format.precision, format.fillChar);
669  }
670 
693  template<typename T>
694  const Printer &operator<< (const T arg) const {
695  this->print(arg, this->m_format);
696  return *this;
697  }
698 
721  template<typename T>
722  Printer &operator<< (const T arg) {
723  this->print(arg, this->m_format);
724  return *this;
725  }
726 
727  Printer &operator<< (const Format arg) {
728  this->m_format = arg;
729  return *this;
730  }
731 
732  protected:
733  PrintCapable *m_printCapable;
734  bool m_cooked;
735  Format m_format;
736 };
737 
738 }
739 
740 #ifndef __PROPELLER_COG__
741 
745 extern PropWare::Printer pwOut;
746 #endif
PropWare::Printer::get_cooked
bool get_cooked() const
Determine if the printer is configured for cooked mode or not.
Definition: printer.h:166
PropWare::Printer::printf
void printf(const char fmt[]) const
Definition: printer.h:570
PropWare::Printer::print
void print(const char string[], const Format &format=DEFAULT_FORMAT) const
Print a null-terminated string.
Definition: printer.h:590
PropWare::Printer::print
void print(const unsigned int x, const Format &format=DEFAULT_FORMAT) const
Print an unsigned integer with the given format.
Definition: printer.h:627
PropWare::Printer::printf
void printf(const char fmt[], const T first, const Targs... remaining) const
Similar in functionality to the C-standard function printf.
Definition: printer.h:497
PropWare::Printer::put_ll
void put_ll(long long x, const uint8_t radix=10, uint16_t width=0, const char fillChar=DEFAULT_FILL_CHAR) const
Print a signed integer in base 10.
Definition: printer.h:256
float
PropWare::Printer::print
void print(const bool b, const Format &format=DEFAULT_FORMAT) const
Print a boolean as either "true" or "false".
Definition: printer.h:617
PropWare::Printer::print
void print(const unsigned long long x, const Format &format=DEFAULT_FORMAT) const
Print an unsigned integer with the given format.
Definition: printer.h:647
PropWare::Printer::print
void print(const int x, const Format &format=DEFAULT_FORMAT) const
Print a single character.
Definition: printer.h:637
PropWare::Printer::Format::precision
uint16_t precision
Number of digits to be printed after the decimal point in a floating point number.
Definition: printer.h:98
PropWare::Printer::put_uint
void put_uint(unsigned int x, const uint8_t radix=10, uint16_t width=0, const char fillChar=DEFAULT_FILL_CHAR) const
Print an unsigned integer in base 10.
Definition: printer.h:222
PropWare::Printer::set_cooked
void set_cooked(const bool cooked)
Turn on or off cooked mode.
Definition: printer.h:150
utility.h
isdigit
#define isdigit(c)
Definition: ctype.h:83
PropWare::Printer::print
void print(const long long x, const Format &format=DEFAULT_FORMAT) const
Print a single character.
Definition: printer.h:657
PropWare::Printer::put_ull
void put_ull(unsigned long long x, const uint8_t radix=10, uint16_t width=0, const char fillChar=DEFAULT_FILL_CHAR) const
Print an unsigned integer in base 10.
Definition: printer.h:273
PropWare::Printer::Printer
Printer(PrintCapable &printCapable, const bool cooked=true)
Construct a Printer instance that will use the given *printCapable instance for sending each characte...
Definition: printer.h:133
PropWare::PrintCapable
Interface for all classes capable of printing.
Definition: printcapable.h:38
PropWare::Printer::Format::fillChar
char fillChar
Character to be printed when a width is provided that is larger than the number.
Definition: printer.h:111
PropWare::Printer::print
void print(const double f, const Format &format=DEFAULT_FORMAT) const
Print a single character.
Definition: printer.h:667
PropWare.h
x
int x
Definition: 07 Box and Lines.c:13
PropWare::Utility::to_string
static const char * to_string(const bool b)
Convert a boolean to the string-literal either "true" or "false"
Definition: utility.h:176
PropWare::Printer::print
void print(const char c, const Format &format=DEFAULT_FORMAT) const
Print a single character.
Definition: printer.h:580
PropWare::Printer::Format::radix
uint8_t radix
Base for the number - usually defaults to 10. Useful for switching between binary,...
Definition: printer.h:103
pwOut
PropWare::Printer pwOut
Most common use of printing in PropWare applications (not thread safe; see PropWare::pwSyncOut for mu...
printcapable.h
char
PropWare::PrintCapable::puts
virtual void puts(const char string[])=0
Send a null-terminated character array. Though this method could be created using put_char,...
PropWare::Printer::puts
void puts(const char string[]) const
Send a null-terminated character array.
Definition: printer.h:188
PropWare::Printer::println
void println() const
Print a newline (' ')
Definition: printer.h:607
PropWare::Printer
Container class that has formatting methods for human-readable output. This class can be constructed ...
Definition: printer.h:76
PropWare
Generic definitions and functions for the Parallax Propeller.
Definition: runnable.h:33
PropWare::Printer::put_float
void put_float(double f, uint16_t width=0, uint16_t precision=6, const char fillChar=DEFAULT_FILL_CHAR) const
Print a floating point number with a given width and precision.
Definition: printer.h:310
PropWare::Printer::Format::width
uint16_t width
Minimum number of characters to be printed.
Definition: printer.h:94
PropWare::Printer::put_int
void put_int(int x, const uint8_t radix=10, uint16_t width=0, const char fillChar=DEFAULT_FILL_CHAR) const
Print a signed integer in base 10.
Definition: printer.h:205
PropWare::Printer::put_char
void put_char(const char c) const
Print a single character.
Definition: printer.h:175
PropWare::Printer::Format
Passed into any of the Printer::print methods, this struct controls how aspects of numerical printing...
Definition: printer.h:87
PropWare::PrintCapable::put_char
virtual void put_char(const char c)=0
Print a single character.
PropWare::Printer::operator<<
const Printer & operator<<(const T arg) const
The << operator allows for highly optimized use of the Printer.
Definition: printer.h:694
PropWare::Printer::println
void println(const char string[]) const
Print a null-terminated string followed by a newline (' ')
Definition: printer.h:599