forked from Vhex-Kernel-Core/fxlibc
95 lines
2.9 KiB
C
95 lines
2.9 KiB
C
|
#include <time.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
static const char *day_names[7] = {
|
||
|
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
|
||
|
"Saturday",
|
||
|
};
|
||
|
static const char *month_names[12] = {
|
||
|
"January", "February", "March", "April", "May", "June", "July",
|
||
|
"August", "September", "October", "November", "December",
|
||
|
};
|
||
|
|
||
|
/* Perform a call to snprintf() to print a value */
|
||
|
#define do_snprintf(...) { \
|
||
|
size_t _written = snprintf(s+len, n-len, __VA_ARGS__); \
|
||
|
len += _written; \
|
||
|
if(len >= n) goto full; \
|
||
|
}; break
|
||
|
/* Perform a sub-call to strftime to expand a complex format */
|
||
|
#define do_strftime(fmt) { \
|
||
|
size_t _written = strftime2(s+len, n-len, fmt, time); \
|
||
|
if(_written == 0) goto full; \
|
||
|
len += _written; \
|
||
|
}; break
|
||
|
|
||
|
size_t strftime2(char * restrict s, size_t n, const char * restrict format,
|
||
|
const struct tm * restrict time)
|
||
|
{
|
||
|
size_t len = 0;
|
||
|
|
||
|
while(*format) {
|
||
|
if(*format != '%') {
|
||
|
s[len++] = *format++;
|
||
|
if(len >= n) goto full;
|
||
|
continue;
|
||
|
}
|
||
|
format++;
|
||
|
int c = *format++;
|
||
|
|
||
|
/* In the "C" locale, ignore modifiers E and O */
|
||
|
if(c == 'E') c = *format++;
|
||
|
else if(c == 'O') c = *format++;
|
||
|
|
||
|
switch(c) {
|
||
|
case 'a': do_snprintf("%.3s", day_names[time->tm_wday]);
|
||
|
case 'A': do_snprintf("%s", day_names[time->tm_wday]);
|
||
|
case 'b': do_snprintf("%.3s", month_names[time->tm_mon]);
|
||
|
case 'B': do_snprintf("%s", month_names[time->tm_mon]);
|
||
|
case 'c': do_strftime("%a %b %e %T %Y");
|
||
|
case 'C': do_snprintf("%02d", (time->tm_year + 1900) / 100);
|
||
|
case 'd': do_snprintf("%02d", time->tm_mday);
|
||
|
case 'D': do_strftime("%m/%d/%y");
|
||
|
case 'e': do_snprintf("%2d", time->tm_mday);
|
||
|
case 'F': do_strftime("%Y-%m-%d");
|
||
|
/* TODO: strftime: Support week-based year */
|
||
|
case 'g': do_snprintf("??");
|
||
|
case 'G': do_snprintf("????");
|
||
|
case 'h': do_strftime("%b");
|
||
|
case 'H': do_snprintf("%02d", time->tm_hour);
|
||
|
case 'I': do_snprintf("%02d", (time->tm_hour+11)%12 + 1);
|
||
|
case 'j': do_snprintf("%03d", time->tm_yday + 1);
|
||
|
case 'm': do_snprintf("%02d", time->tm_mon + 1);
|
||
|
case 'M': do_snprintf("%02d", time->tm_min);
|
||
|
case 'n': do_snprintf("\n");
|
||
|
case 'p': do_snprintf(time->tm_hour < 12 ? "AM" : "PM");
|
||
|
case 'r': do_strftime("%I:%M:%S %p");
|
||
|
case 'R': do_strftime("%H:%M");
|
||
|
case 'S': do_snprintf("%02d", time->tm_sec);
|
||
|
case 't': do_snprintf("\t");
|
||
|
case 'T': do_strftime("%H:%M:%S");
|
||
|
case 'u': do_snprintf("%d", (time->tm_wday+6) % 7 + 1);
|
||
|
/* TODO: strftime: Support week number */
|
||
|
case 'U': do_snprintf("??");
|
||
|
case 'V': do_snprintf("??");
|
||
|
case 'w': do_snprintf("%d", time->tm_wday);
|
||
|
case 'W': do_snprintf("??");
|
||
|
case 'x': do_strftime("%m/%d/%y");
|
||
|
case 'X': do_strftime("%T");
|
||
|
case 'y': do_snprintf("%02d", time->tm_year % 100);
|
||
|
case 'Y': do_snprintf("%d", time->tm_year + 1900);
|
||
|
/* TODO: strftime: Support timezones */
|
||
|
case 'z': break;
|
||
|
case 'Z': break;
|
||
|
case '%': do_snprintf("%%");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
s[len] = 0;
|
||
|
return len;
|
||
|
|
||
|
full:
|
||
|
s[n-1] = 0;
|
||
|
return 0;
|
||
|
}
|