• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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