fxlibc/src/time/strftime.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 = strftime(s+len, n-len, fmt, time); \
if(_written == 0) goto full; \
len += _written; \
}; break
size_t strftime(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;
}