]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/lib/roken/strftime.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / lib / roken / strftime.c
1 /*
2  * Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of KTH nor the names of its contributors may be
18  *    used to endorse or promote products derived from this software without
19  *    specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36 #ifdef TEST_STRPFTIME
37 #include "strpftime-test.h"
38 #endif
39 #include "roken.h"
40
41 RCSID("$Id: strftime.c 21896 2007-08-09 08:46:08Z lha $");
42
43 static const char *abb_weekdays[] = {
44     "Sun",
45     "Mon",
46     "Tue",
47     "Wed",
48     "Thu",
49     "Fri",
50     "Sat",
51 };
52
53 static const char *full_weekdays[] = {
54     "Sunday",
55     "Monday",
56     "Tuesday",
57     "Wednesday",
58     "Thursday",
59     "Friday",
60     "Saturday",
61 };
62
63 static const char *abb_month[] = {
64     "Jan",
65     "Feb",
66     "Mar",
67     "Apr",
68     "May",
69     "Jun",
70     "Jul",
71     "Aug",
72     "Sep",
73     "Oct",
74     "Nov",
75     "Dec"
76 };
77
78 static const char *full_month[] = {
79     "January",
80     "February",
81     "Mars",
82     "April",
83     "May",
84     "June",
85     "July",
86     "August",
87     "September",
88     "October",
89     "November",
90     "December"
91 };
92
93 static const char *ampm[] = {
94     "AM",
95     "PM"
96 };
97
98 /*
99  * Convert hour in [0, 24] to [12 1 - 11 12 1 - 11 12]
100  */
101
102 static int
103 hour_24to12 (int hour)
104 {
105     int ret = hour % 12;
106
107     if (ret == 0)
108         ret = 12;
109     return ret;
110 }
111
112 /*
113  * Return AM or PM for `hour'
114  */
115
116 static const char *
117 hour_to_ampm (int hour)
118 {
119     return ampm[hour / 12];
120 }
121
122 /*
123  * Return the week number of `tm' (Sunday being the first day of the week)
124  * as [0, 53]
125  */
126
127 static int
128 week_number_sun (const struct tm *tm)
129 {
130     return (tm->tm_yday + 7 - (tm->tm_yday % 7 - tm->tm_wday + 7) % 7) / 7;
131 }
132
133 /*
134  * Return the week number of `tm' (Monday being the first day of the week)
135  * as [0, 53]
136  */
137
138 static int
139 week_number_mon (const struct tm *tm)
140 {
141     int wday = (tm->tm_wday + 6) % 7;
142
143     return (tm->tm_yday + 7 - (tm->tm_yday % 7 - wday + 7) % 7) / 7;
144 }
145
146 /*
147  * Return the week number of `tm' (Monday being the first day of the
148  * week) as [01, 53].  Week number one is the one that has four or more
149  * days in that year.
150  */
151
152 static int
153 week_number_mon4 (const struct tm *tm)
154 {
155     int wday  = (tm->tm_wday + 6) % 7;
156     int w1day = (wday - tm->tm_yday % 7 + 7) % 7;
157     int ret;
158     
159     ret = (tm->tm_yday + w1day) / 7;
160     if (w1day >= 4)
161         --ret;
162     if (ret == -1)
163         ret = 53;
164     else
165         ++ret;
166     return ret;
167 }
168
169 /*
170  *
171  */
172
173 size_t ROKEN_LIB_FUNCTION
174 strftime (char *buf, size_t maxsize, const char *format,
175           const struct tm *tm)
176 {
177     size_t n = 0;
178     int ret;
179
180     while (*format != '\0' && n < maxsize) {
181         if (*format == '%') {
182             ++format;
183             if(*format == 'E' || *format == 'O')
184                 ++format;
185             switch (*format) {
186             case 'a' :
187                 ret = snprintf (buf, maxsize - n,
188                                 "%s", abb_weekdays[tm->tm_wday]);
189                 break;
190             case 'A' :
191                 ret = snprintf (buf, maxsize - n,
192                                 "%s", full_weekdays[tm->tm_wday]);
193                 break;
194             case 'h' :
195             case 'b' :
196                 ret = snprintf (buf, maxsize - n,
197                                 "%s", abb_month[tm->tm_mon]);
198                 break;
199             case 'B' :
200                 ret = snprintf (buf, maxsize - n,
201                                 "%s", full_month[tm->tm_mon]);
202                 break;
203             case 'c' :
204                 ret = snprintf (buf, maxsize - n,
205                                 "%d:%02d:%02d %02d:%02d:%02d",
206                                 tm->tm_year,
207                                 tm->tm_mon + 1,
208                                 tm->tm_mday,
209                                 tm->tm_hour,
210                                 tm->tm_min,
211                                 tm->tm_sec);
212                 break;
213             case 'C' :
214                 ret = snprintf (buf, maxsize - n,
215                                 "%02d", (tm->tm_year + 1900) / 100);
216                 break;
217             case 'd' :
218                 ret = snprintf (buf, maxsize - n,
219                                 "%02d", tm->tm_mday);
220                 break;
221             case 'D' :
222                 ret = snprintf (buf, maxsize - n,
223                                 "%02d/%02d/%02d",
224                                 tm->tm_mon + 1,
225                                 tm->tm_mday,
226                                 (tm->tm_year + 1900) % 100);
227                 break;
228             case 'e' :
229                 ret = snprintf (buf, maxsize - n,
230                                 "%2d", tm->tm_mday);
231                 break;
232             case 'F':
233                 ret = snprintf (buf, maxsize - n,
234                                 "%04d-%02d-%02d", tm->tm_year + 1900,
235                                 tm->tm_mon + 1, tm->tm_mday);
236                 break;
237             case 'g':
238                 /* last two digits of week-based year */
239                 abort();
240             case 'G':
241                 /* week-based year */
242                 abort();
243             case 'H' :
244                 ret = snprintf (buf, maxsize - n,
245                                 "%02d", tm->tm_hour);
246                 break;
247             case 'I' :
248                 ret = snprintf (buf, maxsize - n,
249                                 "%02d",
250                                 hour_24to12 (tm->tm_hour));
251                 break;
252             case 'j' :
253                 ret = snprintf (buf, maxsize - n,
254                                 "%03d", tm->tm_yday + 1);
255                 break;
256             case 'k' :
257                 ret = snprintf (buf, maxsize - n,
258                                 "%2d", tm->tm_hour);
259                 break;
260             case 'l' :
261                 ret = snprintf (buf, maxsize - n,
262                                 "%2d",
263                                 hour_24to12 (tm->tm_hour));
264                 break;
265             case 'm' :
266                 ret = snprintf (buf, maxsize - n,
267                                 "%02d", tm->tm_mon + 1);
268                 break;
269             case 'M' :
270                 ret = snprintf (buf, maxsize - n,
271                                 "%02d", tm->tm_min);
272                 break;
273             case 'n' :
274                 ret = snprintf (buf, maxsize - n, "\n");
275                 break;
276             case 'p' :
277                 ret = snprintf (buf, maxsize - n, "%s",
278                                 hour_to_ampm (tm->tm_hour));
279                 break;
280             case 'r' :
281                 ret = snprintf (buf, maxsize - n,
282                                 "%02d:%02d:%02d %s",
283                                 hour_24to12 (tm->tm_hour),
284                                 tm->tm_min,
285                                 tm->tm_sec,
286                                 hour_to_ampm (tm->tm_hour));
287                 break;
288             case 'R' :
289                 ret = snprintf (buf, maxsize - n,
290                                 "%02d:%02d",
291                                 tm->tm_hour,
292                                 tm->tm_min);
293                     
294             case 's' :
295                 ret = snprintf (buf, maxsize - n,
296                                 "%d", (int)mktime(rk_UNCONST(tm)));
297                 break;
298             case 'S' :
299                 ret = snprintf (buf, maxsize - n,
300                                 "%02d", tm->tm_sec);
301                 break;
302             case 't' :
303                 ret = snprintf (buf, maxsize - n, "\t");
304                 break;
305             case 'T' :
306             case 'X' :
307                 ret = snprintf (buf, maxsize - n,
308                                 "%02d:%02d:%02d",
309                                 tm->tm_hour,
310                                 tm->tm_min,
311                                 tm->tm_sec);
312                 break;
313             case 'u' :
314                 ret = snprintf (buf, maxsize - n,
315                                 "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
316                 break;
317             case 'U' :
318                 ret = snprintf (buf, maxsize - n,
319                                 "%02d", week_number_sun (tm));
320                 break;
321             case 'V' :
322                 ret = snprintf (buf, maxsize - n,
323                                 "%02d", week_number_mon4 (tm));
324                 break;
325             case 'w' :
326                 ret = snprintf (buf, maxsize - n,
327                                 "%d", tm->tm_wday);
328                 break;
329             case 'W' :
330                 ret = snprintf (buf, maxsize - n,
331                                 "%02d", week_number_mon (tm));
332                 break;
333             case 'x' :
334                 ret = snprintf (buf, maxsize - n,
335                                 "%d:%02d:%02d",
336                                 tm->tm_year,
337                                 tm->tm_mon + 1,
338                                 tm->tm_mday);
339                 break;
340             case 'y' :
341                 ret = snprintf (buf, maxsize - n,
342                                 "%02d", (tm->tm_year + 1900) % 100);
343                 break;
344             case 'Y' :
345                 ret = snprintf (buf, maxsize - n,
346                                 "%d", tm->tm_year + 1900);
347                 break;
348             case 'z':
349                 ret = snprintf (buf, maxsize - n,
350                                 "%ld",
351 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
352                                 (long)tm->tm_gmtoff
353 #elif defined(HAVE_TIMEZONE)
354 #ifdef HAVE_ALTZONE
355                                 tm->tm_isdst ?
356                                 (long)altzone :
357 #endif
358                                 (long)timezone
359 #else
360 #error Where in timezone chaos are you?
361 #endif    
362                                 );
363                 break;
364             case 'Z' :
365                 ret = snprintf (buf, maxsize - n,
366                                 "%s",
367
368 #if defined(HAVE_STRUCT_TM_TM_ZONE)
369                                 tm->tm_zone
370 #elif defined(HAVE_TIMEZONE)
371                                 tzname[tm->tm_isdst]
372 #else
373 #error what?
374 #endif
375                     );
376                 break;
377             case '\0' :
378                 --format;
379                 /* FALLTHROUGH */
380             case '%' :
381                 ret = snprintf (buf, maxsize - n,
382                                 "%%");
383                 break;
384             default :
385                 ret = snprintf (buf, maxsize - n,
386                                 "%%%c", *format);
387                 break;
388             }
389             if (ret < 0 || ret >= maxsize - n)
390                 return 0;
391             n   += ret;
392             buf += ret;
393             ++format;
394         } else {
395             *buf++ = *format++;
396             ++n;
397         }
398     }
399     *buf++ = '\0';
400     return n;
401 }