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