brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.1 KiB · 53cb7e5 Raw
245 lines · c
1//===-- Composite converter for strftime ------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See htto_conv.times://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_STRFTIME_CORE_COMPOSITE_CONVERTER_H10#define LLVM_LIBC_SRC_STDIO_STRFTIME_CORE_COMPOSITE_CONVERTER_H11 12#include "hdr/types/struct_tm.h"13#include "src/__support/CPP/string_view.h"14#include "src/__support/macros/config.h"15#include "src/stdio/printf_core/writer.h"16#include "src/time/strftime_core/core_structs.h"17#include "src/time/strftime_core/num_converter.h"18#include "src/time/strftime_core/str_converter.h"19#include "src/time/time_constants.h"20#include "src/time/time_utils.h"21 22namespace LIBC_NAMESPACE_DECL {23namespace strftime_core {24 25LIBC_INLINE IntFormatSection26get_specific_int_format(const tm *timeptr, const FormatSection &base_to_conv,27                        char new_conv_name, int TRAILING_CONV_LEN = -1) {28  // a negative padding will be treated as the default29  const int NEW_MIN_WIDTH =30      TRAILING_CONV_LEN > 0 ? base_to_conv.min_width - TRAILING_CONV_LEN : 0;31  FormatSection new_conv = base_to_conv;32  new_conv.conv_name = new_conv_name;33  new_conv.min_width = NEW_MIN_WIDTH;34 35  IntFormatSection result = get_int_format(new_conv, timeptr);36 37  // If the user set the padding, but it's below the width of the trailing38  // conversions, then there should be no padding.39  if (base_to_conv.min_width > 0 && NEW_MIN_WIDTH < 0)40    result.pad_to_len = 0;41 42  return result;43}44 45template <printf_core::WriteMode write_mode>46LIBC_INLINE int convert_date_us(printf_core::Writer<write_mode> *writer,47                                const FormatSection &to_conv,48                                const tm *timeptr) {49  // format is %m/%d/%y (month/day/year)50  // we only pad the first conversion, and we assume all the other values are in51  // their valid ranges.52  constexpr int TRAILING_CONV_LEN = 1 + 2 + 1 + 2; // sizeof("/01/02")53  IntFormatSection year_conv;54  IntFormatSection mon_conv;55  IntFormatSection mday_conv;56 57  mon_conv = get_specific_int_format(timeptr, to_conv, 'm', TRAILING_CONV_LEN);58  mday_conv = get_specific_int_format(timeptr, to_conv, 'd');59  year_conv = get_specific_int_format(timeptr, to_conv, 'y');60 61  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, mon_conv));62  RET_IF_RESULT_NEGATIVE(writer->write('/'));63  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, mday_conv));64  RET_IF_RESULT_NEGATIVE(writer->write('/'));65  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, year_conv));66 67  return WRITE_OK;68}69 70template <printf_core::WriteMode write_mode>71LIBC_INLINE int convert_date_iso(printf_core::Writer<write_mode> *writer,72                                 const FormatSection &to_conv,73                                 const tm *timeptr) {74  // format is "%Y-%m-%d" (year-month-day)75  // we only pad the first conversion, and we assume all the other values are in76  // their valid ranges.77  constexpr int TRAILING_CONV_LEN = 1 + 2 + 1 + 2; // sizeof("-01-02")78  IntFormatSection year_conv;79  IntFormatSection mon_conv;80  IntFormatSection mday_conv;81 82  year_conv = get_specific_int_format(timeptr, to_conv, 'Y', TRAILING_CONV_LEN);83  mon_conv = get_specific_int_format(timeptr, to_conv, 'm');84  mday_conv = get_specific_int_format(timeptr, to_conv, 'd');85 86  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, year_conv));87  RET_IF_RESULT_NEGATIVE(writer->write('-'));88  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, mon_conv));89  RET_IF_RESULT_NEGATIVE(writer->write('-'));90  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, mday_conv));91 92  return WRITE_OK;93}94 95template <printf_core::WriteMode write_mode>96LIBC_INLINE int convert_time_am_pm(printf_core::Writer<write_mode> *writer,97                                   const FormatSection &to_conv,98                                   const tm *timeptr) {99  // format is "%I:%M:%S %p" (hour:minute:second AM/PM)100  // we only pad the first conversion, and we assume all the other values are in101  // their valid ranges.102  constexpr int TRAILING_CONV_LEN =103      1 + 2 + 1 + 2 + 1 + 2; // sizeof(":01:02 AM")104  IntFormatSection hour_conv;105  IntFormatSection min_conv;106  IntFormatSection sec_conv;107 108  const time_utils::TMReader time_reader(timeptr);109 110  hour_conv = get_specific_int_format(timeptr, to_conv, 'I', TRAILING_CONV_LEN);111  min_conv = get_specific_int_format(timeptr, to_conv, 'M');112  sec_conv = get_specific_int_format(timeptr, to_conv, 'S');113 114  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, hour_conv));115  RET_IF_RESULT_NEGATIVE(writer->write(':'));116  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, min_conv));117  RET_IF_RESULT_NEGATIVE(writer->write(':'));118  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, sec_conv));119  RET_IF_RESULT_NEGATIVE(writer->write(' '));120  RET_IF_RESULT_NEGATIVE(writer->write(time_reader.get_am_pm()));121 122  return WRITE_OK;123}124 125template <printf_core::WriteMode write_mode>126LIBC_INLINE int convert_time_minute(printf_core::Writer<write_mode> *writer,127                                    const FormatSection &to_conv,128                                    const tm *timeptr) {129  // format is "%H:%M" (hour:minute)130  // we only pad the first conversion, and we assume all the other values are in131  // their valid ranges.132  constexpr int TRAILING_CONV_LEN = 1 + 2; // sizeof(":01")133  IntFormatSection hour_conv;134  IntFormatSection min_conv;135 136  hour_conv = get_specific_int_format(timeptr, to_conv, 'H', TRAILING_CONV_LEN);137  min_conv = get_specific_int_format(timeptr, to_conv, 'M');138 139  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, hour_conv));140  RET_IF_RESULT_NEGATIVE(writer->write(':'));141  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, min_conv));142 143  return WRITE_OK;144}145 146template <printf_core::WriteMode write_mode>147LIBC_INLINE int convert_time_second(printf_core::Writer<write_mode> *writer,148                                    const FormatSection &to_conv,149                                    const tm *timeptr) {150  // format is "%H:%M:%S" (hour:minute:second)151  // we only pad the first conversion, and we assume all the other values are in152  // their valid ranges.153  constexpr int TRAILING_CONV_LEN = 1 + 2 + 1 + 2; // sizeof(":01:02")154  IntFormatSection hour_conv;155  IntFormatSection min_conv;156  IntFormatSection sec_conv;157 158  hour_conv = get_specific_int_format(timeptr, to_conv, 'H', TRAILING_CONV_LEN);159  min_conv = get_specific_int_format(timeptr, to_conv, 'M');160  sec_conv = get_specific_int_format(timeptr, to_conv, 'S');161 162  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, hour_conv));163  RET_IF_RESULT_NEGATIVE(writer->write(':'));164  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, min_conv));165  RET_IF_RESULT_NEGATIVE(writer->write(':'));166  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, sec_conv));167 168  return WRITE_OK;169}170 171template <printf_core::WriteMode write_mode>172LIBC_INLINE int convert_full_date_time(printf_core::Writer<write_mode> *writer,173                                       const FormatSection &to_conv,174                                       const tm *timeptr) {175  const time_utils::TMReader time_reader(timeptr);176  // format is "%a %b %e %T %Y" (weekday month mday [time] year)177  // we only pad the first conversion, and we assume all the other values are in178  // their valid ranges.179  // sizeof("Sun Jan 12 03:45:06 2025")180  constexpr int FULL_CONV_LEN = 3 + 1 + 3 + 1 + 2 + 1 + 8 + 1 + 4;181  // use the full conv len because this isn't being passed to a proper converter182  // that will handle the width of the leading conversion. Instead it has to be183  // handled below.184  const int requested_padding = to_conv.min_width - FULL_CONV_LEN;185 186  cpp::string_view wday_str = unwrap_opt(time_reader.get_weekday_short_name());187  cpp::string_view month_str = unwrap_opt(time_reader.get_month_short_name());188  IntFormatSection mday_conv;189  IntFormatSection year_conv;190 191  mday_conv = get_specific_int_format(timeptr, to_conv, 'e');192  year_conv = get_specific_int_format(timeptr, to_conv, 'Y');193 194  FormatSection raw_time_conv = to_conv;195  raw_time_conv.conv_name = 'T';196  raw_time_conv.min_width = 0;197 198  if (requested_padding > 0)199    RET_IF_RESULT_NEGATIVE(writer->write(' ', requested_padding));200  RET_IF_RESULT_NEGATIVE(writer->write(wday_str));201  RET_IF_RESULT_NEGATIVE(writer->write(' '));202  RET_IF_RESULT_NEGATIVE(writer->write(month_str));203  RET_IF_RESULT_NEGATIVE(writer->write(' '));204  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, mday_conv));205  RET_IF_RESULT_NEGATIVE(writer->write(' '));206  RET_IF_RESULT_NEGATIVE(convert_time_second(writer, raw_time_conv, timeptr));207  RET_IF_RESULT_NEGATIVE(writer->write(' '));208  RET_IF_RESULT_NEGATIVE(write_padded_int(writer, year_conv));209 210  return WRITE_OK;211}212 213template <printf_core::WriteMode write_mode>214LIBC_INLINE int convert_composite(printf_core::Writer<write_mode> *writer,215                                  const FormatSection &to_conv,216                                  const tm *timeptr) {217  switch (to_conv.conv_name) {218  case 'c': // locale specified date and time219            // in default locale Equivalent to %a %b %e %T %Y.220    return convert_full_date_time(writer, to_conv, timeptr);221  case 'D': // %m/%d/%y (month/day/year)222    return convert_date_us(writer, to_conv, timeptr);223  case 'F': // %Y-%m-%d (year-month-day)224    return convert_date_iso(writer, to_conv, timeptr);225  case 'r': // %I:%M:%S %p (hour:minute:second AM/PM)226    return convert_time_am_pm(writer, to_conv, timeptr);227  case 'R': // %H:%M (hour:minute)228    return convert_time_minute(writer, to_conv, timeptr);229  case 'T': // %H:%M:%S (hour:minute:second)230    return convert_time_second(writer, to_conv, timeptr);231  case 'x': // locale specified date232            // in default locale Equivalent to %m/%d/%y. (same as %D)233    return convert_date_us(writer, to_conv, timeptr);234  case 'X': // locale specified time235            // in default locale Equivalent to %T.236    return convert_time_second(writer, to_conv, timeptr);237  default:238    __builtin_trap(); // this should be unreachable, but trap if you hit it.239  }240}241} // namespace strftime_core242} // namespace LIBC_NAMESPACE_DECL243 244#endif // LLVM_LIBC_SRC_STDIO_STRFTIME_CORE_COMPOSITE_CONVERTER_H245