1 //===-- Format string parser for printf -------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PARSER_H 10 #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PARSER_H 11 12 #include "include/llvm-libc-macros/stdfix-macros.h" 13 #include "src/__support/CPP/algorithm.h" // max 14 #include "src/__support/CPP/limits.h" 15 #include "src/__support/CPP/optional.h" 16 #include "src/__support/CPP/type_traits.h" 17 #include "src/__support/macros/config.h" 18 #include "src/__support/str_to_integer.h" 19 #include "src/stdio/printf_core/core_structs.h" 20 #include "src/stdio/printf_core/printf_config.h" 21 22 #include <stddef.h> 23 24 #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT 25 #include "src/__support/fixed_point/fx_rep.h" 26 #endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT 27 #ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR 28 #include "src/errno/libc_errno.h" 29 #endif // LIBC_COPT_PRINTF_DISABLE_STRERROR 30 31 namespace LIBC_NAMESPACE_DECL { 32 namespace printf_core { 33 34 template <typename T> struct int_type_of { 35 using type = T; 36 }; 37 template <> struct int_type_of<double> { 38 using type = fputil::FPBits<double>::StorageType; 39 }; 40 template <> struct int_type_of<long double> { 41 using type = fputil::FPBits<long double>::StorageType; 42 }; 43 44 #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT 45 template <typename T> 46 struct int_type_of<cpp::enable_if<cpp::is_fixed_point_v<T>, T>> { 47 using type = typename fixed_point::FXRep<T>::StorageType; 48 }; 49 #endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT 50 51 template <typename T> using int_type_of_v = typename int_type_of<T>::type; 52 53 #ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE 54 #define WRITE_ARG_VAL_SIMPLEST(dst, arg_type, index) \ 55 { \ 56 auto temp = get_arg_value<arg_type>(index); \ 57 if (!temp.has_value()) { \ 58 section.has_conv = false; \ 59 } else { \ 60 dst = cpp::bit_cast<int_type_of_v<arg_type>>(temp.value()); \ 61 } \ 62 } 63 #else 64 #define WRITE_ARG_VAL_SIMPLEST(dst, arg_type, _) \ 65 dst = cpp::bit_cast<int_type_of_v<arg_type>>(get_next_arg_value<arg_type>()) 66 #endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE 67 68 template <typename ArgProvider> class Parser { 69 const char *__restrict str; 70 71 size_t cur_pos = 0; 72 ArgProvider args_cur; 73 74 #ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE 75 // args_start stores the start of the va_args, which is allows getting the 76 // value of arguments that have already been passed. args_index is tracked so 77 // that we know which argument args_cur is on. 78 ArgProvider args_start; 79 size_t args_index = 1; 80 81 // Defined in printf_config.h 82 static constexpr size_t DESC_ARR_LEN = LIBC_COPT_PRINTF_INDEX_ARR_LEN; 83 84 // desc_arr stores the sizes of the variables in the ArgProvider. This is used 85 // in index mode to reduce repeated string parsing. The sizes are stored as 86 // TypeDesc objects, which store the size as well as minimal type information. 87 // This is necessary because some systems separate the floating point and 88 // integer values in va_args. 89 TypeDesc desc_arr[DESC_ARR_LEN] = {type_desc_from_type<void>()}; 90 91 // TODO: Look into object stores for optimization. 92 93 #endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE 94 95 public: 96 #ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE 97 LIBC_INLINE Parser(const char *__restrict new_str, ArgProvider &args) 98 : str(new_str), args_cur(args), args_start(args) {} 99 #else 100 LIBC_INLINE Parser(const char *__restrict new_str, ArgProvider &args) 101 : str(new_str), args_cur(args) {} 102 #endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE 103 104 // get_next_section will parse the format string until it has a fully 105 // specified format section. This can either be a raw format section with no 106 // conversion, or a format section with a conversion that has all of its 107 // variables stored in the format section. 108 LIBC_INLINE FormatSection get_next_section() { 109 FormatSection section; 110 size_t starting_pos = cur_pos; 111 if (str[cur_pos] == '%') { 112 // format section 113 section.has_conv = true; 114 115 ++cur_pos; 116 [[maybe_unused]] size_t conv_index = 0; 117 118 #ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE 119 conv_index = parse_index(&cur_pos); 120 #endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE 121 122 section.flags = parse_flags(&cur_pos); 123 124 // handle width 125 section.min_width = 0; 126 if (str[cur_pos] == '*') { 127 ++cur_pos; 128 129 WRITE_ARG_VAL_SIMPLEST(section.min_width, int, parse_index(&cur_pos)); 130 } else if (internal::isdigit(str[cur_pos])) { 131 auto result = internal::strtointeger<int>(str + cur_pos, 10); 132 section.min_width = result.value; 133 cur_pos = cur_pos + result.parsed_len; 134 } 135 if (section.min_width < 0) { 136 section.min_width = 137 (section.min_width == INT_MIN) ? INT_MAX : -section.min_width; 138 section.flags = static_cast<FormatFlags>(section.flags | 139 FormatFlags::LEFT_JUSTIFIED); 140 } 141 142 // handle precision 143 section.precision = -1; // negative precisions are ignored. 144 if (str[cur_pos] == '.') { 145 ++cur_pos; 146 section.precision = 0; // if there's a . but no specified precision, the 147 // precision is implicitly 0. 148 if (str[cur_pos] == '*') { 149 ++cur_pos; 150 151 WRITE_ARG_VAL_SIMPLEST(section.precision, int, parse_index(&cur_pos)); 152 153 } else if (internal::isdigit(str[cur_pos])) { 154 auto result = internal::strtointeger<int>(str + cur_pos, 10); 155 section.precision = result.value; 156 cur_pos = cur_pos + result.parsed_len; 157 } 158 } 159 160 auto [lm, bw] = parse_length_modifier(&cur_pos); 161 section.length_modifier = lm; 162 section.conv_name = str[cur_pos]; 163 section.bit_width = bw; 164 switch (str[cur_pos]) { 165 case ('%'): 166 // Regardless of options, a % conversion is always safe. The standard 167 // says that "The complete conversion specification shall be %%" but it 168 // also says that "If a conversion specification is invalid, the 169 // behavior is undefined." Based on that we define that any conversion 170 // specification ending in '%' shall display as '%' regardless of any 171 // valid or invalid options. 172 section.has_conv = true; 173 break; 174 case ('c'): 175 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index); 176 break; 177 case ('d'): 178 case ('i'): 179 case ('o'): 180 case ('x'): 181 case ('X'): 182 case ('u'): 183 case ('b'): 184 case ('B'): 185 switch (lm) { 186 case (LengthModifier::hh): 187 case (LengthModifier::h): 188 case (LengthModifier::none): 189 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index); 190 break; 191 case (LengthModifier::l): 192 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long, conv_index); 193 break; 194 case (LengthModifier::ll): 195 case (LengthModifier::L): // This isn't in the standard, but is in other 196 // libc implementations. 197 198 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long long, conv_index); 199 break; 200 case (LengthModifier::j): 201 202 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, intmax_t, conv_index); 203 break; 204 case (LengthModifier::z): 205 206 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, size_t, conv_index); 207 break; 208 case (LengthModifier::t): 209 210 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, ptrdiff_t, conv_index); 211 break; 212 213 case (LengthModifier::w): 214 case (LengthModifier::wf): 215 if (bw == 0) { 216 section.has_conv = false; 217 } else if (bw <= cpp::numeric_limits<unsigned int>::digits) { 218 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index); 219 } else if (bw <= cpp::numeric_limits<unsigned long>::digits) { 220 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long, conv_index); 221 } else if (bw <= cpp::numeric_limits<unsigned long long>::digits) { 222 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long long, conv_index); 223 } else { 224 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, intmax_t, conv_index); 225 } 226 break; 227 } 228 break; 229 #ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT 230 case ('f'): 231 case ('F'): 232 case ('e'): 233 case ('E'): 234 case ('a'): 235 case ('A'): 236 case ('g'): 237 case ('G'): 238 if (lm != LengthModifier::L) { 239 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, double, conv_index); 240 } else { 241 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long double, conv_index); 242 } 243 break; 244 #endif // LIBC_COPT_PRINTF_DISABLE_FLOAT 245 #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT 246 // Capitalization represents sign, but we only need to get the right 247 // bitwidth here so we ignore that. 248 case ('r'): 249 case ('R'): 250 // all fract sizes we support are less than 32 bits, and currently doing 251 // va_args with fixed point types just doesn't work. 252 // TODO: Move to fixed point types once va_args supports it. 253 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, uint32_t, conv_index); 254 break; 255 case ('k'): 256 case ('K'): 257 if (lm == LengthModifier::l) { 258 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, uint64_t, conv_index); 259 } else { 260 WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, uint32_t, conv_index); 261 } 262 break; 263 #endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT 264 #ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR 265 case ('m'): 266 // %m is an odd conversion in that it doesn't consume an argument, it 267 // just takes the current value of errno as its argument. 268 section.conv_val_raw = static_cast<int>(libc_errno); 269 break; 270 #endif // LIBC_COPT_PRINTF_DISABLE_STRERROR 271 #ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT 272 case ('n'): // Intentional fallthrough 273 #endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT 274 case ('p'): 275 WRITE_ARG_VAL_SIMPLEST(section.conv_val_ptr, void *, conv_index); 276 break; 277 case ('s'): 278 WRITE_ARG_VAL_SIMPLEST(section.conv_val_ptr, char *, conv_index); 279 break; 280 default: 281 // if the conversion is undefined, change this to a raw section. 282 section.has_conv = false; 283 break; 284 } 285 // If the end of the format section is on the '\0'. This means we need to 286 // not advance the cur_pos. 287 if (str[cur_pos] != '\0') 288 ++cur_pos; 289 290 } else { 291 // raw section 292 section.has_conv = false; 293 while (str[cur_pos] != '%' && str[cur_pos] != '\0') 294 ++cur_pos; 295 } 296 section.raw_string = {str + starting_pos, cur_pos - starting_pos}; 297 return section; 298 } 299 300 private: 301 // parse_flags parses the flags inside a format string. It assumes that 302 // str[*local_pos] is inside a format specifier, and parses any flags it 303 // finds. It returns a FormatFlags object containing the set of found flags 304 // arithmetically or'd together. local_pos will be moved past any flags found. 305 LIBC_INLINE FormatFlags parse_flags(size_t *local_pos) { 306 bool found_flag = true; 307 FormatFlags flags = FormatFlags(0); 308 while (found_flag) { 309 switch (str[*local_pos]) { 310 case '-': 311 flags = static_cast<FormatFlags>(flags | FormatFlags::LEFT_JUSTIFIED); 312 break; 313 case '+': 314 flags = static_cast<FormatFlags>(flags | FormatFlags::FORCE_SIGN); 315 break; 316 case ' ': 317 flags = static_cast<FormatFlags>(flags | FormatFlags::SPACE_PREFIX); 318 break; 319 case '#': 320 flags = static_cast<FormatFlags>(flags | FormatFlags::ALTERNATE_FORM); 321 break; 322 case '0': 323 flags = static_cast<FormatFlags>(flags | FormatFlags::LEADING_ZEROES); 324 break; 325 default: 326 found_flag = false; 327 } 328 if (found_flag) 329 ++*local_pos; 330 } 331 return flags; 332 } 333 334 // parse_length_modifier parses the length modifier inside a format string. It 335 // assumes that str[*local_pos] is inside a format specifier. It returns a 336 // LengthModifier with the length modifier it found. It will advance local_pos 337 // after the format specifier if one is found. 338 LIBC_INLINE LengthSpec parse_length_modifier(size_t *local_pos) { 339 switch (str[*local_pos]) { 340 case ('l'): 341 if (str[*local_pos + 1] == 'l') { 342 *local_pos += 2; 343 return {LengthModifier::ll, 0}; 344 } else { 345 ++*local_pos; 346 return {LengthModifier::l, 0}; 347 } 348 case ('w'): { 349 LengthModifier lm; 350 if (str[*local_pos + 1] == 'f') { 351 *local_pos += 2; 352 lm = LengthModifier::wf; 353 } else { 354 ++*local_pos; 355 lm = LengthModifier::w; 356 } 357 if (internal::isdigit(str[*local_pos])) { 358 const auto result = internal::strtointeger<int>(str + *local_pos, 10); 359 *local_pos += result.parsed_len; 360 return {lm, static_cast<size_t>(cpp::max(0, result.value))}; 361 } 362 return {lm, 0}; 363 } 364 case ('h'): 365 if (str[*local_pos + 1] == 'h') { 366 *local_pos += 2; 367 return {LengthModifier::hh, 0}; 368 } else { 369 ++*local_pos; 370 return {LengthModifier::h, 0}; 371 } 372 case ('L'): 373 ++*local_pos; 374 return {LengthModifier::L, 0}; 375 case ('j'): 376 ++*local_pos; 377 return {LengthModifier::j, 0}; 378 case ('z'): 379 ++*local_pos; 380 return {LengthModifier::z, 0}; 381 case ('t'): 382 ++*local_pos; 383 return {LengthModifier::t, 0}; 384 default: 385 return {LengthModifier::none, 0}; 386 } 387 } 388 389 // get_next_arg_value gets the next value from the arg list as type T. 390 template <class T> LIBC_INLINE T get_next_arg_value() { 391 return args_cur.template next_var<T>(); 392 } 393 394 //---------------------------------------------------- 395 // INDEX MODE ONLY FUNCTIONS AFTER HERE: 396 //---------------------------------------------------- 397 398 #ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE 399 400 // parse_index parses the index of a value inside a format string. It 401 // assumes that str[*local_pos] points to character after a '%' or '*', and 402 // returns 0 if there is no closing $, or if it finds no number. If it finds a 403 // number, it will move local_pos past the end of the $, else it will not move 404 // local_pos. 405 LIBC_INLINE size_t parse_index(size_t *local_pos) { 406 if (internal::isdigit(str[*local_pos])) { 407 auto result = internal::strtointeger<int>(str + *local_pos, 10); 408 size_t index = result.value; 409 if (str[*local_pos + result.parsed_len] != '$') 410 return 0; 411 *local_pos = 1 + result.parsed_len + *local_pos; 412 return index; 413 } 414 return 0; 415 } 416 417 LIBC_INLINE void set_type_desc(size_t index, TypeDesc value) { 418 if (index != 0 && index <= DESC_ARR_LEN) 419 desc_arr[index - 1] = value; 420 } 421 422 // get_arg_value gets the value from the arg list at index (starting at 1). 423 // This may require parsing the format string. An index of 0 is interpreted as 424 // the next value. If the format string is not valid, it may have gaps in its 425 // indexes. Requesting the value for any index after a gap will fail, since 426 // the arg list must be read in order and with the correct types. 427 template <class T> LIBC_INLINE cpp::optional<T> get_arg_value(size_t index) { 428 if (!(index == 0 || index == args_index)) { 429 bool success = args_to_index(index); 430 if (!success) { 431 // If we can't get to this index, then the value of the arg can't be 432 // found. 433 return cpp::optional<T>(); 434 } 435 } 436 437 set_type_desc(index, type_desc_from_type<T>()); 438 439 ++args_index; 440 return get_next_arg_value<T>(); 441 } 442 443 // the ArgProvider can only return the next item in the list. This function is 444 // used in index mode when the item that needs to be read is not the next one. 445 // It moves cur_args to the index requested so the appropriate value may 446 // be read. This may involve parsing the format string, and is in the worst 447 // case an O(n^2) operation. 448 LIBC_INLINE bool args_to_index(size_t index) { 449 if (args_index > index) { 450 args_index = 1; 451 args_cur = args_start; 452 } 453 454 while (args_index < index) { 455 TypeDesc cur_type_desc = type_desc_from_type<void>(); 456 if (args_index <= DESC_ARR_LEN) 457 cur_type_desc = desc_arr[args_index - 1]; 458 459 if (cur_type_desc == type_desc_from_type<void>()) 460 cur_type_desc = get_type_desc(args_index); 461 462 // A type of void represents the type being unknown. If the type for the 463 // requested index isn't in the desc_arr and isn't found by parsing the 464 // string, then then advancing to the requested index is impossible. In 465 // that case the function returns false. 466 if (cur_type_desc == type_desc_from_type<void>()) 467 return false; 468 469 if (cur_type_desc == type_desc_from_type<uint32_t>()) 470 args_cur.template next_var<uint32_t>(); 471 else if (cur_type_desc == type_desc_from_type<uint64_t>()) 472 args_cur.template next_var<uint64_t>(); 473 #ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT 474 // Floating point numbers are stored separately from the other arguments. 475 else if (cur_type_desc == type_desc_from_type<double>()) 476 args_cur.template next_var<double>(); 477 else if (cur_type_desc == type_desc_from_type<long double>()) 478 args_cur.template next_var<long double>(); 479 #endif // LIBC_COPT_PRINTF_DISABLE_FLOAT 480 #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT 481 // Floating point numbers may be stored separately from the other 482 // arguments. 483 else if (cur_type_desc == type_desc_from_type<short fract>()) 484 args_cur.template next_var<short fract>(); 485 else if (cur_type_desc == type_desc_from_type<fract>()) 486 args_cur.template next_var<fract>(); 487 else if (cur_type_desc == type_desc_from_type<long fract>()) 488 args_cur.template next_var<long fract>(); 489 else if (cur_type_desc == type_desc_from_type<short accum>()) 490 args_cur.template next_var<short accum>(); 491 else if (cur_type_desc == type_desc_from_type<accum>()) 492 args_cur.template next_var<accum>(); 493 else if (cur_type_desc == type_desc_from_type<long accum>()) 494 args_cur.template next_var<long accum>(); 495 #endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT 496 // pointers may be stored separately from normal values. 497 else if (cur_type_desc == type_desc_from_type<void *>()) 498 args_cur.template next_var<void *>(); 499 else 500 args_cur.template next_var<uint32_t>(); 501 502 ++args_index; 503 } 504 return true; 505 } 506 507 // get_type_desc assumes that this format string uses index mode. It iterates 508 // through the format string until it finds a format specifier that defines 509 // the type of index, and returns a TypeDesc describing that type. It does not 510 // modify cur_pos. 511 LIBC_INLINE TypeDesc get_type_desc(size_t index) { 512 // index mode is assumed, and the indices start at 1, so an index 513 // of 0 is invalid. 514 size_t local_pos = 0; 515 516 while (str[local_pos]) { 517 if (str[local_pos] == '%') { 518 ++local_pos; 519 520 size_t conv_index = parse_index(&local_pos); 521 522 // the flags aren't relevant for this situation, but I need to skip past 523 // them so they're parsed but the result is discarded. 524 parse_flags(&local_pos); 525 526 // handle width 527 if (str[local_pos] == '*') { 528 ++local_pos; 529 530 size_t width_index = parse_index(&local_pos); 531 set_type_desc(width_index, type_desc_from_type<int>()); 532 if (width_index == index) 533 return type_desc_from_type<int>(); 534 535 } else if (internal::isdigit(str[local_pos])) { 536 while (internal::isdigit(str[local_pos])) 537 ++local_pos; 538 } 539 540 // handle precision 541 if (str[local_pos] == '.') { 542 ++local_pos; 543 if (str[local_pos] == '*') { 544 ++local_pos; 545 546 size_t precision_index = parse_index(&local_pos); 547 set_type_desc(precision_index, type_desc_from_type<int>()); 548 if (precision_index == index) 549 return type_desc_from_type<int>(); 550 551 } else if (internal::isdigit(str[local_pos])) { 552 while (internal::isdigit(str[local_pos])) 553 ++local_pos; 554 } 555 } 556 557 auto [lm, bw] = parse_length_modifier(&local_pos); 558 559 // if we don't have an index for this conversion, then its position is 560 // unknown and all this information is irrelevant. The rest of this 561 // logic has been for skipping past this conversion properly to avoid 562 // weirdness with %%. 563 if (conv_index == 0) { 564 if (str[local_pos] != '\0') 565 ++local_pos; 566 continue; 567 } 568 569 TypeDesc conv_size = type_desc_from_type<void>(); 570 switch (str[local_pos]) { 571 case ('%'): 572 conv_size = type_desc_from_type<void>(); 573 break; 574 case ('c'): 575 conv_size = type_desc_from_type<int>(); 576 break; 577 case ('d'): 578 case ('i'): 579 case ('o'): 580 case ('x'): 581 case ('X'): 582 case ('u'): 583 case ('b'): 584 case ('B'): 585 switch (lm) { 586 case (LengthModifier::hh): 587 case (LengthModifier::h): 588 case (LengthModifier::none): 589 conv_size = type_desc_from_type<int>(); 590 break; 591 case (LengthModifier::l): 592 conv_size = type_desc_from_type<long>(); 593 break; 594 case (LengthModifier::ll): 595 case (LengthModifier::L): // This isn't in the standard, but is in 596 // other libc implementations. 597 conv_size = type_desc_from_type<long long>(); 598 break; 599 case (LengthModifier::j): 600 conv_size = type_desc_from_type<intmax_t>(); 601 break; 602 case (LengthModifier::z): 603 conv_size = type_desc_from_type<size_t>(); 604 break; 605 case (LengthModifier::t): 606 conv_size = type_desc_from_type<ptrdiff_t>(); 607 break; 608 case (LengthModifier::w): 609 case (LengthModifier::wf): 610 if (bw <= cpp::numeric_limits<unsigned int>::digits) { 611 conv_size = type_desc_from_type<int>(); 612 } else if (bw <= cpp::numeric_limits<unsigned long>::digits) { 613 conv_size = type_desc_from_type<long>(); 614 } else if (bw <= cpp::numeric_limits<unsigned long long>::digits) { 615 conv_size = type_desc_from_type<long long>(); 616 } else { 617 conv_size = type_desc_from_type<intmax_t>(); 618 } 619 break; 620 } 621 break; 622 #ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT 623 case ('f'): 624 case ('F'): 625 case ('e'): 626 case ('E'): 627 case ('a'): 628 case ('A'): 629 case ('g'): 630 case ('G'): 631 if (lm != LengthModifier::L) 632 conv_size = type_desc_from_type<double>(); 633 else 634 conv_size = type_desc_from_type<long double>(); 635 break; 636 #endif // LIBC_COPT_PRINTF_DISABLE_FLOAT 637 #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT 638 // Capitalization represents sign, but we only need to get the right 639 // bitwidth here so we ignore that. 640 case ('r'): 641 case ('R'): 642 conv_size = type_desc_from_type<uint32_t>(); 643 break; 644 case ('k'): 645 case ('K'): 646 if (lm == LengthModifier::l) { 647 conv_size = type_desc_from_type<uint64_t>(); 648 } else { 649 conv_size = type_desc_from_type<uint32_t>(); 650 } 651 break; 652 #endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT 653 #ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT 654 case ('n'): 655 #endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT 656 case ('p'): 657 case ('s'): 658 conv_size = type_desc_from_type<void *>(); 659 break; 660 default: 661 conv_size = type_desc_from_type<int>(); 662 break; 663 } 664 665 set_type_desc(conv_index, conv_size); 666 if (conv_index == index) 667 return conv_size; 668 } 669 // If the end of the format section is on the '\0'. This means we need to 670 // not advance the local_pos. 671 if (str[local_pos] != '\0') 672 ++local_pos; 673 } 674 675 // If there is no size for the requested index, then it's unknown. Return 676 // void. 677 return type_desc_from_type<void>(); 678 } 679 680 #endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE 681 }; 682 683 } // namespace printf_core 684 } // namespace LIBC_NAMESPACE_DECL 685 686 #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PARSER_H 687