Serenity Operating System
1/*
2 * Copyright (c) 2020, the SerenityOS developers.
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/CharacterTypes.h>
8#include <AK/Format.h>
9#include <AK/GenericLexer.h>
10#include <AK/IntegralMath.h>
11#include <AK/StringBuilder.h>
12#include <AK/kstdio.h>
13
14#if defined(AK_OS_SERENITY) && !defined(KERNEL)
15# include <serenity.h>
16#endif
17
18#ifdef KERNEL
19# include <Kernel/Process.h>
20# include <Kernel/Thread.h>
21# include <Kernel/Time/TimeManagement.h>
22#else
23# include <math.h>
24# include <stdio.h>
25# include <string.h>
26#endif
27
28namespace AK {
29
30class FormatParser : public GenericLexer {
31public:
32 struct FormatSpecifier {
33 StringView flags;
34 size_t index;
35 };
36
37 explicit FormatParser(StringView input);
38
39 StringView consume_literal();
40 bool consume_number(size_t& value);
41 bool consume_specifier(FormatSpecifier& specifier);
42 bool consume_replacement_field(size_t& index);
43};
44
45namespace {
46
47static constexpr size_t use_next_index = NumericLimits<size_t>::max();
48
49// The worst case is that we have the largest 64-bit value formatted as binary number, this would take
50// 65 bytes. Choosing a larger power of two won't hurt and is a bit of mitigation against out-of-bounds accesses.
51static constexpr size_t convert_unsigned_to_string(u64 value, Array<u8, 128>& buffer, u8 base, bool upper_case)
52{
53 VERIFY(base >= 2 && base <= 16);
54
55 constexpr char const* lowercase_lookup = "0123456789abcdef";
56 constexpr char const* uppercase_lookup = "0123456789ABCDEF";
57
58 if (value == 0) {
59 buffer[0] = '0';
60 return 1;
61 }
62
63 size_t used = 0;
64 while (value > 0) {
65 if (upper_case)
66 buffer[used++] = uppercase_lookup[value % base];
67 else
68 buffer[used++] = lowercase_lookup[value % base];
69
70 value /= base;
71 }
72
73 for (size_t i = 0; i < used / 2; ++i)
74 swap(buffer[i], buffer[used - i - 1]);
75
76 return used;
77}
78
79ErrorOr<void> vformat_impl(TypeErasedFormatParams& params, FormatBuilder& builder, FormatParser& parser)
80{
81 auto const literal = parser.consume_literal();
82 TRY(builder.put_literal(literal));
83
84 FormatParser::FormatSpecifier specifier;
85 if (!parser.consume_specifier(specifier)) {
86 VERIFY(parser.is_eof());
87 return {};
88 }
89
90 if (specifier.index == use_next_index)
91 specifier.index = params.take_next_index();
92
93 auto& parameter = params.parameters().at(specifier.index);
94
95 FormatParser argparser { specifier.flags };
96 TRY(parameter.formatter(params, builder, argparser, parameter.value));
97 TRY(vformat_impl(params, builder, parser));
98 return {};
99}
100
101} // namespace AK::{anonymous}
102
103FormatParser::FormatParser(StringView input)
104 : GenericLexer(input)
105{
106}
107StringView FormatParser::consume_literal()
108{
109 auto const begin = tell();
110
111 while (!is_eof()) {
112 if (consume_specific("{{"))
113 continue;
114
115 if (consume_specific("}}"))
116 continue;
117
118 if (next_is(is_any_of("{}"sv)))
119 return m_input.substring_view(begin, tell() - begin);
120
121 consume();
122 }
123
124 return m_input.substring_view(begin);
125}
126bool FormatParser::consume_number(size_t& value)
127{
128 value = 0;
129
130 bool consumed_at_least_one = false;
131 while (next_is(is_ascii_digit)) {
132 value *= 10;
133 value += parse_ascii_digit(consume());
134 consumed_at_least_one = true;
135 }
136
137 return consumed_at_least_one;
138}
139bool FormatParser::consume_specifier(FormatSpecifier& specifier)
140{
141 VERIFY(!next_is('}'));
142
143 if (!consume_specific('{'))
144 return false;
145
146 if (!consume_number(specifier.index))
147 specifier.index = use_next_index;
148
149 if (consume_specific(':')) {
150 auto const begin = tell();
151
152 size_t level = 1;
153 while (level > 0) {
154 VERIFY(!is_eof());
155
156 if (consume_specific('{')) {
157 ++level;
158 continue;
159 }
160
161 if (consume_specific('}')) {
162 --level;
163 continue;
164 }
165
166 consume();
167 }
168
169 specifier.flags = m_input.substring_view(begin, tell() - begin - 1);
170 } else {
171 if (!consume_specific('}'))
172 VERIFY_NOT_REACHED();
173
174 specifier.flags = ""sv;
175 }
176
177 return true;
178}
179bool FormatParser::consume_replacement_field(size_t& index)
180{
181 if (!consume_specific('{'))
182 return false;
183
184 if (!consume_number(index))
185 index = use_next_index;
186
187 if (!consume_specific('}'))
188 VERIFY_NOT_REACHED();
189
190 return true;
191}
192
193ErrorOr<void> FormatBuilder::put_padding(char fill, size_t amount)
194{
195 for (size_t i = 0; i < amount; ++i)
196 TRY(m_builder.try_append(fill));
197 return {};
198}
199ErrorOr<void> FormatBuilder::put_literal(StringView value)
200{
201 for (size_t i = 0; i < value.length(); ++i) {
202 TRY(m_builder.try_append(value[i]));
203 if (value[i] == '{' || value[i] == '}')
204 ++i;
205 }
206 return {};
207}
208
209ErrorOr<void> FormatBuilder::put_string(
210 StringView value,
211 Align align,
212 size_t min_width,
213 size_t max_width,
214 char fill)
215{
216 auto const used_by_string = min(max_width, value.length());
217 auto const used_by_padding = max(min_width, used_by_string) - used_by_string;
218
219 if (used_by_string < value.length())
220 value = value.substring_view(0, used_by_string);
221
222 if (align == Align::Left || align == Align::Default) {
223 TRY(m_builder.try_append(value));
224 TRY(put_padding(fill, used_by_padding));
225 } else if (align == Align::Center) {
226 auto const used_by_left_padding = used_by_padding / 2;
227 auto const used_by_right_padding = ceil_div<size_t, size_t>(used_by_padding, 2);
228
229 TRY(put_padding(fill, used_by_left_padding));
230 TRY(m_builder.try_append(value));
231 TRY(put_padding(fill, used_by_right_padding));
232 } else if (align == Align::Right) {
233 TRY(put_padding(fill, used_by_padding));
234 TRY(m_builder.try_append(value));
235 }
236 return {};
237}
238
239ErrorOr<void> FormatBuilder::put_u64(
240 u64 value,
241 u8 base,
242 bool prefix,
243 bool upper_case,
244 bool zero_pad,
245 Align align,
246 size_t min_width,
247 char fill,
248 SignMode sign_mode,
249 bool is_negative)
250{
251 if (align == Align::Default)
252 align = Align::Right;
253
254 Array<u8, 128> buffer;
255
256 auto const used_by_digits = convert_unsigned_to_string(value, buffer, base, upper_case);
257
258 size_t used_by_prefix = 0;
259 if (align == Align::Right && zero_pad) {
260 // We want DeprecatedString::formatted("{:#08x}", 32) to produce '0x00000020' instead of '0x000020'. This
261 // behavior differs from both fmtlib and printf, but is more intuitive.
262 used_by_prefix = 0;
263 } else {
264 if (is_negative || sign_mode != SignMode::OnlyIfNeeded)
265 used_by_prefix += 1;
266
267 if (prefix) {
268 if (base == 8)
269 used_by_prefix += 1;
270 else if (base == 16)
271 used_by_prefix += 2;
272 else if (base == 2)
273 used_by_prefix += 2;
274 }
275 }
276
277 auto const used_by_field = used_by_prefix + used_by_digits;
278 auto const used_by_padding = max(used_by_field, min_width) - used_by_field;
279
280 auto const put_prefix = [&]() -> ErrorOr<void> {
281 if (is_negative)
282 TRY(m_builder.try_append('-'));
283 else if (sign_mode == SignMode::Always)
284 TRY(m_builder.try_append('+'));
285 else if (sign_mode == SignMode::Reserved)
286 TRY(m_builder.try_append(' '));
287
288 if (prefix) {
289 if (base == 2) {
290 if (upper_case)
291 TRY(m_builder.try_append("0B"sv));
292 else
293 TRY(m_builder.try_append("0b"sv));
294 } else if (base == 8) {
295 TRY(m_builder.try_append("0"sv));
296 } else if (base == 16) {
297 if (upper_case)
298 TRY(m_builder.try_append("0X"sv));
299 else
300 TRY(m_builder.try_append("0x"sv));
301 }
302 }
303 return {};
304 };
305
306 auto const put_digits = [&]() -> ErrorOr<void> {
307 for (size_t i = 0; i < used_by_digits; ++i)
308 TRY(m_builder.try_append(buffer[i]));
309 return {};
310 };
311
312 if (align == Align::Left) {
313 auto const used_by_right_padding = used_by_padding;
314
315 TRY(put_prefix());
316 TRY(put_digits());
317 TRY(put_padding(fill, used_by_right_padding));
318 } else if (align == Align::Center) {
319 auto const used_by_left_padding = used_by_padding / 2;
320 auto const used_by_right_padding = ceil_div<size_t, size_t>(used_by_padding, 2);
321
322 TRY(put_padding(fill, used_by_left_padding));
323 TRY(put_prefix());
324 TRY(put_digits());
325 TRY(put_padding(fill, used_by_right_padding));
326 } else if (align == Align::Right) {
327 auto const used_by_left_padding = used_by_padding;
328
329 if (zero_pad) {
330 TRY(put_prefix());
331 TRY(put_padding('0', used_by_left_padding));
332 TRY(put_digits());
333 } else {
334 TRY(put_padding(fill, used_by_left_padding));
335 TRY(put_prefix());
336 TRY(put_digits());
337 }
338 }
339 return {};
340}
341
342ErrorOr<void> FormatBuilder::put_i64(
343 i64 value,
344 u8 base,
345 bool prefix,
346 bool upper_case,
347 bool zero_pad,
348 Align align,
349 size_t min_width,
350 char fill,
351 SignMode sign_mode)
352{
353 auto const is_negative = value < 0;
354 value = is_negative ? -value : value;
355
356 TRY(put_u64(static_cast<u64>(value), base, prefix, upper_case, zero_pad, align, min_width, fill, sign_mode, is_negative));
357 return {};
358}
359
360ErrorOr<void> FormatBuilder::put_fixed_point(
361 bool is_negative,
362 i64 integer_value,
363 u64 fraction_value,
364 u64 fraction_one,
365 u8 base,
366 bool upper_case,
367 bool zero_pad,
368 Align align,
369 size_t min_width,
370 size_t precision,
371 char fill,
372 SignMode sign_mode,
373 RealNumberDisplayMode display_mode)
374{
375 StringBuilder string_builder;
376 FormatBuilder format_builder { string_builder };
377
378 if (is_negative)
379 integer_value = -integer_value;
380
381 TRY(format_builder.put_u64(static_cast<u64>(integer_value), base, false, upper_case, false, Align::Right, 0, ' ', sign_mode, is_negative));
382
383 if (precision > 0) {
384 // FIXME: This is a terrible approximation but doing it properly would be a lot of work. If someone is up for that, a good
385 // place to start would be the following video from CppCon 2019:
386 // https://youtu.be/4P_kbF0EbZM (Stephan T. Lavavej “Floating-Point <charconv>: Making Your Code 10x Faster With C++17's Final Boss”)
387
388 u64 scale = pow<u64>(10, precision);
389
390 auto fraction = (scale * fraction_value) / fraction_one; // TODO: overflows
391 if (is_negative)
392 fraction = scale - fraction;
393
394 size_t leading_zeroes = 0;
395 {
396 auto scale_tmp = scale / 10;
397 for (; fraction < scale_tmp; ++leading_zeroes) {
398 scale_tmp /= 10;
399 }
400 }
401
402 while (fraction != 0 && fraction % 10 == 0)
403 fraction /= 10;
404
405 size_t visible_precision = 0;
406 {
407 auto fraction_tmp = fraction;
408 for (; visible_precision < precision; ++visible_precision) {
409 if (fraction_tmp == 0 && display_mode != RealNumberDisplayMode::FixedPoint)
410 break;
411 fraction_tmp /= 10;
412 }
413 }
414
415 if (visible_precision == 0)
416 leading_zeroes = 0;
417
418 if (zero_pad || visible_precision > 0)
419 TRY(string_builder.try_append('.'));
420
421 if (leading_zeroes > 0)
422 TRY(format_builder.put_u64(0, base, false, false, true, Align::Right, leading_zeroes));
423
424 if (visible_precision > 0)
425 TRY(format_builder.put_u64(fraction, base, false, upper_case, true, Align::Right, visible_precision));
426
427 if (zero_pad && (precision - leading_zeroes - visible_precision) > 0)
428 TRY(format_builder.put_u64(0, base, false, false, true, Align::Right, precision - leading_zeroes - visible_precision));
429 }
430
431 TRY(put_string(string_builder.string_view(), align, min_width, NumericLimits<size_t>::max(), fill));
432 return {};
433}
434
435#ifndef KERNEL
436ErrorOr<void> FormatBuilder::put_f64(
437 double value,
438 u8 base,
439 bool upper_case,
440 bool zero_pad,
441 Align align,
442 size_t min_width,
443 size_t precision,
444 char fill,
445 SignMode sign_mode,
446 RealNumberDisplayMode display_mode)
447{
448 StringBuilder string_builder;
449 FormatBuilder format_builder { string_builder };
450
451 if (isnan(value) || isinf(value)) [[unlikely]] {
452 if (value < 0.0)
453 TRY(string_builder.try_append('-'));
454 else if (sign_mode == SignMode::Always)
455 TRY(string_builder.try_append('+'));
456 else if (sign_mode == SignMode::Reserved)
457 TRY(string_builder.try_append(' '));
458
459 if (isnan(value))
460 TRY(string_builder.try_append(upper_case ? "NAN"sv : "nan"sv));
461 else
462 TRY(string_builder.try_append(upper_case ? "INF"sv : "inf"sv));
463 TRY(put_string(string_builder.string_view(), align, min_width, NumericLimits<size_t>::max(), fill));
464 return {};
465 }
466
467 bool is_negative = value < 0.0;
468 if (is_negative)
469 value = -value;
470
471 TRY(format_builder.put_u64(static_cast<u64>(value), base, false, upper_case, false, Align::Right, 0, ' ', sign_mode, is_negative));
472
473 if (precision > 0) {
474 // FIXME: This is a terrible approximation but doing it properly would be a lot of work. If someone is up for that, a good
475 // place to start would be the following video from CppCon 2019:
476 // https://youtu.be/4P_kbF0EbZM (Stephan T. Lavavej “Floating-Point <charconv>: Making Your Code 10x Faster With C++17's Final Boss”)
477 value -= static_cast<i64>(value);
478
479 double epsilon = 0.5;
480 for (size_t i = 0; i < precision; ++i)
481 epsilon /= 10.0;
482
483 size_t visible_precision = 0;
484 for (; visible_precision < precision; ++visible_precision) {
485 if (value - static_cast<i64>(value) < epsilon && display_mode != RealNumberDisplayMode::FixedPoint)
486 break;
487 value *= 10.0;
488 epsilon *= 10.0;
489 }
490
491 if (zero_pad || visible_precision > 0)
492 TRY(string_builder.try_append('.'));
493
494 if (visible_precision > 0)
495 TRY(format_builder.put_u64(static_cast<u64>(value), base, false, upper_case, true, Align::Right, visible_precision));
496
497 if (zero_pad && (precision - visible_precision) > 0)
498 TRY(format_builder.put_u64(0, base, false, false, true, Align::Right, precision - visible_precision));
499 }
500
501 TRY(put_string(string_builder.string_view(), align, min_width, NumericLimits<size_t>::max(), fill));
502 return {};
503}
504
505ErrorOr<void> FormatBuilder::put_f80(
506 long double value,
507 u8 base,
508 bool upper_case,
509 Align align,
510 size_t min_width,
511 size_t precision,
512 char fill,
513 SignMode sign_mode,
514 RealNumberDisplayMode display_mode)
515{
516 StringBuilder string_builder;
517 FormatBuilder format_builder { string_builder };
518
519 if (isnan(value) || isinf(value)) [[unlikely]] {
520 if (value < 0.0l)
521 TRY(string_builder.try_append('-'));
522 else if (sign_mode == SignMode::Always)
523 TRY(string_builder.try_append('+'));
524 else if (sign_mode == SignMode::Reserved)
525 TRY(string_builder.try_append(' '));
526
527 if (isnan(value))
528 TRY(string_builder.try_append(upper_case ? "NAN"sv : "nan"sv));
529 else
530 TRY(string_builder.try_append(upper_case ? "INF"sv : "inf"sv));
531 TRY(put_string(string_builder.string_view(), align, min_width, NumericLimits<size_t>::max(), fill));
532 return {};
533 }
534
535 bool is_negative = value < 0.0l;
536 if (is_negative)
537 value = -value;
538
539 TRY(format_builder.put_u64(static_cast<u64>(value), base, false, upper_case, false, Align::Right, 0, ' ', sign_mode, is_negative));
540
541 if (precision > 0) {
542 // FIXME: This is a terrible approximation but doing it properly would be a lot of work. If someone is up for that, a good
543 // place to start would be the following video from CppCon 2019:
544 // https://youtu.be/4P_kbF0EbZM (Stephan T. Lavavej “Floating-Point <charconv>: Making Your Code 10x Faster With C++17's Final Boss”)
545 value -= static_cast<i64>(value);
546
547 long double epsilon = 0.5l;
548 for (size_t i = 0; i < precision; ++i)
549 epsilon /= 10.0l;
550
551 size_t visible_precision = 0;
552 for (; visible_precision < precision; ++visible_precision) {
553 if (value - static_cast<i64>(value) < epsilon && display_mode != RealNumberDisplayMode::FixedPoint)
554 break;
555 value *= 10.0l;
556 epsilon *= 10.0l;
557 }
558
559 if (visible_precision > 0) {
560 string_builder.append('.');
561 TRY(format_builder.put_u64(static_cast<u64>(value), base, false, upper_case, true, Align::Right, visible_precision));
562 }
563 }
564
565 TRY(put_string(string_builder.string_view(), align, min_width, NumericLimits<size_t>::max(), fill));
566 return {};
567}
568
569#endif
570
571ErrorOr<void> FormatBuilder::put_hexdump(ReadonlyBytes bytes, size_t width, char fill)
572{
573 auto put_char_view = [&](auto i) -> ErrorOr<void> {
574 TRY(put_padding(fill, 4));
575 for (size_t j = i - width; j < i; ++j) {
576 auto ch = bytes[j];
577 TRY(m_builder.try_append(ch >= 32 && ch <= 127 ? ch : '.')); // silly hack
578 }
579 return {};
580 };
581
582 for (size_t i = 0; i < bytes.size(); ++i) {
583 if (width > 0) {
584 if (i % width == 0 && i) {
585 TRY(put_char_view(i));
586 TRY(put_literal("\n"sv));
587 }
588 }
589 TRY(put_u64(bytes[i], 16, false, false, true, Align::Right, 2));
590 }
591
592 if (width > 0 && bytes.size() && bytes.size() % width == 0)
593 TRY(put_char_view(bytes.size()));
594
595 return {};
596}
597
598ErrorOr<void> vformat(StringBuilder& builder, StringView fmtstr, TypeErasedFormatParams& params)
599{
600 FormatBuilder fmtbuilder { builder };
601 FormatParser parser { fmtstr };
602
603 TRY(vformat_impl(params, fmtbuilder, parser));
604 return {};
605}
606
607void StandardFormatter::parse(TypeErasedFormatParams& params, FormatParser& parser)
608{
609 if ("<^>"sv.contains(parser.peek(1))) {
610 VERIFY(!parser.next_is(is_any_of("{}"sv)));
611 m_fill = parser.consume();
612 }
613
614 if (parser.consume_specific('<'))
615 m_align = FormatBuilder::Align::Left;
616 else if (parser.consume_specific('^'))
617 m_align = FormatBuilder::Align::Center;
618 else if (parser.consume_specific('>'))
619 m_align = FormatBuilder::Align::Right;
620
621 if (parser.consume_specific('-'))
622 m_sign_mode = FormatBuilder::SignMode::OnlyIfNeeded;
623 else if (parser.consume_specific('+'))
624 m_sign_mode = FormatBuilder::SignMode::Always;
625 else if (parser.consume_specific(' '))
626 m_sign_mode = FormatBuilder::SignMode::Reserved;
627
628 if (parser.consume_specific('#'))
629 m_alternative_form = true;
630
631 if (parser.consume_specific('0'))
632 m_zero_pad = true;
633
634 if (size_t index = 0; parser.consume_replacement_field(index)) {
635 if (index == use_next_index)
636 index = params.take_next_index();
637
638 m_width = params.parameters().at(index).to_size();
639 } else if (size_t width = 0; parser.consume_number(width)) {
640 m_width = width;
641 }
642
643 if (parser.consume_specific('.')) {
644 if (size_t index = 0; parser.consume_replacement_field(index)) {
645 if (index == use_next_index)
646 index = params.take_next_index();
647
648 m_precision = params.parameters().at(index).to_size();
649 } else if (size_t precision = 0; parser.consume_number(precision)) {
650 m_precision = precision;
651 }
652 }
653
654 if (parser.consume_specific('b'))
655 m_mode = Mode::Binary;
656 else if (parser.consume_specific('B'))
657 m_mode = Mode::BinaryUppercase;
658 else if (parser.consume_specific('d'))
659 m_mode = Mode::Decimal;
660 else if (parser.consume_specific('o'))
661 m_mode = Mode::Octal;
662 else if (parser.consume_specific('x'))
663 m_mode = Mode::Hexadecimal;
664 else if (parser.consume_specific('X'))
665 m_mode = Mode::HexadecimalUppercase;
666 else if (parser.consume_specific('c'))
667 m_mode = Mode::Character;
668 else if (parser.consume_specific('s'))
669 m_mode = Mode::String;
670 else if (parser.consume_specific('p'))
671 m_mode = Mode::Pointer;
672 else if (parser.consume_specific('f'))
673 m_mode = Mode::FixedPoint;
674 else if (parser.consume_specific('a'))
675 m_mode = Mode::Hexfloat;
676 else if (parser.consume_specific('A'))
677 m_mode = Mode::HexfloatUppercase;
678 else if (parser.consume_specific("hex-dump"))
679 m_mode = Mode::HexDump;
680
681 if (!parser.is_eof())
682 dbgln("{} did not consume '{}'", __PRETTY_FUNCTION__, parser.remaining());
683
684 VERIFY(parser.is_eof());
685}
686
687ErrorOr<void> Formatter<StringView>::format(FormatBuilder& builder, StringView value)
688{
689 if (m_sign_mode != FormatBuilder::SignMode::Default)
690 VERIFY_NOT_REACHED();
691 if (m_zero_pad)
692 VERIFY_NOT_REACHED();
693 if (m_mode != Mode::Default && m_mode != Mode::String && m_mode != Mode::Character && m_mode != Mode::HexDump)
694 VERIFY_NOT_REACHED();
695
696 m_width = m_width.value_or(0);
697 m_precision = m_precision.value_or(NumericLimits<size_t>::max());
698
699 if (m_mode == Mode::HexDump)
700 return builder.put_hexdump(value.bytes(), m_width.value(), m_fill);
701 return builder.put_string(value, m_align, m_width.value(), m_precision.value(), m_fill);
702}
703
704ErrorOr<void> Formatter<FormatString>::vformat(FormatBuilder& builder, StringView fmtstr, TypeErasedFormatParams& params)
705{
706 StringBuilder string_builder;
707 TRY(AK::vformat(string_builder, fmtstr, params));
708 TRY(Formatter<StringView>::format(builder, string_builder.string_view()));
709 return {};
710}
711
712template<Integral T>
713ErrorOr<void> Formatter<T>::format(FormatBuilder& builder, T value)
714{
715 if (m_mode == Mode::Character) {
716 // FIXME: We just support ASCII for now, in the future maybe unicode?
717 // VERIFY(value >= 0 && value <= 127);
718
719 m_mode = Mode::String;
720
721 Formatter<StringView> formatter { *this };
722 return formatter.format(builder, StringView { reinterpret_cast<char const*>(&value), 1 });
723 }
724
725 if (m_precision.has_value())
726 VERIFY_NOT_REACHED();
727
728 if (m_mode == Mode::Pointer) {
729 if (m_sign_mode != FormatBuilder::SignMode::Default)
730 VERIFY_NOT_REACHED();
731 if (m_align != FormatBuilder::Align::Default)
732 VERIFY_NOT_REACHED();
733 if (m_alternative_form)
734 VERIFY_NOT_REACHED();
735 if (m_width.has_value())
736 VERIFY_NOT_REACHED();
737
738 m_mode = Mode::Hexadecimal;
739 m_alternative_form = true;
740 m_width = 2 * sizeof(void*);
741 m_zero_pad = true;
742 }
743
744 u8 base = 0;
745 bool upper_case = false;
746 if (m_mode == Mode::Binary) {
747 base = 2;
748 } else if (m_mode == Mode::BinaryUppercase) {
749 base = 2;
750 upper_case = true;
751 } else if (m_mode == Mode::Octal) {
752 base = 8;
753 } else if (m_mode == Mode::Decimal || m_mode == Mode::Default) {
754 base = 10;
755 } else if (m_mode == Mode::Hexadecimal) {
756 base = 16;
757 } else if (m_mode == Mode::HexadecimalUppercase) {
758 base = 16;
759 upper_case = true;
760 } else if (m_mode == Mode::HexDump) {
761 m_width = m_width.value_or(32);
762 return builder.put_hexdump({ &value, sizeof(value) }, m_width.value(), m_fill);
763 } else {
764 VERIFY_NOT_REACHED();
765 }
766
767 m_width = m_width.value_or(0);
768
769 if constexpr (IsSame<MakeUnsigned<T>, T>)
770 return builder.put_u64(value, base, m_alternative_form, upper_case, m_zero_pad, m_align, m_width.value(), m_fill, m_sign_mode);
771 else
772 return builder.put_i64(value, base, m_alternative_form, upper_case, m_zero_pad, m_align, m_width.value(), m_fill, m_sign_mode);
773}
774
775ErrorOr<void> Formatter<char>::format(FormatBuilder& builder, char value)
776{
777 if (m_mode == Mode::Binary || m_mode == Mode::BinaryUppercase || m_mode == Mode::Decimal || m_mode == Mode::Octal || m_mode == Mode::Hexadecimal || m_mode == Mode::HexadecimalUppercase) {
778 // Trick: signed char != char. (Sometimes weird features are actually helpful.)
779 Formatter<signed char> formatter { *this };
780 return formatter.format(builder, static_cast<signed char>(value));
781 } else {
782 Formatter<StringView> formatter { *this };
783 return formatter.format(builder, { &value, 1 });
784 }
785}
786ErrorOr<void> Formatter<wchar_t>::format(FormatBuilder& builder, wchar_t value)
787{
788 if (m_mode == Mode::Binary || m_mode == Mode::BinaryUppercase || m_mode == Mode::Decimal || m_mode == Mode::Octal || m_mode == Mode::Hexadecimal || m_mode == Mode::HexadecimalUppercase) {
789 Formatter<u32> formatter { *this };
790 return formatter.format(builder, static_cast<u32>(value));
791 } else {
792 StringBuilder codepoint;
793 codepoint.append_code_point(value);
794
795 Formatter<StringView> formatter { *this };
796 return formatter.format(builder, codepoint.string_view());
797 }
798}
799ErrorOr<void> Formatter<bool>::format(FormatBuilder& builder, bool value)
800{
801 if (m_mode == Mode::Binary || m_mode == Mode::BinaryUppercase || m_mode == Mode::Decimal || m_mode == Mode::Octal || m_mode == Mode::Hexadecimal || m_mode == Mode::HexadecimalUppercase) {
802 Formatter<u8> formatter { *this };
803 return formatter.format(builder, static_cast<u8>(value));
804 } else if (m_mode == Mode::HexDump) {
805 return builder.put_hexdump({ &value, sizeof(value) }, m_width.value_or(32), m_fill);
806 } else {
807 Formatter<StringView> formatter { *this };
808 return formatter.format(builder, value ? "true"sv : "false"sv);
809 }
810}
811#ifndef KERNEL
812ErrorOr<void> Formatter<long double>::format(FormatBuilder& builder, long double value)
813{
814 u8 base;
815 bool upper_case;
816 FormatBuilder::RealNumberDisplayMode real_number_display_mode = FormatBuilder::RealNumberDisplayMode::General;
817 if (m_mode == Mode::Default || m_mode == Mode::FixedPoint) {
818 base = 10;
819 upper_case = false;
820 if (m_mode == Mode::FixedPoint)
821 real_number_display_mode = FormatBuilder::RealNumberDisplayMode::FixedPoint;
822 } else if (m_mode == Mode::Hexfloat) {
823 base = 16;
824 upper_case = false;
825 } else if (m_mode == Mode::HexfloatUppercase) {
826 base = 16;
827 upper_case = true;
828 } else {
829 VERIFY_NOT_REACHED();
830 }
831
832 m_width = m_width.value_or(0);
833 m_precision = m_precision.value_or(6);
834
835 return builder.put_f80(value, base, upper_case, m_align, m_width.value(), m_precision.value(), m_fill, m_sign_mode, real_number_display_mode);
836}
837
838ErrorOr<void> Formatter<double>::format(FormatBuilder& builder, double value)
839{
840 u8 base;
841 bool upper_case;
842 FormatBuilder::RealNumberDisplayMode real_number_display_mode = FormatBuilder::RealNumberDisplayMode::General;
843 if (m_mode == Mode::Default || m_mode == Mode::FixedPoint) {
844 base = 10;
845 upper_case = false;
846 if (m_mode == Mode::FixedPoint)
847 real_number_display_mode = FormatBuilder::RealNumberDisplayMode::FixedPoint;
848 } else if (m_mode == Mode::Hexfloat) {
849 base = 16;
850 upper_case = false;
851 } else if (m_mode == Mode::HexfloatUppercase) {
852 base = 16;
853 upper_case = true;
854 } else {
855 VERIFY_NOT_REACHED();
856 }
857
858 m_width = m_width.value_or(0);
859 m_precision = m_precision.value_or(6);
860
861 return builder.put_f64(value, base, upper_case, m_zero_pad, m_align, m_width.value(), m_precision.value(), m_fill, m_sign_mode, real_number_display_mode);
862}
863
864ErrorOr<void> Formatter<float>::format(FormatBuilder& builder, float value)
865{
866 Formatter<double> formatter { *this };
867 return formatter.format(builder, value);
868}
869#endif
870
871#ifndef KERNEL
872void vout(FILE* file, StringView fmtstr, TypeErasedFormatParams& params, bool newline)
873{
874 StringBuilder builder;
875 MUST(vformat(builder, fmtstr, params));
876
877 if (newline)
878 builder.append('\n');
879
880 auto const string = builder.string_view();
881 auto const retval = ::fwrite(string.characters_without_null_termination(), 1, string.length(), file);
882 if (static_cast<size_t>(retval) != string.length()) {
883 auto error = ferror(file);
884 dbgln("vout() failed ({} written out of {}), error was {} ({})", retval, string.length(), error, strerror(error));
885 }
886}
887#endif
888
889static bool is_debug_enabled = true;
890
891void set_debug_enabled(bool value)
892{
893 is_debug_enabled = value;
894}
895
896void vdbgln(StringView fmtstr, TypeErasedFormatParams& params)
897{
898 if (!is_debug_enabled)
899 return;
900
901 StringBuilder builder;
902
903#ifdef AK_OS_SERENITY
904# ifdef KERNEL
905 if (Kernel::Processor::is_initialized() && TimeManagement::is_initialized()) {
906 struct timespec ts = TimeManagement::the().monotonic_time(TimePrecision::Coarse).to_timespec();
907 if (Kernel::Thread::current()) {
908 auto& thread = *Kernel::Thread::current();
909 thread.process().name().with([&](auto& process_name) {
910 builder.appendff("{}.{:03} \033[34;1m[#{} {}({}:{})]\033[0m: ", ts.tv_sec, ts.tv_nsec / 1000000, Kernel::Processor::current_id(), process_name->view(), thread.pid().value(), thread.tid().value());
911 });
912 } else {
913 builder.appendff("{}.{:03} \033[34;1m[#{} Kernel]\033[0m: ", ts.tv_sec, ts.tv_nsec / 1000000, Kernel::Processor::current_id());
914 }
915 } else {
916 builder.appendff("\033[34;1m[Kernel]\033[0m: ");
917 }
918# else
919 static TriState got_process_name = TriState::Unknown;
920 static char process_name_buffer[256];
921
922 if (got_process_name == TriState::Unknown) {
923 if (get_process_name(process_name_buffer, sizeof(process_name_buffer)) == 0)
924 got_process_name = TriState::True;
925 else
926 got_process_name = TriState::False;
927 }
928 struct timespec ts;
929 clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
930 if (got_process_name == TriState::True)
931 builder.appendff("{}.{:03} \033[33;1m{}({}:{})\033[0m: ", ts.tv_sec, ts.tv_nsec / 1000000, process_name_buffer, getpid(), gettid());
932# endif
933#endif
934
935 MUST(vformat(builder, fmtstr, params));
936 builder.append('\n');
937
938 auto const string = builder.string_view();
939
940#ifdef AK_OS_SERENITY
941# ifdef KERNEL
942 if (!Kernel::Processor::is_initialized()) {
943 kernelearlyputstr(string.characters_without_null_termination(), string.length());
944 return;
945 }
946# endif
947#endif
948 dbgputstr(string.characters_without_null_termination(), string.length());
949}
950
951#ifdef KERNEL
952void vdmesgln(StringView fmtstr, TypeErasedFormatParams& params)
953{
954 StringBuilder builder;
955
956# ifdef AK_OS_SERENITY
957 struct timespec ts = {};
958
959 if (TimeManagement::is_initialized()) {
960 ts = TimeManagement::the().monotonic_time(TimePrecision::Coarse).to_timespec();
961
962 if (Kernel::Processor::is_initialized() && Kernel::Thread::current()) {
963 auto& thread = *Kernel::Thread::current();
964 thread.process().name().with([&](auto& process_name) {
965 builder.appendff("{}.{:03} \033[34;1m[{}({}:{})]\033[0m: ", ts.tv_sec, ts.tv_nsec / 1000000, process_name->view(), thread.pid().value(), thread.tid().value());
966 });
967 } else {
968 builder.appendff("{}.{:03} \033[34;1m[Kernel]\033[0m: ", ts.tv_sec, ts.tv_nsec / 1000000);
969 }
970 } else {
971 builder.appendff("\033[34;1m[Kernel]\033[0m: ");
972 }
973# endif
974
975 MUST(vformat(builder, fmtstr, params));
976 builder.append('\n');
977
978 auto const string = builder.string_view();
979 kernelputstr(string.characters_without_null_termination(), string.length());
980}
981
982void v_critical_dmesgln(StringView fmtstr, TypeErasedFormatParams& params)
983{
984 // FIXME: Try to avoid memory allocations further to prevent faulting
985 // at OOM conditions.
986
987 StringBuilder builder;
988# ifdef AK_OS_SERENITY
989 if (Kernel::Processor::is_initialized() && Kernel::Thread::current()) {
990 auto& thread = *Kernel::Thread::current();
991 thread.process().name().with([&](auto& process_name) {
992 builder.appendff("[{}({}:{})]: ", process_name->view(), thread.pid().value(), thread.tid().value());
993 });
994 } else {
995 builder.appendff("[Kernel]: ");
996 }
997# endif
998
999 MUST(vformat(builder, fmtstr, params));
1000 builder.append('\n');
1001
1002 auto const string = builder.string_view();
1003 kernelcriticalputstr(string.characters_without_null_termination(), string.length());
1004}
1005
1006#endif
1007
1008template struct Formatter<unsigned char, void>;
1009template struct Formatter<unsigned short, void>;
1010template struct Formatter<unsigned int, void>;
1011template struct Formatter<unsigned long, void>;
1012template struct Formatter<unsigned long long, void>;
1013template struct Formatter<short, void>;
1014template struct Formatter<int, void>;
1015template struct Formatter<long, void>;
1016template struct Formatter<long long, void>;
1017template struct Formatter<signed char, void>;
1018
1019} // namespace AK