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