PageRenderTime 32ms CodeModel.GetById 10ms app.highlight 18ms RepoModel.GetById 2ms app.codeStats 0ms

/crypto/heimdal/lib/roken/strftime.c

https://bitbucket.org/freebsd/freebsd-head/
C | 397 lines | 318 code | 23 blank | 56 comment | 19 complexity | 179d7f1fc925a47735041400152b7f78 MD5 | raw file
  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
 39static const char *abb_weekdays[] = {
 40    "Sun",
 41    "Mon",
 42    "Tue",
 43    "Wed",
 44    "Thu",
 45    "Fri",
 46    "Sat",
 47};
 48
 49static const char *full_weekdays[] = {
 50    "Sunday",
 51    "Monday",
 52    "Tuesday",
 53    "Wednesday",
 54    "Thursday",
 55    "Friday",
 56    "Saturday",
 57};
 58
 59static 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
 74static 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
 89static 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
 98static int
 99hour_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
112static const char *
113hour_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
123static int
124week_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
134static int
135week_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
148static int
149week_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
169ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
170strftime (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}