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)
90 buf[0] = cyg_libc_time_day_name[timeptr->tm_wday][0];
91 buf[1] = cyg_libc_time_day_name[timeptr->tm_wday][1];
92 buf[2] = cyg_libc_time_day_name[timeptr->tm_wday][2];
95 if (sizeleft < cyg_libc_time_day_name_len[timeptr->tm_wday])
97 for (i=0; i<cyg_libc_time_day_name_len[timeptr->tm_wday]; ++i)
98 buf[i] = cyg_libc_time_day_name[timeptr->tm_wday][i];
100 #ifdef CYGFUN_LIBC_TIME_SUS_EXTNS
102 // ** fall through **
107 buf[0] = cyg_libc_time_month_name[timeptr->tm_mon][0];
108 buf[1] = cyg_libc_time_month_name[timeptr->tm_mon][1];
109 buf[2] = cyg_libc_time_month_name[timeptr->tm_mon][2];
112 if (sizeleft < cyg_libc_time_month_name_len[timeptr->tm_mon])
114 for (i=0; i<cyg_libc_time_month_name_len[timeptr->tm_mon]; ++i)
115 buf[i] = cyg_libc_time_month_name[timeptr->tm_mon][i];
121 // Recurse! Note that we know that we will have left room for the
122 // trailing NULL in the strftime body
124 i = strftime( buf, sizeleft+1, "%a %b %d %I:%M:%S%p %Y", timeptr);
126 return ((0==i) ? -1 : i);
130 buf[0] = (timeptr->tm_mday / 10) + '0';
131 buf[1] = (timeptr->tm_mday % 10) + '0';
133 #ifdef CYGFUN_LIBC_TIME_SUS_EXTNS
137 i = (timeptr->tm_mday / 10);
138 buf[0] = (0 == i) ? ' ' : i + '0';
139 buf[1] = (timeptr->tm_mday % 10) + '0';
145 buf[0] = (timeptr->tm_hour / 10) + '0';
146 buf[1] = (timeptr->tm_hour % 10) + '0';
151 buf[0] = ((timeptr->tm_hour%12 + 1) / 10) + '0';
152 buf[1] = ((timeptr->tm_hour%12 + 1) % 10) + '0';
157 buf[0] = (timeptr->tm_yday / 100) + '0';
158 buf[1] = ((timeptr->tm_yday % 100) / 10) + '0';
159 buf[2] = (timeptr->tm_yday % 10) + '0';
164 buf[0] = ((timeptr->tm_mon+1) / 10) + '0';
165 buf[1] = ((timeptr->tm_mon+1) % 10) + '0';
170 buf[0] = (timeptr->tm_min / 10) + '0';
171 buf[1] = (timeptr->tm_min % 10) + '0';
176 buf[0] = (timeptr->tm_hour > 11) ? 'p' : 'a';
182 buf[0] = (timeptr->tm_sec / 10) + '0';
183 buf[1] = (timeptr->tm_sec % 10) + '0';
185 #ifdef CYGFUN_LIBC_TIME_SUS_EXTNS
190 // Recurse! Note that we know that we will have left room for the
191 // trailing NULL in the strftime body
193 i = strftime( buf, sizeleft+1, "%H:%M:%S", timeptr);
195 return ((0==i) ? -1 : i);
200 i = (timeptr->tm_yday - timeptr->tm_wday + 7) / 7;
201 buf[0] = (i / 10) + '0';
202 buf[1] = (i % 10) + '0';
205 // Don't need to check size - we'll always be called with sizeleft > 0
206 buf[0] = timeptr->tm_wday + '0';
211 i = (timeptr->tm_yday + ((8-timeptr->tm_wday) % 7)) / 7;
212 buf[0] = (i / 10) + '0';
213 buf[1] = (i % 10) + '0';
219 // Recurse! Note that we know that we will have left room for the
220 // trailing NULL in the strftime body
222 i = strftime( buf, sizeleft+1, "%a %b %d %Y", timeptr);
224 return (0==i) ? -1 : i;
229 // Recurse! Note that we know that we will have left room for the
230 // trailing NULL in the strftime body
232 i = strftime( buf, sizeleft+1, "%I:%M:%S%p", timeptr);
234 return (0==i) ? -1 : i;
238 buf[0] = ((timeptr->tm_year % 100) / 10) + '0';
239 buf[1] = ((timeptr->tm_year % 100) % 10) + '0';
244 buf[0] = ((1900+timeptr->tm_year) / 1000) + '0';
245 buf[1] = (((1900+timeptr->tm_year) % 1000) / 100) + '0';
246 buf[2] = ((timeptr->tm_year % 100) / 10) + '0';
247 buf[3] = (timeptr->tm_year % 10) + '0';
250 // FIXME: Should store zone in timeptr->tm_zone, or failing that
251 // read TZ env variable using tzset()
254 // Don't need to check size - we'll always be called with sizeleft > 0
258 CYG_FAIL("invalid format character!");
265 strftime( char *s, size_t maxsize, const char *format,
266 const struct tm *timeptr)
268 CYG_REPORT_FUNCNAMETYPE("strftime", "returning string length %d");
269 CYG_CHECK_DATA_PTR(s, "string s is not a valid address!");
270 CYG_CHECK_DATA_PTR(format, "format string is not at a valid address!");
271 CYG_CHECK_DATA_PTR(timeptr,
272 "struct tm argument is not at a valid address!");
273 CYG_REPORT_FUNCARG4("s is at address %08x, maxsize=%d, format=\"%s\", "
274 "timeptr is at address %08x",
275 s, maxsize, format, timeptr);
277 CYG_PRECONDITION((timeptr->tm_sec >= 0) && (timeptr->tm_sec < 62),
278 "timeptr->tm_sec out of range!");
279 CYG_PRECONDITION((timeptr->tm_min >= 0) && (timeptr->tm_min < 60),
280 "timeptr->tm_min out of range!");
281 CYG_PRECONDITION((timeptr->tm_hour >= 0) && (timeptr->tm_hour < 24),
282 "timeptr->tm_hour out of range!");
283 // Currently I don't check _actual_ numbers of days in each month here
284 // FIXME: No reason why not though
285 CYG_PRECONDITION((timeptr->tm_mday >= 1) && (timeptr->tm_mday < 32),
286 "timeptr->tm_mday out of range!");
287 CYG_PRECONDITION((timeptr->tm_mon >= 0) && (timeptr->tm_mon < 12),
288 "timeptr->tm_mon out of range!");
289 CYG_PRECONDITION((timeptr->tm_wday >= 0) && (timeptr->tm_wday < 7),
290 "timeptr->tm_wday out of range!");
291 CYG_PRECONDITION((timeptr->tm_yday >= 0) && (timeptr->tm_yday < 366),
292 "timeptr->tm_yday out of range!");
293 CYG_PRECONDITION((timeptr->tm_year > -1900) &&
294 (timeptr->tm_year < 8100),
295 "timeptr->tm_year out of range!");
298 CYG_REPORT_RETVAL(0);
302 // lets leave the room for the trailing null up front
305 cyg_ucount32 i, spos;
308 for (i=0, spos=0; (spos<maxsize) && (format[i] != '\0'); ++i) {
309 if (format[i] == '%') {
310 if (format[++i] == '\0')
312 dof_ret = do_format(format[i], maxsize - spos, &s[spos], timeptr);
313 // was there room to write _anything_?
315 spos=0; // ISO says we must return 0 and the contents of s
322 s[spos++] = format[i];
328 CYG_REPORT_RETVAL(spos);