ref: c8d87b22d50a17b8832019a93b9293fef19fbd02
dir: /sys/src/ape/lib/ap/gen/strftime.c/
#include <time.h> #include <string.h> static char *awday[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static char *wday[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; static char *amon[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static char *mon[12] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; static char *ampm[2] = {"AM", "PM"}; static char *tz[2] = {"EST", "EDT"}; static int jan1(int); static char *strval(char *, char *, char **, int, int); static char *dval(char *, char *, int, int); size_t strftime(char *s, size_t maxsize, const char *format, const struct tm *t) { char *sp, *se, *fp; int i; sp = s; se = s+maxsize; for(fp=(char *)format; *fp && sp<se; fp++){ if(*fp != '%') *sp++ = *fp; else switch(*++fp){ case 'a': sp = strval(sp, se, awday, t->tm_wday, 7); break; case 'A': sp = strval(sp, se, wday, t->tm_wday, 7); break; case 'b': sp = strval(sp, se, amon, t->tm_mon, 12); break; case 'B': sp = strval(sp, se, mon, t->tm_mon, 12); break; case 'c': sp += strftime(sp, se-sp, "%a %b %d %H:%M:%S %Y", t); break; case 'd': sp = dval(sp, se, t->tm_mday, 2); break; case 'H': sp = dval(sp, se, t->tm_hour, 2); break; case 'I': i = t->tm_hour; if(i == 0) i = 12; else if(i > 12) i -= 12; sp = dval(sp, se, i, 2); break; case 'j': sp = dval(sp, se, t->tm_yday+1, 3); break; case 'm': sp = dval(sp, se, t->tm_mon+1, 2); break; case 'M': sp = dval(sp, se, t->tm_min, 2); break; case 'p': i = (t->tm_hour < 12)? 0 : 1; sp = strval(sp, se, ampm, i, 2); break; case 'S': sp = dval(sp, se, t->tm_sec, 2); break; case 'U': i = 7-jan1(t->tm_year); if(i == 7) i = 0; /* Now i is yday number of first sunday in year */ if(t->tm_yday < i) i = 0; else i = (t->tm_yday-i)/7 + 1; sp = dval(sp, se, i, 2); break; case 'w': sp = dval(sp, se, t->tm_wday, 1); break; case 'W': i = 8-jan1(t->tm_year); if(i >= 7) i -= 7; /* Now i is yday number of first monday in year */ if(t->tm_yday < i) i = 0; else i = (t->tm_yday-i)/7 + 1; sp = dval(sp, se, i, 2); break; case 'x': sp += strftime(sp, se-sp, "%a %b %d, %Y", t); break; case 'X': sp += strftime(sp, se-sp, "%H:%M:%S", t); break; case 'y': sp = dval(sp, se, t->tm_year%100, 2); break; case 'Y': sp = dval(sp, se, t->tm_year+1900, 4); break; case 'Z': /* hack for now: assume eastern time zone */ i = t->tm_isdst? 1 : 0; sp = strval(sp, se, tz, i, 2); break; case 0: fp--; /* stop loop after next fp incr */ break; default: *sp++ = *fp; } } if(*fp) sp = s; /* format string didn't end: no room for conversion */ if(sp<se) *sp = 0; return sp-s; } static char * strval(char *start, char *end, char **array, int index, int alen) { int n; if(index<0 || index>=alen){ *start = '?'; return start+1; } n = strlen(array[index]); if(n > end-start) n = end-start; memcpy(start, array[index], n); return start+n; } static char * dval(char *start, char *end, int val, int width) { char *p; if(val<0 || end-start<width){ *start = '?'; return start+1; } p = start+width-1; while(p>=start){ *p-- = val%10 + '0'; val /= 10; } if(val>0) *start = '*'; return start+width; } /* * return day of the week * of jan 1 of given year */ static int jan1(int yr) { int y, d; /* * normal gregorian calendar * one extra day per four years */ y = yr+1900; d = 4+y+(y+3)/4; /* * julian calendar * regular gregorian * less three days per 400 */ if(y > 1800) { d -= (y-1701)/100; d += (y-1601)/400; } /* * great calendar changeover instant */ if(y > 1752) d += 3; return(d%7); }