]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - crypto/heimdal/lib/roken/strftime.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 #include <config.h>
34 #include "roken.h"
35 #ifdef TEST_STRPFTIME
36 #include "strpftime-test.h"
37 #endif
38
39 static const char *abb_weekdays[] = {
40     "Sun",
41     "Mon",
42     "Tue",
43     "Wed",
44     "Thu",
45     "Fri",
46     "Sat",
47 };
48
49 static const char *full_weekdays[] = {
50     "Sunday",
51     "Monday",
52     "Tuesday",
53     "Wednesday",
54     "Thursday",
55     "Friday",
56     "Saturday",
57 };
58
59 static const char *abb_month[] = {
60     "Jan",
61     "Feb",
62     "Mar",
63     "Apr",
64     "May",
65     "Jun",
66     "Jul",
67     "Aug",
68     "Sep",
69     "Oct",
70     "Nov",
71     "Dec"
72 };
73
74 static const char *full_month[] = {
75     "January",
76     "February",
77     "Mars",
78     "April",
79     "May",
80     "June",
81     "July",
82     "August",
83     "September",
84     "October",
85     "November",
86     "December"
87 };
88
89 static const char *ampm[] = {
90     "AM",
91     "PM"
92 };
93
94 /*
95  * Convert hour in [0, 24] to [12 1 - 11 12 1 - 11 12]
96  */
97
98 static int
99 hour_24to12 (int hour)
100 {
101     int ret = hour % 12;
102
103     if (ret == 0)
104         ret = 12;
105     return ret;
106 }
107
108 /*
109  * Return AM or PM for `hour'
110  */
111
112 static const char *
113 hour_to_ampm (int hour)
114 {
115     return ampm[hour / 12];
116 }
117
118 /*
119  * Return the week number of `tm' (Sunday being the first day of the week)
120  * as [0, 53]
121  */
122
123 static int
124 week_number_sun (const struct tm *tm)
125 {
126     return (tm->tm_yday + 7 - (tm->tm_yday % 7 - tm->tm_wday + 7) % 7) / 7;
127 }
128
129 /*
130  * Return the week number of `tm' (Monday being the first day of the week)
131  * as [0, 53]
132  */
133
134 static int
135 week_number_mon (const struct tm *tm)
136 {
137     int wday = (tm->tm_wday + 6) % 7;
138
139     return (tm->tm_yday + 7 - (tm->tm_yday % 7 - wday + 7) % 7) / 7;
140 }
141
142 /*
143  * Return the week number of `tm' (Monday being the first day of the
144  * week) as [01, 53].  Week number one is the one that has four or more
145  * days in that year.
146  */
147
148 static int
149 week_number_mon4 (const struct tm *tm)
150 {
151     int wday  = (tm->tm_wday + 6) % 7;
152     int w1day = (wday - tm->tm_yday % 7 + 7) % 7;
153     int ret;
154
155     ret = (tm->tm_yday + w1day) / 7;
156     if (w1day >= 4)
157         --ret;
158     if (ret == -1)
159         ret = 53;
160     else
161         ++ret;
162     return ret;
163 }
164
165 /*
166  *
167  */
168
169 ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
170 strftime (char *buf, size_t maxsize, const char *format,
171           const struct tm *tm)
172 {
173     size_t n = 0;
174     int ret;
175
176     while (*format != '\0' && n < maxsize) {
177         if (*format == '%') {
178             ++format;
179             if(*format == 'E' || *format == 'O')
180                 ++format;
181             switch (*format) {
182             case 'a' :
183                 ret = snprintf (buf, maxsize - n,
184                                 "%s", abb_weekdays[tm->tm_wday]);
185                 break;
186             case 'A' :
187                 ret = snprintf (buf, maxsize - n,
188                                 "%s", full_weekdays[tm->tm_wday]);
189                 break;
190             case 'h' :
191             case 'b' :
192                 ret = snprintf (buf, maxsize - n,
193                                 "%s", abb_month[tm->tm_mon]);
194                 break;
195             case 'B' :
196                 ret = snprintf (buf, maxsize - n,
197                                 "%s", full_month[tm->tm_mon]);
198                 break;
199             case 'c' :
200                 ret = snprintf (buf, maxsize - n,
201                                 "%d:%02d:%02d %02d:%02d:%02d",
202                                 tm->tm_year,
203                                 tm->tm_mon + 1,
204                                 tm->tm_mday,
205                                 tm->tm_hour,
206                                 tm->tm_min,
207                                 tm->tm_sec);
208                 break;
209             case 'C' :
210                 ret = snprintf (buf, maxsize - n,
211                                 "%02d", (tm->tm_year + 1900) / 100);
212                 break;
213             case 'd' :
214                 ret = snprintf (buf, maxsize - n,
215                                 "%02d", tm->tm_mday);
216                 break;
217             case 'D' :
218                 ret = snprintf (buf, maxsize - n,
219                                 "%02d/%02d/%02d",
220                                 tm->tm_mon + 1,
221                                 tm->tm_mday,
222                                 (tm->tm_year + 1900) % 100);
223                 break;
224             case 'e' :
225                 ret = snprintf (buf, maxsize - n,
226                                 "%2d", tm->tm_mday);
227                 break;
228             case 'F':
229                 ret = snprintf (buf, maxsize - n,
230                                 "%04d-%02d-%02d", tm->tm_year + 1900,
231                                 tm->tm_mon + 1, tm->tm_mday);
232                 break;
233             case 'g':
234                 /* last two digits of week-based year */
235                 abort();
236             case 'G':
237                 /* week-based year */
238                 abort();
239             case 'H' :
240                 ret = snprintf (buf, maxsize - n,
241                                 "%02d", tm->tm_hour);
242                 break;
243             case 'I' :
244                 ret = snprintf (buf, maxsize - n,
245                                 "%02d",
246                                 hour_24to12 (tm->tm_hour));
247                 break;
248             case 'j' :
249                 ret = snprintf (buf, maxsize - n,
250                                 "%03d", tm->tm_yday + 1);
251                 break;
252             case 'k' :
253                 ret = snprintf (buf, maxsize - n,
254                                 "%2d", tm->tm_hour);
255                 break;
256             case 'l' :
257                 ret = snprintf (buf, maxsize - n,
258                                 "%2d",
259                                 hour_24to12 (tm->tm_hour));
260                 break;
261             case 'm' :
262                 ret = snprintf (buf, maxsize - n,
263                                 "%02d", tm->tm_mon + 1);
264                 break;
265             case 'M' :
266                 ret = snprintf (buf, maxsize - n,
267                                 "%02d", tm->tm_min);
268                 break;
269             case 'n' :
270                 ret = snprintf (buf, maxsize - n, "\n");
271                 break;
272             case 'p' :
273                 ret = snprintf (buf, maxsize - n, "%s",
274                                 hour_to_ampm (tm->tm_hour));
275                 break;
276             case 'r' :
277                 ret = snprintf (buf, maxsize - n,
278                                 "%02d:%02d:%02d %s",
279                                 hour_24to12 (tm->tm_hour),
280                                 tm->tm_min,
281                                 tm->tm_sec,
282                                 hour_to_ampm (tm->tm_hour));
283                 break;
284             case 'R' :
285                 ret = snprintf (buf, maxsize - n,
286                                 "%02d:%02d",
287                                 tm->tm_hour,
288                                 tm->tm_min);
289                 break;
290             case 's' :
291                 ret = snprintf (buf, maxsize - n,
292                                 "%d", (int)mktime(rk_UNCONST(tm)));
293                 break;
294             case 'S' :
295                 ret = snprintf (buf, maxsize - n,
296                                 "%02d", tm->tm_sec);
297                 break;
298             case 't' :
299                 ret = snprintf (buf, maxsize - n, "\t");
300                 break;
301             case 'T' :
302             case 'X' :
303                 ret = snprintf (buf, maxsize - n,
304                                 "%02d:%02d:%02d",
305                                 tm->tm_hour,
306                                 tm->tm_min,
307                                 tm->tm_sec);
308                 break;
309             case 'u' :
310                 ret = snprintf (buf, maxsize - n,
311                                 "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
312                 break;
313             case 'U' :
314                 ret = snprintf (buf, maxsize - n,
315                                 "%02d", week_number_sun (tm));
316                 break;
317             case 'V' :
318                 ret = snprintf (buf, maxsize - n,
319                                 "%02d", week_number_mon4 (tm));
320                 break;
321             case 'w' :
322                 ret = snprintf (buf, maxsize - n,
323                                 "%d", tm->tm_wday);
324                 break;
325             case 'W' :
326                 ret = snprintf (buf, maxsize - n,
327                                 "%02d", week_number_mon (tm));
328                 break;
329             case 'x' :
330                 ret = snprintf (buf, maxsize - n,
331                                 "%d:%02d:%02d",
332                                 tm->tm_year,
333                                 tm->tm_mon + 1,
334                                 tm->tm_mday);
335                 break;
336             case 'y' :
337                 ret = snprintf (buf, maxsize - n,
338                                 "%02d", (tm->tm_year + 1900) % 100);
339                 break;
340             case 'Y' :
341                 ret = snprintf (buf, maxsize - n,
342                                 "%d", tm->tm_year + 1900);
343                 break;
344             case 'z':
345                 ret = snprintf (buf, maxsize - n,
346                                 "%ld",
347 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
348                                 (long)tm->tm_gmtoff
349 #elif defined(HAVE_TIMEZONE)
350 #ifdef HAVE_ALTZONE
351                                 tm->tm_isdst ?
352                                 (long)altzone :
353 #endif
354                                 (long)timezone
355 #else
356 #error Where in timezone chaos are you?
357 #endif
358                                 );
359                 break;
360             case 'Z' :
361                 ret = snprintf (buf, maxsize - n,
362                                 "%s",
363
364 #if defined(HAVE_STRUCT_TM_TM_ZONE)
365                                 tm->tm_zone
366 #elif defined(HAVE_TIMEZONE)
367                                 tzname[tm->tm_isdst]
368 #else
369 #error what?
370 #endif
371                     );
372                 break;
373             case '\0' :
374                 --format;
375                 /* FALLTHROUGH */
376             case '%' :
377                 ret = snprintf (buf, maxsize - n,
378                                 "%%");
379                 break;
380             default :
381                 ret = snprintf (buf, maxsize - n,
382                                 "%%%c", *format);
383                 break;
384             }
385             if (ret < 0 || ret >= (int)(maxsize - n))
386                 return 0;
387             n   += ret;
388             buf += ret;
389             ++format;
390         } else {
391             *buf++ = *format++;
392             ++n;
393         }
394     }
395     *buf = '\0';
396     return n;
397 }