LCOV - code coverage report
Current view: top level - lib/os - cbprintf_complete.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 188 541 34.8 %
Date: 2022-08-18 11:36:24 Functions: 11 16 68.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 90 324 27.8 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 1997-2010, 2012-2015 Wind River Systems, Inc.
       3                 :            :  * Copyright (c) 2020 Nordic Semiconductor ASA
       4                 :            :  *
       5                 :            :  * SPDX-License-Identifier: Apache-2.0
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <ctype.h>
       9                 :            : #include <errno.h>
      10                 :            : #include <inttypes.h>
      11                 :            : #include <limits.h>
      12                 :            : #include <stdarg.h>
      13                 :            : #include <stdbool.h>
      14                 :            : #include <stddef.h>
      15                 :            : #include <stdint.h>
      16                 :            : #include <string.h>
      17                 :            : #include <toolchain.h>
      18                 :            : #include <sys/types.h>
      19                 :            : #include <sys/util.h>
      20                 :            : #include <sys/cbprintf.h>
      21                 :            : 
      22                 :            : /* newlib doesn't declare this function unless __POSIX_VISIBLE >= 200809.  No
      23                 :            :  * idea how to make that happen, so lets put it right here.
      24                 :            :  */
      25                 :            : size_t strnlen(const char *s, size_t maxlen);
      26                 :            : 
      27                 :            : /* Provide typedefs used for signed and unsigned integral types
      28                 :            :  * capable of holding all convertible integral values.
      29                 :            :  */
      30                 :            : #ifdef CONFIG_CBPRINTF_FULL_INTEGRAL
      31                 :            : typedef intmax_t sint_value_type;
      32                 :            : typedef uintmax_t uint_value_type;
      33                 :            : #else
      34                 :            : typedef int32_t sint_value_type;
      35                 :            : typedef uint32_t uint_value_type;
      36                 :            : #endif
      37                 :            : 
      38                 :            : /* The maximum buffer size required is for octal formatting: one character for
      39                 :            :  * every 3 bits.  Neither EOS nor alternate forms are required.
      40                 :            :  */
      41                 :            : #define CONVERTED_INT_BUFLEN ((CHAR_BIT * sizeof(uint_value_type) + 2) / 3)
      42                 :            : 
      43                 :            : /* The float code may extract up to 16 digits, plus a prefix, a
      44                 :            :  * leading 0, a dot, and an exponent in the form e+xxx for a total of
      45                 :            :  * 24. Add a trailing NULL so the buffer length required is 25.
      46                 :            :  */
      47                 :            : #define CONVERTED_FP_BUFLEN 25U
      48                 :            : 
      49                 :            : #ifdef CONFIG_CBPRINTF_FP_SUPPORT
      50                 :            : #define CONVERTED_BUFLEN MAX(CONVERTED_INT_BUFLEN, CONVERTED_FP_BUFLEN)
      51                 :            : #else
      52                 :            : #define CONVERTED_BUFLEN CONVERTED_INT_BUFLEN
      53                 :            : #endif
      54                 :            : 
      55                 :            : /* The allowed types of length modifier. */
      56                 :            : enum length_mod_enum {
      57                 :            :         LENGTH_NONE,            /* int */
      58                 :            :         LENGTH_HH,              /* char */
      59                 :            :         LENGTH_H,               /* short */
      60                 :            :         LENGTH_L,               /* long */
      61                 :            :         LENGTH_LL,              /* long long */
      62                 :            :         LENGTH_J,               /* intmax */
      63                 :            :         LENGTH_Z,               /* size_t */
      64                 :            :         LENGTH_T,               /* ptrdiff_t */
      65                 :            :         LENGTH_UPPER_L,         /* long double */
      66                 :            : };
      67                 :            : 
      68                 :            : /* Categories of conversion specifiers. */
      69                 :            : enum specifier_cat_enum {
      70                 :            :         /* unrecognized */
      71                 :            :         SPECIFIER_INVALID,
      72                 :            :         /* d, i */
      73                 :            :         SPECIFIER_SINT,
      74                 :            :         /* c, o, u, x, X */
      75                 :            :         SPECIFIER_UINT,
      76                 :            :         /* n, p, s */
      77                 :            :         SPECIFIER_PTR,
      78                 :            :         /* a, A, e, E, f, F, g, G */
      79                 :            :         SPECIFIER_FP,
      80                 :            : };
      81                 :            : 
      82                 :            : #define CHAR_IS_SIGNED (CHAR_MIN != 0)
      83                 :            : #if CHAR_IS_SIGNED
      84                 :            : #define CASE_SINT_CHAR case 'c':
      85                 :            : #define CASE_UINT_CHAR
      86                 :            : #else
      87                 :            : #define CASE_SINT_CHAR
      88                 :            : #define CASE_UINT_CHAR case 'c':
      89                 :            : #endif
      90                 :            : 
      91                 :            : /* We need two pieces of information about wchar_t:
      92                 :            :  * * WCHAR_IS_SIGNED: whether it's signed or unsigned;
      93                 :            :  * * WINT_TYPE: the type to use when extracting it from va_args
      94                 :            :  *
      95                 :            :  * The former can be determined from the value of WCHAR_MIN if it's defined.
      96                 :            :  * It's not for minimal libc, so treat it as whatever char is.
      97                 :            :  *
      98                 :            :  * The latter should be wint_t, but minimal libc doesn't provide it.  We can
      99                 :            :  * substitute wchar_t as long as that type does not undergo default integral
     100                 :            :  * promotion as an argument.  But it does for at least one toolchain (xtensa),
     101                 :            :  * and where it does we need to use the promoted type in va_arg() to avoid
     102                 :            :  * build errors, otherwise we can use the base type.  We can tell that
     103                 :            :  * integral promotion occurs if WCHAR_MAX is strictly less than INT_MAX.
     104                 :            :  */
     105                 :            : #ifndef WCHAR_MIN
     106                 :            : #define WCHAR_IS_SIGNED CHAR_IS_SIGNED
     107                 :            : #if WCHAR_IS_SIGNED
     108                 :            : #define WINT_TYPE int
     109                 :            : #else /* wchar signed */
     110                 :            : #define WINT_TYPE unsigned int
     111                 :            : #endif /* wchar signed */
     112                 :            : #else /* WCHAR_MIN defined */
     113                 :            : #define WCHAR_IS_SIGNED ((WCHAR_MIN - 0) != 0)
     114                 :            : #if WCHAR_MAX < INT_MAX
     115                 :            : /* Signed or unsigned, it'll be int */
     116                 :            : #define WINT_TYPE int
     117                 :            : #else /* wchar rank vs int */
     118                 :            : #define WINT_TYPE wchar_t
     119                 :            : #endif /* wchar rank vs int */
     120                 :            : #endif /* WCHAR_MIN defined */
     121                 :            : 
     122                 :            : /* Case label to identify conversions for signed integral values.  The
     123                 :            :  * corresponding argument_value tag is sint and category is
     124                 :            :  * SPECIFIER_SINT.
     125                 :            :  */
     126                 :            : #define SINT_CONV_CASES                         \
     127                 :            :         'd':                                    \
     128                 :            :         CASE_SINT_CHAR                          \
     129                 :            :         case 'i'
     130                 :            : 
     131                 :            : /* Case label to identify conversions for signed integral arguments.
     132                 :            :  * The corresponding argument_value tag is uint and category is
     133                 :            :  * SPECIFIER_UINT.
     134                 :            :  */
     135                 :            : #define UINT_CONV_CASES                         \
     136                 :            :         'o':                                    \
     137                 :            :         CASE_UINT_CHAR                          \
     138                 :            :         case 'u':                               \
     139                 :            :         case 'x':                               \
     140                 :            :         case 'X'
     141                 :            : 
     142                 :            : /* Case label to identify conversions for floating point arguments.
     143                 :            :  * The corresponding argument_value tag is either dbl or ldbl,
     144                 :            :  * depending on length modifier, and the category is SPECIFIER_FP.
     145                 :            :  */
     146                 :            : #define FP_CONV_CASES                           \
     147                 :            :         'a':                                    \
     148                 :            :         case 'A':                               \
     149                 :            :         case 'e':                               \
     150                 :            :         case 'E':                               \
     151                 :            :         case 'f':                               \
     152                 :            :         case 'F':                               \
     153                 :            :         case 'g':                               \
     154                 :            :         case 'G'
     155                 :            : 
     156                 :            : /* Case label to identify conversions for pointer arguments.  The
     157                 :            :  * corresponding argument_value tag is ptr and the category is
     158                 :            :  * SPECIFIER_PTR.
     159                 :            :  */
     160                 :            : #define PTR_CONV_CASES                          \
     161                 :            :         'n':                                    \
     162                 :            :         case 'p':                               \
     163                 :            :         case 's'
     164                 :            : 
     165                 :            : /* Storage for an argument value. */
     166                 :            : union argument_value {
     167                 :            :         /* For SINT conversions */
     168                 :            :         sint_value_type sint;
     169                 :            : 
     170                 :            :         /* For UINT conversions */
     171                 :            :         uint_value_type uint;
     172                 :            : 
     173                 :            :         /* For FP conversions without L length */
     174                 :            :         double dbl;
     175                 :            : 
     176                 :            :         /* For FP conversions with L length */
     177                 :            :         long double ldbl;
     178                 :            : 
     179                 :            :         /* For PTR conversions */
     180                 :            :         void *ptr;
     181                 :            : };
     182                 :            : 
     183                 :            : /* Structure capturing all attributes of a conversion
     184                 :            :  * specification.
     185                 :            :  *
     186                 :            :  * Initial values come from the specification, but are updated during
     187                 :            :  * the conversion.
     188                 :            :  */
     189                 :            : struct conversion {
     190                 :            :         /** Indicates flags are inconsistent */
     191                 :            :         bool invalid: 1;
     192                 :            : 
     193                 :            :         /** Indicates flags are valid but not supported */
     194                 :            :         bool unsupported: 1;
     195                 :            : 
     196                 :            :         /** Left-justify value in width */
     197                 :            :         bool flag_dash: 1;
     198                 :            : 
     199                 :            :         /** Explicit sign */
     200                 :            :         bool flag_plus: 1;
     201                 :            : 
     202                 :            :         /** Space for non-negative sign */
     203                 :            :         bool flag_space: 1;
     204                 :            : 
     205                 :            :         /** Alternative form */
     206                 :            :         bool flag_hash: 1;
     207                 :            : 
     208                 :            :         /** Pad with leading zeroes */
     209                 :            :         bool flag_zero: 1;
     210                 :            : 
     211                 :            :         /** Width field present */
     212                 :            :         bool width_present: 1;
     213                 :            : 
     214                 :            :         /** Width value from int argument
     215                 :            :          *
     216                 :            :          * width_value is set to the absolute value of the argument.
     217                 :            :          * If the argument is negative flag_dash is also set.
     218                 :            :          */
     219                 :            :         bool width_star: 1;
     220                 :            : 
     221                 :            :         /** Precision field present */
     222                 :            :         bool prec_present: 1;
     223                 :            : 
     224                 :            :         /** Precision from int argument
     225                 :            :          *
     226                 :            :          * prec_value is set to the value of a non-negative argument.
     227                 :            :          * If the argument is negative prec_present is cleared.
     228                 :            :          */
     229                 :            :         bool prec_star: 1;
     230                 :            : 
     231                 :            :         /** Length modifier (value from length_mod_enum) */
     232                 :            :         unsigned int length_mod: 4;
     233                 :            : 
     234                 :            :         /** Indicates an a or A conversion specifier.
     235                 :            :          *
     236                 :            :          * This affects how precision is handled.
     237                 :            :          */
     238                 :            :         bool specifier_a: 1;
     239                 :            : 
     240                 :            :         /** Conversion specifier category (value from specifier_cat_enum) */
     241                 :            :         unsigned int specifier_cat: 3;
     242                 :            : 
     243                 :            :         /** If set alternate form requires 0 before octal. */
     244                 :            :         bool altform_0: 1;
     245                 :            : 
     246                 :            :         /** If set alternate form requires 0x before hex. */
     247                 :            :         bool altform_0c: 1;
     248                 :            : 
     249                 :            :         /** Set when pad0_value zeroes are to be to be inserted after
     250                 :            :          * the decimal point in a floating point conversion.
     251                 :            :          */
     252                 :            :         bool pad_postdp: 1;
     253                 :            : 
     254                 :            :         /** Set for floating point values that have a non-zero
     255                 :            :          * pad0_prefix or pad0_pre_exp.
     256                 :            :          */
     257                 :            :         bool pad_fp: 1;
     258                 :            : 
     259                 :            :         /** Conversion specifier character */
     260                 :            :         unsigned char specifier;
     261                 :            : 
     262                 :            :         union {
     263                 :            :                 /** Width value from specification.
     264                 :            :                  *
     265                 :            :                  * Valid until conversion begins.
     266                 :            :                  */
     267                 :            :                 int width_value;
     268                 :            : 
     269                 :            :                 /** Number of extra zeroes to be inserted around a
     270                 :            :                  * formatted value:
     271                 :            :                  *
     272                 :            :                  * * before a formatted integer value due to precision
     273                 :            :                  *   and flag_zero; or
     274                 :            :                  * * before a floating point mantissa decimal point
     275                 :            :                  *   due to precision; or
     276                 :            :                  * * after a floating point mantissa decimal point due
     277                 :            :                  *   to precision.
     278                 :            :                  *
     279                 :            :                  * For example for zero-padded hexadecimal integers
     280                 :            :                  * this would insert where the angle brackets are in:
     281                 :            :                  * 0x<>hhhh.
     282                 :            :                  *
     283                 :            :                  * For floating point numbers this would insert at
     284                 :            :                  * either <1> or <2> depending on #pad_postdp:
     285                 :            :                  * VVV<1>.<2>FFFFeEEE
     286                 :            :                  *
     287                 :            :                  * Valid after conversion begins.
     288                 :            :                  */
     289                 :            :                 int pad0_value;
     290                 :            :         };
     291                 :            : 
     292                 :            :         union {
     293                 :            :                 /** Precision from specification.
     294                 :            :                  *
     295                 :            :                  * Valid until conversion begins.
     296                 :            :                  */
     297                 :            :                 int prec_value;
     298                 :            : 
     299                 :            :                 /** Number of extra zeros to be inserted after a decimal
     300                 :            :                  * point due to precision.
     301                 :            :                  *
     302                 :            :                  * Inserts at <> in: VVVV.FFFF<>eEE
     303                 :            :                  *
     304                 :            :                  * Valid after conversion begins.
     305                 :            :                  */
     306                 :            :                 int pad0_pre_exp;
     307                 :            :         };
     308                 :            : };
     309                 :            : 
     310                 :            : /** Get a size represented as a sequence of decimal digits.
     311                 :            :  *
     312                 :            :  * @param[inout] str where to read from.  Updated to point to the first
     313                 :            :  * unconsumed character.  There must be at least one non-digit character in
     314                 :            :  * the referenced text.
     315                 :            :  *
     316                 :            :  * @return the decoded integer value.
     317                 :            :  */
     318                 :     133519 : static size_t extract_decimal(const char **str)
     319                 :            : {
     320                 :     133519 :         const char *sp = *str;
     321                 :     133519 :         size_t val = 0;
     322                 :            : 
     323         [ +  + ]:     253403 :         while (isdigit((int)(unsigned char)*sp)) {
     324                 :     119884 :                 val = 10U * val + *sp++ - '0';
     325                 :            :         }
     326                 :     133519 :         *str = sp;
     327                 :     133519 :         return val;
     328                 :            : }
     329                 :            : 
     330                 :            : /** Extract C99 conversion specification flags.
     331                 :            :  *
     332                 :            :  * @param conv pointer to the conversion being defined.
     333                 :            :  *
     334                 :            :  * @param sp pointer to the first character after the % of a conversion
     335                 :            :  * specifier.
     336                 :            :  *
     337                 :            :  * @return a pointer the first character that follows the flags.
     338                 :            :  */
     339                 :     133519 : static inline const char *extract_flags(struct conversion *conv,
     340                 :            :                                         const char *sp)
     341                 :            : {
     342                 :     133519 :         bool loop = true;
     343                 :            : 
     344                 :            :         do {
     345   [ -  -  -  -  :     253403 :                 switch (*sp) {
                   +  + ]
     346                 :          0 :                 case '-':
     347                 :          0 :                         conv->flag_dash = true;
     348                 :          0 :                         break;
     349                 :          0 :                 case '+':
     350                 :          0 :                         conv->flag_plus = true;
     351                 :          0 :                         break;
     352                 :          0 :                 case ' ':
     353                 :          0 :                         conv->flag_space = true;
     354                 :          0 :                         break;
     355                 :          0 :                 case '#':
     356                 :          0 :                         conv->flag_hash = true;
     357                 :          0 :                         break;
     358                 :     119884 :                 case '0':
     359                 :     119884 :                         conv->flag_zero = true;
     360                 :     119884 :                         break;
     361                 :     133519 :                 default:
     362                 :     133519 :                         loop = false;
     363                 :            :                 }
     364         [ +  + ]:     253403 :                 if (loop) {
     365                 :     119884 :                         ++sp;
     366                 :            :                 }
     367         [ +  + ]:     253403 :         } while (loop);
     368                 :            : 
     369                 :            :         /* zero && dash => !zero */
     370   [ +  +  -  + ]:     133519 :         if (conv->flag_zero && conv->flag_dash) {
     371                 :          0 :                 conv->flag_zero = false;
     372                 :            :         }
     373                 :            : 
     374                 :            :         /* space && plus => !plus, handled in emitter code */
     375                 :            : 
     376                 :     133519 :         return sp;
     377                 :            : }
     378                 :            : 
     379                 :            : /** Extract a C99 conversion specification width.
     380                 :            :  *
     381                 :            :  * @param conv pointer to the conversion being defined.
     382                 :            :  *
     383                 :            :  * @param sp pointer to the first character after the flags element of a
     384                 :            :  * conversion specification.
     385                 :            :  *
     386                 :            :  * @return a pointer the first character that follows the width.
     387                 :            :  */
     388                 :     133519 : static inline const char *extract_width(struct conversion *conv,
     389                 :            :                                         const char *sp)
     390                 :            : {
     391                 :     133519 :         conv->width_present = true;
     392                 :            : 
     393         [ -  + ]:     133519 :         if (*sp == '*') {
     394                 :          0 :                 conv->width_star = true;
     395                 :          0 :                 return ++sp;
     396                 :            :         }
     397                 :            : 
     398                 :     133519 :         const char *wp = sp;
     399                 :     133519 :         size_t width = extract_decimal(&sp);
     400                 :            : 
     401         [ +  + ]:     133519 :         if (sp != wp) {
     402                 :     119884 :                 conv->width_present = true;
     403                 :     119884 :                 conv->width_value = width;
     404                 :     119884 :                 conv->unsupported |= ((conv->width_value < 0)
     405   [ +  -  -  + ]:     119884 :                                       || (width != (size_t)conv->width_value));
     406                 :            :         }
     407                 :            : 
     408                 :     133519 :         return sp;
     409                 :            : }
     410                 :            : 
     411                 :            : /** Extract a C99 conversion specification precision.
     412                 :            :  *
     413                 :            :  * @param conv pointer to the conversion being defined.
     414                 :            :  *
     415                 :            :  * @param sp pointer to the first character after the width element of a
     416                 :            :  * conversion specification.
     417                 :            :  *
     418                 :            :  * @return a pointer the first character that follows the precision.
     419                 :            :  */
     420                 :     133519 : static inline const char *extract_prec(struct conversion *conv,
     421                 :            :                                        const char *sp)
     422                 :            : {
     423                 :     133519 :         conv->prec_present = (*sp == '.');
     424                 :            : 
     425         [ +  - ]:     133519 :         if (!conv->prec_present) {
     426                 :     133519 :                 return sp;
     427                 :            :         }
     428                 :          0 :         ++sp;
     429                 :            : 
     430         [ #  # ]:          0 :         if (*sp == '*') {
     431                 :          0 :                 conv->prec_star = true;
     432                 :          0 :                 return ++sp;
     433                 :            :         }
     434                 :            : 
     435                 :          0 :         size_t prec = extract_decimal(&sp);
     436                 :            : 
     437                 :          0 :         conv->prec_value = prec;
     438                 :          0 :         conv->unsupported |= ((conv->prec_value < 0)
     439   [ #  #  #  # ]:          0 :                               || (prec != (size_t)conv->prec_value));
     440                 :            : 
     441                 :          0 :         return sp;
     442                 :            : }
     443                 :            : 
     444                 :            : /** Extract a C99 conversion specification length.
     445                 :            :  *
     446                 :            :  * @param conv pointer to the conversion being defined.
     447                 :            :  *
     448                 :            :  * @param sp pointer to the first character after the precision element of a
     449                 :            :  * conversion specification.
     450                 :            :  *
     451                 :            :  * @return a pointer the first character that follows the precision.
     452                 :            :  */
     453                 :     133519 : static inline const char *extract_length(struct conversion *conv,
     454                 :            :                                          const char *sp)
     455                 :            : {
     456   [ -  -  -  -  :     133519 :         switch (*sp) {
                -  -  + ]
     457                 :          0 :         case 'h':
     458         [ #  # ]:          0 :                 if (*++sp == 'h') {
     459                 :          0 :                         conv->length_mod = LENGTH_HH;
     460                 :          0 :                         ++sp;
     461                 :            :                 } else {
     462                 :          0 :                         conv->length_mod = LENGTH_H;
     463                 :            :                 }
     464                 :          0 :                 break;
     465                 :          0 :         case 'l':
     466         [ #  # ]:          0 :                 if (*++sp == 'l') {
     467                 :          0 :                         conv->length_mod = LENGTH_LL;
     468                 :          0 :                         ++sp;
     469                 :            :                 } else {
     470                 :          0 :                         conv->length_mod = LENGTH_L;
     471                 :            :                 }
     472                 :          0 :                 break;
     473                 :          0 :         case 'j':
     474                 :          0 :                 conv->length_mod = LENGTH_J;
     475                 :          0 :                 ++sp;
     476                 :          0 :                 break;
     477                 :          0 :         case 'z':
     478                 :          0 :                 conv->length_mod = LENGTH_Z;
     479                 :          0 :                 ++sp;
     480                 :          0 :                 break;
     481                 :          0 :         case 't':
     482                 :          0 :                 conv->length_mod = LENGTH_T;
     483                 :          0 :                 ++sp;
     484                 :          0 :                 break;
     485                 :          0 :         case 'L':
     486                 :          0 :                 conv->length_mod = LENGTH_UPPER_L;
     487                 :          0 :                 ++sp;
     488                 :            : 
     489                 :            :                 /* We recognize and consume these, but can't format
     490                 :            :                  * them.
     491                 :            :                  */
     492                 :          0 :                 conv->unsupported = true;
     493                 :          0 :                 break;
     494                 :     133519 :         default:
     495                 :     133519 :                 conv->length_mod = LENGTH_NONE;
     496                 :     133519 :                 break;
     497                 :            :         }
     498                 :     133519 :         return sp;
     499                 :            : }
     500                 :            : 
     501                 :            : /* Extract a C99 conversion specifier.
     502                 :            :  *
     503                 :            :  * This is the character that identifies the representation of the converted
     504                 :            :  * value.
     505                 :            :  *
     506                 :            :  * @param conv pointer to the conversion being defined.
     507                 :            :  *
     508                 :            :  * @param sp pointer to the first character after the length element of a
     509                 :            :  * conversion specification.
     510                 :            :  *
     511                 :            :  * @return a pointer the first character that follows the specifier.
     512                 :            :  */
     513                 :     133519 : static inline const char *extract_specifier(struct conversion *conv,
     514                 :            :                                             const char *sp)
     515                 :            : {
     516                 :     133519 :         bool unsupported = false;
     517                 :            : 
     518                 :     133519 :         conv->specifier = *sp++;
     519                 :            : 
     520   [ +  +  -  -  :     133519 :         switch (conv->specifier) {
                   +  - ]
     521                 :          1 :         case SINT_CONV_CASES:
     522                 :          1 :                 conv->specifier_cat = SPECIFIER_SINT;
     523                 :          1 :                 goto int_conv;
     524                 :     133510 :         case UINT_CONV_CASES:
     525                 :     133510 :                 conv->specifier_cat = SPECIFIER_UINT;
     526                 :     133511 : int_conv:
     527                 :            :                 /* L length specifier not acceptable */
     528         [ -  + ]:     133511 :                 if (conv->length_mod == LENGTH_UPPER_L) {
     529                 :          0 :                         conv->invalid = true;
     530                 :            :                 }
     531                 :            : 
     532                 :            :                 /* For c LENGTH_NONE and LENGTH_L would be ok,
     533                 :            :                  * but we don't support formatting wide characters.
     534                 :            :                  */
     535         [ +  + ]:     133511 :                 if (conv->specifier == 'c') {
     536                 :      13624 :                         unsupported = (conv->length_mod != LENGTH_NONE);
     537                 :            :                 } else if (!IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) {
     538                 :            :                         /* Disable conversion that might produce truncated
     539                 :            :                          * results with buffers sized for 32 bits.
     540                 :            :                          */
     541                 :            :                         switch (conv->length_mod) {
     542                 :            :                         case LENGTH_L:
     543                 :            :                                 unsupported = sizeof(long) > 4;
     544                 :            :                                 break;
     545                 :            :                         case LENGTH_LL:
     546                 :            :                                 unsupported = sizeof(long long) > 4;
     547                 :            :                                 break;
     548                 :            :                         case LENGTH_J:
     549                 :            :                                 unsupported = sizeof(uintmax_t) > 4;
     550                 :            :                                 break;
     551                 :            :                         case LENGTH_Z:
     552                 :            :                                 unsupported = sizeof(size_t) > 4;
     553                 :            :                                 break;
     554                 :            :                         case LENGTH_T:
     555                 :            :                                 unsupported = sizeof(ptrdiff_t) > 4;
     556                 :            :                                 break;
     557                 :            :                         default:
     558                 :            :                                 /* Add an empty default with break, this is a defensive
     559                 :            :                                  * programming. Static analysis tool won't raise a violation
     560                 :            :                                  * if default is empty, but has that comment.
     561                 :            :                                  */
     562                 :            :                                 break;
     563                 :            :                         }
     564                 :            :                 } else {
     565                 :            :                         ;
     566                 :            :                 }
     567                 :     133511 :                 break;
     568                 :            : 
     569                 :          0 :         case FP_CONV_CASES:
     570                 :          0 :                 conv->specifier_cat = SPECIFIER_FP;
     571                 :            : 
     572                 :            :                 /* Don't support if disabled */
     573                 :            :                 if (!IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
     574                 :          0 :                         unsupported = true;
     575                 :          0 :                         break;
     576                 :            :                 }
     577                 :            : 
     578                 :            :                 /* When FP enabled %a support is still conditional. */
     579                 :            :                 conv->specifier_a = (conv->specifier == 'a')
     580                 :            :                         || (conv->specifier == 'A');
     581                 :            :                 if (conv->specifier_a
     582                 :            :                     && !IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
     583                 :            :                         unsupported = true;
     584                 :            :                         break;
     585                 :            :                 }
     586                 :            : 
     587                 :            :                 /* The l specifier has no effect.  Otherwise length
     588                 :            :                  * modifiers other than L are invalid.
     589                 :            :                  */
     590                 :            :                 if (conv->length_mod == LENGTH_L) {
     591                 :            :                         conv->length_mod = LENGTH_NONE;
     592                 :            :                 } else if ((conv->length_mod != LENGTH_NONE)
     593                 :            :                            && (conv->length_mod != LENGTH_UPPER_L)) {
     594                 :            :                         conv->invalid = true;
     595                 :            :                 } else {
     596                 :            :                         ;
     597                 :            :                 }
     598                 :            : 
     599                 :            :                 break;
     600                 :            : 
     601                 :            :                 /* PTR cases are distinct */
     602                 :          0 :         case 'n':
     603                 :          0 :                 conv->specifier_cat = SPECIFIER_PTR;
     604                 :            :                 /* Anything except L */
     605         [ #  # ]:          0 :                 if (conv->length_mod == LENGTH_UPPER_L) {
     606                 :          0 :                         unsupported = true;
     607                 :            :                 }
     608                 :          0 :                 break;
     609                 :            : 
     610                 :          8 :         case 's':
     611                 :            :         case 'p':
     612                 :          8 :                 conv->specifier_cat = SPECIFIER_PTR;
     613                 :            : 
     614                 :            :                 /* p: only LENGTH_NONE
     615                 :            :                  *
     616                 :            :                  * s: LENGTH_NONE or LENGTH_L but wide
     617                 :            :                  * characters not supported.
     618                 :            :                  */
     619         [ -  + ]:          8 :                 if (conv->length_mod != LENGTH_NONE) {
     620                 :          0 :                         unsupported = true;
     621                 :            :                 }
     622                 :          8 :                 break;
     623                 :            : 
     624                 :          0 :         default:
     625                 :          0 :                 conv->invalid = true;
     626                 :          0 :                 break;
     627                 :            :         }
     628                 :            : 
     629                 :     133519 :         conv->unsupported |= unsupported;
     630                 :            : 
     631                 :     133519 :         return sp;
     632                 :            : }
     633                 :            : 
     634                 :            : /* Extract the complete C99 conversion specification.
     635                 :            :  *
     636                 :            :  * @param conv pointer to the conversion being defined.
     637                 :            :  *
     638                 :            :  * @param sp pointer to the % that introduces a conversion specification.
     639                 :            :  *
     640                 :            :  * @return pointer to the first character that follows the specification.
     641                 :            :  */
     642                 :     133519 : static inline const char *extract_conversion(struct conversion *conv,
     643                 :            :                                              const char *sp)
     644                 :            : {
     645                 :     133519 :         *conv = (struct conversion) {
     646                 :            :            .invalid = false,
     647                 :            :         };
     648                 :            : 
     649                 :            :         /* Skip over the opening %.  If the conversion specifier is %,
     650                 :            :          * that's the only thing that should be there, so
     651                 :            :          * fast-exit.
     652                 :            :          */
     653                 :     133519 :         ++sp;
     654         [ -  + ]:     133519 :         if (*sp == '%') {
     655                 :          0 :                 conv->specifier = *sp++;
     656                 :          0 :                 return sp;
     657                 :            :         }
     658                 :            : 
     659                 :     133519 :         sp = extract_flags(conv, sp);
     660                 :     133519 :         sp = extract_width(conv, sp);
     661                 :     133519 :         sp = extract_prec(conv, sp);
     662                 :     133519 :         sp = extract_length(conv, sp);
     663                 :     133519 :         sp = extract_specifier(conv, sp);
     664                 :            : 
     665                 :     133519 :         return sp;
     666                 :            : }
     667                 :            : 
     668                 :            : #ifdef CONFIG_64BIT
     669                 :            : 
     670                 :            : static void _ldiv5(uint64_t *v)
     671                 :            : {
     672                 :            :         /* The compiler can optimize this on its own on 64-bit architectures */
     673                 :            :         *v /= 5U;
     674                 :            : }
     675                 :            : 
     676                 :            : #else /* CONFIG_64BIT */
     677                 :            : 
     678                 :            : /*
     679                 :            :  * Tiny integer divide-by-five routine.  The full 64 bit division
     680                 :            :  * implementations in libgcc are very large on some architectures, and
     681                 :            :  * currently nothing in Zephyr pulls it into the link.  So it makes
     682                 :            :  * sense to define this much smaller special case here to avoid
     683                 :            :  * including it just for printf.
     684                 :            :  *
     685                 :            :  * It works by multiplying v by the reciprocal of 5 i.e.:
     686                 :            :  *
     687                 :            :  *      result = v * ((1 << 64) / 5) / (1 << 64)
     688                 :            :  *
     689                 :            :  * This produces a 128-bit result, but we drop the bottom 64 bits which
     690                 :            :  * accounts for the division by (1 << 64). The product is kept to 64 bits
     691                 :            :  * by summing partial multiplications and shifting right by 32 which on
     692                 :            :  * most 32-bit architectures means only a register drop.
     693                 :            :  *
     694                 :            :  * Here the multiplier is: (1 << 64) / 5 = 0x3333333333333333
     695                 :            :  * i.e. a 62 bits value. To compensate for the reduced precision, we
     696                 :            :  * add an initial bias of 1 to v. This conveniently allows for keeping
     697                 :            :  * the multiplier in a single 32-bit register given its pattern.
     698                 :            :  * Enlarging the multiplier to 64 bits would also work but carry handling
     699                 :            :  * on the summing of partial mults would be necessary, and a final right
     700                 :            :  * shift would be needed, requiring more instructions.
     701                 :            :  */
     702                 :          0 : static void _ldiv5(uint64_t *v)
     703                 :            : {
     704                 :          0 :         uint32_t v_lo = *v;
     705                 :          0 :         uint32_t v_hi = *v >> 32;
     706                 :          0 :         uint32_t m = 0x33333333;
     707                 :            :         uint64_t result;
     708                 :            : 
     709                 :            :         /*
     710                 :            :          * Force the multiplier constant into a register and make it
     711                 :            :          * opaque to the compiler, otherwise gcc tries to be too smart
     712                 :            :          * for its own good with a large expansion of adds and shifts.
     713                 :            :          */
     714                 :          0 :         __asm__ ("" : "+r" (m));
     715                 :            : 
     716                 :            :         /*
     717                 :            :          * Apply a bias of 1 to v. We can't add it to v as this would overflow
     718                 :            :          * it when at max range. Factor it out with the multiplier upfront.
     719                 :            :          */
     720                 :          0 :         result = ((uint64_t)m << 32) | m;
     721                 :            : 
     722                 :            :         /* The actual multiplication. */
     723                 :          0 :         result += (uint64_t)v_lo * m;
     724                 :          0 :         result >>= 32;
     725                 :          0 :         result += (uint64_t)v_lo * m;
     726                 :          0 :         result += (uint64_t)v_hi * m;
     727                 :          0 :         result >>= 32;
     728                 :          0 :         result += (uint64_t)v_hi * m;
     729                 :            : 
     730                 :          0 :         *v = result;
     731                 :          0 : }
     732                 :            : 
     733                 :            : #endif /* CONFIG_64BIT */
     734                 :            : 
     735                 :            : /* Division by 10 */
     736                 :          0 : static void _ldiv10(uint64_t *v)
     737                 :            : {
     738                 :          0 :         *v >>= 1;
     739                 :          0 :         _ldiv5(v);
     740                 :          0 : }
     741                 :            : 
     742                 :            : /* Extract the next decimal character in the converted representation of a
     743                 :            :  * fractional component.
     744                 :            :  */
     745                 :          0 : static char _get_digit(uint64_t *fr, int *digit_count)
     746                 :            : {
     747                 :            :         char rval;
     748                 :            : 
     749         [ #  # ]:          0 :         if (*digit_count > 0) {
     750                 :          0 :                 --*digit_count;
     751                 :          0 :                 *fr *= 10U;
     752                 :          0 :                 rval = ((*fr >> 60) & 0xF) + '0';
     753                 :          0 :                 *fr &= (BIT64(60) - 1U);
     754                 :            :         } else {
     755                 :          0 :                 rval = '0';
     756                 :            :         }
     757                 :            : 
     758                 :          0 :         return rval;
     759                 :            : }
     760                 :            : 
     761                 :     119887 : static inline size_t conversion_radix(char specifier)
     762                 :            : {
     763      [ +  -  + ]:     119887 :         switch (specifier) {
     764                 :          3 :         default:
     765                 :            :         case 'd':
     766                 :            :         case 'i':
     767                 :            :         case 'u':
     768                 :          3 :                 return 10;
     769                 :          0 :         case 'o':
     770                 :          0 :                 return 8;
     771                 :     119884 :         case 'p':
     772                 :            :         case 'x':
     773                 :            :         case 'X':
     774                 :     119884 :                 return 16;
     775                 :            :         }
     776                 :            : }
     777                 :            : 
     778                 :            : /* Writes the given value into the buffer in the specified base.
     779                 :            :  *
     780                 :            :  * Precision is applied *ONLY* within the space allowed.
     781                 :            :  *
     782                 :            :  * Alternate form value is applied to o, x, and X conversions.
     783                 :            :  *
     784                 :            :  * The buffer is filled backwards, so the input bpe is the end of the
     785                 :            :  * generated representation.  The returned pointer is to the first
     786                 :            :  * character of the representation.
     787                 :            :  */
     788                 :     119887 : static char *encode_uint(uint_value_type value,
     789                 :            :                          struct conversion *conv,
     790                 :            :                          char *bps,
     791                 :            :                          const char *bpe)
     792                 :            : {
     793                 :     119887 :         bool upcase = isupper((int)conv->specifier);
     794                 :     119887 :         const unsigned int radix = conversion_radix(conv->specifier);
     795                 :     119887 :         char *bp = bps + (bpe - bps);
     796                 :            : 
     797                 :            :         do {
     798                 :     146108 :                 unsigned int lsv = (unsigned int)(value % radix);
     799                 :            : 
     800   [ +  +  -  + ]:     168148 :                 *--bp = (lsv <= 9) ? ('0' + lsv)
     801                 :      22040 :                         : upcase ? ('A' + lsv - 10) : ('a' + lsv - 10);
     802                 :     146108 :                 value /= radix;
     803   [ +  +  +  - ]:     146108 :         } while ((value != 0) && (bps < bp));
     804                 :            : 
     805                 :            :         /* Record required alternate forms.  This can be determined
     806                 :            :          * from the radix without re-checking specifier.
     807                 :            :          */
     808         [ -  + ]:     119887 :         if (conv->flag_hash) {
     809         [ #  # ]:          0 :                 if (radix == 8) {
     810                 :          0 :                         conv->altform_0 = true;
     811         [ #  # ]:          0 :                 } else if (radix == 16) {
     812                 :          0 :                         conv->altform_0c = true;
     813                 :            :                 } else {
     814                 :            :                         ;
     815                 :            :                 }
     816                 :            :         }
     817                 :            : 
     818                 :     119887 :         return bp;
     819                 :            : }
     820                 :            : 
     821                 :            : /* Number of bits in the fractional part of an IEEE 754-2008 double
     822                 :            :  * precision float.
     823                 :            :  */
     824                 :            : #define FRACTION_BITS 52
     825                 :            : 
     826                 :            : /* Number of hex "digits" in the fractional part of an IEEE 754-2008
     827                 :            :  * double precision float.
     828                 :            :  */
     829                 :            : #define FRACTION_HEX ceiling_fraction(FRACTION_BITS, 4)
     830                 :            : 
     831                 :            : /* Number of bits in the exponent of an IEEE 754-2008 double precision
     832                 :            :  * float.
     833                 :            :  */
     834                 :            : #define EXPONENT_BITS 11
     835                 :            : 
     836                 :            : /* Mask for the sign (negative) bit of an IEEE 754-2008 double precision
     837                 :            :  * float.
     838                 :            :  */
     839                 :            : #define SIGN_MASK BIT64(63)
     840                 :            : 
     841                 :            : /* Mask for the high-bit of a uint64_t representation of a fractional
     842                 :            :  * value.
     843                 :            :  */
     844                 :            : #define BIT_63 BIT64(63)
     845                 :            : 
     846                 :            : /* Convert the IEEE 754-2008 double to text format.
     847                 :            :  *
     848                 :            :  * @param value the 64-bit floating point value.
     849                 :            :  *
     850                 :            :  * @param conv details about how the conversion is to proceed.  Some fields
     851                 :            :  * are adjusted based on the value being converted.
     852                 :            :  *
     853                 :            :  * @param precision the precision for the conversion (generally digits past
     854                 :            :  * the decimal point).
     855                 :            :  *
     856                 :            :  * @param bps pointer to the first character in a buffer that will hold the
     857                 :            :  * converted value.
     858                 :            :  *
     859                 :            :  * @param bpe On entry this points to the end of the buffer reserved to hold
     860                 :            :  * the converted value.  On exit it is updated to point just past the
     861                 :            :  * converted value.
     862                 :            :  *
     863                 :            :  * return a pointer to the start of the converted value.  This may not be @p
     864                 :            :  * bps but will be consistent with the exit value of *bpe.
     865                 :            :  */
     866                 :          0 : static char *encode_float(double value,
     867                 :            :                           struct conversion *conv,
     868                 :            :                           int precision,
     869                 :            :                           char *sign,
     870                 :            :                           char *bps,
     871                 :            :                           const char **bpe)
     872                 :            : {
     873                 :            :         union {
     874                 :            :                 uint64_t u64;
     875                 :            :                 double dbl;
     876                 :          0 :         } u = {
     877                 :            :                 .dbl = value,
     878                 :            :         };
     879                 :          0 :         bool prune_zero = false;
     880                 :          0 :         char *buf = bps;
     881                 :            : 
     882                 :            :         /* Prepend the sign: '-' if negative, flags control
     883                 :            :          * non-negative behavior.
     884                 :            :          */
     885         [ #  # ]:          0 :         if ((u.u64 & SIGN_MASK) != 0U) {
     886                 :          0 :                 *sign = '-';
     887         [ #  # ]:          0 :         } else if (conv->flag_plus) {
     888                 :          0 :                 *sign = '+';
     889         [ #  # ]:          0 :         } else if (conv->flag_space) {
     890                 :          0 :                 *sign = ' ';
     891                 :            :         } else {
     892                 :            :                 ;
     893                 :            :         }
     894                 :            : 
     895                 :            :         /* Extract the non-negative offset exponent and fraction.  Record
     896                 :            :          * whether the value is subnormal.
     897                 :            :          */
     898                 :          0 :         char c = conv->specifier;
     899                 :          0 :         int expo = (u.u64 >> FRACTION_BITS) & BIT_MASK(EXPONENT_BITS);
     900                 :          0 :         uint64_t fract = u.u64 & BIT64_MASK(FRACTION_BITS);
     901   [ #  #  #  # ]:          0 :         bool is_subnormal = (expo == 0) && (fract != 0);
     902                 :            : 
     903                 :            :         /* Exponent of all-ones signals infinity or NaN, which are
     904                 :            :          * text constants regardless of specifier.
     905                 :            :          */
     906         [ #  # ]:          0 :         if (expo == BIT_MASK(EXPONENT_BITS)) {
     907         [ #  # ]:          0 :                 if (fract == 0) {
     908         [ #  # ]:          0 :                         if (isupper((int)c)) {
     909                 :          0 :                                 *buf++ = 'I';
     910                 :          0 :                                 *buf++ = 'N';
     911                 :          0 :                                 *buf++ = 'F';
     912                 :            :                         } else {
     913                 :          0 :                                 *buf++ = 'i';
     914                 :          0 :                                 *buf++ = 'n';
     915                 :          0 :                                 *buf++ = 'f';
     916                 :            :                         }
     917                 :            :                 } else {
     918         [ #  # ]:          0 :                         if (isupper((int)c)) {
     919                 :          0 :                                 *buf++ = 'N';
     920                 :          0 :                                 *buf++ = 'A';
     921                 :          0 :                                 *buf++ = 'N';
     922                 :            :                         } else {
     923                 :          0 :                                 *buf++ = 'n';
     924                 :          0 :                                 *buf++ = 'a';
     925                 :          0 :                                 *buf++ = 'n';
     926                 :            :                         }
     927                 :            :                 }
     928                 :            : 
     929                 :            :                 /* No zero-padding with text values */
     930                 :          0 :                 conv->flag_zero = false;
     931                 :            : 
     932                 :          0 :                 *bpe = buf;
     933                 :          0 :                 return bps;
     934                 :            :         }
     935                 :            : 
     936                 :            :         /* The case of an F specifier is no longer relevant. */
     937         [ #  # ]:          0 :         if (c == 'F') {
     938                 :          0 :                 c = 'f';
     939                 :            :         }
     940                 :            : 
     941                 :            :         /* Handle converting to the hex representation. */
     942                 :            :         if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)
     943                 :            :             && (IS_ENABLED(CONFIG_CBPRINTF_FP_ALWAYS_A)
     944                 :            :                 || conv->specifier_a)) {
     945                 :            :                 *buf++ = '0';
     946                 :            :                 *buf++ = 'x';
     947                 :            : 
     948                 :            :                 /* Remove the offset from the exponent, and store the
     949                 :            :                  * non-fractional value.  Subnormals require increasing the
     950                 :            :                  * exponent as first bit isn't the implicit bit.
     951                 :            :                  */
     952                 :            :                 expo -= 1023;
     953                 :            :                 if (is_subnormal) {
     954                 :            :                         *buf++ = '0';
     955                 :            :                         ++expo;
     956                 :            :                 } else {
     957                 :            :                         *buf++ = '1';
     958                 :            :                 }
     959                 :            : 
     960                 :            :                 /* If we didn't get precision from a %a specification then we
     961                 :            :                  * treat it as from a %a specification with no precision: full
     962                 :            :                  * range, zero-pruning enabled.
     963                 :            :                  *
     964                 :            :                  * Otherwise we have to cap the precision of the generated
     965                 :            :                  * fraction, or possibly round it.
     966                 :            :                  */
     967                 :            :                 if (!(conv->specifier_a && conv->prec_present)) {
     968                 :            :                         precision = FRACTION_HEX;
     969                 :            :                         prune_zero = true;
     970                 :            :                 } else if (precision > FRACTION_HEX) {
     971                 :            :                         conv->pad0_pre_exp = precision - FRACTION_HEX;
     972                 :            :                         conv->pad_fp = true;
     973                 :            :                         precision = FRACTION_HEX;
     974                 :            :                 } else if ((fract != 0)
     975                 :            :                            && (precision < FRACTION_HEX)) {
     976                 :            :                         size_t pos = 4 * (FRACTION_HEX - precision) - 1;
     977                 :            :                         uint64_t mask = BIT64(pos);
     978                 :            : 
     979                 :            :                         /* Round only if the bit that would round is
     980                 :            :                          * set.
     981                 :            :                          */
     982                 :            :                         if (fract & mask) {
     983                 :            :                                 fract += mask;
     984                 :            :                         }
     985                 :            :                 }
     986                 :            : 
     987                 :            :                 /* Record whether we must retain the decimal point even if we
     988                 :            :                  * can prune zeros.
     989                 :            :                  */
     990                 :            :                 bool require_dp = ((fract != 0) || conv->flag_hash);
     991                 :            : 
     992                 :            :                 if (require_dp || (precision != 0)) {
     993                 :            :                         *buf++ = '.';
     994                 :            :                 }
     995                 :            : 
     996                 :            :                 /* Get the fractional value as a hexadecimal string, using x
     997                 :            :                  * for a and X for A.
     998                 :            :                  */
     999                 :            :                 struct conversion aconv = {
    1000                 :            :                         .specifier = isupper((int)c) ? 'X' : 'x',
    1001                 :            :                 };
    1002                 :            :                 const char *spe = *bpe;
    1003                 :            :                 char *sp = bps + (spe - bps);
    1004                 :            : 
    1005                 :            :                 if (fract != 0) {
    1006                 :            :                         sp = encode_uint(fract, &aconv, buf, spe);
    1007                 :            :                 }
    1008                 :            : 
    1009                 :            :                 /* Pad out to full range since this is below the decimal
    1010                 :            :                  * point.
    1011                 :            :                  */
    1012                 :            :                 while ((spe - sp) < FRACTION_HEX) {
    1013                 :            :                         *--sp = '0';
    1014                 :            :                 }
    1015                 :            : 
    1016                 :            :                 /* Append the leading significant "digits". */
    1017                 :            :                 while ((sp < spe) && (precision > 0)) {
    1018                 :            :                         *buf++ = *sp++;
    1019                 :            :                         --precision;
    1020                 :            :                 }
    1021                 :            : 
    1022                 :            :                 if (prune_zero) {
    1023                 :            :                         while (*--buf == '0') {
    1024                 :            :                                 ;
    1025                 :            :                         }
    1026                 :            :                         if ((*buf != '.') || require_dp) {
    1027                 :            :                                 ++buf;
    1028                 :            :                         }
    1029                 :            :                 }
    1030                 :            : 
    1031                 :            :                 *buf++ = 'p';
    1032                 :            :                 if (expo >= 0) {
    1033                 :            :                         *buf++ = '+';
    1034                 :            :                 } else {
    1035                 :            :                         *buf++ = '-';
    1036                 :            :                         expo = -expo;
    1037                 :            :                 }
    1038                 :            : 
    1039                 :            :                 aconv.specifier = 'i';
    1040                 :            :                 sp = encode_uint(expo, &aconv, buf, spe);
    1041                 :            : 
    1042                 :            :                 while (sp < spe) {
    1043                 :            :                         *buf++ = *sp++;
    1044                 :            :                 }
    1045                 :            : 
    1046                 :            :                 *bpe = buf;
    1047                 :            :                 return bps;
    1048                 :            :         }
    1049                 :            : 
    1050                 :            :         /* Remainder of code operates on a 64-bit fraction, so shift up (and
    1051                 :            :          * discard garbage from the exponent where the implicit 1 would be
    1052                 :            :          * stored).
    1053                 :            :          */
    1054                 :          0 :         fract <<= EXPONENT_BITS;
    1055                 :          0 :         fract &= ~SIGN_MASK;
    1056                 :            : 
    1057                 :            :         /* Non-zero values need normalization. */
    1058         [ #  # ]:          0 :         if ((expo | fract) != 0) {
    1059         [ #  # ]:          0 :                 if (is_subnormal) {
    1060                 :            :                         /* Fraction is subnormal.  Normalize it and correct
    1061                 :            :                          * the exponent.
    1062                 :            :                          */
    1063         [ #  # ]:          0 :                         while (((fract <<= 1) & BIT_63) == 0) {
    1064                 :          0 :                                 expo--;
    1065                 :            :                         }
    1066                 :            :                 }
    1067                 :            :                 /* Adjust the offset exponent to be signed rather than offset,
    1068                 :            :                  * and set the implicit 1 bit in the (shifted) 53-bit
    1069                 :            :                  * fraction.
    1070                 :            :                  */
    1071                 :          0 :                 expo -= (1023 - 1);     /* +1 since .1 vs 1. */
    1072                 :          0 :                 fract |= BIT_63;
    1073                 :            :         }
    1074                 :            : 
    1075                 :            :         /*
    1076                 :            :          * Let's consider:
    1077                 :            :          *
    1078                 :            :          *      value = fract * 2^expo * 10^decexp
    1079                 :            :          *
    1080                 :            :          * Initially decexp = 0. The goal is to bring exp between
    1081                 :            :          * 0 and -2 as the magnitude of a fractional decimal digit is 3 bits.
    1082                 :            :          */
    1083                 :          0 :         int decexp = 0;
    1084                 :            : 
    1085         [ #  # ]:          0 :         while (expo < -2) {
    1086                 :            :                 /*
    1087                 :            :                  * Make room to allow a multiplication by 5 without overflow.
    1088                 :            :                  * We test only the top part for faster code.
    1089                 :            :                  */
    1090                 :            :                 do {
    1091                 :          0 :                         fract >>= 1;
    1092                 :          0 :                         expo++;
    1093         [ #  # ]:          0 :                 } while ((uint32_t)(fract >> 32) >= (UINT32_MAX / 5U));
    1094                 :            : 
    1095                 :            :                 /* Perform fract * 5 * 2 / 10 */
    1096                 :          0 :                 fract *= 5U;
    1097                 :          0 :                 expo++;
    1098                 :          0 :                 decexp--;
    1099                 :            :         }
    1100                 :            : 
    1101         [ #  # ]:          0 :         while (expo > 0) {
    1102                 :            :                 /*
    1103                 :            :                  * Perform fract / 5 / 2 * 10.
    1104                 :            :                  * The +2 is there to do round the result of the division
    1105                 :            :                  * by 5 not to lose too much precision in extreme cases.
    1106                 :            :                  */
    1107                 :          0 :                 fract += 2;
    1108                 :          0 :                 _ldiv5(&fract);
    1109                 :          0 :                 expo--;
    1110                 :          0 :                 decexp++;
    1111                 :            : 
    1112                 :            :                 /* Bring back our fractional number to full scale */
    1113                 :            :                 do {
    1114                 :          0 :                         fract <<= 1;
    1115                 :          0 :                         expo--;
    1116         [ #  # ]:          0 :                 } while (!(fract & BIT_63));
    1117                 :            :         }
    1118                 :            : 
    1119                 :            :         /*
    1120                 :            :          * The binary fractional point is located somewhere above bit 63.
    1121                 :            :          * Move it between bits 59 and 60 to give 4 bits of room to the
    1122                 :            :          * integer part.
    1123                 :            :          */
    1124                 :          0 :         fract >>= (4 - expo);
    1125                 :            : 
    1126   [ #  #  #  # ]:          0 :         if ((c == 'g') || (c == 'G')) {
    1127                 :            :                 /* Use the specified precision and exponent to select the
    1128                 :            :                  * representation and correct the precision and zero-pruning
    1129                 :            :                  * in accordance with the ISO C rule.
    1130                 :            :                  */
    1131   [ #  #  #  # ]:          0 :                 if (decexp < (-4 + 1) || decexp > precision) {
    1132                 :          0 :                         c += 'e' - 'g';  /* e or E */
    1133         [ #  # ]:          0 :                         if (precision > 0) {
    1134                 :          0 :                                 precision--;
    1135                 :            :                         }
    1136                 :            :                 } else {
    1137                 :          0 :                         c = 'f';
    1138                 :          0 :                         precision -= decexp;
    1139                 :            :                 }
    1140   [ #  #  #  # ]:          0 :                 if (!conv->flag_hash && (precision > 0)) {
    1141                 :          0 :                         prune_zero = true;
    1142                 :            :                 }
    1143                 :            :         }
    1144                 :            : 
    1145                 :            :         int decimals;
    1146         [ #  # ]:          0 :         if (c == 'f') {
    1147                 :          0 :                 decimals = precision + decexp;
    1148         [ #  # ]:          0 :                 if (decimals < 0) {
    1149                 :          0 :                         decimals = 0;
    1150                 :            :                 }
    1151                 :            :         } else {
    1152                 :          0 :                 decimals = precision + 1;
    1153                 :            :         }
    1154                 :            : 
    1155                 :          0 :         int digit_count = 16;
    1156                 :            : 
    1157         [ #  # ]:          0 :         if (decimals > 16) {
    1158                 :          0 :                 decimals = 16;
    1159                 :            :         }
    1160                 :            : 
    1161                 :            :         /* Round the value to the last digit being printed. */
    1162                 :          0 :         uint64_t round = BIT64(59); /* 0.5 */
    1163         [ #  # ]:          0 :         while (decimals--) {
    1164                 :          0 :                 _ldiv10(&round);
    1165                 :            :         }
    1166                 :          0 :         fract += round;
    1167                 :            :         /* Make sure rounding didn't make fract >= 1.0 */
    1168         [ #  # ]:          0 :         if (fract >= BIT64(60)) {
    1169                 :          0 :                 _ldiv10(&fract);
    1170                 :          0 :                 decexp++;
    1171                 :            :         }
    1172                 :            : 
    1173         [ #  # ]:          0 :         if (c == 'f') {
    1174         [ #  # ]:          0 :                 if (decexp > 0) {
    1175                 :            :                         /* Emit the digits above the decimal point. */
    1176   [ #  #  #  # ]:          0 :                         while (decexp > 0 && digit_count > 0) {
    1177                 :          0 :                                 *buf++ = _get_digit(&fract, &digit_count);
    1178                 :          0 :                                 decexp--;
    1179                 :            :                         }
    1180                 :            : 
    1181                 :          0 :                         conv->pad0_value = decexp;
    1182                 :            : 
    1183                 :          0 :                         decexp = 0;
    1184                 :            :                 } else {
    1185                 :          0 :                         *buf++ = '0';
    1186                 :            :                 }
    1187                 :            : 
    1188                 :            :                 /* Emit the decimal point only if required by the alternative
    1189                 :            :                  * format, or if more digits are to follow.
    1190                 :            :                  */
    1191   [ #  #  #  # ]:          0 :                 if (conv->flag_hash || (precision > 0)) {
    1192                 :          0 :                         *buf++ = '.';
    1193                 :            :                 }
    1194                 :            : 
    1195   [ #  #  #  # ]:          0 :                 if (decexp < 0 && precision > 0) {
    1196                 :          0 :                         conv->pad0_value = -decexp;
    1197         [ #  # ]:          0 :                         if (conv->pad0_value > precision) {
    1198                 :          0 :                                 conv->pad0_value = precision;
    1199                 :            :                         }
    1200                 :            : 
    1201                 :          0 :                         precision -= conv->pad0_value;
    1202                 :          0 :                         conv->pad_postdp = (conv->pad0_value > 0);
    1203                 :            :                 }
    1204                 :            :         } else { /* e or E */
    1205                 :            :                 /* Emit the one digit before the decimal.  If it's not zero,
    1206                 :            :                  * this is significant so reduce the base-10 exponent.
    1207                 :            :                  */
    1208                 :          0 :                 *buf = _get_digit(&fract, &digit_count);
    1209         [ #  # ]:          0 :                 if (*buf++ != '0') {
    1210                 :          0 :                         decexp--;
    1211                 :            :                 }
    1212                 :            : 
    1213                 :            :                 /* Emit the decimal point only if required by the alternative
    1214                 :            :                  * format, or if more digits are to follow.
    1215                 :            :                  */
    1216   [ #  #  #  # ]:          0 :                 if (conv->flag_hash || (precision > 0)) {
    1217                 :          0 :                         *buf++ = '.';
    1218                 :            :                 }
    1219                 :            :         }
    1220                 :            : 
    1221   [ #  #  #  # ]:          0 :         while (precision > 0 && digit_count > 0) {
    1222                 :          0 :                 *buf++ = _get_digit(&fract, &digit_count);
    1223                 :          0 :                 precision--;
    1224                 :            :         }
    1225                 :            : 
    1226                 :          0 :         conv->pad0_pre_exp = precision;
    1227                 :            : 
    1228         [ #  # ]:          0 :         if (prune_zero) {
    1229                 :          0 :                 conv->pad0_pre_exp = 0;
    1230         [ #  # ]:          0 :                 while (*--buf == '0') {
    1231                 :            :                         ;
    1232                 :            :                 }
    1233         [ #  # ]:          0 :                 if (*buf != '.') {
    1234                 :          0 :                         buf++;
    1235                 :            :                 }
    1236                 :            :         }
    1237                 :            : 
    1238                 :            :         /* Emit the explicit exponent, if format requires it. */
    1239   [ #  #  #  # ]:          0 :         if ((c == 'e') || (c == 'E')) {
    1240                 :          0 :                 *buf++ = c;
    1241         [ #  # ]:          0 :                 if (decexp < 0) {
    1242                 :          0 :                         decexp = -decexp;
    1243                 :          0 :                         *buf++ = '-';
    1244                 :            :                 } else {
    1245                 :          0 :                         *buf++ = '+';
    1246                 :            :                 }
    1247                 :            : 
    1248                 :            :                 /* At most 3 digits to the decimal.  Spit them out. */
    1249         [ #  # ]:          0 :                 if (decexp >= 100) {
    1250                 :          0 :                         *buf++ = (decexp / 100) + '0';
    1251                 :          0 :                         decexp %= 100;
    1252                 :            :                 }
    1253                 :            : 
    1254                 :          0 :                 *buf++ = (decexp / 10) + '0';
    1255                 :          0 :                 *buf++ = (decexp % 10) + '0';
    1256                 :            :         }
    1257                 :            : 
    1258                 :            :         /* Cache whether there's padding required */
    1259                 :          0 :         conv->pad_fp = (conv->pad0_value > 0)
    1260   [ #  #  #  # ]:          0 :                 || (conv->pad0_pre_exp > 0);
    1261                 :            : 
    1262                 :            :         /* Set the end of the encoded sequence, and return its start.  Also
    1263                 :            :          * store EOS as a non-digit/non-decimal value so we don't have to
    1264                 :            :          * check against bpe when iterating in multiple places.
    1265                 :            :          */
    1266                 :          0 :         *bpe = buf;
    1267                 :          0 :         *buf = 0;
    1268                 :          0 :         return bps;
    1269                 :            : }
    1270                 :            : 
    1271                 :            : /* Store a count into the pointer provided in a %n specifier.
    1272                 :            :  *
    1273                 :            :  * @param conv the specifier that indicates the size of the value into which
    1274                 :            :  * the count will be stored.
    1275                 :            :  *
    1276                 :            :  * @param dp where the count should be stored.
    1277                 :            :  *
    1278                 :            :  * @param count the count to be stored.
    1279                 :            :  */
    1280                 :          0 : static inline void store_count(const struct conversion *conv,
    1281                 :            :                                void *dp,
    1282                 :            :                                int count)
    1283                 :            : {
    1284   [ #  #  #  #  :          0 :         switch ((enum length_mod_enum)conv->length_mod) {
             #  #  #  #  
                      # ]
    1285                 :          0 :         case LENGTH_NONE:
    1286                 :          0 :                 *(int *)dp = count;
    1287                 :          0 :                 break;
    1288                 :          0 :         case LENGTH_HH:
    1289                 :          0 :                 *(signed char *)dp = (signed char)count;
    1290                 :          0 :                 break;
    1291                 :          0 :         case LENGTH_H:
    1292                 :          0 :                 *(short *)dp = (short)count;
    1293                 :          0 :                 break;
    1294                 :          0 :         case LENGTH_L:
    1295                 :          0 :                 *(long *)dp = (long)count;
    1296                 :          0 :                 break;
    1297                 :          0 :         case LENGTH_LL:
    1298                 :          0 :                 *(long long *)dp = (long long)count;
    1299                 :          0 :                 break;
    1300                 :          0 :         case LENGTH_J:
    1301                 :          0 :                 *(intmax_t *)dp = (intmax_t)count;
    1302                 :          0 :                 break;
    1303                 :          0 :         case LENGTH_Z:
    1304                 :          0 :                 *(size_t *)dp = (size_t)count;
    1305                 :          0 :                 break;
    1306                 :          0 :         case LENGTH_T:
    1307                 :          0 :                 *(ptrdiff_t *)dp = (ptrdiff_t)count;
    1308                 :          0 :                 break;
    1309                 :          0 :         default:
    1310                 :            :                 /* Add an empty default with break, this is a defensive programming.
    1311                 :            :                  * Static analysis tool won't raise a violation if default is empty,
    1312                 :            :                  * but has that comment.
    1313                 :            :                  */
    1314                 :          0 :                 break;
    1315                 :            :         }
    1316                 :          0 : }
    1317                 :            : 
    1318                 :            : /* Outline function to emit all characters in [sp, ep). */
    1319                 :     133519 : static int outs(cbprintf_cb out,
    1320                 :            :                 void *ctx,
    1321                 :            :                 const char *sp,
    1322                 :            :                 const char *ep)
    1323                 :            : {
    1324                 :     133519 :         size_t count = 0;
    1325                 :            : 
    1326   [ +  +  -  +  :     293307 :         while ((sp < ep) || ((ep == NULL) && *sp)) {
                   -  - ]
    1327                 :     159788 :                 int rc = out((int)*sp++, ctx);
    1328                 :            : 
    1329         [ -  + ]:     159788 :                 if (rc < 0) {
    1330                 :          0 :                         return rc;
    1331                 :            :                 }
    1332                 :     159788 :                 ++count;
    1333                 :            :         }
    1334                 :            : 
    1335                 :     133519 :         return (int)count;
    1336                 :            : }
    1337                 :            : 
    1338                 :     133520 : int cbvprintf(cbprintf_cb out, void *ctx, const char *fp, va_list ap)
    1339                 :            : {
    1340                 :            :         char buf[CONVERTED_BUFLEN];
    1341                 :     133520 :         size_t count = 0;
    1342                 :            :         sint_value_type sint;
    1343                 :            : 
    1344                 :            : /* Output character, returning EOF if output failed, otherwise
    1345                 :            :  * updating count.
    1346                 :            :  *
    1347                 :            :  * NB: c is evaluated exactly once: side-effects are OK
    1348                 :            :  */
    1349                 :            : #define OUTC(c) do { \
    1350                 :            :         int rc = (*out)((int)(c), ctx); \
    1351                 :            :         \
    1352                 :            :         if (rc < 0) { \
    1353                 :            :                 return rc; \
    1354                 :            :         } \
    1355                 :            :         ++count; \
    1356                 :            : } while (false)
    1357                 :            : 
    1358                 :            : /* Output sequence of characters, returning a negative error if output
    1359                 :            :  * failed.
    1360                 :            :  */
    1361                 :            : 
    1362                 :            : #define OUTS(_sp, _ep) do { \
    1363                 :            :         int rc = outs(out, ctx, _sp, _ep); \
    1364                 :            :         \
    1365                 :            :         if (rc < 0) {            \
    1366                 :            :                 return rc; \
    1367                 :            :         } \
    1368                 :            :         count += rc; \
    1369                 :            : } while (false)
    1370                 :            : 
    1371         [ +  + ]:     387404 :         while (*fp != 0) {
    1372         [ +  + ]:     253884 :                 if (*fp != '%') {
    1373         [ -  + ]:     120365 :                         OUTC(*fp++);
    1374                 :     120365 :                         continue;
    1375                 :            :                 }
    1376                 :            : 
    1377                 :            :                 /* Force union into RAM with conversion state to
    1378                 :            :                  * mitigate LLVM code generation bug.
    1379                 :            :                  */
    1380                 :            :                 struct {
    1381                 :            :                         union argument_value value;
    1382                 :            :                         struct conversion conv;
    1383                 :     133519 :                 } state = {
    1384                 :            :                         .value = {
    1385                 :            :                                 .uint = 0,
    1386                 :            :                         },
    1387                 :            :                 };
    1388                 :     133519 :                 struct conversion *const conv = &state.conv;
    1389                 :     133519 :                 union argument_value *const value = &state.value;
    1390                 :     133519 :                 const char *sp = fp;
    1391                 :     133519 :                 int width = -1;
    1392                 :     133519 :                 int precision = -1;
    1393                 :     133519 :                 const char *bps = NULL;
    1394                 :     133519 :                 const char *bpe = buf + sizeof(buf);
    1395                 :     133519 :                 char sign = 0;
    1396                 :            : 
    1397                 :     133519 :                 fp = extract_conversion(conv, sp);
    1398                 :            : 
    1399                 :            :                 /* If dynamic width is specified, process it,
    1400                 :            :                  * otherwise set width if present.
    1401                 :            :                  */
    1402         [ -  + ]:     133519 :                 if (conv->width_star) {
    1403                 :          0 :                         width = va_arg(ap, int);
    1404                 :            : 
    1405         [ #  # ]:          0 :                         if (width < 0) {
    1406                 :          0 :                                 conv->flag_dash = true;
    1407                 :          0 :                                 width = -width;
    1408                 :            :                         }
    1409         [ +  - ]:     133519 :                 } else if (conv->width_present) {
    1410                 :     133519 :                         width = conv->width_value;
    1411                 :            :                 } else {
    1412                 :            :                         ;
    1413                 :            :                 }
    1414                 :            : 
    1415                 :            :                 /* If dynamic precision is specified, process it, otherwise
    1416                 :            :                  * set precision if present.  For floating point where
    1417                 :            :                  * precision is not present use 6.
    1418                 :            :                  */
    1419         [ -  + ]:     133519 :                 if (conv->prec_star) {
    1420                 :          0 :                         int arg = va_arg(ap, int);
    1421                 :            : 
    1422         [ #  # ]:          0 :                         if (arg < 0) {
    1423                 :          0 :                                 conv->prec_present = false;
    1424                 :            :                         } else {
    1425                 :          0 :                                 precision = arg;
    1426                 :            :                         }
    1427         [ -  + ]:     133519 :                 } else if (conv->prec_present) {
    1428                 :          0 :                         precision = conv->prec_value;
    1429                 :            :                 } else {
    1430                 :            :                         ;
    1431                 :            :                 }
    1432                 :            : 
    1433                 :            :                 /* Reuse width and precision memory in conv for value
    1434                 :            :                  * padding counts.
    1435                 :            :                  */
    1436                 :     133519 :                 conv->pad0_value = 0;
    1437                 :     133519 :                 conv->pad0_pre_exp = 0;
    1438                 :            : 
    1439                 :            :                 /* FP conversion requires knowing the precision. */
    1440                 :            :                 if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)
    1441                 :            :                     && (conv->specifier_cat == SPECIFIER_FP)
    1442                 :            :                     && !conv->prec_present) {
    1443                 :            :                         if (conv->specifier_a) {
    1444                 :            :                                 precision = FRACTION_HEX;
    1445                 :            :                         } else {
    1446                 :            :                                 precision = 6;
    1447                 :            :                         }
    1448                 :            :                 }
    1449                 :            : 
    1450                 :            :                 /* Get the value to be converted from the args.
    1451                 :            :                  *
    1452                 :            :                  * This can't be extracted to a helper function because
    1453                 :            :                  * passing a pointer to va_list doesn't work on x86_64.  See
    1454                 :            :                  * https://stackoverflow.com/a/8048892.
    1455                 :            :                  */
    1456                 :     133519 :                 enum specifier_cat_enum specifier_cat
    1457                 :     133519 :                         = (enum specifier_cat_enum)conv->specifier_cat;
    1458                 :     133519 :                 enum length_mod_enum length_mod
    1459                 :     133519 :                         = (enum length_mod_enum)conv->length_mod;
    1460                 :            : 
    1461                 :            :                 /* Extract the value based on the argument category and length.
    1462                 :            :                  *
    1463                 :            :                  * Note that the length modifier doesn't affect the value of a
    1464                 :            :                  * pointer argument.
    1465                 :            :                  */
    1466         [ +  + ]:     133519 :                 if (specifier_cat == SPECIFIER_SINT) {
    1467   [ +  -  -  -  :          1 :                         switch (length_mod) {
                      - ]
    1468                 :          1 :                         default:
    1469                 :            :                         case LENGTH_NONE:
    1470                 :            :                         case LENGTH_HH:
    1471                 :            :                         case LENGTH_H:
    1472                 :          1 :                                 value->sint = va_arg(ap, int);
    1473                 :          1 :                                 break;
    1474                 :          0 :                         case LENGTH_L:
    1475                 :            :                                 if (WCHAR_IS_SIGNED
    1476                 :            :                                     && (conv->specifier == 'c')) {
    1477                 :            :                                         value->sint = (wchar_t)va_arg(ap,
    1478                 :            :                                                               WINT_TYPE);
    1479                 :            :                                 } else {
    1480                 :          0 :                                         value->sint = va_arg(ap, long);
    1481                 :            :                                 }
    1482                 :          0 :                                 break;
    1483                 :          0 :                         case LENGTH_LL:
    1484                 :          0 :                                 value->sint =
    1485                 :          0 :                                         (sint_value_type)va_arg(ap, long long);
    1486                 :          0 :                                 break;
    1487                 :          0 :                         case LENGTH_J:
    1488                 :          0 :                                 value->sint =
    1489                 :          0 :                                         (sint_value_type)va_arg(ap, intmax_t);
    1490                 :          0 :                                 break;
    1491                 :          0 :                         case LENGTH_Z:          /* size_t */
    1492                 :            :                         case LENGTH_T:          /* ptrdiff_t */
    1493                 :            :                                 /* Though ssize_t is the signed equivalent of
    1494                 :            :                                  * size_t for POSIX, there is no uptrdiff_t.
    1495                 :            :                                  * Assume that size_t and ptrdiff_t are the
    1496                 :            :                                  * unsigned and signed equivalents of each
    1497                 :            :                                  * other.  This can be checked in a platform
    1498                 :            :                                  * test.
    1499                 :            :                                  */
    1500                 :          0 :                                 value->sint =
    1501                 :          0 :                                         (sint_value_type)va_arg(ap, ptrdiff_t);
    1502                 :          0 :                                 break;
    1503                 :            :                         }
    1504         [ -  + ]:          1 :                         if (length_mod == LENGTH_HH) {
    1505                 :          0 :                                 value->sint = (char)value->sint;
    1506         [ -  + ]:          1 :                         } else if (length_mod == LENGTH_H) {
    1507                 :          0 :                                 value->sint = (short)value->sint;
    1508                 :            :                         }
    1509         [ +  + ]:     133518 :                 } else if (specifier_cat == SPECIFIER_UINT) {
    1510   [ +  -  -  -  :     133510 :                         switch (length_mod) {
                      - ]
    1511                 :     133510 :                         default:
    1512                 :            :                         case LENGTH_NONE:
    1513                 :            :                         case LENGTH_HH:
    1514                 :            :                         case LENGTH_H:
    1515                 :     133510 :                                 value->uint = va_arg(ap, unsigned int);
    1516                 :     133510 :                                 break;
    1517                 :          0 :                         case LENGTH_L:
    1518                 :          0 :                                 if ((!WCHAR_IS_SIGNED)
    1519         [ #  # ]:          0 :                                     && (conv->specifier == 'c')) {
    1520                 :          0 :                                         value->uint = (wchar_t)va_arg(ap,
    1521                 :            :                                                               WINT_TYPE);
    1522                 :            :                                 } else {
    1523                 :          0 :                                         value->uint = va_arg(ap, unsigned long);
    1524                 :            :                                 }
    1525                 :          0 :                                 break;
    1526                 :          0 :                         case LENGTH_LL:
    1527                 :          0 :                                 value->uint =
    1528                 :          0 :                                         (uint_value_type)va_arg(ap,
    1529                 :            :                                                 unsigned long long);
    1530                 :          0 :                                 break;
    1531                 :          0 :                         case LENGTH_J:
    1532                 :          0 :                                 value->uint =
    1533                 :          0 :                                         (uint_value_type)va_arg(ap,
    1534                 :            :                                                                 uintmax_t);
    1535                 :          0 :                                 break;
    1536                 :          0 :                         case LENGTH_Z:          /* size_t */
    1537                 :            :                         case LENGTH_T:          /* ptrdiff_t */
    1538                 :          0 :                                 value->uint =
    1539                 :          0 :                                         (uint_value_type)va_arg(ap, size_t);
    1540                 :          0 :                                 break;
    1541                 :            :                         }
    1542         [ -  + ]:     133510 :                         if (length_mod == LENGTH_HH) {
    1543                 :          0 :                                 value->uint = (unsigned char)value->uint;
    1544         [ -  + ]:     133510 :                         } else if (length_mod == LENGTH_H) {
    1545                 :          0 :                                 value->uint = (unsigned short)value->uint;
    1546                 :            :                         }
    1547         [ -  + ]:          8 :                 } else if (specifier_cat == SPECIFIER_FP) {
    1548         [ #  # ]:          0 :                         if (length_mod == LENGTH_UPPER_L) {
    1549                 :          0 :                                 value->ldbl = va_arg(ap, long double);
    1550                 :            :                         } else {
    1551                 :          0 :                                 value->dbl = va_arg(ap, double);
    1552                 :            :                         }
    1553         [ +  - ]:          8 :                 } else if (specifier_cat == SPECIFIER_PTR) {
    1554                 :          8 :                         value->ptr = va_arg(ap, void *);
    1555                 :            :                 }
    1556                 :            : 
    1557                 :            :                 /* We've now consumed all arguments related to this
    1558                 :            :                  * specification.  If the conversion is invalid, or is
    1559                 :            :                  * something we don't support, then output the original
    1560                 :            :                  * specification and move on.
    1561                 :            :                  */
    1562   [ +  -  -  + ]:     133519 :                 if (conv->invalid || conv->unsupported) {
    1563         [ #  # ]:          0 :                         OUTS(sp, fp);
    1564                 :          0 :                         continue;
    1565                 :            :                 }
    1566                 :            : 
    1567                 :            :                 /* Do formatting, either into the buffer or
    1568                 :            :                  * referencing external data.
    1569                 :            :                  */
    1570   [ -  +  +  +  :     133519 :                 switch (conv->specifier) {
             +  -  -  -  
                      - ]
    1571                 :          0 :                 case '%':
    1572         [ #  # ]:          0 :                         OUTC('%');
    1573                 :          0 :                         break;
    1574                 :          8 :                 case 's': {
    1575                 :          8 :                         bps = (const char *)value->ptr;
    1576                 :            : 
    1577                 :            :                         size_t len;
    1578                 :            : 
    1579         [ -  + ]:          8 :                         if (precision >= 0) {
    1580                 :          0 :                                 len = strnlen(bps, precision);
    1581                 :            :                         } else {
    1582                 :          8 :                                 len = strlen(bps);
    1583                 :            :                         }
    1584                 :            : 
    1585                 :          8 :                         bpe = bps + len;
    1586                 :          8 :                         precision = -1;
    1587                 :            : 
    1588                 :          8 :                         break;
    1589                 :            :                 }
    1590                 :      13624 :                 case 'c':
    1591                 :      13624 :                         bps = buf;
    1592                 :      13624 :                         buf[0] = CHAR_IS_SIGNED ? value->sint : value->uint;
    1593                 :      13624 :                         bpe = buf + 1;
    1594                 :      13624 :                         break;
    1595                 :          1 :                 case 'd':
    1596                 :            :                 case 'i':
    1597         [ -  + ]:          1 :                         if (conv->flag_plus) {
    1598                 :          0 :                                 sign = '+';
    1599         [ -  + ]:          1 :                         } else if (conv->flag_space) {
    1600                 :          0 :                                 sign = ' ';
    1601                 :            :                         }
    1602                 :            : 
    1603                 :            :                         /* sint/uint overlay in the union, and so
    1604                 :            :                          * can't appear in read and write operations
    1605                 :            :                          * in the same statement.
    1606                 :            :                          */
    1607                 :          1 :                         sint = value->sint;
    1608         [ -  + ]:          1 :                         if (sint < 0) {
    1609                 :          0 :                                 sign = '-';
    1610                 :          0 :                                 value->uint = (uint_value_type)-sint;
    1611                 :            :                         } else {
    1612                 :          1 :                                 value->uint = (uint_value_type)sint;
    1613                 :            :                         }
    1614                 :            : 
    1615                 :            :                         __fallthrough;
    1616                 :            :                 case 'o':
    1617                 :            :                 case 'u':
    1618                 :            :                 case 'x':
    1619                 :            :                 case 'X':
    1620                 :     119887 :                         bps = encode_uint(value->uint, conv, buf, bpe);
    1621                 :            : 
    1622                 :     119887 :                 prec_int_pad0:
    1623                 :            :                         /* Update pad0 values based on precision and converted
    1624                 :            :                          * length.  Note that a non-empty sign is not in the
    1625                 :            :                          * converted sequence, but it does not affect the
    1626                 :            :                          * padding size.
    1627                 :            :                          */
    1628         [ -  + ]:     119887 :                         if (precision >= 0) {
    1629                 :          0 :                                 size_t len = bpe - bps;
    1630                 :            : 
    1631                 :            :                                 /* Zero-padding flag is ignored for integer
    1632                 :            :                                  * conversions with precision.
    1633                 :            :                                  */
    1634                 :          0 :                                 conv->flag_zero = false;
    1635                 :            : 
    1636                 :            :                                 /* Set pad0_value to satisfy precision */
    1637         [ #  # ]:          0 :                                 if (len < (size_t)precision) {
    1638                 :          0 :                                         conv->pad0_value = precision - (int)len;
    1639                 :            :                                 }
    1640                 :            :                         }
    1641                 :            : 
    1642                 :     119887 :                         break;
    1643                 :          0 :                 case 'p':
    1644                 :            :                         /* Implementation-defined: null is "(nil)", non-null
    1645                 :            :                          * has 0x prefix followed by significant address hex
    1646                 :            :                          * digits, no leading zeros.
    1647                 :            :                          */
    1648         [ #  # ]:          0 :                         if (value->ptr != NULL) {
    1649                 :          0 :                                 bps = encode_uint((uintptr_t)value->ptr, conv,
    1650                 :            :                                                   buf, bpe);
    1651                 :            : 
    1652                 :            :                                 /* Use 0x prefix */
    1653                 :          0 :                                 conv->altform_0c = true;
    1654                 :          0 :                                 conv->specifier = 'x';
    1655                 :            : 
    1656                 :          0 :                                 goto prec_int_pad0;
    1657                 :            :                         }
    1658                 :            : 
    1659                 :          0 :                         bps = "(nil)";
    1660                 :          0 :                         bpe = bps + 5;
    1661                 :            : 
    1662                 :          0 :                         break;
    1663                 :          0 :                 case 'n':
    1664                 :            :                         if (IS_ENABLED(CONFIG_CBPRINTF_N_SPECIFIER)) {
    1665                 :          0 :                                 store_count(conv, value->ptr, count);
    1666                 :            :                         }
    1667                 :            : 
    1668                 :          0 :                         break;
    1669                 :            : 
    1670                 :          0 :                 case FP_CONV_CASES:
    1671                 :            :                         if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
    1672                 :            :                                 bps = encode_float(value->dbl, conv, precision,
    1673                 :            :                                                    &sign, buf, &bpe);
    1674                 :            :                         }
    1675                 :          0 :                         break;
    1676                 :          0 :                 default:
    1677                 :            :                         /* Add an empty default with break, this is a defensive
    1678                 :            :                          * programming. Static analysis tool won't raise a violation
    1679                 :            :                          * if default is empty, but has that comment.
    1680                 :            :                          */
    1681                 :          0 :                         break;
    1682                 :            :                 }
    1683                 :            : 
    1684                 :            :                 /* If we don't have a converted value to emit, move
    1685                 :            :                  * on.
    1686                 :            :                  */
    1687         [ -  + ]:     133519 :                 if (bps == NULL) {
    1688                 :          0 :                         continue;
    1689                 :            :                 }
    1690                 :            : 
    1691                 :            :                 /* The converted value is now stored in [bps, bpe), excluding
    1692                 :            :                  * any required zero padding.
    1693                 :            :                  *
    1694                 :            :                  * The unjustified output will be:
    1695                 :            :                  *
    1696                 :            :                  * * any sign character (sint-only)
    1697                 :            :                  * * any altform prefix
    1698                 :            :                  * * for FP:
    1699                 :            :                  *   * any pre-decimal content from the converted value
    1700                 :            :                  *   * any pad0_value padding (!postdp)
    1701                 :            :                  *   * any decimal point in the converted value
    1702                 :            :                  *   * any pad0_value padding (postdp)
    1703                 :            :                  *   * any pre-exponent content from the converted value
    1704                 :            :                  *   * any pad0_pre_exp padding
    1705                 :            :                  *   * any exponent content from the converted value
    1706                 :            :                  * * for non-FP:
    1707                 :            :                  *   * any pad0_prefix
    1708                 :            :                  *   * the converted value
    1709                 :            :                  */
    1710                 :     133519 :                 size_t nj_len = (bpe - bps);
    1711                 :     133519 :                 int pad_len = 0;
    1712                 :            : 
    1713         [ -  + ]:     133519 :                 if (sign != 0) {
    1714                 :          0 :                         nj_len += 1U;
    1715                 :            :                 }
    1716                 :            : 
    1717         [ -  + ]:     133519 :                 if (conv->altform_0c) {
    1718                 :          0 :                         nj_len += 2U;
    1719         [ -  + ]:     133519 :                 } else if (conv->altform_0) {
    1720                 :          0 :                         nj_len += 1U;
    1721                 :            :                 }
    1722                 :            : 
    1723                 :     133519 :                 nj_len += conv->pad0_value;
    1724         [ -  + ]:     133519 :                 if (conv->pad_fp) {
    1725                 :          0 :                         nj_len += conv->pad0_pre_exp;
    1726                 :            :                 }
    1727                 :            : 
    1728                 :            :                 /* If we have a width update width to hold the padding we need
    1729                 :            :                  * for justification.  The result may be negative, which will
    1730                 :            :                  * result in no padding.
    1731                 :            :                  *
    1732                 :            :                  * If a non-negative padding width is present and we're doing
    1733                 :            :                  * right-justification, emit the padding now.
    1734                 :            :                  */
    1735         [ +  + ]:     133519 :                 if (width > 0) {
    1736                 :     119884 :                         width -= (int)nj_len;
    1737                 :            : 
    1738         [ +  - ]:     119884 :                         if (!conv->flag_dash) {
    1739                 :     119884 :                                 char pad = ' ';
    1740                 :            : 
    1741                 :            :                                 /* If we're zero-padding we have to emit the
    1742                 :            :                                  * sign first.
    1743                 :            :                                  */
    1744         [ +  - ]:     119884 :                                 if (conv->flag_zero) {
    1745         [ -  + ]:     119884 :                                         if (sign != 0) {
    1746         [ #  # ]:          0 :                                                 OUTC(sign);
    1747                 :          0 :                                                 sign = 0;
    1748                 :            :                                         }
    1749                 :     119884 :                                         pad = '0';
    1750                 :            :                                 }
    1751                 :            : 
    1752         [ +  + ]:     213547 :                                 while (width-- > 0) {
    1753         [ -  + ]:      93663 :                                         OUTC(pad);
    1754                 :            :                                 }
    1755                 :            :                         }
    1756                 :            :                 }
    1757                 :            : 
    1758                 :            :                 /* If we have a sign that hasn't been emitted, now's the
    1759                 :            :                  * time....
    1760                 :            :                  */
    1761         [ -  + ]:     133519 :                 if (sign != 0) {
    1762         [ #  # ]:          0 :                         OUTC(sign);
    1763                 :            :                 }
    1764                 :            : 
    1765                 :            :                 if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT) && conv->pad_fp) {
    1766                 :            :                         const char *cp = bps;
    1767                 :            : 
    1768                 :            :                         if (conv->specifier_a) {
    1769                 :            :                                 /* Only padding is pre_exp */
    1770                 :            :                                 while (*cp != 'p') {
    1771                 :            :                                         OUTC(*cp++);
    1772                 :            :                                 }
    1773                 :            :                         } else {
    1774                 :            :                                 while (isdigit((int)*cp)) {
    1775                 :            :                                         OUTC(*cp++);
    1776                 :            :                                 }
    1777                 :            : 
    1778                 :            :                                 pad_len = conv->pad0_value;
    1779                 :            :                                 if (!conv->pad_postdp) {
    1780                 :            :                                         while (pad_len-- > 0) {
    1781                 :            :                                                 OUTC('0');
    1782                 :            :                                         }
    1783                 :            :                                 }
    1784                 :            : 
    1785                 :            :                                 if (*cp == '.') {
    1786                 :            :                                         OUTC(*cp++);
    1787                 :            :                                         /* Remaining padding is
    1788                 :            :                                          * post-dp.
    1789                 :            :                                          */
    1790                 :            :                                         while (pad_len-- > 0) {
    1791                 :            :                                                 OUTC('0');
    1792                 :            :                                         }
    1793                 :            :                                 }
    1794                 :            :                                 while (isdigit((int)*cp)) {
    1795                 :            :                                         OUTC(*cp++);
    1796                 :            :                                 }
    1797                 :            :                         }
    1798                 :            : 
    1799                 :            :                         pad_len = conv->pad0_pre_exp;
    1800                 :            :                         while (pad_len-- > 0) {
    1801                 :            :                                 OUTC('0');
    1802                 :            :                         }
    1803                 :            : 
    1804                 :            :                         OUTS(cp, bpe);
    1805                 :            :                 } else {
    1806         [ -  + ]:     133519 :                         if (conv->altform_0c | conv->altform_0) {
    1807         [ #  # ]:          0 :                                 OUTC('0');
    1808                 :            :                         }
    1809                 :            : 
    1810         [ -  + ]:     133519 :                         if (conv->altform_0c) {
    1811         [ #  # ]:          0 :                                 OUTC(conv->specifier);
    1812                 :            :                         }
    1813                 :            : 
    1814                 :     133519 :                         pad_len = conv->pad0_value;
    1815         [ -  + ]:     133519 :                         while (pad_len-- > 0) {
    1816         [ #  # ]:          0 :                                 OUTC('0');
    1817                 :            :                         }
    1818                 :            : 
    1819         [ -  + ]:     133519 :                         OUTS(bps, bpe);
    1820                 :            :                 }
    1821                 :            : 
    1822                 :            :                 /* Finish left justification */
    1823         [ -  + ]:     133519 :                 while (width > 0) {
    1824         [ #  # ]:          0 :                         OUTC(' ');
    1825                 :          0 :                         --width;
    1826                 :            :                 }
    1827                 :            :         }
    1828                 :            : 
    1829                 :     133520 :         return count;
    1830                 :            : #undef OUTS
    1831                 :            : #undef OUTC
    1832                 :            : }

Generated by: LCOV version 1.14