1 //========================================================================
5 // ISO C date and time implementation for strftime()
7 //========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //========================================================================
41 //#####DESCRIPTIONBEGIN####
43 // Author(s): jlarmour
44 // Contributors: jlarmour
46 // Purpose: Provide implementation of the ISO C function strftime()
47 // from ISO C section 7.12.3.5
48 // Description: This file provides the implementation of strftime()
51 //####DESCRIPTIONEND####
53 //========================================================================
57 #include <pkgconf/libc_time.h> // C library configuration
61 #include <cyg/infra/cyg_type.h> // Common type definitions and support
62 #include <cyg/infra/cyg_ass.h> // Assertion infrastructure
63 #include <cyg/infra/cyg_trac.h> // Tracing infrastructure
64 #include <time.h> // Main date and time definitions
65 #include <cyg/libc/time/timeutil.h>// For cyg_libc_time_{day,month}_name{,_len}
67 // FUNCTION PROTOTYPES
69 // FIXME: This all needs to be internationalized and localized, both in
70 // terms of reading and writing multibyte characters, and that it should
71 // refer to the settings of LC_TIME
75 // This helper function actually processes the format. Which format to insert
76 // is indicated by fmtchar, sizeleft is the maximum space allowed to be used
77 // in buf. The number of bytes written is returned, or -1 if there was no
81 do_format(cyg_uint8 fmtchar, cyg_ucount32 sizeleft, char *buf,
82 const struct tm *timeptr)
88 CYG_PRECONDITION((timeptr->tm_wday >= 0) && (timeptr->tm_wday < 7),
89 "timeptr->tm_wday out of range!");
92 buf[0] = cyg_libc_time_day_name[timeptr->tm_wday][0];
93 buf[1] = cyg_libc_time_day_name[timeptr->tm_wday][1];
94 buf[2] = cyg_libc_time_day_name[timeptr->tm_wday][2];
97 CYG_PRECONDITION((timeptr->tm_wday >= 0) && (timeptr->tm_wday < 7),
98 "timeptr->tm_wday out of range!");
99 if (sizeleft < cyg_libc_time_day_name_len[timeptr->tm_wday])
101 for (i=0; i<cyg_libc_time_day_name_len[timeptr->tm_wday]; ++i)
102 buf[i] = cyg_libc_time_day_name[timeptr->tm_wday][i];
104 #ifdef CYGFUN_LIBC_TIME_SUS_EXTNS
106 // ** fall through **
109 CYG_PRECONDITION((timeptr->tm_mon >= 0) && (timeptr->tm_mon < 12),
110 "timeptr->tm_mon out of range!");
113 buf[0] = cyg_libc_time_month_name[timeptr->tm_mon][0];
114 buf[1] = cyg_libc_time_month_name[timeptr->tm_mon][1];
115 buf[2] = cyg_libc_time_month_name[timeptr->tm_mon][2];
118 CYG_PRECONDITION((timeptr->tm_mon >= 0) && (timeptr->tm_mon < 12),
119 "timeptr->tm_mon out of range!");
120 if (sizeleft < cyg_libc_time_month_name_len[timeptr->tm_mon])
122 for (i=0; i<cyg_libc_time_month_name_len[timeptr->tm_mon]; ++i)
123 buf[i] = cyg_libc_time_month_name[timeptr->tm_mon][i];
129 // Recurse! Note that we know that we will have left room for the
130 // trailing NULL in the strftime body
132 i = strftime( buf, sizeleft+1, "%a %b %d %I:%M:%S%p %Y", timeptr);
134 return ((0==i) ? -1 : i);
136 // Currently I don't check _actual_ numbers of days in each month here
137 // FIXME: No reason why not though
138 CYG_PRECONDITION((timeptr->tm_mday >= 1) && (timeptr->tm_mday < 32),
139 "timeptr->tm_mday out of range!");
143 buf[0] = (timeptr->tm_mday / 10) + '0';
144 buf[1] = (timeptr->tm_mday % 10) + '0';
146 #ifdef CYGFUN_LIBC_TIME_SUS_EXTNS
148 // Currently I don't check _actual_ numbers of days in each month here
149 // FIXME: No reason why not though
150 CYG_PRECONDITION((timeptr->tm_mday >= 1) && (timeptr->tm_mday < 32),
151 "timeptr->tm_mday out of range!");
154 i = (timeptr->tm_mday / 10);
155 buf[0] = (0 == i) ? ' ' : i + '0';
156 buf[1] = (timeptr->tm_mday % 10) + '0';
160 CYG_PRECONDITION((timeptr->tm_hour >= 0) && (timeptr->tm_hour < 24),
161 "timeptr->tm_hour out of range!");
164 buf[0] = (timeptr->tm_hour / 10) + '0';
165 buf[1] = (timeptr->tm_hour % 10) + '0';
168 CYG_PRECONDITION((timeptr->tm_hour >= 0) && (timeptr->tm_hour < 24),
169 "timeptr->tm_hour out of range!");
172 buf[0] = (((timeptr->tm_hour%12) ? (timeptr->tm_hour%12) : 12) / 10) + '0';
173 buf[1] = (((timeptr->tm_hour%12) ? (timeptr->tm_hour%12) : 12) % 10) + '0';
176 CYG_PRECONDITION((timeptr->tm_yday >= 0) && (timeptr->tm_yday < 366),
177 "timeptr->tm_yday out of range!");
180 buf[0] = (timeptr->tm_yday / 100) + '0';
181 buf[1] = ((timeptr->tm_yday % 100) / 10) + '0';
182 buf[2] = (timeptr->tm_yday % 10) + '0';
185 CYG_PRECONDITION((timeptr->tm_mon >= 0) && (timeptr->tm_mon < 12),
186 "timeptr->tm_mon out of range!");
189 buf[0] = ((timeptr->tm_mon+1) / 10) + '0';
190 buf[1] = ((timeptr->tm_mon+1) % 10) + '0';
193 CYG_PRECONDITION((timeptr->tm_min >= 0) && (timeptr->tm_min < 60),
194 "timeptr->tm_min out of range!");
197 buf[0] = (timeptr->tm_min / 10) + '0';
198 buf[1] = (timeptr->tm_min % 10) + '0';
201 CYG_PRECONDITION((timeptr->tm_hour >= 0) && (timeptr->tm_hour < 24),
202 "timeptr->tm_hour out of range!");
205 buf[0] = (timeptr->tm_hour > 11) ? 'p' : 'a';
209 CYG_PRECONDITION((timeptr->tm_sec >= 0) && (timeptr->tm_sec < 62),
210 "timeptr->tm_sec out of range!");
213 buf[0] = (timeptr->tm_sec / 10) + '0';
214 buf[1] = (timeptr->tm_sec % 10) + '0';
216 #ifdef CYGFUN_LIBC_TIME_SUS_EXTNS
221 // Recurse! Note that we know that we will have left room for the
222 // trailing NULL in the strftime body
224 i = strftime( buf, sizeleft+1, "%H:%M:%S", timeptr);
226 return ((0==i) ? -1 : i);
229 CYG_PRECONDITION((timeptr->tm_wday >= 0) && (timeptr->tm_wday < 7),
230 "timeptr->tm_wday out of range!");
231 CYG_PRECONDITION((timeptr->tm_yday >= 0) && (timeptr->tm_yday < 366),
232 "timeptr->tm_yday out of range!");
235 i = (timeptr->tm_yday - timeptr->tm_wday + 7) / 7;
236 buf[0] = (i / 10) + '0';
237 buf[1] = (i % 10) + '0';
240 CYG_PRECONDITION((timeptr->tm_wday >= 0) && (timeptr->tm_wday < 7),
241 "timeptr->tm_wday out of range!");
242 // Don't need to check size - we'll always be called with sizeleft > 0
243 buf[0] = timeptr->tm_wday + '0';
246 CYG_PRECONDITION((timeptr->tm_wday >= 0) && (timeptr->tm_wday < 7),
247 "timeptr->tm_wday out of range!");
248 CYG_PRECONDITION((timeptr->tm_yday >= 0) && (timeptr->tm_yday < 366),
249 "timeptr->tm_yday out of range!");
252 i = (timeptr->tm_yday + ((8-timeptr->tm_wday) % 7)) / 7;
253 buf[0] = (i / 10) + '0';
254 buf[1] = (i % 10) + '0';
260 // Recurse! Note that we know that we will have left room for the
261 // trailing NULL in the strftime body
263 i = strftime( buf, sizeleft+1, "%a %b %d %Y", timeptr);
265 return (0==i) ? -1 : i;
270 // Recurse! Note that we know that we will have left room for the
271 // trailing NULL in the strftime body
273 i = strftime( buf, sizeleft+1, "%I:%M:%S%p", timeptr);
275 return (0==i) ? -1 : i;
277 CYG_PRECONDITION((timeptr->tm_year > -1900) &&
278 (timeptr->tm_year < 8100),
279 "timeptr->tm_year out of range!");
282 buf[0] = ((timeptr->tm_year % 100) / 10) + '0';
283 buf[1] = ((timeptr->tm_year % 100) % 10) + '0';
286 CYG_PRECONDITION((timeptr->tm_year > -1900) &&
287 (timeptr->tm_year < 8100),
288 "timeptr->tm_year out of range!");
291 buf[0] = ((1900+timeptr->tm_year) / 1000) + '0';
292 buf[1] = (((1900+timeptr->tm_year) % 1000) / 100) + '0';
293 buf[2] = ((timeptr->tm_year % 100) / 10) + '0';
294 buf[3] = (timeptr->tm_year % 10) + '0';
297 // FIXME: Should store zone in timeptr->tm_zone, or failing that
298 // read TZ env variable using tzset()
301 // Don't need to check size - we'll always be called with sizeleft > 0
305 CYG_FAIL("invalid format character!");
312 strftime( char *s, size_t maxsize, const char *format,
313 const struct tm *timeptr)
315 CYG_REPORT_FUNCNAMETYPE("strftime", "returning string length %d");
316 CYG_CHECK_DATA_PTR(s, "string s is not a valid address!");
317 CYG_CHECK_DATA_PTR(format, "format string is not at a valid address!");
318 CYG_CHECK_DATA_PTR(timeptr,
319 "struct tm argument is not at a valid address!");
320 CYG_REPORT_FUNCARG4("s is at address %08x, maxsize=%d, format=\"%s\", "
321 "timeptr is at address %08x",
322 s, maxsize, format, timeptr);
325 CYG_REPORT_RETVAL(0);
329 // lets leave the room for the trailing null up front
332 cyg_ucount32 i, spos;
335 for (i=0, spos=0; (spos<maxsize) && (format[i] != '\0'); ++i) {
336 if (format[i] == '%') {
337 if (format[++i] == '\0')
339 dof_ret = do_format(format[i], maxsize - spos, &s[spos], timeptr);
340 // was there room to write _anything_?
342 spos=0; // ISO says we must return 0 and the contents of s
349 s[spos++] = format[i];
355 CYG_REPORT_RETVAL(spos);