LCOV - code coverage report
Current view: top level - AP_HAL/utility - print_vprintf.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 281 290 96.9 %
Date: 2026-09-09 11:02:08 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /*
       2             :    Adapted from the avr-libc vfprintf:
       3             : 
       4             :    Copyright (c) 2002, Alexander Popov ([email protected])
       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             : #if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS
      70             : // get __FPU_PRESENT
      71             : #include <hal.h>
      72             : #endif
      73             : 
      74    44400715 : void print_vprintf(AP_HAL::BetterStream *s, const char *fmt, va_list ap)
      75             : {
      76             :         unsigned char c;        /* holds a char from the format string */
      77             :         uint16_t flags;
      78             :         unsigned char width;
      79             :         unsigned char prec;
      80             :         unsigned char buf[23];
      81             : 
      82             :         for (;;) {
      83             :             /*
      84             :              * Process non-format characters
      85             :              */
      86             :             for (;;) {
      87    44400715 :                 c = *fmt++;
      88    44400715 :                 if (!c) {
      89     2086164 :                     return;
      90             :                 }
      91    42314551 :                 if (c == '%') {
      92     1639016 :                     c = *fmt++;
      93     1639016 :                     if (c != '%') {
      94     1637324 :                         break;
      95             :                     }
      96             :                 }
      97    40677227 :                 s->write(c);
      98             :             }
      99             : 
     100     1637324 :             flags = 0;
     101     1637324 :             width = 0;
     102     1637324 :             prec = 0;
     103             : 
     104             :             /*
     105             :              * Process format adjustment characters, precision, width.
     106             :              */
     107             :             do {
     108     1909133 :                 if (flags < FL_WIDTH) {
     109     1678079 :                     switch (c) {
     110       40263 :                     case '0':
     111       40263 :                         flags |= FL_ZFILL;
     112       40263 :                         continue;
     113           6 :                     case '+':
     114           6 :                         flags |= FL_PLUS;
     115             :                         FALLTHROUGH;
     116         298 :                     case ' ':
     117         298 :                         flags |= FL_SPACE;
     118         298 :                         continue;
     119         188 :                     case '-':
     120         188 :                         flags |= FL_LPAD;
     121         188 :                         continue;
     122           6 :                     case '#':
     123           6 :                         flags |= FL_ALT;
     124           6 :                         continue;
     125             :                     }
     126             :                 }
     127             : 
     128     1868378 :                 if (flags < FL_LONG) {
     129     1866126 :                     if (c >= '0' && c <= '9') {
     130      163824 :                         c -= '0';
     131      163824 :                         if (flags & FL_PREC) {
     132       65164 :                             prec = 10*prec + c;
     133       65164 :                             continue;
     134             :                         }
     135       98660 :                         width = 10*width + c;
     136       98660 :                         flags |= FL_WIDTH;
     137       98660 :                         continue;
     138             :                     }
     139     1702302 :                     if (c == '.') {
     140       64978 :                         if (flags & FL_PREC) {
     141           0 :                             return;
     142             :                         }
     143       64978 :                         flags |= FL_PREC;
     144       64978 :                         continue;
     145             :                     }
     146     1637324 :                     if (c == 'l') {
     147        2234 :                         flags |= FL_LONG;
     148        2234 :                         continue;
     149             :                     }
     150     1635090 :                     if (c == 'h') {
     151           0 :                         continue;
     152             :                     }
     153        2252 :                 } else if ((flags & FL_LONG) && c == 'l') {
     154          18 :                     flags |= FL_LONGLONG;
     155          18 :                     continue;
     156             :                 }
     157             : 
     158     1637324 :                 break;
     159      271809 :             } while ((c = *fmt++) != 0);
     160             : 
     161             : #if CONFIG_HAL_BOARD != HAL_BOARD_CHIBIOS || __FPU_PRESENT
     162             :             /*
     163             :              * Handle floating-point formats E, F, G, e, f, g.
     164             :              */
     165     1637324 :             if (c >= 'E' && c <= 'G') {
     166           8 :                 flags |= FL_FLTUPP;
     167           8 :                 c += 'e' - 'E';
     168           8 :                 goto flt_oper;
     169     1637316 :             } else if (c >= 'e' && c <= 'g') {
     170             :                 int exp;                /* exponent of master decimal digit     */
     171             :                 int n;
     172             :                 unsigned char vtype;    /* result of float value parse  */
     173             :                 unsigned char sign;     /* sign character (or 0)        */
     174             :                 unsigned char ndigs;
     175             : 
     176       66755 :                 flags &= ~FL_FLTUPP;
     177             : 
     178       66763 : flt_oper:
     179       66763 :                 float value = va_arg(ap,double);
     180             : 
     181       66763 :                 if (!(flags & FL_PREC)) {
     182        1982 :                     prec = 6;
     183             :                 }
     184       66763 :                 flags &= ~(FL_FLTEXP | FL_FLTFIX);
     185       66763 :                 if (c == 'e') {
     186           6 :                     flags |= FL_FLTEXP;
     187       66757 :                 } else if (c == 'f') {
     188       66747 :                     flags |= FL_FLTFIX;
     189          10 :                 } else if (prec > 0) {
     190          10 :                     prec -= 1;
     191             :                 }
     192             : 
     193       66763 :                 if ((flags & FL_FLTFIX) && fabsf(value) > 9999999) {
     194          16 :                     flags = (flags & ~FL_FLTFIX) | FL_FLTEXP;
     195             :                 }
     196             : 
     197       66763 :                 if (flags & FL_FLTFIX) {
     198       66731 :                     vtype = 7;              /* 'prec' arg for 'ftoa_engine' */
     199       66731 :                     ndigs = prec < 60 ? prec + 1 : 60;
     200             :                 } else {
     201          32 :                     if (prec > 10) {
     202           0 :                         prec = 10;
     203             :                     }
     204          32 :                     vtype = prec;
     205          32 :                     ndigs = 0;
     206             :                 }
     207       66763 :                 memset(buf, 0, sizeof(buf));
     208       66763 :                 exp = ftoa_engine(value, (char *)buf, vtype, ndigs);
     209       66763 :                 vtype = buf[0];
     210             : 
     211       66763 :                 sign = 0;
     212       66763 :                 if ((vtype & FTOA_MINUS) && !(vtype & FTOA_NAN))
     213         668 :                     sign = '-';
     214       66095 :                 else if (flags & FL_PLUS)
     215           4 :                     sign = '+';
     216       66091 :                 else if (flags & FL_SPACE)
     217         290 :                     sign = ' ';
     218             : 
     219       66763 :                 if (vtype & (FTOA_NAN | FTOA_INF)) {
     220          38 :                     ndigs = sign ? 4 : 3;
     221          38 :                     if (width > ndigs) {
     222           2 :                         width -= ndigs;
     223           2 :                         if (!(flags & FL_LPAD)) {
     224             :                             do {
     225           6 :                                 s->write(' ');
     226           6 :                             } while (--width);
     227             :                         }
     228             :                     } else {
     229          36 :                         width = 0;
     230             :                     }
     231          38 :                     if (sign) {
     232           6 :                         s->write(sign);
     233             :                     }
     234             : 
     235          38 :                     const char *p = "inf";
     236          38 :                     if (vtype & FTOA_NAN)
     237          24 :                         p = "nan";
     238         152 :                     while ((ndigs = *p) != 0) {
     239         114 :                         if (flags & FL_FLTUPP)
     240          12 :                             ndigs += 'I' - 'i';
     241         114 :                         s->write(ndigs);
     242         114 :                         p++;
     243             :                     }
     244          38 :                     goto tail;
     245             :                 }
     246             : 
     247             :                 /* Output format adjustment, number of decimal digits in buf[] */
     248       66725 :                 if (flags & FL_FLTFIX) {
     249       66707 :                     ndigs += exp;
     250       66707 :                     if ((vtype & FTOA_CARRY) && buf[1] == '1') {
     251         556 :                         ndigs -= 1;
     252             :                     }
     253       66707 :                     if ((signed char)ndigs < 1) {
     254        4608 :                         ndigs = 1;
     255       62099 :                     } else if (ndigs > 8) {
     256         386 :                         ndigs = 8;
     257             :                     }
     258          18 :                 } else if (!(flags & FL_FLTEXP)) {              /* 'g(G)' format */
     259          10 :                     if (exp <= prec && exp >= -4) {
     260           6 :                         flags |= FL_FLTFIX;
     261             :                     }
     262          52 :                     while (prec && buf[1+prec] == '0') {
     263          42 :                         prec--;
     264             :                     }
     265          10 :                     if (flags & FL_FLTFIX) {
     266           6 :                         ndigs = prec + 1;               /* number of digits in buf */
     267           6 :                         prec = prec > exp ? prec - exp : 0;       /* fractional part length  */
     268             :                     }
     269             :                 }
     270             : 
     271             :                 /* Conversion result length, width := free space length */
     272       66725 :                 if (flags & FL_FLTFIX) {
     273       66713 :                     n = (exp>0 ? exp+1 : 1);
     274             :                 } else {
     275          12 :                     n = 5;          /* 1e+00 */
     276             :                 }
     277       66725 :                 if (sign) {
     278         956 :                     n += 1;
     279             :                 }
     280       66725 :                 if (prec) {
     281       65482 :                     n += prec + 1;
     282             :                 }
     283       66725 :                 width = width > n ? width - n : 0;
     284             : 
     285             :                 /* Output before first digit    */
     286       66725 :                 if (!(flags & (FL_LPAD | FL_ZFILL))) {
     287       55553 :                     while (width) {
     288         232 :                         s->write(' ');
     289         232 :                         width--;
     290             :                     }
     291             :                 }
     292       66725 :                 if (sign) {
     293         956 :                     s->write(sign);
     294             :                 }
     295       66725 :                 if (!(flags & FL_LPAD)) {
     296       78066 :                     while (width) {
     297       11343 :                         s->write('0');
     298       11343 :                         width--;
     299             :                     }
     300             :                 }
     301             : 
     302       66725 :                 if (flags & FL_FLTFIX) {                /* 'f' format           */
     303             : 
     304       66713 :                     n = exp > 0 ? exp : 0;          /* exponent of left digit */
     305       66713 :                     unsigned char v = 0;
     306             :                     do {
     307      191077 :                         if (n == -1) {
     308       65474 :                             s->write('.');
     309             :                         }
     310      191077 :                         v = (n <= exp && n > exp - ndigs)
     311      176253 :                             ? buf[exp - n + 1] : '0';
     312      191077 :                         if (--n < -prec || v == 0) {
     313       66713 :                             break;
     314             :                         }
     315      124364 :                         s->write(v);
     316             :                     } while (1);
     317       66713 :                     if (n == exp
     318        3356 :                         && (buf[1] > '5'
     319        2275 :                             || (buf[1] == '5' && !(vtype & FTOA_CARRY)))) {
     320        1787 :                         v = '1';
     321             :                     }
     322       66713 :                     if (v) {
     323       65757 :                         s->write(v);
     324             :                     }
     325             :                 } else {                                /* 'e(E)' format        */
     326             :                     /* mantissa     */
     327          12 :                     if (buf[1] != '1')
     328           0 :                         vtype &= ~FTOA_CARRY;
     329          12 :                     s->write(buf[1]);
     330          12 :                     if (prec) {
     331           8 :                         s->write('.');
     332           8 :                         sign = 2;
     333             :                         do {
     334          40 :                             s->write(buf[sign++]);
     335          40 :                         } while (--prec);
     336             :                     }
     337             : 
     338             :                     /* exponent     */
     339          12 :                     s->write(flags & FL_FLTUPP ? 'E' : 'e');
     340          12 :                     ndigs = '+';
     341          12 :                     if (exp < 0 || (exp == 0 && (vtype & FTOA_CARRY) != 0)) {
     342           2 :                         exp = -exp;
     343           2 :                         ndigs = '-';
     344             :                     }
     345          12 :                     s->write(ndigs);
     346          12 :                     for (ndigs = '0'; exp >= 10; exp -= 10)
     347           0 :                         ndigs += 1;
     348          12 :                     s->write(ndigs);
     349          12 :                     s->write('0' + exp);
     350             :                 }
     351             : 
     352       66725 :                 goto tail;
     353             :             }
     354             : #endif //#if CONFIG_HAL_BOARD != HAL_BOARD_CHIBIOS || __FPU_PRESENT
     355             :             /*
     356             :              * Handle string formats c, s, S.
     357             :              */
     358             :             {
     359             :                 const char * pnt;
     360             :                 size_t size;
     361             : 
     362     1570561 :                 switch (c) {
     363       31497 :                 case 'c':
     364       31497 :                     buf[0] = va_arg (ap, int);
     365       31497 :                     pnt = (char *)buf;
     366       31497 :                     size = 1;
     367       31497 :                     break;
     368             : 
     369      329443 :                 case 's':
     370      329443 :                     pnt = va_arg (ap, char *);
     371      329443 :                     size = strnlen (pnt, (flags & FL_PREC) ? prec : ~0);
     372      329443 :                     break;
     373             : 
     374     1209621 :                 default:
     375     1209621 :                         goto non_string;
     376             :                 }
     377             : 
     378      360940 :                 if (!(flags & FL_LPAD)) {
     379      360774 :                     while (size < width) {
     380          18 :                         s->write(' ');
     381          18 :                         width--;
     382             :                     }
     383             :                 }
     384             : 
     385     6494410 :                 while (size) {
     386     6133470 :                     s->write(*pnt++);
     387     6133470 :                     if (width) width -= 1;
     388     6133470 :                     size -= 1;
     389             :                 }
     390      360940 :                 goto tail;
     391             :             }
     392             : 
     393     1209621 :         non_string:
     394             :             
     395             :             /*
     396             :              * Handle integer formats variations for d/i, u, o, p, x, X.
     397             :              */
     398     1209621 :             if (c == 'd' || c == 'i') {
     399       49292 :                 if (flags & FL_LONGLONG) {
     400           2 :                     int64_t x = va_arg(ap,long long);
     401           2 :                     flags &= ~(FL_NEGATIVE | FL_ALT);
     402           2 :                     if (x < 0) {
     403           2 :                         x = -x;
     404           2 :                         flags |= FL_NEGATIVE;
     405             :                     }
     406           2 :                     c = ulltoa_invert (x, (char *)buf, 10) - (char *)buf;
     407             :                 } else {
     408       49290 :                     long x = (flags & FL_LONG) ? va_arg(ap,long) : va_arg(ap,int);
     409       49293 :                     flags &= ~(FL_NEGATIVE | FL_ALT);
     410       49293 :                     if (x < 0) {
     411        1814 :                         x = -x;
     412        1814 :                         flags |= FL_NEGATIVE;
     413             :                     }
     414       49293 :                     c = ultoa_invert (x, (char *)buf, 10) - (char *)buf;
     415             :                 }
     416       49295 :             } else {
     417             :                 int base;
     418             : 
     419     1160329 :                 if (c == 'u') {
     420     1145193 :                     flags &= ~FL_ALT;
     421     1145193 :                     base = 10;
     422     1145193 :                     goto ultoa;
     423             :                 }
     424             : 
     425       15136 :                 flags &= ~(FL_PLUS | FL_SPACE);
     426             : 
     427       15136 :                 switch (c) {
     428           4 :                 case 'o':
     429           4 :                     base = 8;
     430           4 :                     goto ultoa;
     431           2 :                 case 'p':
     432           2 :                     flags |= FL_ALT;
     433             : 
     434             :                     FALLTHROUGH;
     435          38 :                 case 'x':
     436          38 :                     if (flags & FL_ALT)
     437           4 :                         flags |= FL_ALTHEX;
     438          38 :                     base = 16;
     439          38 :                     goto ultoa;
     440       15094 :                 case 'X':
     441       15094 :                     if (flags & FL_ALT)
     442           2 :                         flags |= (FL_ALTHEX | FL_ALTUPP);
     443       15094 :                     base = 16 | XTOA_UPPER;
     444     1160329 : ultoa:
     445     1160329 :                     if (flags & FL_LONGLONG) {
     446          16 :                         c = ulltoa_invert (va_arg(ap, unsigned long long),
     447          16 :                                            (char *)buf, base)  -  (char *)buf;
     448             :                     } else {
     449     1160335 :                         c = ultoa_invert ((flags & FL_LONG)
     450          22 :                                           ? va_arg(ap, unsigned long)
     451             :                                           : va_arg(ap, unsigned int),
     452     1160313 :                                           (char *)buf, base)  -  (char *)buf;
     453             :                     }
     454     1160329 :                     flags &= ~FL_NEGATIVE;
     455     1160329 :                     break;
     456             : 
     457           0 :                 default:
     458           0 :                     return;
     459             :                 }
     460             :             }
     461             : 
     462             :             /*
     463             :              * Format integers.
     464             :              */
     465             :             {
     466             :                 unsigned char len;
     467             : 
     468     1209624 :                 len = c;
     469     1209624 :                 if (flags & FL_PREC) {
     470           2 :                     flags &= ~FL_ZFILL;
     471           2 :                     if (len < prec) {
     472           2 :                         len = prec;
     473           2 :                         if ((flags & FL_ALT) && !(flags & FL_ALTHEX)) {
     474           0 :                             flags &= ~FL_ALT;
     475             :                         }
     476             :                     }
     477             :                 }
     478     1209624 :                 if (flags & FL_ALT) {
     479           8 :                     if (buf[c-1] == '0') {
     480           0 :                         flags &= ~(FL_ALT | FL_ALTHEX | FL_ALTUPP);
     481             :                     } else {
     482           8 :                         len += 1;
     483           8 :                         if (flags & FL_ALTHEX) {
     484           6 :                             len += 1;
     485             :                         }
     486             :                     }
     487     1209616 :                 } else if (flags & (FL_NEGATIVE | FL_PLUS | FL_SPACE)) {
     488        1820 :                     len += 1;
     489             :                 }
     490             : 
     491     1209624 :                 if (!(flags & FL_LPAD)) {
     492     1209622 :                     if (flags & FL_ZFILL) {
     493       28861 :                         prec = c;
     494       28861 :                         if (len < width) {
     495        8159 :                             prec += width - len;
     496        8159 :                             len = width;
     497             :                         }
     498             :                     }
     499     1486197 :                     while (len < width) {
     500      276575 :                         s->write(' ');
     501      276575 :                         len++;
     502             :                     }
     503             :                 }
     504             : 
     505     1209624 :                 width =  (len < width) ? width - len : 0;
     506             : 
     507     1209624 :                 if (flags & FL_ALT) {
     508           8 :                     s->write('0');
     509           8 :                     if (flags & FL_ALTHEX) {
     510           6 :                         s->write(flags & FL_ALTUPP ? 'X' : 'x');
     511             :                     }
     512     1209616 :                 } else if (flags & (FL_NEGATIVE | FL_PLUS | FL_SPACE)) {
     513        1820 :                     unsigned char z = ' ';
     514        1820 :                     if (flags & FL_PLUS) {
     515           2 :                         z = '+';
     516             :                     }
     517        1820 :                     if (flags & FL_NEGATIVE) {
     518        1816 :                         z = '-';
     519             :                     }
     520        1820 :                     s->write(z);
     521             :                 }
     522             : 
     523     1229608 :                 while (prec > c) {
     524       19984 :                     s->write('0');
     525       19984 :                     prec--;
     526             :                 }
     527             : 
     528             :                 do {
     529     3393201 :                     s->write(buf[--c]);
     530     3393200 :                 } while (c);
     531             :             }
     532             : 
     533     1209623 : tail:
     534             :             /* Tail is possible.    */
     535     1638972 :             while (width) {
     536        1647 :                 s->write(' ');
     537        1646 :                 width--;
     538             :             }
     539     1637325 :         } /* for (;;) */
     540             : }

Generated by: LCOV version 1.14