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