1 //
2 // POSIX spec:
3 // http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
4 //
5 #include "absl/strings/internal/str_format/arg.h"
6
7 #include <cassert>
8 #include <cerrno>
9 #include <cstdlib>
10 #include <string>
11 #include <type_traits>
12
13 #include "absl/base/port.h"
14 #include "absl/strings/internal/str_format/float_conversion.h"
15
16 namespace absl {
17 ABSL_NAMESPACE_BEGIN
18 namespace str_format_internal {
19 namespace {
20
21 const char kDigit[2][32] = { "0123456789abcdef", "0123456789ABCDEF" };
22
23 // Reduce *capacity by s.size(), clipped to a 0 minimum.
ReducePadding(string_view s,size_t * capacity)24 void ReducePadding(string_view s, size_t *capacity) {
25 *capacity = Excess(s.size(), *capacity);
26 }
27
28 // Reduce *capacity by n, clipped to a 0 minimum.
ReducePadding(size_t n,size_t * capacity)29 void ReducePadding(size_t n, size_t *capacity) {
30 *capacity = Excess(n, *capacity);
31 }
32
33 template <typename T>
34 struct MakeUnsigned : std::make_unsigned<T> {};
35 template <>
36 struct MakeUnsigned<absl::int128> {
37 using type = absl::uint128;
38 };
39 template <>
40 struct MakeUnsigned<absl::uint128> {
41 using type = absl::uint128;
42 };
43
44 template <typename T>
45 struct IsSigned : std::is_signed<T> {};
46 template <>
47 struct IsSigned<absl::int128> : std::true_type {};
48 template <>
49 struct IsSigned<absl::uint128> : std::false_type {};
50
51 class ConvertedIntInfo {
52 public:
53 template <typename T>
ConvertedIntInfo(T v,ConversionChar conv)54 ConvertedIntInfo(T v, ConversionChar conv) {
55 using Unsigned = typename MakeUnsigned<T>::type;
56 auto u = static_cast<Unsigned>(v);
57 if (IsNeg(v)) {
58 is_neg_ = true;
59 u = Unsigned{} - u;
60 } else {
61 is_neg_ = false;
62 }
63 UnsignedToStringRight(u, conv);
64 }
65
digits() const66 string_view digits() const {
67 return {end() - size_, static_cast<size_t>(size_)};
68 }
is_neg() const69 bool is_neg() const { return is_neg_; }
70
71 private:
72 template <typename T, bool IsSigned>
73 struct IsNegImpl {
Evalabsl::str_format_internal::__anon02784f5b0111::ConvertedIntInfo::IsNegImpl74 static bool Eval(T v) { return v < 0; }
75 };
76 template <typename T>
77 struct IsNegImpl<T, false> {
Evalabsl::str_format_internal::__anon02784f5b0111::ConvertedIntInfo::IsNegImpl78 static bool Eval(T) {
79 return false;
80 }
81 };
82
83 template <typename T>
IsNeg(T v)84 bool IsNeg(T v) {
85 return IsNegImpl<T, IsSigned<T>::value>::Eval(v);
86 }
87
88 template <typename T>
UnsignedToStringRight(T u,ConversionChar conv)89 void UnsignedToStringRight(T u, ConversionChar conv) {
90 char *p = end();
91 switch (FormatConversionCharRadix(conv)) {
92 default:
93 case 10:
94 for (; u; u /= 10)
95 *--p = static_cast<char>('0' + static_cast<size_t>(u % 10));
96 break;
97 case 8:
98 for (; u; u /= 8)
99 *--p = static_cast<char>('0' + static_cast<size_t>(u % 8));
100 break;
101 case 16: {
102 const char *digits = kDigit[FormatConversionCharIsUpper(conv) ? 1 : 0];
103 for (; u; u /= 16) *--p = digits[static_cast<size_t>(u % 16)];
104 break;
105 }
106 }
107 size_ = static_cast<int>(end() - p);
108 }
109
end() const110 const char *end() const { return storage_ + sizeof(storage_); }
end()111 char *end() { return storage_ + sizeof(storage_); }
112
113 bool is_neg_;
114 int size_;
115 // Max size: 128 bit value as octal -> 43 digits
116 char storage_[128 / 3 + 1];
117 };
118
119 // Note: 'o' conversions do not have a base indicator, it's just that
120 // the '#' flag is specified to modify the precision for 'o' conversions.
BaseIndicator(const ConvertedIntInfo & info,const ConversionSpec conv)121 string_view BaseIndicator(const ConvertedIntInfo &info,
122 const ConversionSpec conv) {
123 bool alt = conv.flags().alt;
124 int radix = FormatConversionCharRadix(conv.conv());
125 if (conv.conv() == ConversionChar::p) alt = true; // always show 0x for %p.
126 // From the POSIX description of '#' flag:
127 // "For x or X conversion specifiers, a non-zero result shall have
128 // 0x (or 0X) prefixed to it."
129 if (alt && radix == 16 && !info.digits().empty()) {
130 if (FormatConversionCharIsUpper(conv.conv())) return "0X";
131 return "0x";
132 }
133 return {};
134 }
135
SignColumn(bool neg,const ConversionSpec conv)136 string_view SignColumn(bool neg, const ConversionSpec conv) {
137 if (FormatConversionCharIsSigned(conv.conv())) {
138 if (neg) return "-";
139 if (conv.flags().show_pos) return "+";
140 if (conv.flags().sign_col) return " ";
141 }
142 return {};
143 }
144
ConvertCharImpl(unsigned char v,const ConversionSpec conv,FormatSinkImpl * sink)145 bool ConvertCharImpl(unsigned char v, const ConversionSpec conv,
146 FormatSinkImpl *sink) {
147 size_t fill = 0;
148 if (conv.width() >= 0) fill = conv.width();
149 ReducePadding(1, &fill);
150 if (!conv.flags().left) sink->Append(fill, ' ');
151 sink->Append(1, v);
152 if (conv.flags().left) sink->Append(fill, ' ');
153 return true;
154 }
155
ConvertIntImplInner(const ConvertedIntInfo & info,const ConversionSpec conv,FormatSinkImpl * sink)156 bool ConvertIntImplInner(const ConvertedIntInfo &info,
157 const ConversionSpec conv, FormatSinkImpl *sink) {
158 // Print as a sequence of Substrings:
159 // [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
160 size_t fill = 0;
161 if (conv.width() >= 0) fill = conv.width();
162
163 string_view formatted = info.digits();
164 ReducePadding(formatted, &fill);
165
166 string_view sign = SignColumn(info.is_neg(), conv);
167 ReducePadding(sign, &fill);
168
169 string_view base_indicator = BaseIndicator(info, conv);
170 ReducePadding(base_indicator, &fill);
171
172 int precision = conv.precision();
173 bool precision_specified = precision >= 0;
174 if (!precision_specified)
175 precision = 1;
176
177 if (conv.flags().alt && conv.conv() == ConversionChar::o) {
178 // From POSIX description of the '#' (alt) flag:
179 // "For o conversion, it increases the precision (if necessary) to
180 // force the first digit of the result to be zero."
181 if (formatted.empty() || *formatted.begin() != '0') {
182 int needed = static_cast<int>(formatted.size()) + 1;
183 precision = std::max(precision, needed);
184 }
185 }
186
187 size_t num_zeroes = Excess(formatted.size(), precision);
188 ReducePadding(num_zeroes, &fill);
189
190 size_t num_left_spaces = !conv.flags().left ? fill : 0;
191 size_t num_right_spaces = conv.flags().left ? fill : 0;
192
193 // From POSIX description of the '0' (zero) flag:
194 // "For d, i, o, u, x, and X conversion specifiers, if a precision
195 // is specified, the '0' flag is ignored."
196 if (!precision_specified && conv.flags().zero) {
197 num_zeroes += num_left_spaces;
198 num_left_spaces = 0;
199 }
200
201 sink->Append(num_left_spaces, ' ');
202 sink->Append(sign);
203 sink->Append(base_indicator);
204 sink->Append(num_zeroes, '0');
205 sink->Append(formatted);
206 sink->Append(num_right_spaces, ' ');
207 return true;
208 }
209
210 template <typename T>
ConvertIntImplInner(T v,const ConversionSpec conv,FormatSinkImpl * sink)211 bool ConvertIntImplInner(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
212 ConvertedIntInfo info(v, conv.conv());
213 if (conv.flags().basic && (conv.conv() != ConversionChar::p)) {
214 if (info.is_neg()) sink->Append(1, '-');
215 if (info.digits().empty()) {
216 sink->Append(1, '0');
217 } else {
218 sink->Append(info.digits());
219 }
220 return true;
221 }
222 return ConvertIntImplInner(info, conv, sink);
223 }
224
225 template <typename T>
ConvertIntArg(T v,const ConversionSpec conv,FormatSinkImpl * sink)226 bool ConvertIntArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
227 if (FormatConversionCharIsFloat(conv.conv())) {
228 return FormatConvertImpl(static_cast<double>(v), conv, sink).value;
229 }
230 if (conv.conv() == ConversionChar::c)
231 return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
232 if (!FormatConversionCharIsIntegral(conv.conv())) return false;
233 if (!FormatConversionCharIsSigned(conv.conv()) && IsSigned<T>::value) {
234 using U = typename MakeUnsigned<T>::type;
235 return FormatConvertImpl(static_cast<U>(v), conv, sink).value;
236 }
237 return ConvertIntImplInner(v, conv, sink);
238 }
239
240 template <typename T>
ConvertFloatArg(T v,const ConversionSpec conv,FormatSinkImpl * sink)241 bool ConvertFloatArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
242 return FormatConversionCharIsFloat(conv.conv()) &&
243 ConvertFloatImpl(v, conv, sink);
244 }
245
ConvertStringArg(string_view v,const ConversionSpec conv,FormatSinkImpl * sink)246 inline bool ConvertStringArg(string_view v, const ConversionSpec conv,
247 FormatSinkImpl *sink) {
248 if (conv.conv() != ConversionChar::s) return false;
249 if (conv.flags().basic) {
250 sink->Append(v);
251 return true;
252 }
253 return sink->PutPaddedString(v, conv.width(), conv.precision(),
254 conv.flags().left);
255 }
256
257 } // namespace
258
259 // ==================== Strings ====================
FormatConvertImpl(const std::string & v,const ConversionSpec conv,FormatSinkImpl * sink)260 ConvertResult<Conv::s> FormatConvertImpl(const std::string &v,
261 const ConversionSpec conv,
262 FormatSinkImpl *sink) {
263 return {ConvertStringArg(v, conv, sink)};
264 }
265
FormatConvertImpl(string_view v,const ConversionSpec conv,FormatSinkImpl * sink)266 ConvertResult<Conv::s> FormatConvertImpl(string_view v,
267 const ConversionSpec conv,
268 FormatSinkImpl *sink) {
269 return {ConvertStringArg(v, conv, sink)};
270 }
271
FormatConvertImpl(const char * v,const ConversionSpec conv,FormatSinkImpl * sink)272 ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char *v,
273 const ConversionSpec conv,
274 FormatSinkImpl *sink) {
275 if (conv.conv() == ConversionChar::p)
276 return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
277 size_t len;
278 if (v == nullptr) {
279 len = 0;
280 } else if (conv.precision() < 0) {
281 len = std::strlen(v);
282 } else {
283 // If precision is set, we look for the NUL-terminator on the valid range.
284 len = std::find(v, v + conv.precision(), '\0') - v;
285 }
286 return {ConvertStringArg(string_view(v, len), conv, sink)};
287 }
288
289 // ==================== Raw pointers ====================
FormatConvertImpl(VoidPtr v,const ConversionSpec conv,FormatSinkImpl * sink)290 ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec conv,
291 FormatSinkImpl *sink) {
292 if (conv.conv() != ConversionChar::p) return {false};
293 if (!v.value) {
294 sink->Append("(nil)");
295 return {true};
296 }
297 return {ConvertIntImplInner(v.value, conv, sink)};
298 }
299
300 // ==================== Floats ====================
FormatConvertImpl(float v,const ConversionSpec conv,FormatSinkImpl * sink)301 FloatingConvertResult FormatConvertImpl(float v, const ConversionSpec conv,
302 FormatSinkImpl *sink) {
303 return {ConvertFloatArg(v, conv, sink)};
304 }
FormatConvertImpl(double v,const ConversionSpec conv,FormatSinkImpl * sink)305 FloatingConvertResult FormatConvertImpl(double v, const ConversionSpec conv,
306 FormatSinkImpl *sink) {
307 return {ConvertFloatArg(v, conv, sink)};
308 }
FormatConvertImpl(long double v,const ConversionSpec conv,FormatSinkImpl * sink)309 FloatingConvertResult FormatConvertImpl(long double v,
310 const ConversionSpec conv,
311 FormatSinkImpl *sink) {
312 return {ConvertFloatArg(v, conv, sink)};
313 }
314
315 // ==================== Chars ====================
FormatConvertImpl(char v,const ConversionSpec conv,FormatSinkImpl * sink)316 IntegralConvertResult FormatConvertImpl(char v, const ConversionSpec conv,
317 FormatSinkImpl *sink) {
318 return {ConvertIntArg(v, conv, sink)};
319 }
FormatConvertImpl(signed char v,const ConversionSpec conv,FormatSinkImpl * sink)320 IntegralConvertResult FormatConvertImpl(signed char v,
321 const ConversionSpec conv,
322 FormatSinkImpl *sink) {
323 return {ConvertIntArg(v, conv, sink)};
324 }
FormatConvertImpl(unsigned char v,const ConversionSpec conv,FormatSinkImpl * sink)325 IntegralConvertResult FormatConvertImpl(unsigned char v,
326 const ConversionSpec conv,
327 FormatSinkImpl *sink) {
328 return {ConvertIntArg(v, conv, sink)};
329 }
330
331 // ==================== Ints ====================
FormatConvertImpl(short v,const ConversionSpec conv,FormatSinkImpl * sink)332 IntegralConvertResult FormatConvertImpl(short v, // NOLINT
333 const ConversionSpec conv,
334 FormatSinkImpl *sink) {
335 return {ConvertIntArg(v, conv, sink)};
336 }
FormatConvertImpl(unsigned short v,const ConversionSpec conv,FormatSinkImpl * sink)337 IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT
338 const ConversionSpec conv,
339 FormatSinkImpl *sink) {
340 return {ConvertIntArg(v, conv, sink)};
341 }
FormatConvertImpl(int v,const ConversionSpec conv,FormatSinkImpl * sink)342 IntegralConvertResult FormatConvertImpl(int v, const ConversionSpec conv,
343 FormatSinkImpl *sink) {
344 return {ConvertIntArg(v, conv, sink)};
345 }
FormatConvertImpl(unsigned v,const ConversionSpec conv,FormatSinkImpl * sink)346 IntegralConvertResult FormatConvertImpl(unsigned v, const ConversionSpec conv,
347 FormatSinkImpl *sink) {
348 return {ConvertIntArg(v, conv, sink)};
349 }
FormatConvertImpl(long v,const ConversionSpec conv,FormatSinkImpl * sink)350 IntegralConvertResult FormatConvertImpl(long v, // NOLINT
351 const ConversionSpec conv,
352 FormatSinkImpl *sink) {
353 return {ConvertIntArg(v, conv, sink)};
354 }
FormatConvertImpl(unsigned long v,const ConversionSpec conv,FormatSinkImpl * sink)355 IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT
356 const ConversionSpec conv,
357 FormatSinkImpl *sink) {
358 return {ConvertIntArg(v, conv, sink)};
359 }
FormatConvertImpl(long long v,const ConversionSpec conv,FormatSinkImpl * sink)360 IntegralConvertResult FormatConvertImpl(long long v, // NOLINT
361 const ConversionSpec conv,
362 FormatSinkImpl *sink) {
363 return {ConvertIntArg(v, conv, sink)};
364 }
FormatConvertImpl(unsigned long long v,const ConversionSpec conv,FormatSinkImpl * sink)365 IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT
366 const ConversionSpec conv,
367 FormatSinkImpl *sink) {
368 return {ConvertIntArg(v, conv, sink)};
369 }
FormatConvertImpl(absl::int128 v,const ConversionSpec conv,FormatSinkImpl * sink)370 IntegralConvertResult FormatConvertImpl(absl::int128 v,
371 const ConversionSpec conv,
372 FormatSinkImpl *sink) {
373 return {ConvertIntArg(v, conv, sink)};
374 }
FormatConvertImpl(absl::uint128 v,const ConversionSpec conv,FormatSinkImpl * sink)375 IntegralConvertResult FormatConvertImpl(absl::uint128 v,
376 const ConversionSpec conv,
377 FormatSinkImpl *sink) {
378 return {ConvertIntArg(v, conv, sink)};
379 }
380
381 ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_();
382
383
384
385 } // namespace str_format_internal
386
387 ABSL_NAMESPACE_END
388 } // namespace absl
389