Skip to content

Commit

Permalink
Merge pull request #1079 from Dennisbonke/strftime
Browse files Browse the repository at this point in the history
  • Loading branch information
no92 authored Jul 6, 2024
2 parents 7f40225 + 38a1df9 commit 3fc8753
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 7 deletions.
83 changes: 78 additions & 5 deletions options/ansi/generic/time-stubs.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

#include <algorithm>
#include <array>
#include <errno.h>
#include <stdio.h>
#include <string.h>
Expand Down Expand Up @@ -92,6 +93,8 @@ size_t strftime(char *__restrict dest, size_t max_size,
const char *__restrict format, const struct tm *__restrict tm) {
auto c = format;
auto p = dest;
[[maybe_unused]] bool use_alternative_symbols = false;
[[maybe_unused]] bool use_alternative_era_format = false;

while(*c) {
int chunk;
Expand All @@ -107,6 +110,38 @@ size_t strftime(char *__restrict dest, size_t max_size,
continue;
}

if(*(c + 1) == 'O') {
std::array<char, 15> valid{{'B', 'b', 'd', 'e', 'H', 'I', 'm', 'M', 'S', 'u', 'U', 'V', 'w', 'W', 'y'}};
auto next = *(c + 2);
if(std::find(valid.begin(), valid.end(), next) != valid.end()) {
use_alternative_symbols = true;
c++;
} else {
*p = '%';
p++;
c++;
*p = 'O';
p++;
c++;
continue;
}
} else if(*(c + 1) == 'E') {
std::array<char, 6> valid{{'c', 'C', 'x', 'X', 'y', 'Y'}};
auto next = *(c + 2);
if(std::find(valid.begin(), valid.end(), next) != valid.end()) {
use_alternative_era_format = true;
c++;
} else {
*p = '%';
p++;
c++;
*p = 'E';
p++;
c++;
continue;
}
}

switch(*++c) {
case 'Y': {
chunk = snprintf(p, space, "%d", 1900 + tm->tm_year);
Expand All @@ -133,7 +168,7 @@ size_t strftime(char *__restrict dest, size_t max_size,
break;
}
case 'Z': {
chunk = snprintf(p, space, "%s", "GMT");
chunk = snprintf(p, space, "%s", "UTC");
if(chunk >= space)
return 0;
p += chunk;
Expand Down Expand Up @@ -190,7 +225,7 @@ size_t strftime(char *__restrict dest, size_t max_size,
break;
}
case 'D': {
chunk = snprintf(p, space, "%.2d/%.2d/%.2d", tm->tm_mon + 1, tm->tm_mday, tm->tm_year % 100);
chunk = snprintf(p, space, "%.2d/%.2d/%.2d", tm->tm_mon + 1, tm->tm_mday, (tm->tm_year + 1900) % 100);
if(chunk >= space)
return 0;
p += chunk;
Expand Down Expand Up @@ -226,8 +261,16 @@ size_t strftime(char *__restrict dest, size_t max_size,
break;
}
case 'c': {
chunk = snprintf(p, space, "%d/%.2d/%.2d %.2d:%.2d:%.2d", 1900 + tm->tm_year,
tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
int day = tm->tm_wday;
if(day < 0 || day > 6)
__ensure(!"Day not in bounds.");

int mon = tm->tm_mon;
if(mon < 0 || mon > 11)
__ensure(!"Month not in bounds.");

chunk = snprintf(p, space, "%s %s %2d %.2i:%.2i:%.2d %d", mlibc::nl_langinfo(ABDAY_1 + day),
mlibc::nl_langinfo(ABMON_1 + mon), tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, 1900 + tm->tm_year);
if(chunk >= space)
return 0;
p += chunk;
Expand Down Expand Up @@ -255,6 +298,14 @@ size_t strftime(char *__restrict dest, size_t max_size,
c++;
break;
}
case 'k': {
chunk = snprintf(p, space, "%2d", tm->tm_hour);
if(chunk >= space)
return 0;
p += chunk;
c++;
break;
}
case 'I': {
int hour = tm->tm_hour;
if(!hour)
Expand All @@ -276,6 +327,20 @@ size_t strftime(char *__restrict dest, size_t max_size,
c++;
break;
}
case 'P': {
char *str = mlibc::nl_langinfo((tm->tm_hour < 12) ? AM_STR : PM_STR);
char *str_lower = reinterpret_cast<char *>(getAllocator().allocate(strlen(str) + 1));
for(size_t i = 0; str[i]; i++)
str_lower[i] = tolower(str[i]);
str_lower[strlen(str)] = '\0';

chunk = snprintf(p, space, "%s", str_lower);
if(chunk >= space)
return 0;
p += chunk;
c++;
break;
}
case 'C': {
chunk = snprintf(p, space, "%.2d", (1900 + tm->tm_year) / 100);
if(chunk >= space)
Expand Down Expand Up @@ -330,6 +395,14 @@ size_t strftime(char *__restrict dest, size_t max_size,
c++;
break;
}
case 'n': {
chunk = snprintf(p, space, "\n");
if(chunk >= space)
return 0;
p += chunk;
c++;
break;
}
case 't': {
chunk = snprintf(p, space, "\t");
if(chunk >= space)
Expand Down
8 changes: 8 additions & 0 deletions options/internal/generic/locale.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ char *nl_langinfo(nl_item item) {
return const_cast<char *>("%m/%d/%y");
}else if(item == T_FMT) {
return const_cast<char *>("%H:%M:%S");
}else if(item == T_FMT_AMPM) {
return const_cast<char *>("%I:%M:%S %p");
}else if(item == D_T_FMT) {
return const_cast<char *>("%a %b %e %T %Y");
}else if(item == YESEXPR) {
return const_cast<char *>("^[yY]");
}else if(item == NOEXPR) {
return const_cast<char *>("^[nN]");
}else{
mlibc::infoLogger() << "mlibc: nl_langinfo item "
<< item << " is not implemented properly" << frg::endlog;
Expand Down
22 changes: 20 additions & 2 deletions tests/ansi/strftime.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ int main() {
fputs("strftime testcase could not set locale, errors may be expected!", stderr);
}

char timebuf[16];
char result[16] = " 8";
char timebuf[32];
char result[32] = " 8";
struct tm tm;
tm.tm_sec = 0;
tm.tm_min = 17;
Expand All @@ -33,6 +33,24 @@ int main() {
strftime(timebuf, sizeof(timebuf), "%X", &tm);
assert(!strcmp(timebuf, "17:17:00"));

memset(timebuf, 0, sizeof(timebuf));
strftime(timebuf, sizeof(timebuf), "%D", &tm);
assert(!strcmp(timebuf, "03/08/21"));

memset(timebuf, 0, sizeof(timebuf));
strftime(timebuf, sizeof(timebuf), "%OB %Ob", &tm);
assert(!strcmp(timebuf, "March Mar"));

memset(timebuf, 0, sizeof(timebuf));
strftime(timebuf, sizeof(timebuf), "%c", &tm);
memset(result, 0, sizeof(result));
strftime(result, sizeof(result), "%a %b %e %H:%M:%S %Y", &tm);
assert(!strcmp(timebuf, result));

memset(timebuf, 0, sizeof(timebuf));
strftime(timebuf, sizeof(timebuf), "%k %p %P%n", &tm);
assert(!strcmp(timebuf, "17 PM pm\n"));

memset(timebuf, 0, sizeof(timebuf));
strftime(timebuf, sizeof(timebuf), "%a %A", &tm);
assert(!strcmp(timebuf, "Tue Tuesday"));
Expand Down

0 comments on commit 3fc8753

Please sign in to comment.