APM:Libraries
print_vprintf.cpp
Go to the documentation of this file.
1 /*
2  Adapted from the avr-libc vfprintf:
3 
4  Copyright (c) 2002, Alexander Popov (sasho@vip.bg)
5  Copyright (c) 2002,2004,2005 Joerg Wunsch
6  Copyright (c) 2005, Helmut Wallner
7  Copyright (c) 2007, Dmitry Xmelkov
8  All rights reserved.
9 
10  Redistribution and use in source and binary forms, with or without
11  modification, are permitted provided that the following conditions are met:
12 
13  * Redistributions of source code must retain the above copyright
14  notice, this list of conditions and the following disclaimer.
15  * Redistributions in binary form must reproduce the above copyright
16  notice, this list of conditions and the following disclaimer in
17  the documentation and/or other materials provided with the
18  distribution.
19  * Neither the name of the copyright holders nor the names of
20  contributors may be used to endorse or promote products derived
21  from this software without specific prior written permission.
22 
23  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  POSSIBILITY OF SUCH DAMAGE.
34 */
35 
36 /* From: Id: printf_p_new.c,v 1.1.1.9 2002/10/15 20:10:28 joerg_wunsch Exp */
37 /* $Id: vfprintf.c,v 1.18.2.1 2009/04/01 23:12:06 arcanum Exp $ */
38 
39 #include "print_vprintf.h"
40 
41 #include <cmath>
42 #include <stdarg.h>
43 #include <string.h>
44 
45 #include <AP_HAL/AP_HAL.h>
46 
47 #include "ftoa_engine.h"
48 #include "xtoa_fast.h"
49 
50 #define FL_ZFILL 0x01
51 #define FL_PLUS 0x02
52 #define FL_SPACE 0x04
53 #define FL_LPAD 0x08
54 #define FL_ALT 0x10
55 #define FL_WIDTH 0x20
56 #define FL_PREC 0x40
57 #define FL_LONG 0x80
58 #define FL_LONGLONG 0x100
59 
60 #define FL_NEGATIVE FL_LONG
61 
62 #define FL_ALTUPP FL_PLUS
63 #define FL_ALTHEX FL_SPACE
64 
65 #define FL_FLTUPP FL_ALT
66 #define FL_FLTEXP FL_PREC
67 #define FL_FLTFIX FL_LONG
68 
69 void print_vprintf(AP_HAL::BetterStream *s, const char *fmt, va_list ap)
70 {
71  unsigned char c; /* holds a char from the format string */
72  uint16_t flags;
73  unsigned char width;
74  unsigned char prec;
75  unsigned char buf[23];
76 
77  for (;;) {
78  /*
79  * Process non-format characters
80  */
81  for (;;) {
82  c = *fmt++;
83  if (!c) {
84  return;
85  }
86  if (c == '%') {
87  c = *fmt++;
88  if (c != '%') {
89  break;
90  }
91  }
92  /* emit cr before lf to make most terminals happy */
93  if (c == '\n') {
94  s->write('\r');
95  }
96  s->write(c);
97  }
98 
99  flags = 0;
100  width = 0;
101  prec = 0;
102 
103  /*
104  * Process format adjustment characters, precision, width.
105  */
106  do {
107  if (flags < FL_WIDTH) {
108  switch (c) {
109  case '0':
110  flags |= FL_ZFILL;
111  continue;
112  case '+':
113  flags |= FL_PLUS;
114  FALLTHROUGH;
115  case ' ':
116  flags |= FL_SPACE;
117  continue;
118  case '-':
119  flags |= FL_LPAD;
120  continue;
121  case '#':
122  flags |= FL_ALT;
123  continue;
124  }
125  }
126 
127  if (flags < FL_LONG) {
128  if (c >= '0' && c <= '9') {
129  c -= '0';
130  if (flags & FL_PREC) {
131  prec = 10*prec + c;
132  continue;
133  }
134  width = 10*width + c;
135  flags |= FL_WIDTH;
136  continue;
137  }
138  if (c == '.') {
139  if (flags & FL_PREC) {
140  return;
141  }
142  flags |= FL_PREC;
143  continue;
144  }
145  if (c == 'l') {
146  flags |= FL_LONG;
147  continue;
148  }
149  if (c == 'h') {
150  continue;
151  }
152  } else if ((flags & FL_LONG) && c == 'l') {
153  flags |= FL_LONGLONG;
154  continue;
155  }
156 
157  break;
158  } while ((c = *fmt++) != 0);
159 
160  /*
161  * Handle floating-point formats E, F, G, e, f, g.
162  */
163  if (c >= 'E' && c <= 'G') {
164  flags |= FL_FLTUPP;
165  c += 'e' - 'E';
166  goto flt_oper;
167  } else if (c >= 'e' && c <= 'g') {
168  int exp; /* exponent of master decimal digit */
169  int n;
170  unsigned char vtype; /* result of float value parse */
171  unsigned char sign; /* sign character (or 0) */
172  unsigned char ndigs;
173 
174  flags &= ~FL_FLTUPP;
175 
176 flt_oper:
177  float value = va_arg(ap,double);
178 
179  if (!(flags & FL_PREC)) {
180  prec = 6;
181  }
182  flags &= ~(FL_FLTEXP | FL_FLTFIX);
183  if (c == 'e') {
184  flags |= FL_FLTEXP;
185  } else if (c == 'f') {
186  flags |= FL_FLTFIX;
187  } else if (prec > 0) {
188  prec -= 1;
189  }
190 
191  if ((flags & FL_FLTFIX) && fabsf(value) > 9999999) {
192  flags = (flags & ~FL_FLTFIX) | FL_FLTEXP;
193  }
194 
195  if (flags & FL_FLTFIX) {
196  vtype = 7; /* 'prec' arg for 'ftoa_engine' */
197  ndigs = prec < 60 ? prec + 1 : 60;
198  } else {
199  if (prec > 10) {
200  prec = 10;
201  }
202  vtype = prec;
203  ndigs = 0;
204  }
205  memset(buf, 0, sizeof(buf));
206  exp = ftoa_engine(value, (char *)buf, vtype, ndigs);
207  vtype = buf[0];
208 
209  sign = 0;
210  if ((vtype & FTOA_MINUS) && !(vtype & FTOA_NAN))
211  sign = '-';
212  else if (flags & FL_PLUS)
213  sign = '+';
214  else if (flags & FL_SPACE)
215  sign = ' ';
216 
217  if (vtype & (FTOA_NAN | FTOA_INF)) {
218  ndigs = sign ? 4 : 3;
219  if (width > ndigs) {
220  width -= ndigs;
221  if (!(flags & FL_LPAD)) {
222  do {
223  s->write(' ');
224  } while (--width);
225  }
226  } else {
227  width = 0;
228  }
229  if (sign) {
230  s->write(sign);
231  }
232 
233  const char *p = "inf";
234  if (vtype & FTOA_NAN)
235  p = "nan";
236  while ((ndigs = *p) != 0) {
237  if (flags & FL_FLTUPP)
238  ndigs += 'I' - 'i';
239  s->write(ndigs);
240  p++;
241  }
242  goto tail;
243  }
244 
245  /* Output format adjustment, number of decimal digits in buf[] */
246  if (flags & FL_FLTFIX) {
247  ndigs += exp;
248  if ((vtype & FTOA_CARRY) && buf[1] == '1') {
249  ndigs -= 1;
250  }
251  if ((signed char)ndigs < 1) {
252  ndigs = 1;
253  } else if (ndigs > 8) {
254  ndigs = 8;
255  }
256  } else if (!(flags & FL_FLTEXP)) { /* 'g(G)' format */
257  if (exp <= prec && exp >= -4) {
258  flags |= FL_FLTFIX;
259  }
260  while (prec && buf[1+prec] == '0') {
261  prec--;
262  }
263  if (flags & FL_FLTFIX) {
264  ndigs = prec + 1; /* number of digits in buf */
265  prec = prec > exp ? prec - exp : 0; /* fractional part length */
266  }
267  }
268 
269  /* Conversion result length, width := free space length */
270  if (flags & FL_FLTFIX) {
271  n = (exp>0 ? exp+1 : 1);
272  } else {
273  n = 5; /* 1e+00 */
274  }
275  if (sign) {
276  n += 1;
277  }
278  if (prec) {
279  n += prec + 1;
280  }
281  width = width > n ? width - n : 0;
282 
283  /* Output before first digit */
284  if (!(flags & (FL_LPAD | FL_ZFILL))) {
285  while (width) {
286  s->write(' ');
287  width--;
288  }
289  }
290  if (sign) {
291  s->write(sign);
292  }
293  if (!(flags & FL_LPAD)) {
294  while (width) {
295  s->write('0');
296  width--;
297  }
298  }
299 
300  if (flags & FL_FLTFIX) { /* 'f' format */
301 
302  n = exp > 0 ? exp : 0; /* exponent of left digit */
303  unsigned char v = 0;
304  do {
305  if (n == -1) {
306  s->write('.');
307  }
308  v = (n <= exp && n > exp - ndigs)
309  ? buf[exp - n + 1] : '0';
310  if (--n < -prec || v == 0) {
311  break;
312  }
313  s->write(v);
314  } while (1);
315  if (n == exp
316  && (buf[1] > '5'
317  || (buf[1] == '5' && !(vtype & FTOA_CARRY)))) {
318  v = '1';
319  }
320  if (v) {
321  s->write(v);
322  }
323  } else { /* 'e(E)' format */
324  /* mantissa */
325  if (buf[1] != '1')
326  vtype &= ~FTOA_CARRY;
327  s->write(buf[1]);
328  if (prec) {
329  s->write('.');
330  sign = 2;
331  do {
332  s->write(buf[sign++]);
333  } while (--prec);
334  }
335 
336  /* exponent */
337  s->write(flags & FL_FLTUPP ? 'E' : 'e');
338  ndigs = '+';
339  if (exp < 0 || (exp == 0 && (vtype & FTOA_CARRY) != 0)) {
340  exp = -exp;
341  ndigs = '-';
342  }
343  s->write(ndigs);
344  for (ndigs = '0'; exp >= 10; exp -= 10)
345  ndigs += 1;
346  s->write(ndigs);
347  s->write('0' + exp);
348  }
349 
350  goto tail;
351  }
352 
353  /*
354  * Handle string formats c, s, S.
355  */
356  {
357  const char * pnt;
358  size_t size;
359 
360  switch (c) {
361  case 'c':
362  buf[0] = va_arg (ap, int);
363  pnt = (char *)buf;
364  size = 1;
365  break;
366 
367  case 's':
368  pnt = va_arg (ap, char *);
369  size = strnlen (pnt, (flags & FL_PREC) ? prec : ~0);
370  break;
371 
372  default:
373  goto non_string;
374  }
375 
376  if (!(flags & FL_LPAD)) {
377  while (size < width) {
378  s->write(' ');
379  width--;
380  }
381  }
382 
383  while (size) {
384  s->write(*pnt++);
385  if (width) width -= 1;
386  size -= 1;
387  }
388  goto tail;
389  }
390 
391  non_string:
392 
393  /*
394  * Handle integer formats variations for d/i, u, o, p, x, X.
395  */
396  if (c == 'd' || c == 'i') {
397  if (flags & FL_LONGLONG) {
398  int64_t x = va_arg(ap,long long);
399  flags &= ~(FL_NEGATIVE | FL_ALT);
400  if (x < 0) {
401  x = -x;
402  flags |= FL_NEGATIVE;
403  }
404  c = ulltoa_invert (x, (char *)buf, 10) - (char *)buf;
405  } else {
406  long x = (flags & FL_LONG) ? va_arg(ap,long) : va_arg(ap,int);
407  flags &= ~(FL_NEGATIVE | FL_ALT);
408  if (x < 0) {
409  x = -x;
410  flags |= FL_NEGATIVE;
411  }
412  c = ultoa_invert (x, (char *)buf, 10) - (char *)buf;
413  }
414  } else {
415  int base;
416 
417  if (c == 'u') {
418  flags &= ~FL_ALT;
419  base = 10;
420  goto ultoa;
421  }
422 
423  flags &= ~(FL_PLUS | FL_SPACE);
424 
425  switch (c) {
426  case 'o':
427  base = 8;
428  goto ultoa;
429  case 'p':
430  flags |= FL_ALT;
431 
432  FALLTHROUGH;
433  case 'x':
434  if (flags & FL_ALT)
435  flags |= FL_ALTHEX;
436  base = 16;
437  goto ultoa;
438  case 'X':
439  if (flags & FL_ALT)
440  flags |= (FL_ALTHEX | FL_ALTUPP);
441  base = 16 | XTOA_UPPER;
442 ultoa:
443  if (flags & FL_LONGLONG) {
444  c = ulltoa_invert (va_arg(ap, unsigned long long),
445  (char *)buf, base) - (char *)buf;
446  } else {
447  c = ultoa_invert ((flags & FL_LONG)
448  ? va_arg(ap, unsigned long)
449  : va_arg(ap, unsigned int),
450  (char *)buf, base) - (char *)buf;
451  }
452  flags &= ~FL_NEGATIVE;
453  break;
454 
455  default:
456  return;
457  }
458  }
459 
460  /*
461  * Format integers.
462  */
463  {
464  unsigned char len;
465 
466  len = c;
467  if (flags & FL_PREC) {
468  flags &= ~FL_ZFILL;
469  if (len < prec) {
470  len = prec;
471  if ((flags & FL_ALT) && !(flags & FL_ALTHEX)) {
472  flags &= ~FL_ALT;
473  }
474  }
475  }
476  if (flags & FL_ALT) {
477  if (buf[c-1] == '0') {
478  flags &= ~(FL_ALT | FL_ALTHEX | FL_ALTUPP);
479  } else {
480  len += 1;
481  if (flags & FL_ALTHEX) {
482  len += 1;
483  }
484  }
485  } else if (flags & (FL_NEGATIVE | FL_PLUS | FL_SPACE)) {
486  len += 1;
487  }
488 
489  if (!(flags & FL_LPAD)) {
490  if (flags & FL_ZFILL) {
491  prec = c;
492  if (len < width) {
493  prec += width - len;
494  len = width;
495  }
496  }
497  while (len < width) {
498  s->write(' ');
499  len++;
500  }
501  }
502 
503  width = (len < width) ? width - len : 0;
504 
505  if (flags & FL_ALT) {
506  s->write('0');
507  if (flags & FL_ALTHEX) {
508  s->write(flags & FL_ALTUPP ? 'X' : 'x');
509  }
510  } else if (flags & (FL_NEGATIVE | FL_PLUS | FL_SPACE)) {
511  unsigned char z = ' ';
512  if (flags & FL_PLUS) {
513  z = '+';
514  }
515  if (flags & FL_NEGATIVE) {
516  z = '-';
517  }
518  s->write(z);
519  }
520 
521  while (prec > c) {
522  s->write('0');
523  prec--;
524  }
525 
526  do {
527  s->write(buf[--c]);
528  } while (c);
529  }
530 
531 tail:
532  /* Tail is possible. */
533  while (width) {
534  s->write(' ');
535  width--;
536  }
537  } /* for (;;) */
538 }
#define FTOA_NAN
Definition: ftoa_engine.h:42
#define FALLTHROUGH
Definition: AP_Common.h:50
#define FTOA_MINUS
Definition: ftoa_engine.h:39
char * ultoa_invert(uint32_t val, char *s, uint8_t base)
Definition: utoa_invert.cpp:34
#define x(i)
char * ulltoa_invert(uint64_t val, char *s, uint8_t base)
Definition: utoa_invert.cpp:79
const char * fmt
Definition: Printf.cpp:14
int16_t ftoa_engine(float val, char *buf, uint8_t precision, uint8_t maxDecimals)
Definition: ftoa_engine.cpp:88
virtual size_t write(uint8_t)=0
#define XTOA_UPPER
Definition: xtoa_fast.h:41
float v
Definition: Printf.cpp:15
#define FTOA_CARRY
Definition: ftoa_engine.h:43
float value
#define FTOA_INF
Definition: ftoa_engine.h:41