]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/language/c/libc/time/v2_0/src/strftime.cxx
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / language / c / libc / time / v2_0 / src / strftime.cxx
1 //========================================================================
2 //
3 //      strftime.cxx
4 //
5 //      ISO C date and time implementation for strftime()
6 //
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.
12 //
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.
16 //
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
20 // for more details.
21 //
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.
25 //
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.
32 //
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.
35 //
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####
42 //
43 // Author(s):    jlarmour
44 // Contributors: jlarmour
45 // Date:         1999-02-26
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()
49 // Usage:         
50 //
51 //####DESCRIPTIONEND####
52 //
53 //========================================================================
54
55 // CONFIGURATION
56
57 #include <pkgconf/libc_time.h>          // C library configuration
58
59 // INCLUDES
60
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}
66
67 // FUNCTION PROTOTYPES
68
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
72
73 // FUNCTIONS
74
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
78 // space
79
80 static cyg_count8
81 do_format(cyg_uint8 fmtchar, cyg_ucount32 sizeleft, char *buf,
82           const struct tm *timeptr)
83 {
84     cyg_count8 i;
85
86     switch (fmtchar) {
87     case 'a':
88         CYG_PRECONDITION((timeptr->tm_wday >= 0) && (timeptr->tm_wday < 7),
89                          "timeptr->tm_wday out of range!");
90         if (sizeleft<3)
91             return -1;
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];
95         return 3;
96     case 'A':
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])
100             return -1;
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];
103         return i;
104 #ifdef CYGFUN_LIBC_TIME_SUS_EXTNS
105     case 'h':
106         // ** fall through **
107 #endif
108     case 'b':
109         CYG_PRECONDITION((timeptr->tm_mon >= 0) && (timeptr->tm_mon < 12),
110                          "timeptr->tm_mon out of range!");
111         if (sizeleft<3)
112             return -1;
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];
116         return 3;
117     case 'B':
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])
121             return -1;
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];
124         return i;
125     case 'c':
126         if (sizeleft < 26)
127             return -1;
128
129         // Recurse! Note that we know that we will have left room for the
130         // trailing NULL in the strftime body
131         
132         i = strftime( buf, sizeleft+1, "%a %b %d %I:%M:%S%p %Y", timeptr);
133         
134         return ((0==i) ? -1 : i);
135     case 'd':
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!");
140
141         if (sizeleft < 2)
142             return -1;
143         buf[0] = (timeptr->tm_mday / 10) + '0';
144         buf[1] = (timeptr->tm_mday % 10) + '0';
145         return 2;
146 #ifdef CYGFUN_LIBC_TIME_SUS_EXTNS
147     case 'e':
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!");
152         if (sizeleft < 2)
153             return -1;
154         i = (timeptr->tm_mday / 10);
155         buf[0] = (0 == i) ? ' ' : i + '0';
156         buf[1] = (timeptr->tm_mday % 10) + '0';
157         return 2;
158 #endif
159     case 'H':
160         CYG_PRECONDITION((timeptr->tm_hour >= 0) && (timeptr->tm_hour < 24),
161                          "timeptr->tm_hour out of range!");
162         if (sizeleft < 2)
163             return -1;
164         buf[0] = (timeptr->tm_hour / 10) + '0';
165         buf[1] = (timeptr->tm_hour % 10) + '0';
166         return 2;
167     case 'I':
168         CYG_PRECONDITION((timeptr->tm_hour >= 0) && (timeptr->tm_hour < 24),
169                          "timeptr->tm_hour out of range!");
170         if (sizeleft < 2)
171             return -1;
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';
174         return 2;
175     case 'j':
176         CYG_PRECONDITION((timeptr->tm_yday >= 0) && (timeptr->tm_yday < 366),
177                          "timeptr->tm_yday out of range!");
178         if (sizeleft < 3)
179             return -1;
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';
183         return 3;
184     case 'm':
185         CYG_PRECONDITION((timeptr->tm_mon >= 0) && (timeptr->tm_mon < 12),
186                          "timeptr->tm_mon out of range!");
187         if (sizeleft < 2)
188             return -1;
189         buf[0] = ((timeptr->tm_mon+1) / 10) + '0';
190         buf[1] = ((timeptr->tm_mon+1) % 10) + '0';
191         return 2;
192     case 'M':
193         CYG_PRECONDITION((timeptr->tm_min >= 0) && (timeptr->tm_min < 60),
194                          "timeptr->tm_min out of range!");
195         if (sizeleft < 2)
196             return -1;
197         buf[0] = (timeptr->tm_min / 10) + '0';
198         buf[1] = (timeptr->tm_min % 10) + '0';
199         return 2;
200     case 'p':
201         CYG_PRECONDITION((timeptr->tm_hour >= 0) && (timeptr->tm_hour < 24),
202                          "timeptr->tm_hour out of range!");
203         if (sizeleft < 2)
204             return -1;
205         buf[0] = (timeptr->tm_hour > 11) ? 'p' : 'a';
206         buf[1] = 'm';
207         return 2;
208     case 'S':
209         CYG_PRECONDITION((timeptr->tm_sec >= 0) && (timeptr->tm_sec < 62),
210                          "timeptr->tm_sec out of range!");
211         if (sizeleft < 2)
212             return -1;
213         buf[0] = (timeptr->tm_sec / 10) + '0';
214         buf[1] = (timeptr->tm_sec % 10) + '0';
215         return 2;
216 #ifdef CYGFUN_LIBC_TIME_SUS_EXTNS
217     case 'T':
218         if (sizeleft < 8)
219             return -1;
220
221         // Recurse! Note that we know that we will have left room for the
222         // trailing NULL in the strftime body
223         
224         i = strftime( buf, sizeleft+1, "%H:%M:%S", timeptr);
225         
226         return ((0==i) ? -1 : i);
227 #endif
228     case 'U':
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!");
233         if (sizeleft < 2)
234             return -1;
235         i = (timeptr->tm_yday - timeptr->tm_wday + 7) / 7;
236         buf[0] = (i / 10) + '0';
237         buf[1] = (i % 10) + '0';
238         return 2;
239     case 'w':
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';
244         return 1;
245     case 'W':
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!");
250         if (sizeleft < 2)
251             return -1;
252         i = (timeptr->tm_yday + ((8-timeptr->tm_wday) % 7)) / 7;
253         buf[0] = (i / 10) + '0';
254         buf[1] = (i % 10) + '0';
255         return 2;
256     case 'x':
257         if (sizeleft < 15)
258             return -1;
259
260         // Recurse! Note that we know that we will have left room for the
261         // trailing NULL in the strftime body
262
263         i = strftime( buf, sizeleft+1, "%a %b %d %Y", timeptr);
264
265         return (0==i) ? -1 : i;
266     case 'X':
267         if (sizeleft < 10)
268             return -1;
269
270         // Recurse! Note that we know that we will have left room for the
271         // trailing NULL in the strftime body
272
273         i = strftime( buf, sizeleft+1, "%I:%M:%S%p", timeptr);
274
275         return (0==i) ? -1 : i;
276     case 'y':
277         CYG_PRECONDITION((timeptr->tm_year > -1900) &&
278                          (timeptr->tm_year < 8100),
279                          "timeptr->tm_year out of range!");
280         if (sizeleft < 2)
281             return -1;
282         buf[0] = ((timeptr->tm_year % 100) / 10) + '0';
283         buf[1] = ((timeptr->tm_year % 100) % 10) + '0';
284         return 2;
285     case 'Y':
286         CYG_PRECONDITION((timeptr->tm_year > -1900) &&
287                          (timeptr->tm_year < 8100),
288                          "timeptr->tm_year out of range!");
289         if (sizeleft < 4)
290             return -1;
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';
295         return 4;
296     case 'Z':
297         // FIXME: Should store zone in timeptr->tm_zone, or failing that
298         // read TZ env variable using tzset()
299         return 0;
300     case '%':
301         // Don't need to check size - we'll always be called with sizeleft > 0
302         buf[0] = '%';
303         return 1;
304     default:
305         CYG_FAIL("invalid format character!");
306         return -1;
307     } // switch
308
309 } // do_format()
310
311 externC size_t
312 strftime( char *s, size_t maxsize, const char *format,
313           const struct tm *timeptr)
314 {
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);
323
324     if (!maxsize) {
325         CYG_REPORT_RETVAL(0);
326         return 0;
327     } // if
328
329     // lets leave the room for the trailing null up front
330     --maxsize;
331
332     cyg_ucount32 i, spos;
333     cyg_count8 dof_ret;
334     
335     for (i=0, spos=0; (spos<maxsize) && (format[i] != '\0'); ++i) {
336         if (format[i] == '%') {
337             if (format[++i] == '\0')
338                 break;
339             dof_ret = do_format(format[i], maxsize - spos, &s[spos], timeptr);
340             // was there room to write _anything_?
341             if (dof_ret < 0) {
342                 spos=0;  // ISO says we must return 0 and the contents of s
343                          // are indeterminate
344                 break;
345             }
346             spos += dof_ret;
347         }
348         else {
349             s[spos++] = format[i];
350         } // else
351     } // for
352     
353     s[spos] = '\0';
354     
355     CYG_REPORT_RETVAL(spos);
356     return spos;
357
358 } // strftime()
359
360
361 // EOF strftime.cxx