#include <stdlib.h>
#include <stdio.h>
#include <time.h>
extern long __utc_offset;
#ifdef __MEMX
const __memx char strfwkdays[] = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday ";
const __memx char strfmonths[] = "January February March April May June July August September October November December ";
#else
const char strfwkdays[] = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday ";
const char strfmonths[] = "January February March April May June July August September October November December ";
#endif
#ifdef __MEMX
unsigned char
pgm_copystring(const char __memx * p, unsigned char i, char *b, unsigned char l)
{
#else
unsigned char
pgm_copystring(const char *p, unsigned char i, char *b, unsigned char l)
{
#endif
unsigned char ret, c;
ret = 0;
while (i) {
c = *p++;
if (c == ' ')
i--;
}
c = *p++;
while (c != ' ' && l--) {
*b++ = c;
ret++;
c = *p++;
}
*b = 0;
return ret;
}
size_t
strftime(char *buffer, size_t limit, const char *pattern, const struct tm * timeptr)
{
unsigned int count, length;
int d, w;
char c;
char _store[26];
struct week_date wd;
count = length = 0;
while (count < limit) {
c = *pattern++;
if (c == '%') {
c = *pattern++;
if (c == 'E' || c == 'O')
c = *pattern++;
switch (c) {
case ('%'):
_store[0] = c;
length = 1;
break;
case ('a'):
length = pgm_copystring(strfwkdays, timeptr->tm_wday, _store, 3);
break;
case ('A'):
length = pgm_copystring(strfwkdays, timeptr->tm_wday, _store, 255);
break;
case ('b'):
case ('h'):
length = pgm_copystring(strfmonths, timeptr->tm_mon, _store, 3);
break;
case ('B'):
length = pgm_copystring(strfmonths, timeptr->tm_mon, _store, 255);
break;
case ('c'):
asctime_r(timeptr, _store);
length = 0;
while (_store[length])
length++;
break;
case ('C'):
d = timeptr->tm_year + 1900;
d /= 100;
length = sprintf(_store, "%.2d", d);
break;
case ('d'):
length = sprintf(_store, "%.2u", timeptr->tm_mday);
break;
case ('D'):
length = sprintf(_store, "%.2u/%.2u/%.2u", \
timeptr->tm_mon + 1, \
timeptr->tm_mday, \
timeptr->tm_year % 100 \
);
break;
case ('e'):
length = sprintf(_store, "%2d", timeptr->tm_mday);
break;
case ('F'):
length = sprintf(_store, "%d-%.2d-%.2d", \
timeptr->tm_year + 1900, \
timeptr->tm_mon + 1, \
timeptr->tm_mday \
);
break;
case ('g'):
case ('G'):
iso_week_date_r(timeptr->tm_year + 1900, timeptr->tm_yday, &wd);
if (c == 'g') {
length = sprintf(_store, "%.2d", wd.year % 100);
} else {
length = sprintf(_store, "%.4d", wd.year);
}
break;
case ('H'):
length = sprintf(_store, "%.2u", timeptr->tm_hour);
break;
case ('I'):
d = timeptr->tm_hour % 12;
if (d == 0)
d = 12;
length = sprintf(_store, "%.2u", d);
break;
case ('j'):
length = sprintf(_store, "%.3u", timeptr->tm_yday + 1);
break;
case ('m'):
length = sprintf(_store, "%.2u", timeptr->tm_mon + 1);
break;
case ('M'):
length = sprintf(_store, "%.2u", timeptr->tm_min);
break;
case ('n'):
_store[0] = 10;
length = 1;
break;
case ('p'):
length = 2;
_store[0] = 'A';
if (timeptr->tm_hour > 11)
_store[0] = 'P';
_store[1] = 'M';
_store[2] = 0;
break;
case ('r'):
d = timeptr->tm_hour % 12;
if (d == 0)
d = 12;
length = sprintf(_store, "%2d:%.2d:%.2d AM", \
d, \
timeptr->tm_min, \
timeptr->tm_sec \
);
if (timeptr->tm_hour > 11)
_store[10] = 'P';
break;
case ('R'):
length = sprintf(_store, "%.2d:%.2d", timeptr->tm_hour, timeptr->tm_min);
break;
case ('S'):
length = sprintf(_store, "%.2u", timeptr->tm_sec);
break;
case ('t'):
length = sprintf(_store, "\t");
break;
case ('T'):
length = sprintf(_store, "%.2d:%.2d:%.2d", \
timeptr->tm_hour, \
timeptr->tm_min, \
timeptr->tm_sec \
);
break;
case ('u'):
w = timeptr->tm_wday;
if (w == 0)
w = 7;
length = sprintf(_store, "%d", w);
break;
case ('U'):
length = sprintf(_store, "%.2u", week_of_year(timeptr, 0));
break;
case ('V'):
iso_week_date_r(timeptr->tm_year + 1900, timeptr->tm_yday, &wd);
length = sprintf(_store, "%.2u", wd.week);
break;
case ('w'):
length = sprintf(_store, "%u", timeptr->tm_wday);
break;
case ('W'):
w = week_of_year(timeptr, 1);
length = sprintf(_store, "%.2u", w);
break;
case ('x'):
length = sprintf(_store, "%.2u/%.2u/%.2u", timeptr->tm_mon + 1, timeptr->tm_mday, timeptr->tm_year % 100);
break;
case ('X'):
length = sprintf(_store, "%.2u:%.2u:%.2u", timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec);
break;
case ('y'):
length = sprintf(_store, "%.2u", timeptr->tm_year % 100);
break;
case ('Y'):
length = sprintf(_store, "%u", timeptr->tm_year + 1900);
break;
case ('z'):
d = __utc_offset / 60;
w = timeptr->tm_isdst / 60;
if (w > 0)
d += w;
w = abs(d % 60);
d = d / 60;
length = sprintf(_store, "%+.2d%.2d", d, w);
break;
default:
length = 1;
_store[0] = '?';
_store[1] = 0;
break;
}
if ((length + count) < limit) {
count += length;
for (d = 0; d < (int) length; d++) {
*buffer++ = _store[d];
}
} else {
*buffer = 0;
return count;
}
} else {
*buffer = c;
buffer++;
count++;
if (c == 0)
return count;
}
}
*buffer = 0;
return count;
}