-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc] Implement strftime #111305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc] Implement strftime #111305
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
//===-- Implementation of strftime function -------------------------------===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "src/time/strftime.h" | ||
#include "src/__support/common.h" | ||
#include "src/__support/macros/config.h" | ||
#include "src/errno/libc_errno.h" | ||
#include "src/time/time_utils.h" | ||
|
||
#include "src/stdio/printf_core/writer.h" | ||
#include "src/time/strftime_core/strftime_main.h" | ||
namespace LIBC_NAMESPACE_DECL { | ||
|
||
size_t strftime(char *__restrict buffer, size_t buffsz, | ||
const char *__restrict format, const struct tm *timeptr) { | ||
|
||
printf_core::WriteBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0), | ||
strftime_core::overflow_write_mock, nullptr); | ||
printf_core::Writer writer(&wb); | ||
int ret = strftime_core::strftime_main(&writer, format, timeptr); | ||
if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps before doing any work, we should explicitly validate the inputs? Then we could explicit check that the pointer parameters are not null, bufsz is not zero, etc. |
||
wb.buff[wb.buff_cur] = '\0'; | ||
return ret > 0 ? ret : 0; | ||
} | ||
|
||
} // namespace LIBC_NAMESPACE_DECL |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
//===-- Implementation header of strftime -----------------------*- C++ -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_LIBC_SRC_TIME_STRFTIME_H | ||
#define LLVM_LIBC_SRC_TIME_STRFTIME_H | ||
|
||
#include "src/__support/macros/config.h" | ||
#include <stddef.h> | ||
#include <time.h> | ||
|
||
namespace LIBC_NAMESPACE_DECL { | ||
|
||
size_t strftime(char *__restrict, size_t max, const char *__restrict format, | ||
const struct tm *timeptr); | ||
|
||
} // namespace LIBC_NAMESPACE_DECL | ||
|
||
#endif // LLVM_LIBC_SRC_TIME_STRFTIME_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
add_header_library( | ||
core_structs | ||
HDRS | ||
core_structs.h | ||
DEPENDS | ||
libc.src.__support.CPP.string_view | ||
libc.include.time | ||
) | ||
|
||
add_header_library( | ||
parser | ||
HDRS | ||
parser.h | ||
DEPENDS | ||
.core_structs | ||
libc.src.string.string_utils | ||
libc.include.time | ||
|
||
) | ||
|
||
add_object_library( | ||
converter | ||
SRCS | ||
converter.cpp | ||
HDRS | ||
converter.h | ||
num_converter.h | ||
str_converter.h | ||
composite_converter.h | ||
DEPENDS | ||
.core_structs | ||
libc.src.__support.arg_list | ||
libc.src.stdio.printf_core.writer | ||
libc.src.stdio.printf_core.printf_main | ||
libc.src.__support.big_int | ||
libc.src.__support.CPP.string_view | ||
libc.src.__support.float_to_string | ||
libc.src.__support.integer_to_string | ||
libc.src.__support.uint128 | ||
libc.src.__support.StringUtil.error_to_string | ||
libc.include.time | ||
|
||
) | ||
|
||
add_object_library( | ||
strftime_main | ||
SRCS | ||
strftime_main.cpp | ||
HDRS | ||
strftime_main.h | ||
DEPENDS | ||
.core_structs | ||
.parser | ||
.converter | ||
libc.src.stdio.printf_core.writer | ||
libc.include.time | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing newline. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
//===-- Format specifier converter for printf -------------------*- C++ -*-===// | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: fix this comment |
||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See htto_conv.times://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_LIBC_SRC_STDIO_STRFTIME_CORE_COMPOSITE_CONVERTER_H | ||
#define LLVM_LIBC_SRC_STDIO_STRFTIME_CORE_COMPOSITE_CONVERTER_H | ||
|
||
#include "src/__support/CPP/string_view.h" | ||
#include "src/__support/arg_list.h" | ||
#include "src/__support/integer_to_string.h" | ||
#include "src/__support/macros/config.h" | ||
#include "src/stdio/printf_core/printf_main.h" | ||
#include "src/stdio/printf_core/writer.h" | ||
#include "src/time/strftime_core/core_structs.h" | ||
#include "src/time/strftime_core/time_internal_def.h" | ||
|
||
namespace LIBC_NAMESPACE_DECL { | ||
namespace strftime_core { | ||
|
||
namespace details { | ||
int snprintf_impl(char *__restrict buffer, size_t buffsz, | ||
const char *__restrict format, ...) { | ||
va_list vlist; | ||
va_start(vlist, format); | ||
internal::ArgList args(vlist); | ||
va_end(vlist); | ||
printf_core::WriteBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0)); | ||
printf_core::Writer writer(&wb); | ||
|
||
int ret_val = printf_core::printf_main(&writer, format, args); | ||
if (buffsz > 0) | ||
wb.buff[wb.buff_cur] = '\0'; | ||
return ret_val; | ||
} | ||
} // namespace details | ||
|
||
int write_composite(printf_core::Writer *writer, const FormatSection &to_conv) { | ||
char buffer[100]; | ||
auto &time = *to_conv.time; | ||
|
||
switch (to_conv.conv_name) { | ||
// Full date and time representation (e.g., equivalent to %a %b %e %T %Y) | ||
case 'c': { | ||
RET_IF_RESULT_NEGATIVE(details::snprintf_impl( | ||
buffer, sizeof(buffer), "%s %s %02d %02d:%02d:%02d %d", | ||
safe_abbreviated_day_name(time.tm_wday), | ||
safe_abbreviated_month_name(time.tm_mon), time.tm_mday, time.tm_hour, | ||
time.tm_min, time.tm_sec, time.tm_year + 1900)); | ||
break; | ||
} | ||
|
||
// Zero-padded day of the month (equivalent to %m/%d/%y) | ||
case 'D': { | ||
RET_IF_RESULT_NEGATIVE(details::snprintf_impl( | ||
buffer, sizeof(buffer), "%02d/%02d/%02d", time.tm_mon + 1, time.tm_mday, | ||
(time.tm_year + 1900) % 100)); | ||
break; | ||
} | ||
|
||
// ISO 8601 date representation in YYYY-MM-DD (equivalent to %Y-%m-%d) | ||
case 'F': { | ||
RET_IF_RESULT_NEGATIVE(details::snprintf_impl( | ||
buffer, sizeof(buffer), "%04d-%02d-%02d", time.tm_year + 1900, | ||
time.tm_mon + 1, time.tm_mday)); | ||
break; | ||
} | ||
|
||
// 12-hour clock time with seconds and AM/PM (equivalent to %I:%M:%S %p) | ||
case 'r': { | ||
int hour12 = time.tm_hour % 12; | ||
if (hour12 == 0) | ||
hour12 = 12; | ||
RET_IF_RESULT_NEGATIVE(details::snprintf_impl( | ||
buffer, sizeof(buffer), "%02d:%02d:%02d %s", hour12, time.tm_min, | ||
time.tm_sec, | ||
to_conv.time->tm_hour >= 12 ? default_PM_str : default_AM_str)); | ||
break; | ||
} | ||
|
||
// 24-hour time without seconds (equivalent to %H:%M) | ||
case 'R': { | ||
RET_IF_RESULT_NEGATIVE(details::snprintf_impl( | ||
buffer, sizeof(buffer), "%02d:%02d", time.tm_hour, time.tm_min)); | ||
break; | ||
} | ||
|
||
// Time with seconds (equivalent to %H:%M:%S) | ||
case 'T': { | ||
RET_IF_RESULT_NEGATIVE( | ||
details::snprintf_impl(buffer, sizeof(buffer), "%02d:%02d:%02d", | ||
time.tm_hour, time.tm_min, time.tm_sec)); | ||
break; | ||
} | ||
|
||
// Locale's date representation (often equivalent to %m/%d/%y) | ||
case 'x': { | ||
RET_IF_RESULT_NEGATIVE(details::snprintf_impl( | ||
buffer, sizeof(buffer), "%02d/%02d/%02d", time.tm_mon + 1, time.tm_mday, | ||
(time.tm_year + 1900) % 100)); | ||
break; | ||
} | ||
|
||
// Locale's time representation (equivalent to %H:%M:%S) | ||
case 'X': { | ||
RET_IF_RESULT_NEGATIVE( | ||
details::snprintf_impl(buffer, sizeof(buffer), "%02d:%02d:%02d", | ||
time.tm_hour, time.tm_min, time.tm_sec)); | ||
break; | ||
} | ||
|
||
default: | ||
return writer->write(to_conv.raw_string); | ||
} | ||
return writer->write(buffer); | ||
} | ||
|
||
} // namespace strftime_core | ||
} // namespace LIBC_NAMESPACE_DECL | ||
|
||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why was this removed?