This commit is contained in:
parent
1733fc810d
commit
b7df596f8a
@ -7,6 +7,7 @@ set(SOURCES
|
|||||||
src/unistd.cpp
|
src/unistd.cpp
|
||||||
src/errno.cpp
|
src/errno.cpp
|
||||||
src/string.cpp
|
src/string.cpp
|
||||||
|
src/strftime.cpp
|
||||||
src/fcntl.cpp
|
src/fcntl.cpp
|
||||||
src/assert.cpp
|
src/assert.cpp
|
||||||
src/atexit.cpp
|
src/atexit.cpp
|
||||||
|
@ -42,6 +42,9 @@ extern "C"
|
|||||||
/* Build a string representation of UNIX time. */
|
/* Build a string representation of UNIX time. */
|
||||||
char* ctime_r(const time_t* tp, char buf[26]);
|
char* ctime_r(const time_t* tp, char buf[26]);
|
||||||
|
|
||||||
|
/* Format a string representation of broken-down time using a format string. */
|
||||||
|
size_t strftime(char* buf, size_t max, const char* format, const struct tm* tm);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
140
libc/src/strftime.cpp
Normal file
140
libc/src/strftime.cpp
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
#include <luna/Check.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
struct strftime_state
|
||||||
|
{
|
||||||
|
char* const buf;
|
||||||
|
const size_t max;
|
||||||
|
size_t pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool try_put_char(strftime_state& state, char c)
|
||||||
|
{
|
||||||
|
if (state.pos == state.max) return false;
|
||||||
|
|
||||||
|
state.buf[state.pos++] = c;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool try_put_string(strftime_state& state, const char* s)
|
||||||
|
{
|
||||||
|
if (state.pos + strlen(s) == (state.max - 1)) return false;
|
||||||
|
|
||||||
|
memcpy(state.buf + state.pos, s, strlen(s));
|
||||||
|
|
||||||
|
state.pos += strlen(s);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool try_format(strftime_state& state, const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
|
||||||
|
char buf[1024];
|
||||||
|
vsnprintf(buf, sizeof(buf), format, ap);
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return try_put_string(state, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* abday_names[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
||||||
|
static const char* day_names[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
|
||||||
|
static const char* abmon_names[] = {
|
||||||
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||||
|
};
|
||||||
|
static const char* mon_names[] = { "January", "February", "March", "April", "May", "June",
|
||||||
|
"July", "August", "September", "October", "November", "December" };
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
size_t strftime(char* buf, size_t max, const char* format, const struct tm* tm)
|
||||||
|
{
|
||||||
|
strftime_state state = { .buf = buf, .max = max, .pos = 0 };
|
||||||
|
|
||||||
|
while (*format)
|
||||||
|
{
|
||||||
|
if (*format != '%')
|
||||||
|
{
|
||||||
|
if (!try_put_char(state, *format)) return 0;
|
||||||
|
|
||||||
|
format++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
format++;
|
||||||
|
switch (*format)
|
||||||
|
{
|
||||||
|
case 'a':
|
||||||
|
if (!try_put_string(state, abday_names[tm->tm_wday])) return 0;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
if (!try_put_string(state, day_names[tm->tm_wday])) return 0;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
if (!try_put_string(state, abmon_names[tm->tm_mon])) return 0;
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
if (!try_put_string(state, mon_names[tm->tm_mon])) return 0;
|
||||||
|
break;
|
||||||
|
case 'c': todo();
|
||||||
|
case 'd':
|
||||||
|
if (!try_format(state, "%.2d", tm->tm_mday)) return 0;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
if (!try_format(state, "%.2d", tm->tm_hour)) return 0;
|
||||||
|
break;
|
||||||
|
case 'I': {
|
||||||
|
int hour = tm->tm_hour % 12;
|
||||||
|
if (hour == 0) hour = 12;
|
||||||
|
if (!try_format(state, "%.2d", hour)) return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'j': todo();
|
||||||
|
case 'm':
|
||||||
|
if (!try_format(state, "%.2d", tm->tm_mon + 1)) return 0;
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
if (!try_format(state, "%.2d", tm->tm_min)) return 0;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
if (tm->tm_hour >= 12)
|
||||||
|
{
|
||||||
|
if (!try_put_string(state, "PM")) return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!try_put_string(state, "AM")) return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
if (!try_format(state, "%.2d", tm->tm_sec)) return 0;
|
||||||
|
break;
|
||||||
|
case 'x': todo();
|
||||||
|
case 'X': todo();
|
||||||
|
case 'y':
|
||||||
|
if (!try_format(state, "%.2d", (tm->tm_year + 1900) % 100)) return 0;
|
||||||
|
break;
|
||||||
|
case 'Y':
|
||||||
|
if (!try_format(state, "%d", tm->tm_year + 1900)) return 0;
|
||||||
|
break;
|
||||||
|
default: fprintf(stderr, "strftime: unexpected conversion specifier %%%c\n", *format); exit(255);
|
||||||
|
}
|
||||||
|
|
||||||
|
format++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.buf[state.pos] = '\0';
|
||||||
|
|
||||||
|
return state.pos;
|
||||||
|
}
|
||||||
|
}
|
@ -85,9 +85,6 @@ static void time_to_struct_tm(time_t time, struct tm* result)
|
|||||||
result->tm_sec = (int)time;
|
result->tm_sec = (int)time;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* wday_names[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
|
||||||
const char* month_names[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
int clock_gettime(clockid_t id, struct timespec* ts)
|
int clock_gettime(clockid_t id, struct timespec* ts)
|
||||||
@ -132,8 +129,7 @@ extern "C"
|
|||||||
|
|
||||||
char* asctime_r(const struct tm* tm, char buf[26])
|
char* asctime_r(const struct tm* tm, char buf[26])
|
||||||
{
|
{
|
||||||
string_format(buf, 26, "%s %s %.2d %.2d:%.2d:%.2d %4d\n", wday_names[tm->tm_wday], month_names[tm->tm_mon],
|
strftime(buf, 26, "%a %b %d %H:%M:%S %Y\n", tm);
|
||||||
tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_year + 1900);
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user