LCOV - code coverage report
Current view: top level - /home/runner/zephyrproject/zephyr/lib/os - cbprintf_complete.c (source / functions) Coverage Total Hit
Test: lcov.info Lines: 51.7 % 383 198
Test Date: 2026-01-29 09:48:10 Functions: 91.7 % 12 11
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 41.5 % 205 85

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

Generated by: LCOV version 2.0-1