brintos

brintos / llvm-project-archived public Read only

0
0
Text · 24.8 KiB · cef9b1a Raw
689 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PARSER_H10#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PARSER_H11 12#include "include/llvm-libc-macros/stdfix-macros.h"13#include "src/__support/CPP/algorithm.h" // max14#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_POINT25#include "src/__support/fixed_point/fx_rep.h"26#endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT27#ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR28#include "src/__support/libc_errno.h"29#endif // LIBC_COPT_PRINTF_DISABLE_STRERROR30 31namespace LIBC_NAMESPACE_DECL {32namespace printf_core {33 34template <typename T> struct int_type_of {35  using type = T;36};37template <> struct int_type_of<double> {38  using type = fputil::FPBits<double>::StorageType;39};40template <> struct int_type_of<long double> {41  using type = fputil::FPBits<long double>::StorageType;42};43 44#ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT45template <typename T>46struct 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_POINT50 51template <typename T> using int_type_of_v = typename int_type_of<T>::type;52 53#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE54#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 = static_cast<decltype(dst)>(                                        \61          cpp::bit_cast<int_type_of_v<arg_type>>(temp.value()));               \62    }                                                                          \63  }64#else65#define WRITE_ARG_VAL_SIMPLEST(dst, arg_type, _)                               \66  dst = cpp::bit_cast<int_type_of_v<arg_type>>(get_next_arg_value<arg_type>())67#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE68 69template <typename ArgProvider> class Parser {70  const char *__restrict str;71 72  size_t cur_pos = 0;73  ArgProvider args_cur;74 75#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE76  // args_start stores the start of the va_args, which is allows getting the77  // value of arguments that have already been passed. args_index is tracked so78  // that we know which argument args_cur is on.79  ArgProvider args_start;80  size_t args_index = 1;81 82  // Defined in printf_config.h83  static constexpr size_t DESC_ARR_LEN = LIBC_COPT_PRINTF_INDEX_ARR_LEN;84 85  // desc_arr stores the sizes of the variables in the ArgProvider. This is used86  // in index mode to reduce repeated string parsing. The sizes are stored as87  // TypeDesc objects, which store the size as well as minimal type information.88  // This is necessary because some systems separate the floating point and89  // integer values in va_args.90  TypeDesc desc_arr[DESC_ARR_LEN] = {type_desc_from_type<void>()};91 92  // TODO: Look into object stores for optimization.93 94#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE95 96public:97#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE98  LIBC_INLINE Parser(const char *__restrict new_str, ArgProvider &args)99      : str(new_str), args_cur(args), args_start(args) {}100#else101  LIBC_INLINE Parser(const char *__restrict new_str, ArgProvider &args)102      : str(new_str), args_cur(args) {}103#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE104 105  // get_next_section will parse the format string until it has a fully106  // specified format section. This can either be a raw format section with no107  // conversion, or a format section with a conversion that has all of its108  // variables stored in the format section.109  LIBC_INLINE FormatSection get_next_section() {110    FormatSection section;111    size_t starting_pos = cur_pos;112    if (str[cur_pos] == '%') {113      // format section114      section.has_conv = true;115 116      ++cur_pos;117      [[maybe_unused]] size_t conv_index = 0;118 119#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE120      conv_index = parse_index(&cur_pos);121#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE122 123      section.flags = parse_flags(&cur_pos);124 125      // handle width126      section.min_width = 0;127      if (str[cur_pos] == '*') {128        ++cur_pos;129 130        WRITE_ARG_VAL_SIMPLEST(section.min_width, int, parse_index(&cur_pos));131      } else if (internal::isdigit(str[cur_pos])) {132        auto result = internal::strtointeger<int>(str + cur_pos, 10);133        section.min_width = result.value;134        cur_pos = cur_pos + static_cast<size_t>(result.parsed_len);135      }136      if (section.min_width < 0) {137        section.min_width =138            (section.min_width == INT_MIN) ? INT_MAX : -section.min_width;139        section.flags = static_cast<FormatFlags>(section.flags |140                                                 FormatFlags::LEFT_JUSTIFIED);141      }142 143      // handle precision144      section.precision = -1; // negative precisions are ignored.145      if (str[cur_pos] == '.') {146        ++cur_pos;147        section.precision = 0; // if there's a . but no specified precision, the148                               // precision is implicitly 0.149        if (str[cur_pos] == '*') {150          ++cur_pos;151 152          WRITE_ARG_VAL_SIMPLEST(section.precision, int, parse_index(&cur_pos));153 154        } else if (internal::isdigit(str[cur_pos])) {155          auto result = internal::strtointeger<int>(str + cur_pos, 10);156          section.precision = result.value;157          cur_pos = cur_pos + static_cast<size_t>(result.parsed_len);158        }159      }160 161      auto [lm, bw] = parse_length_modifier(&cur_pos);162      section.length_modifier = lm;163      section.conv_name = str[cur_pos];164      section.bit_width = bw;165      switch (str[cur_pos]) {166      case ('%'):167        // Regardless of options, a % conversion is always safe. The standard168        // says that "The complete conversion specification shall be %%" but it169        // also says that "If a conversion specification is invalid, the170        // behavior is undefined." Based on that we define that any conversion171        // specification ending in '%' shall display as '%' regardless of any172        // valid or invalid options.173        section.has_conv = true;174        break;175      case ('c'):176        WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index);177        break;178      case ('d'):179      case ('i'):180      case ('o'):181      case ('x'):182      case ('X'):183      case ('u'):184      case ('b'):185      case ('B'):186        switch (lm) {187        case (LengthModifier::hh):188        case (LengthModifier::h):189        case (LengthModifier::none):190          WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index);191          break;192        case (LengthModifier::l):193          WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long, conv_index);194          break;195        case (LengthModifier::ll):196        case (LengthModifier::L): // This isn't in the standard, but is in other197                                  // libc implementations.198 199          WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long long, conv_index);200          break;201        case (LengthModifier::j):202 203          WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, intmax_t, conv_index);204          break;205        case (LengthModifier::z):206 207          WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, size_t, conv_index);208          break;209        case (LengthModifier::t):210 211          WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, ptrdiff_t, conv_index);212          break;213 214        case (LengthModifier::w):215        case (LengthModifier::wf):216          if (bw == 0) {217            section.has_conv = false;218          } else if (bw <= cpp::numeric_limits<unsigned int>::digits) {219            WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index);220          } else if (bw <= cpp::numeric_limits<unsigned long>::digits) {221            WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long, conv_index);222          } else if (bw <= cpp::numeric_limits<unsigned long long>::digits) {223            WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long long, conv_index);224          } else {225            WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, intmax_t, conv_index);226          }227          break;228        }229        break;230#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT231      case ('f'):232      case ('F'):233      case ('e'):234      case ('E'):235      case ('a'):236      case ('A'):237      case ('g'):238      case ('G'):239        if (lm != LengthModifier::L) {240          WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, double, conv_index);241        } else {242          WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long double, conv_index);243        }244        break;245#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT246#ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT247      // Capitalization represents sign, but we only need to get the right248      // bitwidth here so we ignore that.249      case ('r'):250      case ('R'):251        // all fract sizes we support are less than 32 bits, and currently doing252        // va_args with fixed point types just doesn't work.253        // TODO: Move to fixed point types once va_args supports it.254        WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, uint32_t, conv_index);255        break;256      case ('k'):257      case ('K'):258        if (lm == LengthModifier::l) {259          WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, uint64_t, conv_index);260        } else {261          WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, uint32_t, conv_index);262        }263        break;264#endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT265#ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR266      case ('m'):267        // %m is an odd conversion in that it doesn't consume an argument, it268        // just takes the current value of errno as its argument.269        section.conv_val_raw =270            static_cast<fputil::FPBits<double>::StorageType>(libc_errno);271        break;272#endif // LIBC_COPT_PRINTF_DISABLE_STRERROR273#ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT274      case ('n'): // Intentional fallthrough275#endif            // LIBC_COPT_PRINTF_DISABLE_WRITE_INT276      case ('p'):277        WRITE_ARG_VAL_SIMPLEST(section.conv_val_ptr, void *, conv_index);278        break;279      case ('s'):280        WRITE_ARG_VAL_SIMPLEST(section.conv_val_ptr, char *, conv_index);281        break;282      default:283        // if the conversion is undefined, change this to a raw section.284        section.has_conv = false;285        break;286      }287      // If the end of the format section is on the '\0'. This means we need to288      // not advance the cur_pos.289      if (str[cur_pos] != '\0')290        ++cur_pos;291 292    } else {293      // raw section294      section.has_conv = false;295      while (str[cur_pos] != '%' && str[cur_pos] != '\0')296        ++cur_pos;297    }298    section.raw_string = {str + starting_pos, cur_pos - starting_pos};299    return section;300  }301 302private:303  // parse_flags parses the flags inside a format string. It assumes that304  // str[*local_pos] is inside a format specifier, and parses any flags it305  // finds. It returns a FormatFlags object containing the set of found flags306  // arithmetically or'd together. local_pos will be moved past any flags found.307  LIBC_INLINE FormatFlags parse_flags(size_t *local_pos) {308    bool found_flag = true;309    FormatFlags flags = FormatFlags(0);310    while (found_flag) {311      switch (str[*local_pos]) {312      case '-':313        flags = static_cast<FormatFlags>(flags | FormatFlags::LEFT_JUSTIFIED);314        break;315      case '+':316        flags = static_cast<FormatFlags>(flags | FormatFlags::FORCE_SIGN);317        break;318      case ' ':319        flags = static_cast<FormatFlags>(flags | FormatFlags::SPACE_PREFIX);320        break;321      case '#':322        flags = static_cast<FormatFlags>(flags | FormatFlags::ALTERNATE_FORM);323        break;324      case '0':325        flags = static_cast<FormatFlags>(flags | FormatFlags::LEADING_ZEROES);326        break;327      default:328        found_flag = false;329      }330      if (found_flag)331        ++*local_pos;332    }333    return flags;334  }335 336  // parse_length_modifier parses the length modifier inside a format string. It337  // assumes that str[*local_pos] is inside a format specifier. It returns a338  // LengthModifier with the length modifier it found. It will advance local_pos339  // after the format specifier if one is found.340  LIBC_INLINE LengthSpec parse_length_modifier(size_t *local_pos) {341    switch (str[*local_pos]) {342    case ('l'):343      if (str[*local_pos + 1] == 'l') {344        *local_pos += 2;345        return {LengthModifier::ll, 0};346      } else {347        ++*local_pos;348        return {LengthModifier::l, 0};349      }350    case ('w'): {351      LengthModifier lm;352      if (str[*local_pos + 1] == 'f') {353        *local_pos += 2;354        lm = LengthModifier::wf;355      } else {356        ++*local_pos;357        lm = LengthModifier::w;358      }359      if (internal::isdigit(str[*local_pos])) {360        const auto result = internal::strtointeger<int>(str + *local_pos, 10);361        *local_pos += static_cast<size_t>(result.parsed_len);362        return {lm, static_cast<size_t>(cpp::max(0, result.value))};363      }364      return {lm, 0};365    }366    case ('h'):367      if (str[*local_pos + 1] == 'h') {368        *local_pos += 2;369        return {LengthModifier::hh, 0};370      } else {371        ++*local_pos;372        return {LengthModifier::h, 0};373      }374    case ('L'):375      ++*local_pos;376      return {LengthModifier::L, 0};377    case ('j'):378      ++*local_pos;379      return {LengthModifier::j, 0};380    case ('z'):381      ++*local_pos;382      return {LengthModifier::z, 0};383    case ('t'):384      ++*local_pos;385      return {LengthModifier::t, 0};386    default:387      return {LengthModifier::none, 0};388    }389  }390 391  // get_next_arg_value gets the next value from the arg list as type T.392  template <class T> LIBC_INLINE T get_next_arg_value() {393    return args_cur.template next_var<T>();394  }395 396  //----------------------------------------------------397  // INDEX MODE ONLY FUNCTIONS AFTER HERE:398  //----------------------------------------------------399 400#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE401 402  // parse_index parses the index of a value inside a format string. It403  // assumes that str[*local_pos] points to character after a '%' or '*', and404  // returns 0 if there is no closing $, or if it finds no number. If it finds a405  // number, it will move local_pos past the end of the $, else it will not move406  // local_pos.407  LIBC_INLINE size_t parse_index(size_t *local_pos) {408    if (internal::isdigit(str[*local_pos])) {409      auto result = internal::strtointeger<int>(str + *local_pos, 10);410      size_t index = static_cast<size_t>(result.value);411      if (str[*local_pos + static_cast<size_t>(result.parsed_len)] != '$')412        return 0;413      *local_pos = static_cast<size_t>(1 + result.parsed_len) + *local_pos;414      return index;415    }416    return 0;417  }418 419  LIBC_INLINE void set_type_desc(size_t index, TypeDesc value) {420    if (index != 0 && index <= DESC_ARR_LEN)421      desc_arr[index - 1] = value;422  }423 424  // get_arg_value gets the value from the arg list at index (starting at 1).425  // This may require parsing the format string. An index of 0 is interpreted as426  // the next value. If the format string is not valid, it may have gaps in its427  // indexes. Requesting the value for any index after a gap will fail, since428  // the arg list must be read in order and with the correct types.429  template <class T> LIBC_INLINE cpp::optional<T> get_arg_value(size_t index) {430    if (!(index == 0 || index == args_index)) {431      bool success = args_to_index(index);432      if (!success) {433        // If we can't get to this index, then the value of the arg can't be434        // found.435        return cpp::optional<T>();436      }437    }438 439    set_type_desc(index, type_desc_from_type<T>());440 441    ++args_index;442    return get_next_arg_value<T>();443  }444 445  // the ArgProvider can only return the next item in the list. This function is446  // used in index mode when the item that needs to be read is not the next one.447  // It moves cur_args to the index requested so the appropriate value may448  // be read. This may involve parsing the format string, and is in the worst449  // case an O(n^2) operation.450  LIBC_INLINE bool args_to_index(size_t index) {451    if (args_index > index) {452      args_index = 1;453      args_cur = args_start;454    }455 456    while (args_index < index) {457      TypeDesc cur_type_desc = type_desc_from_type<void>();458      if (args_index <= DESC_ARR_LEN)459        cur_type_desc = desc_arr[args_index - 1];460 461      if (cur_type_desc == type_desc_from_type<void>())462        cur_type_desc = get_type_desc(args_index);463 464      // A type of void represents the type being unknown. If the type for the465      // requested index isn't in the desc_arr and isn't found by parsing the466      // string, then then advancing to the requested index is impossible. In467      // that case the function returns false.468      if (cur_type_desc == type_desc_from_type<void>())469        return false;470 471      if (cur_type_desc == type_desc_from_type<uint32_t>())472        args_cur.template next_var<uint32_t>();473      else if (cur_type_desc == type_desc_from_type<uint64_t>())474        args_cur.template next_var<uint64_t>();475#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT476      // Floating point numbers are stored separately from the other arguments.477      else if (cur_type_desc == type_desc_from_type<double>())478        args_cur.template next_var<double>();479      else if (cur_type_desc == type_desc_from_type<long double>())480        args_cur.template next_var<long double>();481#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT482#ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT483      // Floating point numbers may be stored separately from the other484      // arguments.485      else if (cur_type_desc == type_desc_from_type<short fract>())486        args_cur.template next_var<short fract>();487      else if (cur_type_desc == type_desc_from_type<fract>())488        args_cur.template next_var<fract>();489      else if (cur_type_desc == type_desc_from_type<long fract>())490        args_cur.template next_var<long fract>();491      else if (cur_type_desc == type_desc_from_type<short accum>())492        args_cur.template next_var<short accum>();493      else if (cur_type_desc == type_desc_from_type<accum>())494        args_cur.template next_var<accum>();495      else if (cur_type_desc == type_desc_from_type<long accum>())496        args_cur.template next_var<long accum>();497#endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT498      // pointers may be stored separately from normal values.499      else if (cur_type_desc == type_desc_from_type<void *>())500        args_cur.template next_var<void *>();501      else502        args_cur.template next_var<uint32_t>();503 504      ++args_index;505    }506    return true;507  }508 509  // get_type_desc assumes that this format string uses index mode. It iterates510  // through the format string until it finds a format specifier that defines511  // the type of index, and returns a TypeDesc describing that type. It does not512  // modify cur_pos.513  LIBC_INLINE TypeDesc get_type_desc(size_t index) {514    // index mode is assumed, and the indices start at 1, so an index515    // of 0 is invalid.516    size_t local_pos = 0;517 518    while (str[local_pos]) {519      if (str[local_pos] == '%') {520        ++local_pos;521 522        size_t conv_index = parse_index(&local_pos);523 524        // the flags aren't relevant for this situation, but I need to skip past525        // them so they're parsed but the result is discarded.526        parse_flags(&local_pos);527 528        // handle width529        if (str[local_pos] == '*') {530          ++local_pos;531 532          size_t width_index = parse_index(&local_pos);533          set_type_desc(width_index, type_desc_from_type<int>());534          if (width_index == index)535            return type_desc_from_type<int>();536 537        } else if (internal::isdigit(str[local_pos])) {538          while (internal::isdigit(str[local_pos]))539            ++local_pos;540        }541 542        // handle precision543        if (str[local_pos] == '.') {544          ++local_pos;545          if (str[local_pos] == '*') {546            ++local_pos;547 548            size_t precision_index = parse_index(&local_pos);549            set_type_desc(precision_index, type_desc_from_type<int>());550            if (precision_index == index)551              return type_desc_from_type<int>();552 553          } else if (internal::isdigit(str[local_pos])) {554            while (internal::isdigit(str[local_pos]))555              ++local_pos;556          }557        }558 559        auto [lm, bw] = parse_length_modifier(&local_pos);560 561        // if we don't have an index for this conversion, then its position is562        // unknown and all this information is irrelevant. The rest of this563        // logic has been for skipping past this conversion properly to avoid564        // weirdness with %%.565        if (conv_index == 0) {566          if (str[local_pos] != '\0')567            ++local_pos;568          continue;569        }570 571        TypeDesc conv_size = type_desc_from_type<void>();572        switch (str[local_pos]) {573        case ('%'):574          conv_size = type_desc_from_type<void>();575          break;576        case ('c'):577          conv_size = type_desc_from_type<int>();578          break;579        case ('d'):580        case ('i'):581        case ('o'):582        case ('x'):583        case ('X'):584        case ('u'):585        case ('b'):586        case ('B'):587          switch (lm) {588          case (LengthModifier::hh):589          case (LengthModifier::h):590          case (LengthModifier::none):591            conv_size = type_desc_from_type<int>();592            break;593          case (LengthModifier::l):594            conv_size = type_desc_from_type<long>();595            break;596          case (LengthModifier::ll):597          case (LengthModifier::L): // This isn't in the standard, but is in598                                    // other libc implementations.599            conv_size = type_desc_from_type<long long>();600            break;601          case (LengthModifier::j):602            conv_size = type_desc_from_type<intmax_t>();603            break;604          case (LengthModifier::z):605            conv_size = type_desc_from_type<size_t>();606            break;607          case (LengthModifier::t):608            conv_size = type_desc_from_type<ptrdiff_t>();609            break;610          case (LengthModifier::w):611          case (LengthModifier::wf):612            if (bw <= cpp::numeric_limits<unsigned int>::digits) {613              conv_size = type_desc_from_type<int>();614            } else if (bw <= cpp::numeric_limits<unsigned long>::digits) {615              conv_size = type_desc_from_type<long>();616            } else if (bw <= cpp::numeric_limits<unsigned long long>::digits) {617              conv_size = type_desc_from_type<long long>();618            } else {619              conv_size = type_desc_from_type<intmax_t>();620            }621            break;622          }623          break;624#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT625        case ('f'):626        case ('F'):627        case ('e'):628        case ('E'):629        case ('a'):630        case ('A'):631        case ('g'):632        case ('G'):633          if (lm != LengthModifier::L)634            conv_size = type_desc_from_type<double>();635          else636            conv_size = type_desc_from_type<long double>();637          break;638#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT639#ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT640        // Capitalization represents sign, but we only need to get the right641        // bitwidth here so we ignore that.642        case ('r'):643        case ('R'):644          conv_size = type_desc_from_type<uint32_t>();645          break;646        case ('k'):647        case ('K'):648          if (lm == LengthModifier::l) {649            conv_size = type_desc_from_type<uint64_t>();650          } else {651            conv_size = type_desc_from_type<uint32_t>();652          }653          break;654#endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT655#ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT656        case ('n'):657#endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT658        case ('p'):659        case ('s'):660          conv_size = type_desc_from_type<void *>();661          break;662        default:663          conv_size = type_desc_from_type<int>();664          break;665        }666 667        set_type_desc(conv_index, conv_size);668        if (conv_index == index)669          return conv_size;670      }671      // If the end of the format section is on the '\0'. This means we need to672      // not advance the local_pos.673      if (str[local_pos] != '\0')674        ++local_pos;675    }676 677    // If there is no size for the requested index, then it's unknown. Return678    // void.679    return type_desc_from_type<void>();680  }681 682#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE683};684 685} // namespace printf_core686} // namespace LIBC_NAMESPACE_DECL687 688#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PARSER_H689