Serenity Operating System
at master 1019 lines 33 kB view raw
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