(root)/
glibc-2.38/
stdlib/
strfrom-skeleton.c
       1  /* Convert a floating-point number to string.
       2     Copyright (C) 2016-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  /* Generic implementation for strfrom functions.  The implementation is generic
      20     for several floating-point types (e.g.: float, double), so that each
      21     function, such as strfromf and strfroml, share the same code, thus avoiding
      22     code duplication.  */
      23  
      24  #include <ctype.h>
      25  #include "../libio/libioP.h"
      26  #include "../libio/strfile.h"
      27  #include <printf.h>
      28  #include <string.h>
      29  #include <locale/localeinfo.h>
      30  #include <fix-float-double-convert-nan.h>
      31  #include <printf_buffer.h>
      32  
      33  #define UCHAR_T char
      34  #define L_(Str) Str
      35  #define ISDIGIT(Ch) isdigit (Ch)
      36  #include "stdio-common/printf-parse.h"
      37  
      38  int
      39  STRFROM (char *dest, size_t size, const char *format, FLOAT f)
      40  {
      41    struct __printf_buffer_snprintf buf;
      42  
      43    /* Single-precision values need to be stored in a double type, because
      44       __printf_fp_l and __printf_fphex do not accept the float type.  */
      45    union {
      46      double flt;
      47      FLOAT value;
      48    } fpnum;
      49    const void *fpptr;
      50    fpptr = &fpnum;
      51  
      52    /* Variables to control the output format.  */
      53    int precision = -1; /* printf_fp and printf_fphex treat this internally.  */
      54    int specifier;
      55    struct printf_info info;
      56  
      57    /* Single-precision values need to be converted into double-precision,
      58       because __printf_fp and __printf_fphex only accept double and long double
      59       as the floating-point argument.  */
      60    if (__builtin_types_compatible_p (FLOAT, float))
      61      fpnum.flt = keep_sign_conversion (f);
      62    else
      63      fpnum.value = f;
      64  
      65    /* Check if the first character in the format string is indeed the '%'
      66       character.  Otherwise, abort.  */
      67    if (*format == '%')
      68      format++;
      69    else
      70      abort ();
      71  
      72    /* The optional precision specification always starts with a '.'.  If such
      73       character is present, read the precision.  */
      74    if (*format == '.')
      75      {
      76        format++;
      77  
      78        /* Parse the precision.  */
      79        if (ISDIGIT (*format))
      80  	precision = read_int (&format);
      81        /* If only the period is specified, the precision is taken as zero, as
      82  	 described in ISO/IEC 9899:2011, section 7.21.6.1, 4th paragraph, 3rd
      83  	 item.  */
      84        else
      85  	precision = 0;
      86      }
      87  
      88    /* Now there is only the conversion specifier to be read.  */
      89    switch (*format)
      90      {
      91      case 'a':
      92      case 'A':
      93      case 'e':
      94      case 'E':
      95      case 'f':
      96      case 'F':
      97      case 'g':
      98      case 'G':
      99        specifier = *format;
     100        break;
     101      default:
     102        abort ();
     103      }
     104  
     105    /* Prepare the string buffer.  */
     106    __printf_buffer_snprintf_init (&buf, dest, size);
     107  
     108    /* Prepare the format specification for printf_fp.  */
     109    memset (&info, '\0', sizeof (info));
     110  
     111    /* The functions strfromd and strfromf pass a floating-point number with
     112       double precision to printf_fp, whereas strfroml passes a floating-point
     113       number with long double precision.  The following line informs printf_fp
     114       which type of floating-point number is being passed.  */
     115    info.is_long_double = __builtin_types_compatible_p (FLOAT, long double);
     116  
     117    /* Similarly, the function strfromf128 passes a floating-point number in
     118       _Float128 format to printf_fp.  */
     119  #if __HAVE_DISTINCT_FLOAT128
     120    info.is_binary128 = __builtin_types_compatible_p (FLOAT, _Float128);
     121  #endif
     122  
     123    /* Set info according to the format string.  */
     124    info.prec = precision;
     125    info.spec = specifier;
     126  
     127    if (info.spec != 'a' && info.spec != 'A')
     128      __printf_fp_l_buffer (&buf.base, _NL_CURRENT_LOCALE, &info, &fpptr);
     129    else
     130      __printf_fphex_l_buffer (&buf.base, _NL_CURRENT_LOCALE, &info, &fpptr);
     131    return __printf_buffer_snprintf_done (&buf);
     132  }