clean test-rc-file.rc
[heimdal.git] / lib / roken / strftime.c
blob471078753e68b74c34f66d6b82d2272dde3f8feb
1 /*
2 * Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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. */
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"
41 RCSID("$Id$");
43 static const char *abb_weekdays[] = {
44 "Sun",
45 "Mon",
46 "Tue",
47 "Wed",
48 "Thu",
49 "Fri",
50 "Sat",
53 static const char *full_weekdays[] = {
54 "Sunday",
55 "Monday",
56 "Tuesday",
57 "Wednesday",
58 "Thursday",
59 "Friday",
60 "Saturday",
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"
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"
93 static const char *ampm[] = {
94 "AM",
95 "PM"
99 * Convert hour in [0, 24] to [12 1 - 11 12 1 - 11 12]
102 static int
103 hour_24to12 (int hour)
105 int ret = hour % 12;
107 if (ret == 0)
108 ret = 12;
109 return ret;
113 * Return AM or PM for `hour'
116 static const char *
117 hour_to_ampm (int hour)
119 return ampm[hour / 12];
123 * Return the week number of `tm' (Sunday being the first day of the week)
124 * as [0, 53]
127 static int
128 week_number_sun (const struct tm *tm)
130 return (tm->tm_yday + 7 - (tm->tm_yday % 7 - tm->tm_wday + 7) % 7) / 7;
134 * Return the week number of `tm' (Monday being the first day of the week)
135 * as [0, 53]
138 static int
139 week_number_mon (const struct tm *tm)
141 int wday = (tm->tm_wday + 6) % 7;
143 return (tm->tm_yday + 7 - (tm->tm_yday % 7 - wday + 7) % 7) / 7;
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.
152 static int
153 week_number_mon4 (const struct tm *tm)
155 int wday = (tm->tm_wday + 6) % 7;
156 int w1day = (wday - tm->tm_yday % 7 + 7) % 7;
157 int ret;
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;
173 size_t ROKEN_LIB_FUNCTION
174 strftime (char *buf, size_t maxsize, const char *format,
175 const struct tm *tm)
177 size_t n = 0;
178 int ret;
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);
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
363 break;
364 case 'Z' :
365 ret = snprintf (buf, maxsize - n,
366 "%s",
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
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;
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;
399 *buf++ = '\0';
400 return n;