1 /* Copyright (C) 2002 Manuel Novoa III
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Library General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Library General Public License for more details.
13 * You should have received a copy of the GNU Library General Public
14 * License along with this library; if not, write to the Free
15 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 /* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION!
20 * Besides uClibc, I'm using this code in my libc for elks, which is
21 * a 16-bit environment with a fairly limited compiler. It would make
22 * things much easier for me if this file isn't modified unnecessarily.
23 * In particular, please put any new or replacement functions somewhere
24 * else, and modify the makefile to use your version instead.
27 * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */
29 /* June 15, 2002 Initial Notes:
31 * Note: It is assumed throught that time_t is either long or unsigned long.
32 * Similarly, clock_t is assumed to be long int.
34 * Warning: Assumptions are made about the layout of struct tm! It is
35 * assumed that the initial fields of struct tm are (in order):
36 * tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday
38 * Reached the inital goal of supporting the ANSI/ISO C99 time functions
39 * as well as SUSv3's strptime. All timezone info is obtained from the
42 * Differences from glibc worth noting:
44 * Leap seconds are not considered here.
46 * glibc stores additional timezone info the struct tm, whereas we don't.
48 * Alternate digits and era handling are not currently implemented.
49 * The modifiers are accepted, and tested for validity with the following
50 * specifier, but are ignored otherwise.
52 * strftime does not implement glibc extension modifiers or widths for
53 * conversion specifiers. However it does implement the glibc
54 * extension specifiers %l, %k, and %s. It also recognizes %P, but
55 * treats it as a synonym for %p; i.e. doesn't convert to lower case.
57 * strptime implements the glibc extension specifiers. However, it follows
58 * SUSv3 in requiring at least one non-alphanumeric char between
59 * conversion specifiers. Also, strptime only sets struct tm fields
60 * for which format specifiers appear and does not try to infer other
61 * fields (such as wday) as glibc's version does.
63 * TODO - Since glibc's %l and %k can space-pad their output in strftime,
64 * it might be reasonable to eat whitespace first for those specifiers.
65 * This could be done by pushing " %I" and " %H" respectively so that
66 * leading whitespace is consumed. This is really only an issue if %l
67 * or %k occurs at the start of the format string.
69 * TODO - Implement getdate? tzfile? struct tm extensions?
71 * TODO - Rework _time_mktime to remove the dependency on long long.
76 * Fixed allowed char check for std and dst TZ fields.
78 * Added several options concerned with timezone support. The names will
79 * probably change once Erik gets the new config system in place.
81 * Defining __TIME_TZ_FILE causes tzset() to attempt to read the TZ value
82 * from the file /etc/TZ if the TZ env variable isn't set. The file contents
83 * must be the intended value of TZ, followed by a newline. No other chars,
84 * spacing, etc is allowed. As an example, an easy way for me to init
85 * /etc/TZ appropriately would be: echo CST6CDT > /etc/TZ
87 * Defining __TIME_TZ_FILE_ONCE will cause all further accesses of /etc/TZ
88 * to be skipped once a legal value has been read.
90 * Defining __TIME_TZ_OPT_SPEED will cause a tzset() to keep a copy of the
91 * last TZ setting string and do a "fast out" if the current string is the
94 * Nov 21, 2002 Fix an error return case in _time_mktime.
96 * Nov 26, 2002 Fix bug in setting daylight and timezone when no (valid) TZ.
97 * Bug reported by Arne Bernin <arne@alamut.de> in regards to freeswan.
99 * July 27, 2003 Adjust the struct tm extension field support.
100 * Change __tm_tzone back to a ptr and add the __tm_tzname[] buffer for
101 * __tm_tzone to point to. This gets around complaints from g++.
102 * Who knows... it might even fix the PPC timezone init problem.
104 * July 29, 2003 Fix a bug in mktime behavior when tm_isdst was -1.
105 * Bug reported by "Sid Wade" <sid@vivato.net> in regards to busybox.
107 * NOTE: uClibc mktime behavior is different than glibc's when
108 * the struct tm has tm_isdst == -1 and also had fields outside of
111 * Apparently, glibc examines (at least) tm_sec and guesses the app's
112 * intention of assuming increasing or decreasing time when entering an
113 * ambiguous time period at the dst<->st boundaries.
115 * The uClibc behavior is to always normalize the struct tm and then
116 * try to determing the dst setting.
118 * As long as tm_isdst != -1 or the time specifiec by struct tm is
119 * unambiguous (not falling in the dst<->st transition region) both
120 * uClibc and glibc should produce the same result for mktime.
125 #define _STDIO_UTILITY
135 #include <langinfo.h>
138 #ifdef __UCLIBC_HAS_XLOCALE__
143 #define __isleap(y) ( !((y) % 4) && ( ((y) % 100) || !((y) % 400) ) )
147 #define TZNAME_MAX _POSIX_TZNAME_MAX
150 /**********************************************************************/
151 /* The era code is currently unfinished. */
152 /* #define ENABLE_ERA_CODE */
154 #define TZ_BUFLEN (2*TZNAME_MAX + 56)
156 #ifdef __UCLIBC_HAS_TZ_FILE__
158 #include <sys/stat.h>
162 /* ":<tzname>+hh:mm:ss<tzname>+hh:mm:ss,Mmm.w.d/hh:mm:ss,Mmm.w.d/hh:mm:ss" + nul */
163 /* 1 + 2*(1+TZNAME_MAX+1 + 9 + 7 + 9) + 1 = 2*TZNAME_MAX + 56 */
165 #else /* __UCLIBC_HAS_TZ_FILE__ */
167 /* Probably no longer needed. */
168 #undef __UCLIBC_HAS_TZ_FILE_READ_MANY__
170 #endif /* __UCLIBC_HAS_TZ_FILE__ */
172 /**********************************************************************/
174 extern struct tm __time_tm;
179 short day; /* for J or normal */
182 short rule_type; /* J, M, \0 */
183 char tzname[TZNAME_MAX+1];
186 #ifdef __UCLIBC_HAS_THREADS__
190 extern pthread_mutex_t _time_tzlock;
192 #define TZLOCK pthread_mutex_lock(&_time_tzlock)
193 #define TZUNLOCK pthread_mutex_unlock(&_time_tzlock)
197 #define TZLOCK ((void) 0)
198 #define TZUNLOCK ((void) 0)
202 extern rule_struct _time_tzinfo[2];
204 extern struct tm *_time_t2tm(const time_t *__restrict timer,
205 int offset, struct tm *__restrict result);
207 extern time_t _time_mktime(struct tm *timeptr, int store_on_success);
209 /**********************************************************************/
212 static char __time_str[26];
214 char *asctime(const struct tm *__restrict ptm)
216 return asctime_r(ptm, __time_str);
220 /**********************************************************************/
223 /* Strictly speaking, this implementation isn't correct. ANSI/ISO specifies
224 * that the implementation of asctime() be equivalent to
226 * char *asctime(const struct tm *timeptr)
228 * static char wday_name[7][3] = {
229 * "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
231 * static char mon_name[12][3] = {
232 * "Jan", "Feb", "Mar", "Apr", "May", "Jun",
233 * "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
235 * static char result[26];
237 * sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
238 * wday_name[timeptr->tm_wday],
239 * mon_name[timeptr->tm_mon],
240 * timeptr->tm_mday, timeptr->tm_hour,
241 * timeptr->tm_min, timeptr->tm_sec,
242 * 1900 + timeptr->tm_year);
246 * but the above is either inherently unsafe, or carries with it the implicit
247 * assumption that all fields of timeptr fall within their usual ranges, and
248 * that the tm_year value falls in the range [-2899,8099] to avoid overflowing
251 * If we take the implicit assumption as given, then the implementation below
252 * is still incorrect for tm_year values < -900, as there will be either
253 * 0-padding and/or a missing negative sign for the year conversion . But given
254 * the ususal use of asctime(), I think it isn't unreasonable to restrict correct
255 * operation to the domain of years between 1000 and 9999.
258 /* This is generally a good thing, but if you're _sure_ any data passed will be
259 * in range, you can #undef this. */
260 #define SAFE_ASCTIME_R 1
262 static const unsigned char at_data[] = {
263 'S', 'u', 'n', 'M', 'o', 'n', 'T', 'u', 'e', 'W', 'e', 'd',
264 'T', 'h', 'u', 'F', 'r', 'i', 'S', 'a', 't',
266 'J', 'a', 'n', 'F', 'e', 'b', 'M', 'a', 'r', 'A', 'p', 'r',
267 'M', 'a', 'y', 'J', 'u', 'n', 'J', 'u', 'l', 'A', 'u', 'g',
268 'S', 'e', 'p', 'O', 'c', 't', 'N', 'o', 'v', 'D', 'e', 'c',
270 #ifdef SAFE_ASCTIME_R
275 offsetof(struct tm, tm_mday),
277 offsetof(struct tm, tm_hour),
279 offsetof(struct tm, tm_min),
281 offsetof(struct tm, tm_sec),
282 ' ', '?', '?', '?', '?', '\n', 0
285 char *asctime_r(register const struct tm *__restrict ptm,
286 register char *__restrict buffer)
293 #ifdef SAFE_ASCTIME_R
294 memcpy(buffer, at_data + 3*(7 + 12), sizeof(at_data) - 3*(7 + 12));
296 if (((unsigned int)(ptm->tm_wday)) <= 6) {
297 memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);
300 if (((unsigned int)(ptm->tm_mon)) <= 11) {
301 memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
304 assert(((unsigned int)(ptm->tm_wday)) <= 6);
305 assert(((unsigned int)(ptm->tm_mon)) <= 11);
307 memcpy(buffer, at_data + 3*(7 + 12) - 3, sizeof(at_data) + 3 - 3*(7 + 12));
309 memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);
310 memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
313 #ifdef SAFE_ASCTIME_R
315 tmp = ptm->tm_year + 1900;
316 if (((unsigned int) tmp) < 10000) {
319 *buffer = '0' + (tmp % 10);
321 } while (*--buffer == '?');
323 #else /* SAFE_ASCTIME_R */
325 tmp = ptm->tm_year + 1900;
326 assert( ((unsigned int) tmp) < 10000 );
328 *buffer = '0' + (tmp % 10);
330 } while (*--buffer == '?');
331 #endif /* SAFE_ASCTIME_R */
335 tmp = *((int *)(((const char *) ptm) + (int) *buffer));
336 #ifdef SAFE_ASCTIME_R
337 if (((unsigned int) tmp) >= 100) { /* Just check 2 digit non-neg. */
338 buffer[-1] = *buffer = '?';
340 #else /* SAFE_ASCTIME_R */
341 assert(((unsigned int) tmp) < 100); /* Just check 2 digit non-neg. */
342 #endif /* SAFE_ASCTIME_R */
344 *buffer = '0' + (tmp % 10);
346 buffer[-1] = '0' + (tmp/10);
348 buffer[-1] += (tmp/10);
351 } while ((buffer -= 2)[-2] == '0');
353 if (*++buffer == '0') { /* Space-pad day of month. */
361 /**********************************************************************/
364 #include <sys/times.h>
366 /* Note: According to glibc...
367 * CAE XSH, Issue 4, Version 2: <time.h>
368 * The value of CLOCKS_PER_SEC is required to be 1 million on all
369 * XSI-conformant systems.
373 #if CLOCKS_PER_SEC != 1000000L
374 #error unexpected value for CLOCKS_PER_SEC!
384 t = ((unsigned long) xtms.tms_utime) + xtms.tms_stime;
386 #ifndef __UCLIBC_CLK_TCK_CONST
387 #error __UCLIBC_CLK_TCK_CONST not defined!
391 #define CLK_TCK __UCLIBC_CLK_TCK_CONST
393 #if CLK_TCK > CLOCKS_PER_SEC
394 #error __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC!
396 #error __UCLIBC_CLK_TCK_CONST < 1!
399 #if (CLK_TCK == CLOCKS_PER_SEC)
400 return (t <= LONG_MAX) ? t : -1;
401 #elif (CLOCKS_PER_SEC % CLK_TCK) == 0
402 return (t <= (LONG_MAX / (CLOCKS_PER_SEC/CLK_TCK)))
403 ? t * (CLOCKS_PER_SEC/CLK_TCK)
406 return (t <= ((LONG_MAX / CLOCKS_PER_SEC) * CLK_TCK
407 + ((LONG_MAX % CLOCKS_PER_SEC) * CLK_TCK) / CLOCKS_PER_SEC))
408 ? (((t / CLK_TCK) * CLOCKS_PER_SEC)
409 + (((t % CLK_TCK) * CLOCKS_PER_SEC) / CLK_TCK))
415 /**********************************************************************/
418 char *ctime(const time_t *clock)
420 /* ANSI/ISO/SUSv3 say that ctime is equivalent to the following. */
421 return asctime(localtime(clock));
425 /**********************************************************************/
428 char *ctime_r(const time_t *clock, char *buf)
432 return asctime_r(localtime_r(clock, &xtm), buf);
436 /**********************************************************************/
442 #error difftime implementation assumptions violated for you arch!
445 double difftime(time_t time1, time_t time0)
447 #if (LONG_MAX >> DBL_MANT_DIG) == 0
449 /* time_t fits in the mantissa of a double. */
450 return ((double) time1) - time0;
452 #elif ((LONG_MAX >> DBL_MANT_DIG) >> DBL_MANT_DIG) == 0
454 /* time_t can overflow the mantissa of a double. */
457 d = ((time_t) 1) << DBL_MANT_DIG;
463 /* Since FLT_RADIX==2 and d is a power of 2, the only possible
464 * rounding error in the expression below would occur from the
466 return (((double) t1) - t0) * d + (((double) time1) - time0);
469 #error difftime needs special implementation on your arch.
474 /**********************************************************************/
477 struct tm *gmtime(const time_t *timer)
479 register struct tm *ptm = &__time_tm;
481 _time_t2tm(timer, 0, ptm); /* Can return NULL... */
487 /**********************************************************************/
490 struct tm *gmtime_r(const time_t *__restrict timer,
491 struct tm *__restrict result)
493 return _time_t2tm(timer, 0, result);
497 /**********************************************************************/
500 struct tm *localtime(const time_t *timer)
502 register struct tm *ptm = &__time_tm;
504 /* In this implementation, tzset() is called by localtime_r(). */
506 localtime_r(timer, ptm); /* Can return NULL... */
512 /**********************************************************************/
515 static const unsigned char day_cor[] = { /* non-leap */
516 31, 31, 34, 34, 35, 35, 36, 36, 36, 37, 37, 38, 38
517 /* 0, 0, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7 */
518 /* 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 */
521 /* Note: timezone locking is done by localtime_r. */
523 static int tm_isdst(register const struct tm *__restrict ptm)
525 register rule_struct *r = _time_tzinfo;
527 int i, isdst, isleap, day, day0, monlen, mday;
528 int oday; /* Note: oday can be uninitialized. */
531 if (r[1].tzname[0] != 0) {
532 /* First, get the current seconds offset from the start of the year.
533 * Fields of ptm are assumed to be in their normal ranges. */
536 + 60 * (long)(ptm->tm_hour
537 + 24 * ptm->tm_yday));
538 /* Do some prep work. */
539 i = (ptm->tm_year % 400) + 1900; /* Make sure we don't overflow. */
540 isleap = __isleap(i);
543 + i /* Normal years increment 1 wday. */
549 day = r->day; /* Common for 'J' and # case. */
550 if (r->rule_type == 'J') {
551 if (!isleap || (day < (31+29))) {
554 } else if (r->rule_type == 'M') {
555 /* Find 0-based day number for 1st of the month. */
556 day = 31*r->month - day_cor[r->month -1];
557 if (isleap && (day >= 59)) {
560 monlen = 31 + day_cor[r->month -1] - day_cor[r->month];
561 if (isleap && (r->month > 1)) {
564 /* Wweekday (0 is Sunday) of 1st of the month
565 * is (day0 + day) % 7. */
566 if ((mday = r->day - ((day0 + day) % 7)) >= 0) {
567 mday -= 7; /* Back up into prev month since r->week>0. */
569 if ((mday += 7 * r->week) >= monlen) {
572 /* So, 0-based day number is... */
577 /* Adjust sec since dst->std change time is in dst. */
578 sec += (r[-1].gmt_offset - r->gmt_offset);
580 ++isdst; /* Year starts in dst. */
585 /* Now convert day to seconds and add offset and compare. */
586 if (sec >= (day * 86400L) + r->dst_offset) {
596 struct tm *localtime_r(register const time_t *__restrict timer,
597 register struct tm *__restrict result)
610 offset = 604800L - _time_tzinfo[dst].gmt_offset;
611 if (*timer > (LONG_MAX - 604800L)) {
615 *x = *timer + offset;
617 _time_t2tm(x, days, result);
618 result->tm_isdst = dst;
619 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
620 result->tm_gmtoff = - _time_tzinfo[dst].gmt_offset;
621 result->tm_zone = result->__tm_tzname;
622 strcpy(result->__tm_tzname, _time_tzinfo[dst].tzname);
623 #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
624 } while ((++dst < 2) && (result->tm_isdst = tm_isdst(result)) != 0);
632 /**********************************************************************/
635 /* Another name for `mktime'. */
636 /* time_t timelocal(struct tm *tp) */
637 weak_alias(mktime,timelocal);
639 time_t mktime(struct tm *timeptr)
641 return _time_mktime(timeptr, 1);
646 /**********************************************************************/
647 #if defined(L_strftime) || defined(L_strftime_l)
649 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
651 size_t strftime(char *__restrict s, size_t maxsize,
652 const char *__restrict format,
653 const struct tm *__restrict timeptr)
655 return __strftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE);
658 #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
660 #define NO_E_MOD 0x80
661 #define NO_O_MOD 0x40
663 #define ILLEGAL_SPEC 0x3f
665 #define INT_SPEC 0x00 /* must be 0x00!! */
666 #define STRING_SPEC 0x10 /* must be 0x10!! */
667 #define CALC_SPEC 0x20
668 #define STACKED_SPEC 0x30
670 #define MASK_SPEC 0x30
674 * No alternate digit (%O?) handling. Always uses 0-9.
675 * Alternate locale format (%E?) handling is broken for nontrivial ERAs.
676 * glibc's %P is currently faked by %p. This means it doesn't do lower case.
677 * glibc's %k, %l, and %s are handled.
678 * glibc apparently allows (and ignores) extraneous 'E' and 'O' modifiers,
679 * while they are flagged as illegal conversions here.
682 /* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
683 static const unsigned char spec[] = {
684 /* A */ 0x03 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
685 /* B */ 0x04 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
686 /* C */ 0x0a | INT_SPEC | NO_O_MOD,
687 /* D */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
688 /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
689 /* F */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
690 /* G */ 0x03 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
691 /* H */ 0x0b | INT_SPEC | NO_E_MOD,
692 /* I */ 0x0c | INT_SPEC | NO_E_MOD,
693 /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
694 /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
695 /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
696 /* M */ 0x0d | INT_SPEC | NO_E_MOD,
697 /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
698 /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
699 /* P */ 0x05 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc ; use %p */
700 /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
701 /* R */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
702 /* S */ 0x0e | INT_SPEC | NO_E_MOD,
703 /* T */ 0x05 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
704 /* U */ 0x04 | CALC_SPEC | NO_E_MOD,
705 /* V */ 0x05 | CALC_SPEC | NO_E_MOD,
706 /* W */ 0x06 | CALC_SPEC | NO_E_MOD,
707 /* X */ 0x0a | STACKED_SPEC | NO_O_MOD,
708 /* Y */ 0x0f | INT_SPEC | NO_O_MOD,
709 /* Z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
716 /* a */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
717 /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
718 /* c */ 0x08 | STACKED_SPEC | NO_O_MOD,
719 /* d */ 0x00 | INT_SPEC | NO_E_MOD,
720 /* e */ 0x01 | INT_SPEC | NO_E_MOD,
721 /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
722 /* g */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
723 /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* same as b */
724 /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
725 /* j */ 0x08 | INT_SPEC | NO_E_MOD | NO_O_MOD,
726 /* k */ 0x03 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
727 /* l */ 0x04 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
728 /* m */ 0x05 | INT_SPEC | NO_E_MOD,
729 /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
730 /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
731 /* p */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
732 /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
733 /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
734 /* s */ 0x07 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
735 /* t */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
736 /* u */ 0x07 | INT_SPEC | NO_E_MOD,
737 /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
738 /* w */ 0x02 | INT_SPEC | NO_E_MOD,
739 /* x */ 0x09 | STACKED_SPEC | NO_O_MOD,
740 /* y */ 0x09 | INT_SPEC,
741 /* z */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
744 /* WARNING!!! These are dependent on the layout of struct tm!!! */
745 #define FIELD_MAX (26+6+26)
746 60 /* 61? */, 59, 23, 31, 11, 0 /* 9999 */, 6, 0 /* 365 */,
748 #define TP_OFFSETS (FIELD_MAX+8)
755 0, /* CURRENTLY UNUSED */
756 /* NOTE: u,j,y order must be preserved as 6,7,5 seq is used in the code! */
757 #define CALC_OFFSETS (TP_OFFSETS + 7)
774 #define TP_CODES (TP_OFFSETS + 16 + 6)
781 0, /* CURRENTLY UNUSED */
784 2 | 128 | 32 | 16 , /* y */
785 2 | 128 | 64 | 32 | 16 , /* C */
787 2 | 32 | 16 | 0, /* I */
798 #define STRINGS_NL_ITEM_START (TP_CODES + 16 + 6)
799 _NL_ITEM_INDEX(ABDAY_1), /* a */
800 _NL_ITEM_INDEX(ABMON_1), /* b, h */
801 _NL_ITEM_INDEX(AM_STR), /* p */
802 _NL_ITEM_INDEX(DAY_1), /* A */
803 _NL_ITEM_INDEX(MON_1), /* B */
804 _NL_ITEM_INDEX(AM_STR), /* P -- wrong! need lower case */
806 #define STACKED_STRINGS_START (STRINGS_NL_ITEM_START+6)
807 6, 7, 8, 16, 24, 29, /* 6 - offsets from offset-count to strings */
810 '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
811 '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
812 '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
813 '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
815 #define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 43)
816 _NL_ITEM_INDEX(D_T_FMT), /* c */
817 _NL_ITEM_INDEX(D_FMT), /* x */
818 _NL_ITEM_INDEX(T_FMT), /* X */
819 _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
820 #ifdef ENABLE_ERA_CODE
821 _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
822 _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */
823 _NL_ITEM_INDEX(ERA_T_FMT), /* EX */
827 static int load_field(int k, const struct tm *__restrict timeptr)
832 r = ((int *) timeptr)[k];
834 r_max = spec[FIELD_MAX + k];
843 if ((((unsigned int) r) > r_max) || ((k == 3) && !r)) {
852 #ifdef __UCLIBC_MJN3_ONLY__
853 #warning TODO: Check multibyte format string validity.
856 size_t __XL(strftime)(char *__restrict s, size_t maxsize,
857 const char *__restrict format,
858 const struct tm *__restrict timeptr __LOCALE_PARAM )
861 register const char *p;
862 register const char *o;
863 const rule_struct *rsp;
864 const char *stack[MAX_PUSH];
867 int field_val, i, j, lvl;
868 int x[3]; /* wday, yday, year */
870 char buf[__UIM_BUFLEN_LONG];
874 tzset(); /* We'll, let's get this out of the way. */
886 *s = 0; /* nul-terminate */
887 return maxsize - count;
894 if ((*(o = p) == '%') && (*++p != '%')) {
897 if ((*p == 'O') || (*p == 'E')) { /* modifier */
898 mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
902 if ((((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
903 || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
911 code &= ILLEGAL_SPEC; /* modifiers are preserved in mod var. */
913 if ((code & MASK_SPEC) == STACKED_SPEC) {
914 if (lvl == MAX_PUSH) {
915 goto OUTPUT; /* Stack full so treat as illegal spec. */
918 if ((code &= 0xf) < 8) {
919 p = ((const char *) spec) + STACKED_STRINGS_START + code;
920 p += *((unsigned char *)p);
923 p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
925 #ifdef ENABLE_ERA_CODE
926 if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
927 && (*(o = __XL(nl_langinfo)(_NL_ITEM(LC_TIME,
928 (int)(((unsigned char *)p)[4]))
936 p = __XL(nl_langinfo)(_NL_ITEM(LC_TIME,
937 (int)(*((unsigned char *)p)))
943 o = spec + 26; /* set to "????" */
944 if ((code & MASK_SPEC) == CALC_SPEC) {
949 /* Use a cast to silence the warning since *timeptr won't
951 if ((t = _time_mktime((struct tm *) timeptr, 0))
957 #ifdef TIME_T_IS_UNSIGNED
958 o = _uintmaxtostr(buf + sizeof(buf) - 1,
962 o = _uintmaxtostr(buf + sizeof(buf) - 1,
966 o_count = sizeof(buf);
968 } else if (((*p) | 0x20) == 'z') { /* 'z' or 'Z' */
970 if (timeptr->tm_isdst < 0) {
971 /* SUSv3 specifies this behavior for 'z', but we'll also
972 * treat it as "no timezone info" for 'Z' too. */
980 if (timeptr->tm_isdst > 0) {
988 if (!o) { /* PARANOIA */
989 o = spec+30; /* empty string */
997 if ((tzo = -rsp->gmt_offset) < 0) {
1006 field_val = ((i / 60) * 100) + (i % 60);
1008 i = 16 + 6; /* 0-fill, width = 4 */
1011 /* TODO: don't need year for U, W */
1012 for (i=0 ; i < 3 ; i++) {
1013 if ((x[i] = load_field(spec[CALC_OFFSETS+i],timeptr)) < 0) {
1018 i = 16 + 2; /* 0-fill, width = 2 */
1020 if ((*p == 'U') || (*p == 'W')) {
1021 field_val = ((x[1] - x[0]) + 7);
1026 if ((*p == 'W') && !x[0]) {
1029 } else { /* ((*p == 'g') || (*p == 'G') || (*p == 'V')) */
1031 isofm = (((x[1] - x[0]) + 11) % 7) - 3; /* [-3,3] */
1033 if (x[1] < isofm) { /* belongs to previous year */
1035 x[1] += 365 + __isleap(x[2]);
1039 field_val = ((x[1] - isofm) / 7) + 1; /* week # */
1040 days = 365 + __isleap(x[2]);
1041 isofm = ((isofm + 7*53 + 3 - days)) %7 + days - 3; /* next year */
1042 if (x[1] >= isofm) { /* next year */
1048 if (*p != 'V') { /* need year */
1049 field_val = x[2]; /* TODO: what if x[2] now 10000 ?? */
1053 i = 16 + 6; /* 0-fill, width = 4 */
1059 i = TP_OFFSETS + (code & 0x1f);
1060 if ((field_val = load_field(spec[i],timeptr)) < 0) {
1064 i = spec[i+(TP_CODES - TP_OFFSETS)];
1066 j = (i & 128) ? 100: 12;
1072 if (((i&128) + field_val) == 0) { /* mod 12? == 0 */
1073 field_val = j; /* set to 12 */
1076 field_val += (i & 1);
1077 if ((i & 8) && !field_val) {
1082 if ((code & MASK_SPEC) == STRING_SPEC) {
1084 field_val += spec[STRINGS_NL_ITEM_START + (code & 0xf)];
1085 o = __XL(nl_langinfo)(_NL_ITEM(LC_TIME, field_val) __LOCALE_ARG );
1087 o_count = ((i >> 1) & 3) + 1;
1090 *(char *)(--o) = '0' + (field_val % 10);
1094 *buf = ' ' + (i & 16);
1101 while (o_count && count && *o) {
1109 __XL_ALIAS(strftime)
1111 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1114 /**********************************************************************/
1115 #if defined(L_strptime) || defined(L_strptime_l)
1117 #if defined(L_strptime) || defined(L_strptime_l)
1118 #define ISDIGIT(C) __isdigit_char((C))
1121 #ifdef __UCLIBC_DO_XLOCALE
1122 #define ISSPACE(C) isspace_l((C), locale_arg)
1124 #define ISSPACE(C) isspace((C))
1127 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
1129 char *strptime(const char *__restrict buf, const char *__restrict format,
1130 struct tm *__restrict tm)
1132 return __strptime_l(buf, format, tm, __UCLIBC_CURLOCALE);
1135 #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1138 * 1) %l and %k are space-padded, so "%l" by itself fails while " %l" succeeds.
1139 * Both work for glibc. So, should we always strip spaces?
1144 * There are several differences between this strptime and glibc's strptime.
1145 * 1) glibc strips leading space before numeric conversions.
1146 * 2) glibc will read fields without whitespace in between. SUSv3 states
1147 * that you must have whitespace between conversion operators. Besides,
1148 * how do you know how long a number should be if there are leading 0s?
1149 * 3) glibc attempts to compute some the struct tm fields based on the
1150 * data retrieved; tm_wday in particular. I don't as I consider it
1151 * another glibc attempt at mind-reading...
1154 #define NO_E_MOD 0x80
1155 #define NO_O_MOD 0x40
1157 #define ILLEGAL_SPEC 0x3f
1159 #define INT_SPEC 0x00 /* must be 0x00!! */
1160 #define STRING_SPEC 0x10 /* must be 0x10!! */
1161 #define CALC_SPEC 0x20
1162 #define STACKED_SPEC 0x30
1164 #define MASK_SPEC 0x30
1166 /* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
1167 static const unsigned char spec[] = {
1168 /* A */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1169 /* B */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1170 /* C */ 0x08 | INT_SPEC | NO_O_MOD,
1171 /* D */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1172 /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1173 /* F */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1174 /* G */ 0x0f | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1175 /* H */ 0x06 | INT_SPEC | NO_E_MOD,
1176 /* I */ 0x07 | INT_SPEC | NO_E_MOD,
1177 /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1178 /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1179 /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1180 /* M */ 0x04 | INT_SPEC | NO_E_MOD,
1181 /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1182 /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1183 /* P */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1184 /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1185 /* R */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1186 /* S */ 0x05 | INT_SPEC | NO_E_MOD,
1187 /* T */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1188 /* U */ 0x0c | INT_SPEC | NO_E_MOD,
1189 /* V */ 0x0d | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1190 /* W */ 0x0c | INT_SPEC | NO_E_MOD,
1191 /* X */ 0x0a | STACKED_SPEC | NO_O_MOD,
1192 /* Y */ 0x0a | INT_SPEC | NO_O_MOD,
1193 /* Z */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1195 /* WARNING! This assumes orderings:
1197 * ABDAY_1-ABDAY-7,DAY_1-DAY_7
1198 * ABMON_1-ABMON_12,MON_1-MON12
1199 * Also, there are exactly 6 bytes between 'Z' and 'a'.
1201 #define STRINGS_NL_ITEM_START (26)
1202 _NL_ITEM_INDEX(AM_STR), /* p (P) */
1203 _NL_ITEM_INDEX(ABMON_1), /* B, b */
1204 _NL_ITEM_INDEX(ABDAY_1), /* A, a */
1209 /* a */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1210 /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1211 /* c */ 0x08 | STACKED_SPEC | NO_O_MOD,
1212 /* d */ 0x00 | INT_SPEC | NO_E_MOD,
1213 /* e */ 0x00 | INT_SPEC | NO_E_MOD,
1214 /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1215 /* g */ 0x0e | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1216 /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1217 /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1218 /* j */ 0x01 | INT_SPEC | NO_E_MOD | NO_O_MOD,
1219 /* k */ 0x06 | INT_SPEC | NO_E_MOD, /* glibc */
1220 /* l */ 0x07 | INT_SPEC | NO_E_MOD, /* glibc */
1221 /* m */ 0x02 | INT_SPEC | NO_E_MOD,
1222 /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1223 /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1224 /* p */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1225 /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1226 /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1227 /* s */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1228 /* t */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1229 /* u */ 0x0b | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1230 /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1231 /* w */ 0x03 | INT_SPEC | NO_E_MOD,
1232 /* x */ 0x09 | STACKED_SPEC | NO_O_MOD,
1233 /* y */ 0x09 | INT_SPEC,
1234 /* z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1236 #define INT_FIELD_START (26+6+26)
1237 /* (field #) << 3 + lower bound (0|1) + correction 0:none, 2:-1, 4:-1900
1238 * followed by upper bound prior to correction with 1=>366 and 2=>9999. */
1239 /* d, e */ (3 << 3) + 1 + 0, 31,
1240 /* j */ (7 << 3) + 1 + 2, /* 366 */ 1,
1241 /* m */ (4 << 3) + 1 + 2, 12,
1242 /* w */ (6 << 3) + 0 + 0, 6,
1243 /* M */ (1 << 3) + 0 + 0, 59,
1244 /* S */ 0 + 0 + 0, 60,
1245 /* H (k) */ (2 << 3) + 0 + 0, 23,
1246 /* I (l) */ (9 << 3) + 1 + 0, 12, /* goes with 8 -- am/pm */
1247 /* C */ (10<< 3) + 0 + 0, 99,
1248 /* y */ (11<< 3) + 0 + 0, 99,
1249 /* Y */ (5 << 3) + 0 + 4, /* 9999 */ 2,
1250 /* u */ (6 << 3) + 1 + 0, 7,
1251 /* The following are processed and range-checked, but ignored otherwise. */
1252 /* U, W */ (12<< 3) + 0 + 0, 53,
1253 /* V */ (12<< 3) + 1 + 0, 53,
1254 /* g */ (12<< 3) + 0 + 0, 99,
1255 /* G */ (12<< 3) + 0 /*+ 4*/, /* 9999 */ 2, /* Note: -1 or 10000? */
1257 #define STACKED_STRINGS_START (INT_FIELD_START+32)
1258 5, 6, 14, 22, 27, /* 5 - offsets from offset-count to strings */
1259 ' ', 0, /* 2 - %n or %t */
1260 '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
1261 '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
1262 '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
1263 '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
1265 #define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 40)
1266 _NL_ITEM_INDEX(D_T_FMT), /* c */
1267 _NL_ITEM_INDEX(D_FMT), /* x */
1268 _NL_ITEM_INDEX(T_FMT), /* X */
1269 _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
1270 #ifdef ENABLE_ERA_CODE
1271 _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
1272 _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */
1273 _NL_ITEM_INDEX(ERA_T_FMT), /* EX */
1279 char *__XL(strptime)(const char *__restrict buf, const char *__restrict format,
1280 struct tm *__restrict tm __LOCALE_PARAM)
1282 register const char *p;
1284 const char *stack[MAX_PUSH];
1292 fields[i] = INT_MIN;
1300 if (lvl == 0) { /* Done. */
1301 if (fields[6] == 7) { /* Cleanup for %u here since just once. */
1302 fields[6] = 0; /* Don't use mod in case unset. */
1306 do { /* Store the values into tm. */
1307 ((int *) tm)[i] = fields[i];
1310 return (char *) buf; /* Success. */
1316 if ((*p == '%') && (*++p != '%')) {
1318 if ((*p == 'O') || (*p == 'E')) { /* Modifier? */
1319 mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
1324 || (((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
1325 || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
1327 return NULL; /* Illegal spec. */
1330 if ((code & MASK_SPEC) == STACKED_SPEC) {
1331 if (lvl == MAX_PUSH) {
1332 return NULL; /* Stack full so treat as illegal spec. */
1335 if ((code &= 0xf) < 8) {
1336 p = ((const char *) spec) + STACKED_STRINGS_START + code;
1337 p += *((unsigned char *)p);
1341 p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
1343 #ifdef ENABLE_ERA_CODE
1344 if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
1345 && (*(o = __XL(nl_langinfo)(_NL_ITEM(LC_TIME,
1346 (int)(((unsigned char *)p)[4]))
1354 p = __XL(nl_langinfo)(_NL_ITEM(LC_TIME,
1355 (int)(*((unsigned char *)p)))
1362 if ((code & MASK_SPEC) == STRING_SPEC) {
1364 j = spec[STRINGS_NL_ITEM_START + 3 + code];
1365 i = _NL_ITEM(LC_TIME, spec[STRINGS_NL_ITEM_START + code]);
1366 /* Go backwards to check full names before abreviations. */
1369 o = __XL(nl_langinfo)(i+j __LOCALE_ARG);
1370 if (!__XL(strncasecmp)(buf,o,strlen(o) __LOCALE_ARG) && *o) {
1371 do { /* Found a match. */
1374 if (!code) { /* am/pm */
1376 if (fields[9] >= 0) { /* We have a previous %I or %l. */
1377 fields[2] = fields[9] + fields[8];
1379 } else { /* day (4) or month (6) */
1380 fields[2 + (code << 1)]
1381 = j % (spec[STRINGS_NL_ITEM_START + 3 + code] >> 1);
1386 return NULL; /* Failed to match. */
1389 if ((code & MASK_SPEC) == CALC_SPEC) {
1390 if ((code &= 0xf) < 1) { /* s or z*/
1396 if (!ISSPACE(*buf)) { /* Signal an error if whitespace. */
1397 #ifdef TIME_T_IS_UNSIGNED
1398 t = __XL(strtoul)(buf, &o, 10 __LOCALE_ARG);
1400 t = __XL(strtol)(buf, &o, 10 __LOCALE_ARG);
1403 if ((o == buf) || errno) { /* Not a number or overflow. */
1406 __set_errno(i); /* Restore errno. */
1409 if (!code) { /* s */
1410 localtime_r(&t, tm); /* TODO: check for failure? */
1412 do { /* Now copy values from tm to fields. */
1413 fields[i] = ((int *) tm)[i];
1417 /* TODO: glibc treats %Z as a nop. For now, do the same. */
1421 assert((code & MASK_SPEC) == INT_SPEC);
1423 register const unsigned char *x;
1425 x = spec + INT_FIELD_START + (code << 1);
1426 if ((j = x[1]) < 3) { /* upper bound (inclusive) */
1427 j = ((j==1) ? 366 : 9999);
1430 while (ISDIGIT(*buf)) {
1434 if ((i = 10*i + (*buf - '0')) > j) { /* Overflow. */
1439 if (i < (*x & 1)) { /* This catches no-digit case too. */
1449 if (*x == (9 << 3) + 1 + 0) { /* %I or %l */
1453 if (fields[8] >= 0) { /* We have a previous %p or %P. */
1454 fields[2] = i + fields[8];
1458 fields[(*x) >> 3] = i;
1460 if (((unsigned char)(*x - (10<< 3) + 0 + 0)) <= 8) { /* %C or %y */
1461 if ((j = fields[10]) < 0) { /* No %C, so i must be %y data. */
1462 if (i <= 68) { /* Map [0-68] to 2000+i */
1465 } else { /* Have %C data, but what about %y? */
1466 if ((i = fields[11]) < 0) { /* No %y data. */
1467 i = 0; /* Treat %y val as 0 following glibc's example. */
1475 } else if (ISSPACE(*p)) {
1477 while (ISSPACE(*buf)) {
1481 } else if (*buf++ == *p++) {
1487 __XL_ALIAS(strptime)
1489 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1492 /**********************************************************************/
1496 #error The uClibc version of time is in sysdeps/linux/common.
1499 time_t time(register time_t *tloc)
1502 register struct timeval *p = &tv;
1504 gettimeofday(p, NULL); /* This should never fail... */
1514 /**********************************************************************/
1517 static const char vals[] = {
1518 'T', 'Z', 0, /* 3 */
1519 'U', 'T', 'C', 0, /* 4 */
1520 25, 60, 60, 1, /* 4 */
1523 6, 0, 0, /* Note: overloaded for non-M non-J case... */
1525 ',', 'M', '4', '.', '1', '.', '0',
1526 ',', 'M', '1', '0', '.', '5', '.', '0', 0
1530 #define UTC (vals + 3)
1531 #define RANGE (vals + 7)
1532 #define RULE (vals + 11 - 1)
1533 #define DEFAULT_RULES (vals + 22)
1535 /* Initialize to UTC. */
1538 char *tzname[2] = { (char *) UTC, (char *) (UTC-1) };
1540 #ifdef __UCLIBC_HAS_THREADS__
1541 pthread_mutex_t _time_tzlock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
1544 rule_struct _time_tzinfo[2];
1546 static const char *getoffset(register const char *e, long *pn)
1548 register const char *s = RANGE-1;
1556 if (__isdigit_char(*e)) {
1559 if (__isdigit_char(*e)) {
1560 f = 10 * f + (*e++ - '0');
1562 if (((unsigned int)f) >= *s) {
1577 static const char *getnumber(register const char *e, int *pn)
1580 /* bcc can optimize the counter if it thinks it is a pointer... */
1581 register const char *n = (const char *) 3;
1585 while (n && __isdigit_char(*e)) {
1586 f = 10 * f + (*e++ - '0');
1591 return (n == (const char *) 3) ? NULL : e;
1597 while (n && __isdigit_char(*e)) {
1598 f = 10 * f + (*e++ - '0');
1603 return (n == 3) ? NULL : e;
1604 #endif /* __BCC__ */
1608 #ifdef __UCLIBC_MJN3_ONLY__
1609 #warning CONSIDER: Should we preserve errno from open/read/close errors re TZ file?
1612 #ifdef __UCLIBC_HAS_TZ_FILE__
1614 #ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1615 static int TZ_file_read; /* Let BSS initialization set this to 0. */
1616 #endif /* __UCLIBC_HAS_TZ_FILE_READ_MANY__ */
1618 static char *read_TZ_file(char *buf)
1625 if ((fd = open(__UCLIBC_TZ_FILE_PATH__, O_RDONLY)) >= 0) {
1629 if ((r = read(fd, p, todo)) < 0) {
1639 if ((p > buf) && (p[-1] == '\n')) { /* Must end with newline. */
1642 #ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1644 #endif /* __UCLIBC_HAS_TZ_FILE_READ_MANY__ */
1654 #endif /* __UCLIBC_HAS_TZ_FILE__ */
1658 register const char *e;
1662 rule_struct new_rules[2];
1665 #ifdef __UCLIBC_HAS_TZ_FILE__
1666 char buf[TZ_BUFLEN];
1667 #endif /* __UCLIBC_HAS_TZ_FILE__ */
1668 #ifdef __UCLIBC_HAS_TZ_CACHING__
1669 static char oldval[TZ_BUFLEN]; /* BSS-zero'd. */
1670 #endif /* __UCLIBC_HAS_TZ_CACHING__ */
1674 e = getenv(TZ); /* TZ env var always takes precedence. */
1676 #if defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__)
1677 /* Put this inside the lock to prevent the possiblity of two different
1678 * timezones being used in a threaded app. */
1681 TZ_file_read = 0; /* Reset if the TZ env var is set. */
1682 } else if (TZ_file_read > 0) {
1685 #endif /* defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__) */
1687 /* Warning!!! Since uClibc doesn't do lib locking, the following is
1688 * potentially unsafe in a multi-threaded program since it is remotely
1689 * possible that another thread could call setenv() for TZ and overwrite
1690 * the string being parsed. So, don't do that... */
1692 if ((!e /* TZ env var not set... */
1693 #ifdef __UCLIBC_HAS_TZ_FILE__
1694 && !(e = read_TZ_file(buf)) /* and no file or invalid file */
1695 #endif /* __UCLIBC_HAS_TZ_FILE__ */
1696 ) || !*e) { /* or set to empty string. */
1697 ILLEGAL: /* TODO: Clean up the following... */
1698 #ifdef __UCLIBC_HAS_TZ_CACHING__
1699 *oldval = 0; /* Set oldval to an empty string. */
1700 #endif /* __UCLIBC_HAS_TZ_CACHING__ */
1701 _time_tzinfo[0].gmt_offset = 0L;
1702 s = _time_tzinfo[0].tzname;
1707 *_time_tzinfo[1].tzname = 0;
1711 if (*e == ':') { /* Ignore leading ':'. */
1715 #ifdef __UCLIBC_HAS_TZ_CACHING__
1716 if (strcmp(e, oldval) == 0) { /* Same string as last time... */
1717 goto FAST_DONE; /* So nothing to do. */
1719 /* Make a copy of the TZ env string. It won't be nul-terminated if
1720 * it is too long, but it that case it will be illegal and will be reset
1721 * to the empty string anyway. */
1722 strncpy(oldval, e, TZ_BUFLEN);
1723 #endif /* __UCLIBC_HAS_TZ_CACHING__ */
1726 new_rules[1].tzname[0] = 0;
1728 /* Get std or dst name. */
1735 s = new_rules[count].tzname;
1738 && isascii(*e) /* SUSv3 requires char in portable char set. */
1740 || (c && (isalnum(*e) || (*e == '+') || (*e == '-'))))
1743 if (++n > TZNAME_MAX) {
1749 if ((n < 3) /* Check for minimum length. */
1750 || (c && (*e++ != c)) /* Match any quoting '<'. */
1757 if ((*e != '-') && (*e != '+')) {
1758 if (count && !__isdigit_char(*e)) {
1759 off -= 3600; /* Default to 1 hour ahead of std. */
1766 if (!(e = getoffset(e, &off))) {
1771 off = -off; /* Save off in case needed for dst default. */
1774 new_rules[count].gmt_offset = off;
1781 } else { /* OK, we have dst, so get some rules. */
1783 if (!*e) { /* No rules so default to US rules. */
1794 if ((c = *e++) == 'M') {
1796 } else if (c == 'J') {
1804 *(p = &new_rules[count].rule_type) = c;
1811 if (!(e = getnumber(e, &f))
1812 || (((unsigned int)(f - s[1])) > n)
1813 || (*s && (*e++ != *s))
1818 } while ((n = *(s += 2)) > 0);
1820 off = 2 * 60 * 60; /* Default to 2:00:00 */
1823 if (!(e = getoffset(e, &off))) {
1827 new_rules[count].dst_offset = off;
1828 } while (++count < 2);
1835 memcpy(_time_tzinfo, new_rules, sizeof(new_rules));
1837 tzname[0] = _time_tzinfo[0].tzname;
1838 tzname[1] = _time_tzinfo[1].tzname;
1839 daylight = !!_time_tzinfo[1].tzname[0];
1840 timezone = _time_tzinfo[0].gmt_offset;
1847 /**********************************************************************/
1848 /* #ifdef L_utime */
1850 /* utime is a syscall in both linux and elks. */
1851 /* int utime(const char *path, const struct utimbuf *times) */
1854 /**********************************************************************/
1856 /**********************************************************************/
1860 #error The uClibc version of utimes is in sysdeps/linux/common.
1864 #include <sys/time.h>
1866 int utimes(const char *filename, register const struct timeval *tvp)
1868 register struct utimbuf *p = NULL;
1873 p->actime = tvp[0].tv_sec;
1874 p->modtime = tvp[1].tv_sec;
1876 return utime(filename, p);
1880 /**********************************************************************/
1883 static const uint16_t vals[] = {
1884 60, 60, 24, 7 /* special */, 36524, 1461, 365, 0
1887 static const unsigned char days[] = {
1888 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
1893 * If time_t is 32 bits, then no overflow is possible.
1894 * It time_t is > 32 bits, this needs to be adjusted to deal with overflow.
1897 /* Note: offset is the correction in _days_ to *timer! */
1899 struct tm *_time_t2tm(const time_t *__restrict timer,
1900 int offset, struct tm *__restrict result)
1904 int wday; /* Note: wday can be uninitialized. */
1907 register const uint16_t *vp;
1913 if ((v = *vp) == 7) {
1914 /* Overflow checking, assuming time_t is long int... */
1915 #if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
1916 #if (INT_MAX == 2147483647L) && (LONG_MAX == 9223372036854775807L)
1917 /* Valid range for t is [-784223472856L, 784223421720L].
1918 * Outside of this range, the tm_year field will overflow. */
1919 if (((unsigned long)(t + offset- -784223472856L))
1920 > (784223421720L - -784223472856L)
1925 #error overflow conditions unknown
1929 /* We have days since the epoch, so caluclate the weekday. */
1930 #if defined(__BCC__) && TIME_T_IS_UNSIGNED
1931 wday = (t + 4) % (*vp); /* t is unsigned */
1933 wday = ((int)((t % (*vp)) + 11)) % ((int)(*vp)); /* help bcc */
1935 /* Set divisor to days in 400 years. Be kind to bcc... */
1936 v = ((time_t)(vp[1])) << 2;
1938 /* Change to days since 1/1/1601 so that for 32 bit time_t
1939 * values, we'll have t >= 0. This should be changed for
1940 * archs with larger time_t types.
1941 * Also, correct for offset since a multiple of 7. */
1943 /* TODO: Does this still work on archs with time_t > 32 bits? */
1944 t += (135140L - 366) + offset; /* 146097 - (365*30 + 7) -366 */
1946 #if defined(__BCC__) && TIME_T_IS_UNSIGNED
1947 t -= ((t1 = t / v) * v);
1949 if ((t -= ((t1 = t / v) * v)) < 0) {
1955 if ((*vp == 7) && (t == v-1)) {
1956 --t; /* Correct for 400th year leap case */
1957 ++p[4]; /* Stash the extra day... */
1960 #if defined(__BCC__) && 0
1984 *p += ((int) t); /* result[7] .. tm_yday */
1986 p -= 2; /* at result[5] */
1988 #if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
1989 /* Protect against overflow. TODO: Unecessary if int arith wraps? */
1990 *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + (p[1] - 299); /* tm_year */
1992 *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + p[1] - 299; /* tm_year */
1995 p[1] = wday; /* result[6] .. tm_wday */
1998 register const unsigned char *d = days;
2001 if (__isleap(wday)) {
2005 wday = p[2] + 1; /* result[7] .. tm_yday */
2006 *--p = 0; /* at result[4] .. tm_mon */
2010 d -= 11; /* Backup to non-leap Feb. */
2013 ++*p; /* Increment tm_mon. */
2015 p[-1] = wday; /* result[3] .. tm_mday */
2017 /* TODO -- should this be 0? */
2018 p[4] = 0; /* result[8] .. tm_isdst */
2019 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
2020 result->tm_gmtoff = 0;
2021 result->tm_zone = result->__tm_tzname;
2023 register char *s = result->__tm_tzname;
2029 #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
2035 /**********************************************************************/
2038 struct tm __time_tm; /* Global shared by gmtime() and localtime(). */
2041 /**********************************************************************/
2042 #ifdef L__time_mktime
2044 static const unsigned char vals[] = {
2045 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
2049 time_t _time_mktime(struct tm *timeptr, int store_on_success)
2058 /* 0:sec 1:min 2:hour 3:mday 4:mon 5:year 6:wday 7:yday 8:isdst */
2059 register int *p = (int *) &x;
2060 register const unsigned char *s;
2065 memcpy(p, timeptr, sizeof(struct tm));
2067 if ((default_dst = p[8]) < 0) {
2068 default_dst = 1; /* Assume advancing */
2072 p[5] = (p[5] - ((p[6] = p[5]/d) * d)) + (p[7] = p[4]/12);
2073 if ((p[4] -= 12 * p[7]) < 0) {
2079 d = (p[5] += 1900); /* Correct year. Now between 1900 and 2300. */
2089 s -= 11; /* Backup to non-leap Feb. */
2099 days = -719163L + ((long)d)*365 + ((d/4) - (d/100) + (d/400) + p[3] + p[7]);
2100 secs = p[0] + 60*( p[1] + 60*((long)(p[2])) )
2101 + _time_tzinfo[default_dst].gmt_offset;
2107 if ( ((unsigned long)(days + secs/86400L)) > 49710L) {
2111 secs += (days * 86400L);
2114 d = -719163L + d*365 + (d/4) - (d/100) + (d/400);
2116 + _time_tzinfo[default_dst].gmt_offset
2119 + 24*(((146073L * ((long long)(p[6])) + d)
2123 if (((unsigned long long)(secs - LONG_MIN))
2124 > (((unsigned long long)LONG_MAX) - LONG_MIN)
2131 d = ((struct tm *)p)->tm_isdst;
2134 localtime_r(&t, (struct tm *)p);
2136 if (t == ((time_t)(-1))) { /* Remember, time_t can be unsigned. */
2140 if ((d < 0) && (((struct tm *)p)->tm_isdst != default_dst)) {
2142 secs -= (days * 86400L);
2144 secs += (_time_tzinfo[1-default_dst].gmt_offset
2145 - _time_tzinfo[default_dst].gmt_offset);
2150 if (store_on_success) {
2151 memcpy(timeptr, p, sizeof(struct tm));
2162 /**********************************************************************/
2164 /* Return the number of days in YEAR. */
2166 int dysize(int year)
2168 return __isleap(year) ? 366 : 365;
2172 /**********************************************************************/
2173 /* Like `mktime', but for TP represents Universal Time, not local time. */
2174 /* time_t timegm(struct tm *tp) */