]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/language/c/libc/time/v2_0/src/strftime.cxx
c6e7bc3ac7afa2c9dc2dbe1c6e1b6b327e8932ec
[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         if (sizeleft<3)
89             return -1;
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];
93         return 3;
94     case 'A':
95         if (sizeleft < cyg_libc_time_day_name_len[timeptr->tm_wday])
96             return -1;
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];
99         return i;
100 #ifdef CYGFUN_LIBC_TIME_SUS_EXTNS
101     case 'h':
102         // ** fall through **
103 #endif
104     case 'b':
105         if (sizeleft<3)
106             return -1;
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];
110         return 3;
111     case 'B':
112         if (sizeleft < cyg_libc_time_month_name_len[timeptr->tm_mon])
113             return -1;
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];
116         return i;
117     case 'c':
118         if (sizeleft < 26)
119             return -1;
120
121         // Recurse! Note that we know that we will have left room for the
122         // trailing NULL in the strftime body
123         
124         i = strftime( buf, sizeleft+1, "%a %b %d %I:%M:%S%p %Y", timeptr);
125         
126         return ((0==i) ? -1 : i);
127     case 'd':
128         if (sizeleft < 2)
129             return -1;
130         buf[0] = (timeptr->tm_mday / 10) + '0';
131         buf[1] = (timeptr->tm_mday % 10) + '0';
132         return 2;
133 #ifdef CYGFUN_LIBC_TIME_SUS_EXTNS
134     case 'e':
135         if (sizeleft < 2)
136             return -1;
137         i = (timeptr->tm_mday / 10);
138         buf[0] = (0 == i) ? ' ' : i + '0';
139         buf[1] = (timeptr->tm_mday % 10) + '0';
140         return 2;
141 #endif
142     case 'H':
143         if (sizeleft < 2)
144             return -1;
145         buf[0] = (timeptr->tm_hour / 10) + '0';
146         buf[1] = (timeptr->tm_hour % 10) + '0';
147         return 2;
148     case 'I':
149         if (sizeleft < 2)
150             return -1;
151         buf[0] = ((timeptr->tm_hour%12 + 1) / 10) + '0';
152         buf[1] = ((timeptr->tm_hour%12 + 1) % 10) + '0';
153         return 2;
154     case 'j':
155         if (sizeleft < 3)
156             return -1;
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';
160         return 3;
161     case 'm':
162         if (sizeleft < 2)
163             return -1;
164         buf[0] = ((timeptr->tm_mon+1) / 10) + '0';
165         buf[1] = ((timeptr->tm_mon+1) % 10) + '0';
166         return 2;
167     case 'M':
168         if (sizeleft < 2)
169             return -1;
170         buf[0] = (timeptr->tm_min / 10) + '0';
171         buf[1] = (timeptr->tm_min % 10) + '0';
172         return 2;
173     case 'p':
174         if (sizeleft < 2)
175             return -1;
176         buf[0] = (timeptr->tm_hour > 11) ? 'p' : 'a';
177         buf[1] = 'm';
178         return 2;
179     case 'S':
180         if (sizeleft < 2)
181             return -1;
182         buf[0] = (timeptr->tm_sec / 10) + '0';
183         buf[1] = (timeptr->tm_sec % 10) + '0';
184         return 2;
185 #ifdef CYGFUN_LIBC_TIME_SUS_EXTNS
186     case 'T':
187         if (sizeleft < 8)
188             return -1;
189
190         // Recurse! Note that we know that we will have left room for the
191         // trailing NULL in the strftime body
192         
193         i = strftime( buf, sizeleft+1, "%H:%M:%S", timeptr);
194         
195         return ((0==i) ? -1 : i);
196 #endif
197     case 'U':
198         if (sizeleft < 2)
199             return -1;
200         i = (timeptr->tm_yday - timeptr->tm_wday + 7) / 7;
201         buf[0] = (i / 10) + '0';
202         buf[1] = (i % 10) + '0';
203         return 2;
204     case 'w':
205         // Don't need to check size - we'll always be called with sizeleft > 0
206         buf[0] = timeptr->tm_wday + '0';
207         return 1;
208     case 'W':
209         if (sizeleft < 2)
210             return -1;
211         i = (timeptr->tm_yday + ((8-timeptr->tm_wday) % 7)) / 7;
212         buf[0] = (i / 10) + '0';
213         buf[1] = (i % 10) + '0';
214         return 2;
215     case 'x':
216         if (sizeleft < 15)
217             return -1;
218
219         // Recurse! Note that we know that we will have left room for the
220         // trailing NULL in the strftime body
221
222         i = strftime( buf, sizeleft+1, "%a %b %d %Y", timeptr);
223
224         return (0==i) ? -1 : i;
225     case 'X':
226         if (sizeleft < 10)
227             return -1;
228
229         // Recurse! Note that we know that we will have left room for the
230         // trailing NULL in the strftime body
231
232         i = strftime( buf, sizeleft+1, "%I:%M:%S%p", timeptr);
233
234         return (0==i) ? -1 : i;
235     case 'y':
236         if (sizeleft < 2)
237             return -1;
238         buf[0] = ((timeptr->tm_year % 100) / 10) + '0';
239         buf[1] = ((timeptr->tm_year % 100) % 10) + '0';
240         return 2;
241     case 'Y':
242         if (sizeleft < 4)
243             return -1;
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';
248         return 4;
249     case 'Z':
250         // FIXME: Should store zone in timeptr->tm_zone, or failing that
251         // read TZ env variable using tzset()
252         return 0;
253     case '%':
254         // Don't need to check size - we'll always be called with sizeleft > 0
255         buf[0] = '%';
256         return 1;
257     default:
258         CYG_FAIL("invalid format character!");
259         return -1;
260     } // switch
261
262 } // do_format()
263
264 externC size_t
265 strftime( char *s, size_t maxsize, const char *format,
266           const struct tm *timeptr)
267 {
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);
276
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!");
296
297     if (!maxsize) {
298         CYG_REPORT_RETVAL(0);
299         return 0;
300     } // if
301
302     // lets leave the room for the trailing null up front
303     --maxsize;
304
305     cyg_ucount32 i, spos;
306     cyg_count8 dof_ret;
307     
308     for (i=0, spos=0; (spos<maxsize) && (format[i] != '\0'); ++i) {
309         if (format[i] == '%') {
310             if (format[++i] == '\0')
311                 break;
312             dof_ret = do_format(format[i], maxsize - spos, &s[spos], timeptr);
313             // was there room to write _anything_?
314             if (dof_ret < 0) {
315                 spos=0;  // ISO says we must return 0 and the contents of s
316                          // are indeterminate
317                 break;
318             }
319             spos += dof_ret;
320         }
321         else {
322             s[spos++] = format[i];
323         } // else
324     } // for
325     
326     s[spos] = '\0';
327     
328     CYG_REPORT_RETVAL(spos);
329     return spos;
330
331 } // strftime()
332
333
334 // EOF strftime.cxx