1 | /** @file
|
---|
2 | Implementation of the strftime function for <time.h>.
|
---|
3 |
|
---|
4 | Based on the UCB version with the ID appearing below.
|
---|
5 | This is ANSIish only when "multibyte character == plain character".
|
---|
6 |
|
---|
7 | Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
|
---|
8 | This program and the accompanying materials are licensed and made available under
|
---|
9 | the terms and conditions of the BSD License that accompanies this distribution.
|
---|
10 | The full text of the license may be found at
|
---|
11 | http://opensource.org/licenses/bsd-license.php.
|
---|
12 |
|
---|
13 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
---|
14 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
---|
15 |
|
---|
16 | Copyright (c) 1989, 1993
|
---|
17 | The Regents of the University of California. All rights reserved.
|
---|
18 |
|
---|
19 | Redistribution and use in source and binary forms, with or without
|
---|
20 | modification, are permitted provided that the following conditions
|
---|
21 | are met:
|
---|
22 | 1. Redistributions of source code must retain the above copyright
|
---|
23 | notice, this list of conditions and the following disclaimer.
|
---|
24 | 2. Redistributions in binary form must reproduce the above copyright
|
---|
25 | notice, this list of conditions and the following disclaimer in the
|
---|
26 | documentation and/or other materials provided with the distribution.
|
---|
27 | 3. All advertising materials mentioning features or use of this software
|
---|
28 | must display the following acknowledgement:
|
---|
29 | This product includes software developed by the University of
|
---|
30 | California, Berkeley and its contributors.
|
---|
31 | 4. Neither the name of the University nor the names of its contributors
|
---|
32 | may be used to endorse or promote products derived from this software
|
---|
33 | without specific prior written permission.
|
---|
34 |
|
---|
35 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
---|
36 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
---|
37 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
---|
38 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
---|
39 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
---|
40 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
---|
41 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
---|
42 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
---|
43 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
---|
44 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
---|
45 | SUCH DAMAGE.
|
---|
46 |
|
---|
47 | NetBSD: strftime.c,v 1.17.4.1 2007/08/21 20:08:21 liamjfoy Exp
|
---|
48 | **/
|
---|
49 | #include <LibConfig.h>
|
---|
50 | #include <sys/EfiCdefs.h>
|
---|
51 |
|
---|
52 | #include "namespace.h"
|
---|
53 | #include <time.h>
|
---|
54 | #include "tzfile.h"
|
---|
55 | #include "TimeVals.h"
|
---|
56 | #include "fcntl.h"
|
---|
57 | #include "locale.h"
|
---|
58 |
|
---|
59 | #include "sys/localedef.h"
|
---|
60 | #include <MainData.h>
|
---|
61 |
|
---|
62 | /*
|
---|
63 | ** We don't use these extensions in strftime operation even when
|
---|
64 | ** supported by the local tzcode configuration. A strictly
|
---|
65 | ** conforming C application may leave them in undefined state.
|
---|
66 | */
|
---|
67 |
|
---|
68 | #ifdef _LIBC
|
---|
69 | #undef TM_ZONE
|
---|
70 | #undef TM_GMTOFF
|
---|
71 | #endif
|
---|
72 |
|
---|
73 | #define Locale _CurrentTimeLocale
|
---|
74 |
|
---|
75 | static char * _add(const char *, char *, const char * const);
|
---|
76 | static char * _conv(const int, const char * const, char * const, const char * const);
|
---|
77 | static char * _fmt(const char *, const struct tm * const, char *, const char * const, int *);
|
---|
78 |
|
---|
79 | #define NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
|
---|
80 |
|
---|
81 | #ifndef YEAR_2000_NAME
|
---|
82 | #define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
|
---|
83 | #endif /* !defined YEAR_2000_NAME */
|
---|
84 |
|
---|
85 |
|
---|
86 | #define IN_NONE 0
|
---|
87 | #define IN_SOME 1
|
---|
88 | #define IN_THIS 2
|
---|
89 | #define IN_ALL 3
|
---|
90 |
|
---|
91 | size_t
|
---|
92 | strftime(
|
---|
93 | char * __restrict s,
|
---|
94 | size_t maxsize,
|
---|
95 | const char * __restrict format,
|
---|
96 | const struct tm * __restrict timeptr
|
---|
97 | )
|
---|
98 | {
|
---|
99 | char * p;
|
---|
100 | int warn;
|
---|
101 |
|
---|
102 | tzset();
|
---|
103 | warn = IN_NONE;
|
---|
104 | p = _fmt(((format == NULL) ? "%c" : format), timeptr, s, s + maxsize, &warn);
|
---|
105 |
|
---|
106 | #ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
|
---|
107 | if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
|
---|
108 | (void) fprintf(stderr, "\n");
|
---|
109 | if (format == NULL)
|
---|
110 | (void) fprintf(stderr, "NULL strftime format ");
|
---|
111 | else (void) fprintf(stderr, "strftime format \"%s\" ",
|
---|
112 | format);
|
---|
113 | (void) fprintf(stderr, "yields only two digits of years in ");
|
---|
114 | if (warn == IN_SOME)
|
---|
115 | (void) fprintf(stderr, "some locales");
|
---|
116 | else if (warn == IN_THIS)
|
---|
117 | (void) fprintf(stderr, "the current locale");
|
---|
118 | else (void) fprintf(stderr, "all locales");
|
---|
119 | (void) fprintf(stderr, "\n");
|
---|
120 | }
|
---|
121 | #endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
|
---|
122 |
|
---|
123 | if (p == s + maxsize)
|
---|
124 | return 0;
|
---|
125 | *p = '\0';
|
---|
126 | return p - s;
|
---|
127 | }
|
---|
128 |
|
---|
129 | static char *
|
---|
130 | _fmt(
|
---|
131 | const char * format,
|
---|
132 | const struct tm * const t,
|
---|
133 | char * pt,
|
---|
134 | const char * const ptlim,
|
---|
135 | int * warnp
|
---|
136 | )
|
---|
137 | {
|
---|
138 | for ( ; *format; ++format) {
|
---|
139 | if (*format == '%') {
|
---|
140 | label:
|
---|
141 | switch (*++format) {
|
---|
142 | case '\0':
|
---|
143 | --format;
|
---|
144 | break;
|
---|
145 | case 'A':
|
---|
146 | pt = _add((t->tm_wday < 0 ||
|
---|
147 | t->tm_wday >= DAYSPERWEEK) ?
|
---|
148 | "?" : Locale->day[t->tm_wday],
|
---|
149 | pt, ptlim);
|
---|
150 | continue;
|
---|
151 | case 'a':
|
---|
152 | pt = _add((t->tm_wday < 0 ||
|
---|
153 | t->tm_wday >= DAYSPERWEEK) ?
|
---|
154 | "?" : Locale->abday[t->tm_wday],
|
---|
155 | pt, ptlim);
|
---|
156 | continue;
|
---|
157 | case 'B':
|
---|
158 | pt = _add((t->tm_mon < 0 ||
|
---|
159 | t->tm_mon >= MONSPERYEAR) ?
|
---|
160 | "?" : Locale->mon[t->tm_mon],
|
---|
161 | pt, ptlim);
|
---|
162 | continue;
|
---|
163 | case 'b':
|
---|
164 | case 'h':
|
---|
165 | pt = _add((t->tm_mon < 0 ||
|
---|
166 | t->tm_mon >= MONSPERYEAR) ?
|
---|
167 | "?" : Locale->abmon[t->tm_mon],
|
---|
168 | pt, ptlim);
|
---|
169 | continue;
|
---|
170 | case 'C':
|
---|
171 | /*
|
---|
172 | ** %C used to do a...
|
---|
173 | ** _fmt("%a %b %e %X %Y", t);
|
---|
174 | ** ...whereas now POSIX 1003.2 calls for
|
---|
175 | ** something completely different.
|
---|
176 | ** (ado, 1993-05-24)
|
---|
177 | */
|
---|
178 | pt = _conv((t->tm_year + TM_YEAR_BASE) / 100,
|
---|
179 | "%02d", pt, ptlim);
|
---|
180 | continue;
|
---|
181 | case 'c':
|
---|
182 | {
|
---|
183 | int warn2 = IN_SOME;
|
---|
184 |
|
---|
185 | pt = _fmt(Locale->d_t_fmt, t, pt, ptlim, &warn2);
|
---|
186 | if (warn2 == IN_ALL)
|
---|
187 | warn2 = IN_THIS;
|
---|
188 | if (warn2 > *warnp)
|
---|
189 | *warnp = warn2;
|
---|
190 | }
|
---|
191 | continue;
|
---|
192 | case 'D':
|
---|
193 | pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
|
---|
194 | continue;
|
---|
195 | case 'd':
|
---|
196 | pt = _conv(t->tm_mday, "%02d", pt, ptlim);
|
---|
197 | continue;
|
---|
198 | case 'E':
|
---|
199 | case 'O':
|
---|
200 | /*
|
---|
201 | ** C99 locale modifiers.
|
---|
202 | ** The sequences
|
---|
203 | ** %Ec %EC %Ex %EX %Ey %EY
|
---|
204 | ** %Od %oe %OH %OI %Om %OM
|
---|
205 | ** %OS %Ou %OU %OV %Ow %OW %Oy
|
---|
206 | ** are supposed to provide alternate
|
---|
207 | ** representations.
|
---|
208 | */
|
---|
209 | goto label;
|
---|
210 | case 'e':
|
---|
211 | pt = _conv(t->tm_mday, "%2d", pt, ptlim);
|
---|
212 | continue;
|
---|
213 | case 'F':
|
---|
214 | pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
|
---|
215 | continue;
|
---|
216 | case 'H':
|
---|
217 | pt = _conv(t->tm_hour, "%02d", pt, ptlim);
|
---|
218 | continue;
|
---|
219 | case 'I':
|
---|
220 | pt = _conv((t->tm_hour % 12) ?
|
---|
221 | (t->tm_hour % 12) : 12,
|
---|
222 | "%02d", pt, ptlim);
|
---|
223 | continue;
|
---|
224 | case 'j':
|
---|
225 | pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);
|
---|
226 | continue;
|
---|
227 | case 'k':
|
---|
228 | /*
|
---|
229 | ** This used to be...
|
---|
230 | ** _conv(t->tm_hour % 12 ?
|
---|
231 | ** t->tm_hour % 12 : 12, 2, ' ');
|
---|
232 | ** ...and has been changed to the below to
|
---|
233 | ** match SunOS 4.1.1 and Arnold Robbins'
|
---|
234 | ** strftime version 3.0. That is, "%k" and
|
---|
235 | ** "%l" have been swapped.
|
---|
236 | ** (ado, 1993-05-24)
|
---|
237 | */
|
---|
238 | pt = _conv(t->tm_hour, "%2d", pt, ptlim);
|
---|
239 | continue;
|
---|
240 | #ifdef KITCHEN_SINK
|
---|
241 | case 'K':
|
---|
242 | /*
|
---|
243 | ** After all this time, still unclaimed!
|
---|
244 | */
|
---|
245 | pt = _add("kitchen sink", pt, ptlim);
|
---|
246 | continue;
|
---|
247 | #endif /* defined KITCHEN_SINK */
|
---|
248 | case 'l':
|
---|
249 | /*
|
---|
250 | ** This used to be...
|
---|
251 | ** _conv(t->tm_hour, 2, ' ');
|
---|
252 | ** ...and has been changed to the below to
|
---|
253 | ** match SunOS 4.1.1 and Arnold Robbin's
|
---|
254 | ** strftime version 3.0. That is, "%k" and
|
---|
255 | ** "%l" have been swapped.
|
---|
256 | ** (ado, 1993-05-24)
|
---|
257 | */
|
---|
258 | pt = _conv((t->tm_hour % 12) ?
|
---|
259 | (t->tm_hour % 12) : 12,
|
---|
260 | "%2d", pt, ptlim);
|
---|
261 | continue;
|
---|
262 | case 'M':
|
---|
263 | pt = _conv(t->tm_min, "%02d", pt, ptlim);
|
---|
264 | continue;
|
---|
265 | case 'm':
|
---|
266 | pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);
|
---|
267 | continue;
|
---|
268 | case 'n':
|
---|
269 | pt = _add("\n", pt, ptlim);
|
---|
270 | continue;
|
---|
271 | case 'p':
|
---|
272 | pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
|
---|
273 | Locale->am_pm[1] :
|
---|
274 | Locale->am_pm[0],
|
---|
275 | pt, ptlim);
|
---|
276 | continue;
|
---|
277 | case 'R':
|
---|
278 | pt = _fmt("%H:%M", t, pt, ptlim, warnp);
|
---|
279 | continue;
|
---|
280 | case 'r':
|
---|
281 | pt = _fmt(Locale->t_fmt_ampm, t, pt, ptlim,
|
---|
282 | warnp);
|
---|
283 | continue;
|
---|
284 | case 'S':
|
---|
285 | pt = _conv(t->tm_sec, "%02d", pt, ptlim);
|
---|
286 | continue;
|
---|
287 | case 's':
|
---|
288 | {
|
---|
289 | struct tm tm;
|
---|
290 | char buf[INT_STRLEN_MAXIMUM(
|
---|
291 | time_t) + 1];
|
---|
292 | time_t mkt;
|
---|
293 |
|
---|
294 | tm = *t;
|
---|
295 | mkt = mktime(&tm);
|
---|
296 | /* CONSTCOND */
|
---|
297 | if (TYPE_SIGNED(time_t))
|
---|
298 | (void) sprintf(buf, "%ld",
|
---|
299 | (long) mkt);
|
---|
300 | else (void) sprintf(buf, "%lu",
|
---|
301 | (unsigned long) mkt);
|
---|
302 | pt = _add(buf, pt, ptlim);
|
---|
303 | }
|
---|
304 | continue;
|
---|
305 | case 'T':
|
---|
306 | pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
|
---|
307 | continue;
|
---|
308 | case 't':
|
---|
309 | pt = _add("\t", pt, ptlim);
|
---|
310 | continue;
|
---|
311 | case 'U':
|
---|
312 | pt = _conv((t->tm_yday + DAYSPERWEEK -
|
---|
313 | t->tm_wday) / DAYSPERWEEK,
|
---|
314 | "%02d", pt, ptlim);
|
---|
315 | continue;
|
---|
316 | case 'u':
|
---|
317 | /*
|
---|
318 | ** From Arnold Robbins' strftime version 3.0:
|
---|
319 | ** "ISO 8601: Weekday as a decimal number
|
---|
320 | ** [1 (Monday) - 7]"
|
---|
321 | ** (ado, 1993-05-24)
|
---|
322 | */
|
---|
323 | pt = _conv((t->tm_wday == 0) ?
|
---|
324 | DAYSPERWEEK : t->tm_wday,
|
---|
325 | "%d", pt, ptlim);
|
---|
326 | continue;
|
---|
327 | case 'V': /* ISO 8601 week number */
|
---|
328 | case 'G': /* ISO 8601 year (four digits) */
|
---|
329 | case 'g': /* ISO 8601 year (two digits) */
|
---|
330 | /*
|
---|
331 | ** From Arnold Robbins' strftime version 3.0: "the week number of the
|
---|
332 | ** year (the first Monday as the first day of week 1) as a decimal number
|
---|
333 | ** (01-53)."
|
---|
334 | ** (ado, 1993-05-24)
|
---|
335 | **
|
---|
336 | ** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
|
---|
337 | ** "Week 01 of a year is per definition the first week which has the
|
---|
338 | ** Thursday in this year, which is equivalent to the week which contains
|
---|
339 | ** the fourth day of January. In other words, the first week of a new year
|
---|
340 | ** is the week which has the majority of its days in the new year. Week 01
|
---|
341 | ** might also contain days from the previous year and the week before week
|
---|
342 | ** 01 of a year is the last week (52 or 53) of the previous year even if
|
---|
343 | ** it contains days from the new year. A week starts with Monday (day 1)
|
---|
344 | ** and ends with Sunday (day 7). For example, the first week of the year
|
---|
345 | ** 1997 lasts from 1996-12-30 to 1997-01-05..."
|
---|
346 | ** (ado, 1996-01-02)
|
---|
347 | */
|
---|
348 | {
|
---|
349 | int year;
|
---|
350 | int yday;
|
---|
351 | int wday;
|
---|
352 | int w;
|
---|
353 |
|
---|
354 | year = t->tm_year + TM_YEAR_BASE;
|
---|
355 | yday = t->tm_yday;
|
---|
356 | wday = t->tm_wday;
|
---|
357 | for ( ; ; ) {
|
---|
358 | int len;
|
---|
359 | int bot;
|
---|
360 | int top;
|
---|
361 |
|
---|
362 | len = isleap(year) ?
|
---|
363 | DAYSPERLYEAR :
|
---|
364 | DAYSPERNYEAR;
|
---|
365 | /*
|
---|
366 | ** What yday (-3 ... 3) does
|
---|
367 | ** the ISO year begin on?
|
---|
368 | */
|
---|
369 | bot = ((yday + 11 - wday) %
|
---|
370 | DAYSPERWEEK) - 3;
|
---|
371 | /*
|
---|
372 | ** What yday does the NEXT
|
---|
373 | ** ISO year begin on?
|
---|
374 | */
|
---|
375 | top = bot -
|
---|
376 | (len % DAYSPERWEEK);
|
---|
377 | if (top < -3)
|
---|
378 | top += DAYSPERWEEK;
|
---|
379 | top += len;
|
---|
380 | if (yday >= top) {
|
---|
381 | ++year;
|
---|
382 | w = 1;
|
---|
383 | break;
|
---|
384 | }
|
---|
385 | if (yday >= bot) {
|
---|
386 | w = 1 + ((yday - bot) /
|
---|
387 | DAYSPERWEEK);
|
---|
388 | break;
|
---|
389 | }
|
---|
390 | --year;
|
---|
391 | yday += isleap(year) ?
|
---|
392 | DAYSPERLYEAR :
|
---|
393 | DAYSPERNYEAR;
|
---|
394 | }
|
---|
395 | #ifdef XPG4_1994_04_09
|
---|
396 | if ((w == 52
|
---|
397 | && t->tm_mon == TM_JANUARY)
|
---|
398 | || (w == 1
|
---|
399 | && t->tm_mon == TM_DECEMBER))
|
---|
400 | w = 53;
|
---|
401 | #endif /* defined XPG4_1994_04_09 */
|
---|
402 | if (*format == 'V')
|
---|
403 | pt = _conv(w, "%02d",
|
---|
404 | pt, ptlim);
|
---|
405 | else if (*format == 'g') {
|
---|
406 | *warnp = IN_ALL;
|
---|
407 | pt = _conv(year % 100, "%02d",
|
---|
408 | pt, ptlim);
|
---|
409 | } else pt = _conv(year, "%04d",
|
---|
410 | pt, ptlim);
|
---|
411 | }
|
---|
412 | continue;
|
---|
413 | case 'v':
|
---|
414 | /*
|
---|
415 | ** From Arnold Robbins' strftime version 3.0:
|
---|
416 | ** "date as dd-bbb-YYYY"
|
---|
417 | ** (ado, 1993-05-24)
|
---|
418 | */
|
---|
419 | pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
|
---|
420 | continue;
|
---|
421 | case 'W':
|
---|
422 | pt = _conv((t->tm_yday + DAYSPERWEEK -
|
---|
423 | (t->tm_wday ?
|
---|
424 | (t->tm_wday - 1) :
|
---|
425 | (DAYSPERWEEK - 1))) / DAYSPERWEEK,
|
---|
426 | "%02d", pt, ptlim);
|
---|
427 | continue;
|
---|
428 | case 'w':
|
---|
429 | pt = _conv(t->tm_wday, "%d", pt, ptlim);
|
---|
430 | continue;
|
---|
431 | case 'X':
|
---|
432 | pt = _fmt(Locale->t_fmt, t, pt, ptlim, warnp);
|
---|
433 | continue;
|
---|
434 | case 'x':
|
---|
435 | {
|
---|
436 | int warn2 = IN_SOME;
|
---|
437 |
|
---|
438 | pt = _fmt(Locale->d_fmt, t, pt, ptlim, &warn2);
|
---|
439 | if (warn2 == IN_ALL)
|
---|
440 | warn2 = IN_THIS;
|
---|
441 | if (warn2 > *warnp)
|
---|
442 | *warnp = warn2;
|
---|
443 | }
|
---|
444 | continue;
|
---|
445 | case 'y':
|
---|
446 | *warnp = IN_ALL;
|
---|
447 | pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,
|
---|
448 | "%02d", pt, ptlim);
|
---|
449 | continue;
|
---|
450 | case 'Y':
|
---|
451 | pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d",
|
---|
452 | pt, ptlim);
|
---|
453 | continue;
|
---|
454 | case 'Z':
|
---|
455 | #ifdef TM_ZONE
|
---|
456 | if (t->TM_ZONE != NULL)
|
---|
457 | pt = _add(t->TM_ZONE, pt, ptlim);
|
---|
458 | else
|
---|
459 | #endif /* defined TM_ZONE */
|
---|
460 | if (t->tm_isdst >= 0)
|
---|
461 | pt = _add(tzname[t->tm_isdst != 0],
|
---|
462 | pt, ptlim);
|
---|
463 | /*
|
---|
464 | ** C99 says that %Z must be replaced by the
|
---|
465 | ** empty string if the time zone is not
|
---|
466 | ** determinable.
|
---|
467 | */
|
---|
468 | continue;
|
---|
469 | case 'z':
|
---|
470 | {
|
---|
471 | int diff;
|
---|
472 | char const * sign;
|
---|
473 |
|
---|
474 | if (t->tm_isdst < 0)
|
---|
475 | continue;
|
---|
476 | #ifdef TM_GMTOFF
|
---|
477 | diff = (int)t->TM_GMTOFF;
|
---|
478 | #else /* !defined TM_GMTOFF */
|
---|
479 | /*
|
---|
480 | ** C99 says that the UTC offset must
|
---|
481 | ** be computed by looking only at
|
---|
482 | ** tm_isdst. This requirement is
|
---|
483 | ** incorrect, since it means the code
|
---|
484 | ** must rely on magic (in this case
|
---|
485 | ** altzone and timezone), and the
|
---|
486 | ** magic might not have the correct
|
---|
487 | ** offset. Doing things correctly is
|
---|
488 | ** tricky and requires disobeying C99;
|
---|
489 | ** see GNU C strftime for details.
|
---|
490 | ** For now, punt and conform to the
|
---|
491 | ** standard, even though it's incorrect.
|
---|
492 | **
|
---|
493 | ** C99 says that %z must be replaced by the
|
---|
494 | ** empty string if the time zone is not
|
---|
495 | ** determinable, so output nothing if the
|
---|
496 | ** appropriate variables are not available.
|
---|
497 | */
|
---|
498 | #ifndef STD_INSPIRED
|
---|
499 | if (t->tm_isdst == 0)
|
---|
500 | #ifdef USG_COMPAT
|
---|
501 | diff = -timezone;
|
---|
502 | #else /* !defined USG_COMPAT */
|
---|
503 | continue;
|
---|
504 | #endif /* !defined USG_COMPAT */
|
---|
505 | else
|
---|
506 | #ifdef ALTZONE
|
---|
507 | diff = -altzone;
|
---|
508 | #else /* !defined ALTZONE */
|
---|
509 | continue;
|
---|
510 | #endif /* !defined ALTZONE */
|
---|
511 | #else /* defined STD_INSPIRED */
|
---|
512 | {
|
---|
513 | struct tm tmp;
|
---|
514 | time_t lct, gct;
|
---|
515 |
|
---|
516 | /*
|
---|
517 | ** Get calendar time from t
|
---|
518 | ** being treated as local.
|
---|
519 | */
|
---|
520 | tmp = *t; /* mktime discards const */
|
---|
521 | lct = mktime(&tmp);
|
---|
522 |
|
---|
523 | if (lct == (time_t)-1)
|
---|
524 | continue;
|
---|
525 |
|
---|
526 | /*
|
---|
527 | ** Get calendar time from t
|
---|
528 | ** being treated as GMT.
|
---|
529 | **/
|
---|
530 | tmp = *t; /* mktime discards const */
|
---|
531 | gct = timegm(&tmp);
|
---|
532 |
|
---|
533 | if (gct == (time_t)-1)
|
---|
534 | continue;
|
---|
535 |
|
---|
536 | /* LINTED difference will fit int */
|
---|
537 | diff = (intmax_t)gct - (intmax_t)lct;
|
---|
538 | }
|
---|
539 | #endif /* defined STD_INSPIRED */
|
---|
540 | #endif /* !defined TM_GMTOFF */
|
---|
541 | if (diff < 0) {
|
---|
542 | sign = "-";
|
---|
543 | diff = -diff;
|
---|
544 | } else sign = "+";
|
---|
545 | pt = _add(sign, pt, ptlim);
|
---|
546 | diff /= 60;
|
---|
547 | pt = _conv((diff/60)*100 + diff%60,
|
---|
548 | "%04d", pt, ptlim);
|
---|
549 | }
|
---|
550 | continue;
|
---|
551 | #if 0
|
---|
552 | case '+':
|
---|
553 | pt = _fmt(Locale->date_fmt, t, pt, ptlim,
|
---|
554 | warnp);
|
---|
555 | continue;
|
---|
556 | #endif
|
---|
557 | case '%':
|
---|
558 | /*
|
---|
559 | ** X311J/88-090 (4.12.3.5): if conversion char is
|
---|
560 | ** undefined, behavior is undefined. Print out the
|
---|
561 | ** character itself as printf(3) also does.
|
---|
562 | */
|
---|
563 | default:
|
---|
564 | break;
|
---|
565 | }
|
---|
566 | }
|
---|
567 | if (pt == ptlim)
|
---|
568 | break;
|
---|
569 | *pt++ = *format;
|
---|
570 | }
|
---|
571 | return pt;
|
---|
572 | }
|
---|
573 |
|
---|
574 | static char *
|
---|
575 | _conv(
|
---|
576 | const int n,
|
---|
577 | const char * const format,
|
---|
578 | char * const pt,
|
---|
579 | const char * const ptlim
|
---|
580 | )
|
---|
581 | {
|
---|
582 | char buf[INT_STRLEN_MAXIMUM(int) + 1];
|
---|
583 |
|
---|
584 | (void) sprintf(buf, format, n);
|
---|
585 | return _add(buf, pt, ptlim);
|
---|
586 | }
|
---|
587 |
|
---|
588 | static char *
|
---|
589 | _add(
|
---|
590 | const char * str,
|
---|
591 | char * pt,
|
---|
592 | const char * const ptlim
|
---|
593 | )
|
---|
594 | {
|
---|
595 | while (pt < ptlim && (*pt = *str++) != '\0')
|
---|
596 | ++pt;
|
---|
597 | return pt;
|
---|
598 | }
|
---|