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