|
2
|
1 //======================================================================== |
|
|
2 // |
|
|
3 // strftime.cxx |
|
|
4 // |
|
|
5 // ISO C date and time implementation for strftime() |
|
|
6 // |
|
|
7 //======================================================================== |
|
|
8 //####COPYRIGHTBEGIN#### |
|
|
9 // |
|
|
10 // ------------------------------------------- |
|
|
11 // The contents of this file are subject to the Cygnus eCos Public License |
|
|
12 // Version 1.0 (the "License"); you may not use this file except in |
|
|
13 // compliance with the License. You may obtain a copy of the License at |
|
|
14 // http://sourceware.cygnus.com/ecos |
|
|
15 // |
|
|
16 // Software distributed under the License is distributed on an "AS IS" |
|
|
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
|
|
18 // License for the specific language governing rights and limitations under |
|
|
19 // the License. |
|
|
20 // |
|
|
21 // The Original Code is eCos - Embedded Cygnus Operating System, released |
|
|
22 // September 30, 1998. |
|
|
23 // |
|
|
24 // The Initial Developer of the Original Code is Cygnus. Portions created |
|
|
25 // by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. |
|
|
26 // ------------------------------------------- |
|
|
27 // |
|
|
28 //####COPYRIGHTEND#### |
|
|
29 //======================================================================== |
|
|
30 //#####DESCRIPTIONBEGIN#### |
|
|
31 // |
|
|
32 // Author(s): jlarmour |
|
|
33 // Contributors: jlarmour |
|
|
34 // Date: 1999-02-26 |
|
|
35 // Purpose: Provide implementation of the ISO C function strftime() |
|
|
36 // from ISO C section 7.12.3.5 |
|
|
37 // Description: This file provides the implementation of strftime() |
|
|
38 // Usage: |
|
|
39 // |
|
|
40 //####DESCRIPTIONEND#### |
|
|
41 // |
|
|
42 //======================================================================== |
|
|
43 |
|
|
44 // CONFIGURATION |
|
|
45 |
|
|
46 #include <pkgconf/libc.h> // C library configuration |
|
|
47 |
|
|
48 // INCLUDES |
|
|
49 |
|
|
50 #include <cyg/infra/cyg_type.h> // Common type definitions and support |
|
|
51 #include <cyg/infra/cyg_ass.h> // Assertion infrastructure |
|
|
52 #include <cyg/infra/cyg_trac.h> // Tracing infrastructure |
|
|
53 #include <time.h> // Main date and time definitions |
|
|
54 #include <sys/timeutil.h> // For cyg_libc_time_{day,month}_name{,_len} |
|
|
55 |
|
|
56 // FUNCTION PROTOTYPES |
|
|
57 |
|
|
58 // forward declaration for do_format() |
|
|
59 externC size_t |
|
|
60 __strftime( char *s, size_t maxsize, const char *format, |
|
|
61 const struct tm *timeptr); |
|
|
62 |
|
|
63 |
|
|
64 // FIXME: This all needs to be internationalized and localized, both in |
|
|
65 // terms of reading and writing multibyte characters, and that it should |
|
|
66 // refer to the settings of LC_TIME |
|
|
67 |
|
|
68 // FUNCTIONS |
|
|
69 |
|
|
70 // This helper function actually processes the format. Which format to insert |
|
|
71 // is indicated by fmtchar, sizeleft is the maximum space allowed to be used |
|
|
72 // in buf. The number of bytes written is returned, or -1 if there was no |
|
|
73 // space |
|
|
74 |
|
|
75 static cyg_int8 |
|
|
76 do_format(cyg_uint8 fmtchar, cyg_ucount32 sizeleft, char *buf, |
|
|
77 const struct tm *timeptr) |
|
|
78 { |
|
|
79 cyg_count8 i; |
|
|
80 |
|
|
81 switch (fmtchar) { |
|
|
82 case 'a': |
|
|
83 if (sizeleft<3) |
|
|
84 return -1; |
|
|
85 buf[0] = cyg_libc_time_day_name[timeptr->tm_wday][0]; |
|
|
86 buf[1] = cyg_libc_time_day_name[timeptr->tm_wday][1]; |
|
|
87 buf[2] = cyg_libc_time_day_name[timeptr->tm_wday][2]; |
|
|
88 return 3; |
|
|
89 case 'A': |
|
|
90 if (sizeleft < cyg_libc_time_day_name_len[timeptr->tm_wday]) |
|
|
91 return -1; |
|
|
92 for (i=0; i<cyg_libc_time_day_name_len[timeptr->tm_wday]; ++i) |
|
|
93 buf[i] = cyg_libc_time_day_name[timeptr->tm_wday][i]; |
|
|
94 return i; |
|
|
95 case 'b': |
|
|
96 if (sizeleft<3) |
|
|
97 return -1; |
|
|
98 buf[0] = cyg_libc_time_month_name[timeptr->tm_mon][0]; |
|
|
99 buf[1] = cyg_libc_time_month_name[timeptr->tm_mon][1]; |
|
|
100 buf[2] = cyg_libc_time_month_name[timeptr->tm_mon][2]; |
|
|
101 return 3; |
|
|
102 case 'B': |
|
|
103 if (sizeleft < cyg_libc_time_month_name_len[timeptr->tm_mon]) |
|
|
104 return -1; |
|
|
105 for (i=0; i<cyg_libc_time_month_name_len[timeptr->tm_mon]; ++i) |
|
|
106 buf[i] = cyg_libc_time_month_name[timeptr->tm_mon][i]; |
|
|
107 return i; |
|
|
108 case 'c': |
|
|
109 if (sizeleft < 26) |
|
|
110 return -1; |
|
|
111 |
|
|
112 // Recurse! Note that we know that we will have left room for the |
|
|
113 // trailing NULL in the strftime body |
|
|
114 |
|
|
115 i = __strftime( buf, sizeleft+1, "%a %b %d %I:%M:%S%p %Y", timeptr); |
|
|
116 |
|
|
117 return ((0==i) ? -1 : i); |
|
|
118 case 'd': |
|
|
119 if (sizeleft < 2) |
|
|
120 return -1; |
|
|
121 buf[0] = (timeptr->tm_mday / 10) + '0'; |
|
|
122 buf[1] = (timeptr->tm_mday % 10) + '0'; |
|
|
123 return 2; |
|
|
124 case 'H': |
|
|
125 if (sizeleft < 2) |
|
|
126 return -1; |
|
|
127 buf[0] = (timeptr->tm_hour / 10) + '0'; |
|
|
128 buf[1] = (timeptr->tm_hour % 10) + '0'; |
|
|
129 return 2; |
|
|
130 case 'I': |
|
|
131 if (sizeleft < 2) |
|
|
132 return -1; |
|
|
133 buf[0] = ((timeptr->tm_hour%12 + 1) / 10) + '0'; |
|
|
134 buf[1] = ((timeptr->tm_hour%12 + 1) % 10) + '0'; |
|
|
135 return 2; |
|
|
136 case 'j': |
|
|
137 if (sizeleft < 3) |
|
|
138 return -1; |
|
|
139 buf[0] = (timeptr->tm_yday / 100) + '0'; |
|
|
140 buf[1] = ((timeptr->tm_yday % 100) / 10) + '0'; |
|
|
141 buf[2] = (timeptr->tm_yday % 10) + '0'; |
|
|
142 return 3; |
|
|
143 case 'm': |
|
|
144 if (sizeleft < 2) |
|
|
145 return -1; |
|
|
146 buf[0] = (timeptr->tm_mon / 10) + '0'; |
|
|
147 buf[1] = (timeptr->tm_mon % 10) + '0'; |
|
|
148 return 2; |
|
|
149 case 'M': |
|
|
150 if (sizeleft < 2) |
|
|
151 return -1; |
|
|
152 buf[0] = (timeptr->tm_min / 10) + '0'; |
|
|
153 buf[1] = (timeptr->tm_min % 10) + '0'; |
|
|
154 return 2; |
|
|
155 case 'p': |
|
|
156 if (sizeleft < 2) |
|
|
157 return -1; |
|
|
158 buf[0] = (timeptr->tm_hour > 11) ? 'p' : 'a'; |
|
|
159 buf[1] = 'm'; |
|
|
160 return 2; |
|
|
161 case 'S': |
|
|
162 if (sizeleft < 2) |
|
|
163 return -1; |
|
|
164 buf[0] = (timeptr->tm_sec / 10) + '0'; |
|
|
165 buf[1] = (timeptr->tm_sec % 10) + '0'; |
|
|
166 return 2; |
|
|
167 case 'U': |
|
|
168 if (sizeleft < 2) |
|
|
169 return -1; |
|
|
170 i = (timeptr->tm_yday - timeptr->tm_wday + 7) / 7; |
|
|
171 buf[0] = (i / 10) + '0'; |
|
|
172 buf[1] = (i % 10) + '0'; |
|
|
173 return 2; |
|
|
174 case 'w': |
|
|
175 // Don't need to check size - we'll always be called with sizeleft > 0 |
|
|
176 buf[0] = timeptr->tm_wday + '0'; |
|
|
177 return 1; |
|
|
178 case 'W': |
|
|
179 if (sizeleft < 2) |
|
|
180 return -1; |
|
|
181 i = (timeptr->tm_yday + ((8-timeptr->tm_wday) % 7)) / 7; |
|
|
182 buf[0] = (i / 10) + '0'; |
|
|
183 buf[1] = (i % 10) + '0'; |
|
|
184 return 2; |
|
|
185 case 'x': |
|
|
186 if (sizeleft < 15) |
|
|
187 return -1; |
|
|
188 |
|
|
189 // Recurse! Note that we know that we will have left room for the |
|
|
190 // trailing NULL in the strftime body |
|
|
191 |
|
|
192 i = __strftime( buf, sizeleft+1, "%a %b %d %Y", timeptr); |
|
|
193 |
|
|
194 return (0==i) ? -1 : i; |
|
|
195 case 'X': |
|
|
196 if (sizeleft < 10) |
|
|
197 return -1; |
|
|
198 |
|
|
199 // Recurse! Note that we know that we will have left room for the |
|
|
200 // trailing NULL in the strftime body |
|
|
201 |
|
|
202 i = __strftime( buf, sizeleft+1, "%I:%M:%S%p", timeptr); |
|
|
203 |
|
|
204 return (0==i) ? -1 : i; |
|
|
205 case 'y': |
|
|
206 if (sizeleft < 2) |
|
|
207 return -1; |
|
|
208 buf[0] = ((timeptr->tm_year % 100) / 10) + '0'; |
|
|
209 buf[1] = ((timeptr->tm_year % 100) % 10) + '0'; |
|
|
210 return 2; |
|
|
211 case 'Y': |
|
|
212 if (sizeleft < 4) |
|
|
213 return -1; |
|
|
214 buf[0] = ((1900+timeptr->tm_year) / 1000) + '0'; |
|
|
215 buf[1] = (((1900+timeptr->tm_year) % 1000) / 100) + '0'; |
|
|
216 buf[2] = ((timeptr->tm_year % 100) / 10) + '0'; |
|
|
217 buf[3] = (timeptr->tm_year % 10) + '0'; |
|
|
218 return 4; |
|
|
219 case 'Z': |
|
|
220 // FIXME: Should store zone in timeptr->tm_zone, or failing that |
|
|
221 // read TZ env variable using tzset() |
|
|
222 return 0; |
|
|
223 case '%': |
|
|
224 // Don't need to check size - we'll always be called with sizeleft > 0 |
|
|
225 buf[0] = '%'; |
|
|
226 return 1; |
|
|
227 default: |
|
|
228 CYG_FAIL("invalid format character!"); |
|
|
229 return -1; |
|
|
230 } // switch |
|
|
231 |
|
|
232 } // do_format() |
|
|
233 |
|
|
234 externC size_t |
|
|
235 __strftime( char *s, size_t maxsize, const char *format, |
|
|
236 const struct tm *timeptr) |
|
|
237 { |
|
|
238 CYG_REPORT_FUNCNAMETYPE("__strftime", "returning string length %d"); |
|
|
239 CYG_CHECK_DATA_PTR(s, "string s is not a valid address!"); |
|
|
240 CYG_CHECK_DATA_PTR(format, "format string is not at a valid address!"); |
|
|
241 CYG_CHECK_DATA_PTR(timeptr, |
|
|
242 "struct tm argument is not at a valid address!"); |
|
|
243 CYG_REPORT_FUNCARG4("s is at address %08x, maxsize=%d, format=\"%s\", " |
|
|
244 "timeptr is at address %08x", |
|
|
245 s, maxsize, format, timeptr); |
|
|
246 |
|
|
247 CYG_PRECONDITION((timeptr->tm_sec >= 0) && (timeptr->tm_sec < 62), |
|
|
248 "timeptr->tm_sec out of range!"); |
|
|
249 CYG_PRECONDITION((timeptr->tm_min >= 0) && (timeptr->tm_min < 60), |
|
|
250 "timeptr->tm_min out of range!"); |
|
|
251 CYG_PRECONDITION((timeptr->tm_hour >= 0) && (timeptr->tm_hour < 24), |
|
|
252 "timeptr->tm_hour out of range!"); |
|
|
253 // Currently I don't check _actual_ numbers of days in each month here |
|
|
254 // FIXME: No reason why not though |
|
|
255 CYG_PRECONDITION((timeptr->tm_mday >= 1) && (timeptr->tm_mday < 32), |
|
|
256 "timeptr->tm_mday out of range!"); |
|
|
257 CYG_PRECONDITION((timeptr->tm_mon >= 0) && (timeptr->tm_mon < 12), |
|
|
258 "timeptr->tm_mon out of range!"); |
|
|
259 CYG_PRECONDITION((timeptr->tm_wday >= 0) && (timeptr->tm_wday < 7), |
|
|
260 "timeptr->tm_wday out of range!"); |
|
|
261 CYG_PRECONDITION((timeptr->tm_yday >= 0) && (timeptr->tm_yday < 366), |
|
|
262 "timeptr->tm_yday out of range!"); |
|
|
263 CYG_PRECONDITION((timeptr->tm_year > -1900) && |
|
|
264 (timeptr->tm_year < 8100), |
|
|
265 "timeptr->tm_year out of range!"); |
|
|
266 |
|
|
267 if (!maxsize) { |
|
|
268 CYG_REPORT_RETVAL(0); |
|
|
269 return 0; |
|
|
270 } // if |
|
|
271 |
|
|
272 // lets leave the room for the trailing null up front |
|
|
273 --maxsize; |
|
|
274 |
|
|
275 cyg_ucount32 i, spos; |
|
|
276 cyg_int8 dof_ret; |
|
|
277 |
|
|
278 for (i=0, spos=0; (spos<maxsize) && (format[i] != '\0'); ++i) { |
|
|
279 if (format[i] == '%') { |
|
|
280 if (format[++i] == '\0') |
|
|
281 break; |
|
|
282 dof_ret = do_format(format[i], maxsize - spos, &s[spos], timeptr); |
|
|
283 // was there room to write _anything_? |
|
|
284 if (dof_ret < 0) { |
|
|
285 spos=0; // ISO says we must return 0 and the contents of s |
|
|
286 // are indeterminate |
|
|
287 break; |
|
|
288 } |
|
|
289 spos += dof_ret; |
|
|
290 } |
|
|
291 else { |
|
|
292 s[spos++] = format[i]; |
|
|
293 } // else |
|
|
294 } // for |
|
|
295 |
|
|
296 s[spos] = '\0'; |
|
|
297 |
|
|
298 CYG_REPORT_RETVAL(spos); |
|
|
299 return spos; |
|
|
300 |
|
|
301 } // __strftime() |
|
|
302 |
|
|
303 |
|
|
304 // SYMBOL DEFINITIONS |
|
|
305 |
|
|
306 externC size_t |
|
|
307 strftime( char *s, size_t maxsize, const char *format, |
|
|
308 const struct tm *timeptr) CYGBLD_ATTRIB_WEAK_ALIAS(__strftime); |
|
|
309 |
|
|
310 // EOF strftime.cxx |