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

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

Generated by: LCOV version 1.14