]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * (c)2012 Michael Duane Rice All rights reserved. | |
3 | * | |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions are | |
6 | * met: | |
7 | * | |
8 | * Redistributions of source code must retain the above copyright notice, this | |
9 | * list of conditions and the following disclaimer. Redistributions in binary | |
10 | * form must reproduce the above copyright notice, this list of conditions | |
11 | * and the following disclaimer in the documentation and/or other materials | |
12 | * provided with the distribution. Neither the name of the copyright holders | |
13 | * nor the names of contributors may be used to endorse or promote products | |
14 | * derived from this software without specific prior written permission. | |
15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
26 | * POSSIBILITY OF SUCH DAMAGE. | |
27 | */ | |
28 | ||
29 | /* $Id: strftime.c 2391 2013-05-03 20:53:06Z swfltek $ */ | |
30 | ||
31 | /* | |
32 | Standard strftime(). This is a memory hungry monster. | |
33 | */ | |
34 | ||
35 | #include <stdlib.h> | |
36 | #include <stdio.h> | |
37 | #include <time.h> | |
38 | ||
39 | extern long __utc_offset; | |
40 | ||
41 | #ifdef __MEMX | |
42 | ||
43 | const __memx char strfwkdays[] = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday "; | |
44 | const __memx char strfmonths[] = "January February March April May June July August September October November December "; | |
45 | ||
46 | #else | |
47 | ||
48 | const char strfwkdays[] = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday "; | |
49 | const char strfmonths[] = "January February March April May June July August September October November December "; | |
50 | ||
51 | #endif | |
52 | ||
53 | #ifdef __MEMX | |
54 | ||
55 | unsigned char | |
56 | pgm_copystring(const char __memx * p, unsigned char i, char *b, unsigned char l) | |
57 | { | |
58 | ||
59 | #else | |
60 | ||
61 | unsigned char | |
62 | pgm_copystring(const char *p, unsigned char i, char *b, unsigned char l) | |
63 | { | |
64 | ||
65 | #endif | |
66 | ||
67 | unsigned char ret, c; | |
68 | ||
69 | ret = 0; | |
70 | while (i) { | |
71 | c = *p++; | |
72 | if (c == ' ') | |
73 | i--; | |
74 | } | |
75 | ||
76 | c = *p++; | |
77 | while (c != ' ' && l--) { | |
78 | *b++ = c; | |
79 | ret++; | |
80 | c = *p++; | |
81 | } | |
82 | *b = 0; | |
83 | return ret; | |
84 | } | |
85 | ||
86 | size_t | |
87 | strftime(char *buffer, size_t limit, const char *pattern, const struct tm * timeptr) | |
88 | { | |
89 | unsigned int count, length; | |
90 | int d, w; | |
91 | char c; | |
92 | char _store[26]; | |
93 | struct week_date wd; | |
94 | ||
95 | count = length = 0; | |
96 | while (count < limit) { | |
97 | c = *pattern++; | |
98 | if (c == '%') { | |
99 | c = *pattern++; | |
100 | if (c == 'E' || c == 'O') | |
101 | c = *pattern++; | |
102 | switch (c) { | |
103 | case ('%'): | |
104 | _store[0] = c; | |
105 | length = 1; | |
106 | break; | |
107 | ||
108 | case ('a'): | |
109 | length = pgm_copystring(strfwkdays, timeptr->tm_wday, _store, 3); | |
110 | break; | |
111 | ||
112 | case ('A'): | |
113 | length = pgm_copystring(strfwkdays, timeptr->tm_wday, _store, 255); | |
114 | break; | |
115 | ||
116 | case ('b'): | |
117 | case ('h'): | |
118 | length = pgm_copystring(strfmonths, timeptr->tm_mon, _store, 3); | |
119 | break; | |
120 | ||
121 | case ('B'): | |
122 | length = pgm_copystring(strfmonths, timeptr->tm_mon, _store, 255); | |
123 | break; | |
124 | ||
125 | case ('c'): | |
126 | asctime_r(timeptr, _store); | |
127 | length = 0; | |
128 | while (_store[length]) | |
129 | length++; | |
130 | break; | |
131 | ||
132 | case ('C'): | |
133 | d = timeptr->tm_year + 1900; | |
134 | d /= 100; | |
135 | length = sprintf(_store, "%.2d", d); | |
136 | break; | |
137 | ||
138 | case ('d'): | |
139 | length = sprintf(_store, "%.2u", timeptr->tm_mday); | |
140 | break; | |
141 | ||
142 | case ('D'): | |
143 | length = sprintf(_store, "%.2u/%.2u/%.2u", \ | |
144 | timeptr->tm_mon + 1, \ | |
145 | timeptr->tm_mday, \ | |
146 | timeptr->tm_year % 100 \ | |
147 | ); | |
148 | break; | |
149 | ||
150 | case ('e'): | |
151 | length = sprintf(_store, "%2d", timeptr->tm_mday); | |
152 | break; | |
153 | ||
154 | case ('F'): | |
155 | length = sprintf(_store, "%d-%.2d-%.2d", \ | |
156 | timeptr->tm_year + 1900, \ | |
157 | timeptr->tm_mon + 1, \ | |
158 | timeptr->tm_mday \ | |
159 | ); | |
160 | break; | |
161 | ||
162 | case ('g'): | |
163 | case ('G'): | |
164 | iso_week_date_r(timeptr->tm_year + 1900, timeptr->tm_yday, &wd); | |
165 | if (c == 'g') { | |
166 | length = sprintf(_store, "%.2d", wd.year % 100); | |
167 | } else { | |
168 | length = sprintf(_store, "%.4d", wd.year); | |
169 | } | |
170 | ||
171 | break; | |
172 | ||
173 | case ('H'): | |
174 | length = sprintf(_store, "%.2u", timeptr->tm_hour); | |
175 | break; | |
176 | ||
177 | case ('I'): | |
178 | d = timeptr->tm_hour % 12; | |
179 | if (d == 0) | |
180 | d = 12; | |
181 | length = sprintf(_store, "%.2u", d); | |
182 | break; | |
183 | ||
184 | case ('j'): | |
185 | length = sprintf(_store, "%.3u", timeptr->tm_yday + 1); | |
186 | break; | |
187 | ||
188 | case ('m'): | |
189 | length = sprintf(_store, "%.2u", timeptr->tm_mon + 1); | |
190 | break; | |
191 | ||
192 | case ('M'): | |
193 | length = sprintf(_store, "%.2u", timeptr->tm_min); | |
194 | break; | |
195 | ||
196 | case ('n'): | |
197 | _store[0] = 10; | |
198 | length = 1; | |
199 | break; | |
200 | ||
201 | case ('p'): | |
202 | length = 2; | |
203 | _store[0] = 'A'; | |
204 | if (timeptr->tm_hour > 11) | |
205 | _store[0] = 'P'; | |
206 | _store[1] = 'M'; | |
207 | _store[2] = 0; | |
208 | break; | |
209 | ||
210 | case ('r'): | |
211 | d = timeptr->tm_hour % 12; | |
212 | if (d == 0) | |
213 | d = 12; | |
214 | length = sprintf(_store, "%2d:%.2d:%.2d AM", \ | |
215 | d, \ | |
216 | timeptr->tm_min, \ | |
217 | timeptr->tm_sec \ | |
218 | ); | |
219 | if (timeptr->tm_hour > 11) | |
220 | _store[10] = 'P'; | |
221 | break; | |
222 | ||
223 | case ('R'): | |
224 | length = sprintf(_store, "%.2d:%.2d", timeptr->tm_hour, timeptr->tm_min); | |
225 | break; | |
226 | ||
227 | case ('S'): | |
228 | length = sprintf(_store, "%.2u", timeptr->tm_sec); | |
229 | break; | |
230 | ||
231 | case ('t'): | |
232 | length = sprintf(_store, "\t"); | |
233 | break; | |
234 | ||
235 | case ('T'): | |
236 | length = sprintf(_store, "%.2d:%.2d:%.2d", \ | |
237 | timeptr->tm_hour, \ | |
238 | timeptr->tm_min, \ | |
239 | timeptr->tm_sec \ | |
240 | ); | |
241 | break; | |
242 | ||
243 | case ('u'): | |
244 | w = timeptr->tm_wday; | |
245 | if (w == 0) | |
246 | w = 7; | |
247 | length = sprintf(_store, "%d", w); | |
248 | break; | |
249 | ||
250 | case ('U'): | |
251 | length = sprintf(_store, "%.2u", week_of_year(timeptr, 0)); | |
252 | break; | |
253 | ||
254 | case ('V'): | |
255 | iso_week_date_r(timeptr->tm_year + 1900, timeptr->tm_yday, &wd); | |
256 | length = sprintf(_store, "%.2u", wd.week); | |
257 | break; | |
258 | ||
259 | case ('w'): | |
260 | length = sprintf(_store, "%u", timeptr->tm_wday); | |
261 | break; | |
262 | ||
263 | case ('W'): | |
264 | w = week_of_year(timeptr, 1); | |
265 | length = sprintf(_store, "%.2u", w); | |
266 | break; | |
267 | ||
268 | case ('x'): | |
269 | length = sprintf(_store, "%.2u/%.2u/%.2u", timeptr->tm_mon + 1, timeptr->tm_mday, timeptr->tm_year % 100); | |
270 | break; | |
271 | ||
272 | case ('X'): | |
273 | length = sprintf(_store, "%.2u:%.2u:%.2u", timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec); | |
274 | break; | |
275 | ||
276 | case ('y'): | |
277 | length = sprintf(_store, "%.2u", timeptr->tm_year % 100); | |
278 | break; | |
279 | ||
280 | case ('Y'): | |
281 | length = sprintf(_store, "%u", timeptr->tm_year + 1900); | |
282 | break; | |
283 | ||
284 | case ('z'): | |
285 | d = __utc_offset / 60; | |
286 | w = timeptr->tm_isdst / 60; | |
287 | if (w > 0) | |
288 | d += w; | |
289 | w = abs(d % 60); | |
290 | d = d / 60; | |
291 | length = sprintf(_store, "%+.2d%.2d", d, w); | |
292 | break; | |
293 | ||
294 | default: | |
295 | length = 1; | |
296 | _store[0] = '?'; | |
297 | _store[1] = 0; | |
298 | break; | |
299 | } | |
300 | ||
301 | if ((length + count) < limit) { | |
302 | count += length; | |
303 | for (d = 0; d < (int) length; d++) { | |
304 | *buffer++ = _store[d]; | |
305 | } | |
306 | } else { | |
307 | *buffer = 0; | |
308 | return count; | |
309 | } | |
310 | ||
311 | } else { /* copy a literal */ | |
312 | *buffer = c; | |
313 | buffer++; | |
314 | count++; | |
315 | if (c == 0) | |
316 | return count; | |
317 | } | |
318 | } | |
319 | ||
320 | *buffer = 0; | |
321 | return count; | |
322 | } |