Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#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);
}