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 #include "absl/strings/numbers.h"
16
17 namespace absl {
18 ABSL_NAMESPACE_BEGIN
19 namespace str_format_internal {
20 namespace {
21
22 // Reduce *capacity by s.size(), clipped to a 0 minimum.
ReducePadding(string_view s,size_t * capacity)23 void ReducePadding(string_view s, size_t *capacity) {
24 *capacity = Excess(s.size(), *capacity);
25 }
26
27 // Reduce *capacity by n, clipped to a 0 minimum.
ReducePadding(size_t n,size_t * capacity)28 void ReducePadding(size_t n, size_t *capacity) {
29 *capacity = Excess(n, *capacity);
30 }
31
32 template <typename T>
33 struct MakeUnsigned : std::make_unsigned<T> {};
34 template <>
35 struct MakeUnsigned<absl::int128> {
36 using type = absl::uint128;
37 };
38 template <>
39 struct MakeUnsigned<absl::uint128> {
40 using type = absl::uint128;
41 };
42
43 template <typename T>
44 struct IsSigned : std::is_signed<T> {};
45 template <>
46 struct IsSigned<absl::int128> : std::true_type {};
47 template <>
48 struct IsSigned<absl::uint128> : std::false_type {};
49
50 // Integral digit printer.
51 // Call one of the PrintAs* routines after construction once.
52 // Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results.
53 class IntDigits {
54 public:
55 // Print the unsigned integer as octal.
56 // Supports unsigned integral types and uint128.
57 template <typename T>
PrintAsOct(T v)58 void PrintAsOct(T v) {
59 static_assert(!IsSigned<T>::value, "");
60 char *p = storage_ + sizeof(storage_);
61 do {
62 *--p = static_cast<char>('0' + (static_cast<size_t>(v) & 7));
63 v >>= 3;
64 } while (v);
65 start_ = p;
66 size_ = storage_ + sizeof(storage_) - p;
67 }
68
69 // Print the signed or unsigned integer as decimal.
70 // Supports all integral types.
71 template <typename T>
PrintAsDec(T v)72 void PrintAsDec(T v) {
73 static_assert(std::is_integral<T>::value, "");
74 start_ = storage_;
75 size_ = numbers_internal::FastIntToBuffer(v, storage_) - storage_;
76 }
77
PrintAsDec(int128 v)78 void PrintAsDec(int128 v) {
79 auto u = static_cast<uint128>(v);
80 bool add_neg = false;
81 if (v < 0) {
82 add_neg = true;
83 u = uint128{} - u;
84 }
85 PrintAsDec(u, add_neg);
86 }
87
PrintAsDec(uint128 v,bool add_neg=false)88 void PrintAsDec(uint128 v, bool add_neg = false) {
89 // This function can be sped up if needed. We can call FastIntToBuffer
90 // twice, or fix FastIntToBuffer to support uint128.
91 char *p = storage_ + sizeof(storage_);
92 do {
93 p -= 2;
94 numbers_internal::PutTwoDigits(static_cast<size_t>(v % 100), p);
95 v /= 100;
96 } while (v);
97 if (p[0] == '0') {
98 // We printed one too many hexits.
99 ++p;
100 }
101 if (add_neg) {
102 *--p = '-';
103 }
104 size_ = storage_ + sizeof(storage_) - p;
105 start_ = p;
106 }
107
108 // Print the unsigned integer as hex using lowercase.
109 // Supports unsigned integral types and uint128.
110 template <typename T>
PrintAsHexLower(T v)111 void PrintAsHexLower(T v) {
112 static_assert(!IsSigned<T>::value, "");
113 char *p = storage_ + sizeof(storage_);
114
115 do {
116 p -= 2;
117 constexpr const char* table = numbers_internal::kHexTable;
118 std::memcpy(p, table + 2 * (static_cast<size_t>(v) & 0xFF), 2);
119 if (sizeof(T) == 1) break;
120 v >>= 8;
121 } while (v);
122 if (p[0] == '0') {
123 // We printed one too many digits.
124 ++p;
125 }
126 start_ = p;
127 size_ = storage_ + sizeof(storage_) - p;
128 }
129
130 // Print the unsigned integer as hex using uppercase.
131 // Supports unsigned integral types and uint128.
132 template <typename T>
PrintAsHexUpper(T v)133 void PrintAsHexUpper(T v) {
134 static_assert(!IsSigned<T>::value, "");
135 char *p = storage_ + sizeof(storage_);
136
137 // kHexTable is only lowercase, so do it manually for uppercase.
138 do {
139 *--p = "0123456789ABCDEF"[static_cast<size_t>(v) & 15];
140 v >>= 4;
141 } while (v);
142 start_ = p;
143 size_ = storage_ + sizeof(storage_) - p;
144 }
145
146 // The printed value including the '-' sign if available.
147 // For inputs of value `0`, this will return "0"
with_neg_and_zero() const148 string_view with_neg_and_zero() const { return {start_, size_}; }
149
150 // The printed value not including the '-' sign.
151 // For inputs of value `0`, this will return "".
without_neg_or_zero() const152 string_view without_neg_or_zero() const {
153 static_assert('-' < '0', "The check below verifies both.");
154 size_t advance = start_[0] <= '0' ? 1 : 0;
155 return {start_ + advance, size_ - advance};
156 }
157
is_negative() const158 bool is_negative() const { return start_[0] == '-'; }
159
160 private:
161 const char *start_;
162 size_t size_;
163 // Max size: 128 bit value as octal -> 43 digits, plus sign char
164 char storage_[128 / 3 + 1 + 1];
165 };
166
167 // Note: 'o' conversions do not have a base indicator, it's just that
168 // the '#' flag is specified to modify the precision for 'o' conversions.
BaseIndicator(const IntDigits & as_digits,const FormatConversionSpecImpl conv)169 string_view BaseIndicator(const IntDigits &as_digits,
170 const FormatConversionSpecImpl conv) {
171 // always show 0x for %p.
172 bool alt = conv.has_alt_flag() ||
173 conv.conversion_char() == FormatConversionCharInternal::p;
174 bool hex = (conv.conversion_char() == FormatConversionCharInternal::x ||
175 conv.conversion_char() == FormatConversionCharInternal::X ||
176 conv.conversion_char() == FormatConversionCharInternal::p);
177 // From the POSIX description of '#' flag:
178 // "For x or X conversion specifiers, a non-zero result shall have
179 // 0x (or 0X) prefixed to it."
180 if (alt && hex && !as_digits.without_neg_or_zero().empty()) {
181 return conv.conversion_char() == FormatConversionCharInternal::X ? "0X"
182 : "0x";
183 }
184 return {};
185 }
186
SignColumn(bool neg,const FormatConversionSpecImpl conv)187 string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) {
188 if (conv.conversion_char() == FormatConversionCharInternal::d ||
189 conv.conversion_char() == FormatConversionCharInternal::i) {
190 if (neg) return "-";
191 if (conv.has_show_pos_flag()) return "+";
192 if (conv.has_sign_col_flag()) return " ";
193 }
194 return {};
195 }
196
ConvertCharImpl(unsigned char v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)197 bool ConvertCharImpl(unsigned char v, const FormatConversionSpecImpl conv,
198 FormatSinkImpl *sink) {
199 size_t fill = 0;
200 if (conv.width() >= 0) fill = conv.width();
201 ReducePadding(1, &fill);
202 if (!conv.has_left_flag()) sink->Append(fill, ' ');
203 sink->Append(1, v);
204 if (conv.has_left_flag()) sink->Append(fill, ' ');
205 return true;
206 }
207
ConvertIntImplInnerSlow(const IntDigits & as_digits,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)208 bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
209 const FormatConversionSpecImpl conv,
210 FormatSinkImpl *sink) {
211 // Print as a sequence of Substrings:
212 // [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
213 size_t fill = 0;
214 if (conv.width() >= 0) fill = conv.width();
215
216 string_view formatted = as_digits.without_neg_or_zero();
217 ReducePadding(formatted, &fill);
218
219 string_view sign = SignColumn(as_digits.is_negative(), conv);
220 ReducePadding(sign, &fill);
221
222 string_view base_indicator = BaseIndicator(as_digits, conv);
223 ReducePadding(base_indicator, &fill);
224
225 int precision = conv.precision();
226 bool precision_specified = precision >= 0;
227 if (!precision_specified)
228 precision = 1;
229
230 if (conv.has_alt_flag() &&
231 conv.conversion_char() == FormatConversionCharInternal::o) {
232 // From POSIX description of the '#' (alt) flag:
233 // "For o conversion, it increases the precision (if necessary) to
234 // force the first digit of the result to be zero."
235 if (formatted.empty() || *formatted.begin() != '0') {
236 int needed = static_cast<int>(formatted.size()) + 1;
237 precision = std::max(precision, needed);
238 }
239 }
240
241 size_t num_zeroes = Excess(formatted.size(), precision);
242 ReducePadding(num_zeroes, &fill);
243
244 size_t num_left_spaces = !conv.has_left_flag() ? fill : 0;
245 size_t num_right_spaces = conv.has_left_flag() ? fill : 0;
246
247 // From POSIX description of the '0' (zero) flag:
248 // "For d, i, o, u, x, and X conversion specifiers, if a precision
249 // is specified, the '0' flag is ignored."
250 if (!precision_specified && conv.has_zero_flag()) {
251 num_zeroes += num_left_spaces;
252 num_left_spaces = 0;
253 }
254
255 sink->Append(num_left_spaces, ' ');
256 sink->Append(sign);
257 sink->Append(base_indicator);
258 sink->Append(num_zeroes, '0');
259 sink->Append(formatted);
260 sink->Append(num_right_spaces, ' ');
261 return true;
262 }
263
264 template <typename T>
ConvertIntArg(T v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)265 bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
266 FormatSinkImpl *sink) {
267 using U = typename MakeUnsigned<T>::type;
268 IntDigits as_digits;
269
270 // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes
271 // it to complain about a switch/case type mismatch, even though both are
272 // FormatConverionChar. Likely this is because at this point
273 // FormatConversionChar is declared, but not defined.
274 switch (static_cast<uint8_t>(conv.conversion_char())) {
275 case static_cast<uint8_t>(FormatConversionCharInternal::c):
276 return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
277
278 case static_cast<uint8_t>(FormatConversionCharInternal::o):
279 as_digits.PrintAsOct(static_cast<U>(v));
280 break;
281
282 case static_cast<uint8_t>(FormatConversionCharInternal::x):
283 as_digits.PrintAsHexLower(static_cast<U>(v));
284 break;
285 case static_cast<uint8_t>(FormatConversionCharInternal::X):
286 as_digits.PrintAsHexUpper(static_cast<U>(v));
287 break;
288
289 case static_cast<uint8_t>(FormatConversionCharInternal::u):
290 as_digits.PrintAsDec(static_cast<U>(v));
291 break;
292
293 case static_cast<uint8_t>(FormatConversionCharInternal::d):
294 case static_cast<uint8_t>(FormatConversionCharInternal::i):
295 as_digits.PrintAsDec(v);
296 break;
297
298 case static_cast<uint8_t>(FormatConversionCharInternal::a):
299 case static_cast<uint8_t>(FormatConversionCharInternal::e):
300 case static_cast<uint8_t>(FormatConversionCharInternal::f):
301 case static_cast<uint8_t>(FormatConversionCharInternal::g):
302 case static_cast<uint8_t>(FormatConversionCharInternal::A):
303 case static_cast<uint8_t>(FormatConversionCharInternal::E):
304 case static_cast<uint8_t>(FormatConversionCharInternal::F):
305 case static_cast<uint8_t>(FormatConversionCharInternal::G):
306 return ConvertFloatImpl(static_cast<double>(v), conv, sink);
307
308 default:
309 ABSL_INTERNAL_ASSUME(false);
310 }
311
312 if (conv.is_basic()) {
313 sink->Append(as_digits.with_neg_and_zero());
314 return true;
315 }
316 return ConvertIntImplInnerSlow(as_digits, conv, sink);
317 }
318
319 template <typename T>
ConvertFloatArg(T v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)320 bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv,
321 FormatSinkImpl *sink) {
322 return FormatConversionCharIsFloat(conv.conversion_char()) &&
323 ConvertFloatImpl(v, conv, sink);
324 }
325
ConvertStringArg(string_view v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)326 inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv,
327 FormatSinkImpl *sink) {
328 if (conv.is_basic()) {
329 sink->Append(v);
330 return true;
331 }
332 return sink->PutPaddedString(v, conv.width(), conv.precision(),
333 conv.has_left_flag());
334 }
335
336 } // namespace
337
338 // ==================== Strings ====================
FormatConvertImpl(const std::string & v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)339 StringConvertResult FormatConvertImpl(const std::string &v,
340 const FormatConversionSpecImpl conv,
341 FormatSinkImpl *sink) {
342 return {ConvertStringArg(v, conv, sink)};
343 }
344
FormatConvertImpl(string_view v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)345 StringConvertResult FormatConvertImpl(string_view v,
346 const FormatConversionSpecImpl conv,
347 FormatSinkImpl *sink) {
348 return {ConvertStringArg(v, conv, sink)};
349 }
350
351 ArgConvertResult<FormatConversionCharSetUnion(
352 FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
FormatConvertImpl(const char * v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)353 FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv,
354 FormatSinkImpl *sink) {
355 if (conv.conversion_char() == FormatConversionCharInternal::p)
356 return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
357 size_t len;
358 if (v == nullptr) {
359 len = 0;
360 } else if (conv.precision() < 0) {
361 len = std::strlen(v);
362 } else {
363 // If precision is set, we look for the NUL-terminator on the valid range.
364 len = std::find(v, v + conv.precision(), '\0') - v;
365 }
366 return {ConvertStringArg(string_view(v, len), conv, sink)};
367 }
368
369 // ==================== Raw pointers ====================
FormatConvertImpl(VoidPtr v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)370 ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
371 VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
372 if (!v.value) {
373 sink->Append("(nil)");
374 return {true};
375 }
376 IntDigits as_digits;
377 as_digits.PrintAsHexLower(v.value);
378 return {ConvertIntImplInnerSlow(as_digits, conv, sink)};
379 }
380
381 // ==================== Floats ====================
FormatConvertImpl(float v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)382 FloatingConvertResult FormatConvertImpl(float v,
383 const FormatConversionSpecImpl conv,
384 FormatSinkImpl *sink) {
385 return {ConvertFloatArg(v, conv, sink)};
386 }
FormatConvertImpl(double v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)387 FloatingConvertResult FormatConvertImpl(double v,
388 const FormatConversionSpecImpl conv,
389 FormatSinkImpl *sink) {
390 return {ConvertFloatArg(v, conv, sink)};
391 }
FormatConvertImpl(long double v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)392 FloatingConvertResult FormatConvertImpl(long double v,
393 const FormatConversionSpecImpl conv,
394 FormatSinkImpl *sink) {
395 return {ConvertFloatArg(v, conv, sink)};
396 }
397
398 // ==================== Chars ====================
FormatConvertImpl(char v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)399 IntegralConvertResult FormatConvertImpl(char v,
400 const FormatConversionSpecImpl conv,
401 FormatSinkImpl *sink) {
402 return {ConvertIntArg(v, conv, sink)};
403 }
FormatConvertImpl(signed char v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)404 IntegralConvertResult FormatConvertImpl(signed char v,
405 const FormatConversionSpecImpl conv,
406 FormatSinkImpl *sink) {
407 return {ConvertIntArg(v, conv, sink)};
408 }
FormatConvertImpl(unsigned char v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)409 IntegralConvertResult FormatConvertImpl(unsigned char v,
410 const FormatConversionSpecImpl conv,
411 FormatSinkImpl *sink) {
412 return {ConvertIntArg(v, conv, sink)};
413 }
414
415 // ==================== Ints ====================
FormatConvertImpl(short v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)416 IntegralConvertResult FormatConvertImpl(short v, // NOLINT
417 const FormatConversionSpecImpl conv,
418 FormatSinkImpl *sink) {
419 return {ConvertIntArg(v, conv, sink)};
420 }
FormatConvertImpl(unsigned short v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)421 IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT
422 const FormatConversionSpecImpl conv,
423 FormatSinkImpl *sink) {
424 return {ConvertIntArg(v, conv, sink)};
425 }
FormatConvertImpl(int v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)426 IntegralConvertResult FormatConvertImpl(int v,
427 const FormatConversionSpecImpl conv,
428 FormatSinkImpl *sink) {
429 return {ConvertIntArg(v, conv, sink)};
430 }
FormatConvertImpl(unsigned v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)431 IntegralConvertResult FormatConvertImpl(unsigned v,
432 const FormatConversionSpecImpl conv,
433 FormatSinkImpl *sink) {
434 return {ConvertIntArg(v, conv, sink)};
435 }
FormatConvertImpl(long v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)436 IntegralConvertResult FormatConvertImpl(long v, // NOLINT
437 const FormatConversionSpecImpl conv,
438 FormatSinkImpl *sink) {
439 return {ConvertIntArg(v, conv, sink)};
440 }
FormatConvertImpl(unsigned long v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)441 IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT
442 const FormatConversionSpecImpl conv,
443 FormatSinkImpl *sink) {
444 return {ConvertIntArg(v, conv, sink)};
445 }
FormatConvertImpl(long long v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)446 IntegralConvertResult FormatConvertImpl(long long v, // NOLINT
447 const FormatConversionSpecImpl conv,
448 FormatSinkImpl *sink) {
449 return {ConvertIntArg(v, conv, sink)};
450 }
FormatConvertImpl(unsigned long long v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)451 IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT
452 const FormatConversionSpecImpl conv,
453 FormatSinkImpl *sink) {
454 return {ConvertIntArg(v, conv, sink)};
455 }
FormatConvertImpl(absl::int128 v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)456 IntegralConvertResult FormatConvertImpl(absl::int128 v,
457 const FormatConversionSpecImpl conv,
458 FormatSinkImpl *sink) {
459 return {ConvertIntArg(v, conv, sink)};
460 }
FormatConvertImpl(absl::uint128 v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)461 IntegralConvertResult FormatConvertImpl(absl::uint128 v,
462 const FormatConversionSpecImpl conv,
463 FormatSinkImpl *sink) {
464 return {ConvertIntArg(v, conv, sink)};
465 }
466
467 ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_();
468
469
470
471 } // namespace str_format_internal
472
473 ABSL_NAMESPACE_END
474 } // namespace absl
475