Reactos
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}