Reactos
at master 159 lines 4.2 kB view raw
1// 2// gcvt.cpp 3// 4// Copyright (c) Microsoft Corporation. All rights reserved. 5// 6// Defines the _gcvt functions, which convert a floating point value to a narrow 7// character string. It attempts to produce 'precision' significant digits in 8// the Fortran F format if possible, otherwise the E format. Trailing zeroes may 9// be suppressed. The _s-suffixed function returns zero on success; an error 10// code on failure. If the buffer is too small, that is an error. 11// 12#include <corecrt_internal.h> 13#include <corecrt_internal_fltintrn.h> 14#include <corecrt_internal_ptd_propagation.h> 15#include <corecrt_internal_securecrt.h> 16#include <corecrt_stdio_config.h> 17#include <locale.h> 18#include <stdlib.h> 19 20 21 22static errno_t __cdecl _gcvt_s_internal( 23 char* const buffer, 24 size_t const buffer_count, 25 double const value, 26 int const precision, 27 __crt_cached_ptd_host& ptd 28 ) 29{ 30 _UCRT_VALIDATE_RETURN_ERRCODE(ptd, buffer != nullptr, EINVAL); 31 _UCRT_VALIDATE_RETURN_ERRCODE(ptd, buffer_count > 0, EINVAL); 32 _RESET_STRING(buffer, buffer_count); 33 _UCRT_VALIDATE_RETURN_ERRCODE(ptd, static_cast<size_t>(precision) < buffer_count, ERANGE); 34 // Additional validation will be performed in the fp_format functions. 35 36 char const decimal_point = *ptd.get_locale()->locinfo->lconv->decimal_point; 37 38 // We only call __acrt_fltout in order to parse the correct exponent value (strflt.decpt). 39 // Therefore, we don't want to generate any digits, so we pass a buffer size only large 40 // enough to hold the inf, nan, or ind string to prevent failure. 41 42 size_t const restricted_count = 7; // "1#SNAN" + 1 null terminator 43 char result_string[restricted_count]; 44 45 _strflt strflt{}; 46 47 __acrt_fltout( 48 reinterpret_cast<_CRT_DOUBLE const&>(value), 49 precision, 50 __acrt_precision_style::fixed, 51 &strflt, 52 result_string, 53 restricted_count); 54 55 int const magnitude = strflt.decpt - 1; 56 57 // Output the result according to the Fortran G format as outlined in the 58 // Fortran language specification. 59 if (magnitude < -1 || magnitude > precision - 1) 60 { 61 // Ew.d where d = precision 62 char scratch_buffer[_CVTBUFSIZE + 1]; 63 errno_t const e = __acrt_fp_format( 64 &value, 65 buffer, 66 buffer_count, 67 scratch_buffer, 68 _countof(scratch_buffer), 69 'e', 70 precision - 1, 71 _CRT_INTERNAL_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS, 72 __acrt_rounding_mode::legacy, 73 ptd); 74 75 if (e != 0) 76 { 77 return ptd.get_errno().set(e); 78 } 79 } 80 else 81 { 82 // Fw.d where d = precision-string->decpt 83 char scratch_buffer[_CVTBUFSIZE + 1]; 84 errno_t const e = __acrt_fp_format( 85 &value, 86 buffer, 87 buffer_count, 88 scratch_buffer, 89 _countof(scratch_buffer), 90 'f', 91 precision - strflt.decpt, 92 _CRT_INTERNAL_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS, 93 __acrt_rounding_mode::legacy, 94 ptd); 95 96 if (e != 0) 97 { 98 return ptd.get_errno().set(e); 99 } 100 } 101 102 // Remove the trailing zeroes before the exponent; we don't need to check 103 // for buffer_count: 104 char* p = buffer; 105 while (*p && *p != decimal_point) 106 { 107 ++p; 108 } 109 110 if (*p == '\0') 111 { 112 return 0; 113 } 114 115 ++p; 116 117 while (*p && *p != 'e') 118 { 119 ++p; 120 } 121 122 char* stop = p; 123 --p; 124 125 while (*p == '0') 126 { 127 --p; 128 } 129 130 while ((*++p = *stop++) != '\0') { } 131 132 return 0; 133} 134 135extern "C" errno_t __cdecl _gcvt_s( 136 char* const buffer, 137 size_t const buffer_count, 138 double const value, 139 int const precision 140 ) 141{ 142 __crt_cached_ptd_host ptd; 143 return _gcvt_s_internal(buffer, buffer_count, value, precision, ptd); 144} 145 146extern "C" char* __cdecl _gcvt( 147 double const value, 148 int const precision, 149 char* const buffer 150 ) 151{ 152 errno_t const e = _gcvt_s(buffer, _CRT_UNBOUNDED_BUFFER_SIZE, value, precision); 153 if (e != 0) 154 { 155 return nullptr; 156 } 157 158 return buffer; 159}