1*3e12c5d1SDavid du Colombier #include <time.h>
2*3e12c5d1SDavid du Colombier #include <string.h>
3*3e12c5d1SDavid du Colombier
4*3e12c5d1SDavid du Colombier static char *awday[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
5*3e12c5d1SDavid du Colombier static char *wday[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
6*3e12c5d1SDavid du Colombier "Friday", "Saturday"};
7*3e12c5d1SDavid du Colombier static char *amon[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
8*3e12c5d1SDavid du Colombier "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
9*3e12c5d1SDavid du Colombier static char *mon[12] = {"January", "February", "March", "April", "May", "June",
10*3e12c5d1SDavid du Colombier "July", "August", "September", "October", "November", "December"};
11*3e12c5d1SDavid du Colombier static char *ampm[2] = {"AM", "PM"};
12*3e12c5d1SDavid du Colombier static char *tz[2] = {"EST", "EDT"};
13*3e12c5d1SDavid du Colombier
14*3e12c5d1SDavid du Colombier static int jan1(int);
15*3e12c5d1SDavid du Colombier static char *strval(char *, char *, char **, int, int);
16*3e12c5d1SDavid du Colombier static char *dval(char *, char *, int, int);
17*3e12c5d1SDavid du Colombier
18*3e12c5d1SDavid du Colombier size_t
strftime(char * s,size_t maxsize,const char * format,const struct tm * t)19*3e12c5d1SDavid du Colombier strftime(char *s, size_t maxsize, const char *format, const struct tm *t)
20*3e12c5d1SDavid du Colombier {
21*3e12c5d1SDavid du Colombier char *sp, *se, *fp;
22*3e12c5d1SDavid du Colombier int i;
23*3e12c5d1SDavid du Colombier
24*3e12c5d1SDavid du Colombier sp = s;
25*3e12c5d1SDavid du Colombier se = s+maxsize;
26*3e12c5d1SDavid du Colombier for(fp=(char *)format; *fp && sp<se; fp++){
27*3e12c5d1SDavid du Colombier if(*fp != '%')
28*3e12c5d1SDavid du Colombier *sp++ = *fp;
29*3e12c5d1SDavid du Colombier else switch(*++fp){
30*3e12c5d1SDavid du Colombier case 'a':
31*3e12c5d1SDavid du Colombier sp = strval(sp, se, awday, t->tm_wday, 7);
32*3e12c5d1SDavid du Colombier break;
33*3e12c5d1SDavid du Colombier case 'A':
34*3e12c5d1SDavid du Colombier sp = strval(sp, se, wday, t->tm_wday, 7);
35*3e12c5d1SDavid du Colombier break;
36*3e12c5d1SDavid du Colombier case 'b':
37*3e12c5d1SDavid du Colombier sp = strval(sp, se, amon, t->tm_mon, 12);
38*3e12c5d1SDavid du Colombier break;
39*3e12c5d1SDavid du Colombier case 'B':
40*3e12c5d1SDavid du Colombier sp = strval(sp, se, mon, t->tm_mon, 12);
41*3e12c5d1SDavid du Colombier break;
42*3e12c5d1SDavid du Colombier case 'c':
43*3e12c5d1SDavid du Colombier sp += strftime(sp, se-sp, "%a %b %d %H:%M:%S %Y", t);
44*3e12c5d1SDavid du Colombier break;
45*3e12c5d1SDavid du Colombier case 'd':
46*3e12c5d1SDavid du Colombier sp = dval(sp, se, t->tm_mday, 2);
47*3e12c5d1SDavid du Colombier break;
48*3e12c5d1SDavid du Colombier case 'H':
49*3e12c5d1SDavid du Colombier sp = dval(sp, se, t->tm_hour, 2);
50*3e12c5d1SDavid du Colombier break;
51*3e12c5d1SDavid du Colombier case 'I':
52*3e12c5d1SDavid du Colombier i = t->tm_hour;
53*3e12c5d1SDavid du Colombier if(i == 0)
54*3e12c5d1SDavid du Colombier i = 12;
55*3e12c5d1SDavid du Colombier else if(i > 12)
56*3e12c5d1SDavid du Colombier i -= 12;
57*3e12c5d1SDavid du Colombier sp = dval(sp, se, i, 2);
58*3e12c5d1SDavid du Colombier break;
59*3e12c5d1SDavid du Colombier case 'j':
60*3e12c5d1SDavid du Colombier sp = dval(sp, se, t->tm_yday+1, 3);
61*3e12c5d1SDavid du Colombier break;
62*3e12c5d1SDavid du Colombier case 'm':
63*3e12c5d1SDavid du Colombier sp = dval(sp, se, t->tm_mon+1, 2);
64*3e12c5d1SDavid du Colombier break;
65*3e12c5d1SDavid du Colombier case 'M':
66*3e12c5d1SDavid du Colombier sp = dval(sp, se, t->tm_min, 2);
67*3e12c5d1SDavid du Colombier break;
68*3e12c5d1SDavid du Colombier case 'p':
69*3e12c5d1SDavid du Colombier i = (t->tm_hour < 12)? 0 : 1;
70*3e12c5d1SDavid du Colombier sp = strval(sp, se, ampm, i, 2);
71*3e12c5d1SDavid du Colombier break;
72*3e12c5d1SDavid du Colombier case 'S':
73*3e12c5d1SDavid du Colombier sp = dval(sp, se, t->tm_sec, 2);
74*3e12c5d1SDavid du Colombier break;
75*3e12c5d1SDavid du Colombier case 'U':
76*3e12c5d1SDavid du Colombier i = 7-jan1(t->tm_year);
77*3e12c5d1SDavid du Colombier if(i == 7)
78*3e12c5d1SDavid du Colombier i = 0;
79*3e12c5d1SDavid du Colombier /* Now i is yday number of first sunday in year */
80*3e12c5d1SDavid du Colombier if(t->tm_yday < i)
81*3e12c5d1SDavid du Colombier i = 0;
82*3e12c5d1SDavid du Colombier else
83*3e12c5d1SDavid du Colombier i = (t->tm_yday-i)/7 + 1;
84*3e12c5d1SDavid du Colombier sp = dval(sp, se, i, 2);
85*3e12c5d1SDavid du Colombier break;
86*3e12c5d1SDavid du Colombier case 'w':
87*3e12c5d1SDavid du Colombier sp = dval(sp, se, t->tm_wday, 1);
88*3e12c5d1SDavid du Colombier break;
89*3e12c5d1SDavid du Colombier case 'W':
90*3e12c5d1SDavid du Colombier i = 8-jan1(t->tm_year);
91*3e12c5d1SDavid du Colombier if(i >= 7)
92*3e12c5d1SDavid du Colombier i -= 7;
93*3e12c5d1SDavid du Colombier /* Now i is yday number of first monday in year */
94*3e12c5d1SDavid du Colombier if(t->tm_yday < i)
95*3e12c5d1SDavid du Colombier i = 0;
96*3e12c5d1SDavid du Colombier else
97*3e12c5d1SDavid du Colombier i = (t->tm_yday-i)/7 + 1;
98*3e12c5d1SDavid du Colombier sp = dval(sp, se, i, 2);
99*3e12c5d1SDavid du Colombier break;
100*3e12c5d1SDavid du Colombier case 'x':
101*3e12c5d1SDavid du Colombier sp += strftime(sp, se-sp, "%a %b %d, %Y", t);
102*3e12c5d1SDavid du Colombier break;
103*3e12c5d1SDavid du Colombier case 'X':
104*3e12c5d1SDavid du Colombier sp += strftime(sp, se-sp, "%H:%M:%S", t);
105*3e12c5d1SDavid du Colombier break;
106*3e12c5d1SDavid du Colombier case 'y':
107*3e12c5d1SDavid du Colombier sp = dval(sp, se, t->tm_year%100, 2);
108*3e12c5d1SDavid du Colombier break;
109*3e12c5d1SDavid du Colombier case 'Y':
110*3e12c5d1SDavid du Colombier sp = dval(sp, se, t->tm_year+1900, 4);
111*3e12c5d1SDavid du Colombier break;
112*3e12c5d1SDavid du Colombier case 'Z':
113*3e12c5d1SDavid du Colombier /* hack for now: assume eastern time zone */
114*3e12c5d1SDavid du Colombier i = t->tm_isdst? 1 : 0;
115*3e12c5d1SDavid du Colombier sp = strval(sp, se, tz, i, 2);
116*3e12c5d1SDavid du Colombier break;
117*3e12c5d1SDavid du Colombier case 0:
118*3e12c5d1SDavid du Colombier fp--; /* stop loop after next fp incr */
119*3e12c5d1SDavid du Colombier break;
120*3e12c5d1SDavid du Colombier default:
121*3e12c5d1SDavid du Colombier *sp++ = *fp;
122*3e12c5d1SDavid du Colombier }
123*3e12c5d1SDavid du Colombier }
124*3e12c5d1SDavid du Colombier if(*fp)
125*3e12c5d1SDavid du Colombier sp = s; /* format string didn't end: no room for conversion */
126*3e12c5d1SDavid du Colombier if(sp<se)
127*3e12c5d1SDavid du Colombier *sp = 0;
128*3e12c5d1SDavid du Colombier return sp-s;
129*3e12c5d1SDavid du Colombier }
130*3e12c5d1SDavid du Colombier
131*3e12c5d1SDavid du Colombier static char *
strval(char * start,char * end,char ** array,int index,int alen)132*3e12c5d1SDavid du Colombier strval(char *start, char *end, char **array, int index, int alen)
133*3e12c5d1SDavid du Colombier {
134*3e12c5d1SDavid du Colombier int n;
135*3e12c5d1SDavid du Colombier
136*3e12c5d1SDavid du Colombier if(index<0 || index>=alen){
137*3e12c5d1SDavid du Colombier *start = '?';
138*3e12c5d1SDavid du Colombier return start+1;
139*3e12c5d1SDavid du Colombier }
140*3e12c5d1SDavid du Colombier n = strlen(array[index]);
141*3e12c5d1SDavid du Colombier if(n > end-start)
142*3e12c5d1SDavid du Colombier n = end-start;
143*3e12c5d1SDavid du Colombier memcpy(start, array[index], n);
144*3e12c5d1SDavid du Colombier return start+n;
145*3e12c5d1SDavid du Colombier }
146*3e12c5d1SDavid du Colombier
147*3e12c5d1SDavid du Colombier static char *
dval(char * start,char * end,int val,int width)148*3e12c5d1SDavid du Colombier dval(char *start, char *end, int val, int width)
149*3e12c5d1SDavid du Colombier {
150*3e12c5d1SDavid du Colombier char *p;
151*3e12c5d1SDavid du Colombier
152*3e12c5d1SDavid du Colombier if(val<0 || end-start<width){
153*3e12c5d1SDavid du Colombier *start = '?';
154*3e12c5d1SDavid du Colombier return start+1;
155*3e12c5d1SDavid du Colombier }
156*3e12c5d1SDavid du Colombier p = start+width-1;
157*3e12c5d1SDavid du Colombier while(p>=start){
158*3e12c5d1SDavid du Colombier *p-- = val%10 + '0';
159*3e12c5d1SDavid du Colombier val /= 10;
160*3e12c5d1SDavid du Colombier }
161*3e12c5d1SDavid du Colombier if(val>0)
162*3e12c5d1SDavid du Colombier *start = '*';
163*3e12c5d1SDavid du Colombier return start+width;
164*3e12c5d1SDavid du Colombier }
165*3e12c5d1SDavid du Colombier
166*3e12c5d1SDavid du Colombier /*
167*3e12c5d1SDavid du Colombier * return day of the week
168*3e12c5d1SDavid du Colombier * of jan 1 of given year
169*3e12c5d1SDavid du Colombier */
170*3e12c5d1SDavid du Colombier static int
jan1(int yr)171*3e12c5d1SDavid du Colombier jan1(int yr)
172*3e12c5d1SDavid du Colombier {
173*3e12c5d1SDavid du Colombier int y, d;
174*3e12c5d1SDavid du Colombier
175*3e12c5d1SDavid du Colombier /*
176*3e12c5d1SDavid du Colombier * normal gregorian calendar
177*3e12c5d1SDavid du Colombier * one extra day per four years
178*3e12c5d1SDavid du Colombier */
179*3e12c5d1SDavid du Colombier
180*3e12c5d1SDavid du Colombier y = yr+1900;
181*3e12c5d1SDavid du Colombier d = 4+y+(y+3)/4;
182*3e12c5d1SDavid du Colombier
183*3e12c5d1SDavid du Colombier /*
184*3e12c5d1SDavid du Colombier * julian calendar
185*3e12c5d1SDavid du Colombier * regular gregorian
186*3e12c5d1SDavid du Colombier * less three days per 400
187*3e12c5d1SDavid du Colombier */
188*3e12c5d1SDavid du Colombier
189*3e12c5d1SDavid du Colombier if(y > 1800) {
190*3e12c5d1SDavid du Colombier d -= (y-1701)/100;
191*3e12c5d1SDavid du Colombier d += (y-1601)/400;
192*3e12c5d1SDavid du Colombier }
193*3e12c5d1SDavid du Colombier
194*3e12c5d1SDavid du Colombier /*
195*3e12c5d1SDavid du Colombier * great calendar changeover instant
196*3e12c5d1SDavid du Colombier */
197*3e12c5d1SDavid du Colombier
198*3e12c5d1SDavid du Colombier if(y > 1752)
199*3e12c5d1SDavid du Colombier d += 3;
200*3e12c5d1SDavid du Colombier
201*3e12c5d1SDavid du Colombier return(d%7);
202*3e12c5d1SDavid du Colombier }
203