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