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.
102 #define _STDIO_UTILITY
112 #include <langinfo.h>
116 #define __isleap(y) ( !((y) % 4) && ( ((y) % 100) || !((y) % 400) ) )
120 #define TZNAME_MAX _POSIX_TZNAME_MAX
123 /**********************************************************************/
125 /* The era code is currently unfinished. */
126 /* #define ENABLE_ERA_CODE */
128 #define __TIME_TZ_FILE
129 /* #define __TIME_TZ_FILE_ONCE */
131 #define __TIME_TZ_OPT_SPEED
133 #define TZ_BUFLEN (2*TZNAME_MAX + 56)
135 #ifdef __TIME_TZ_FILE
136 #include <sys/stat.h>
139 /* ":<tzname>+hh:mm:ss<tzname>+hh:mm:ss,Mmm.w.d/hh:mm:ss,Mmm.w.d/hh:mm:ss" + nul */
140 /* 1 + 2*(1+TZNAME_MAX+1 + 9 + 7 + 9) + 1 = 2*TZNAME_MAX + 56 */
141 #else /* __TIME_TZ_FILE */
142 #undef __TIME_TZ_FILE_ONCE
143 #endif /* __TIME_TZ_FILE */
145 /**********************************************************************/
147 extern struct tm __time_tm;
152 short day; /* for J or normal */
155 short rule_type; /* J, M, \0 */
156 char tzname[TZNAME_MAX+1];
159 #ifdef __UCLIBC_HAS_THREADS__
163 extern pthread_mutex_t _time_tzlock;
165 #define TZLOCK pthread_mutex_lock(&_time_tzlock)
166 #define TZUNLOCK pthread_mutex_unlock(&_time_tzlock)
170 #define TZLOCK ((void) 0)
171 #define TZUNLOCK ((void) 0)
175 extern rule_struct _time_tzinfo[2];
177 extern struct tm *_time_t2tm(const time_t *__restrict timer,
178 int offset, struct tm *__restrict result);
180 extern time_t _time_mktime(struct tm *timeptr, int store_on_success);
182 /**********************************************************************/
185 static char __time_str[26];
187 char *asctime(const struct tm *__restrict ptm)
189 return asctime_r(ptm, __time_str);
193 /**********************************************************************/
196 /* Strictly speaking, this implementation isn't correct. ANSI/ISO specifies
197 * that the implementation of asctime() be equivalent to
199 * char *asctime(const struct tm *timeptr)
201 * static char wday_name[7][3] = {
202 * "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
204 * static char mon_name[12][3] = {
205 * "Jan", "Feb", "Mar", "Apr", "May", "Jun",
206 * "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
208 * static char result[26];
210 * sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
211 * wday_name[timeptr->tm_wday],
212 * mon_name[timeptr->tm_mon],
213 * timeptr->tm_mday, timeptr->tm_hour,
214 * timeptr->tm_min, timeptr->tm_sec,
215 * 1900 + timeptr->tm_year);
219 * but the above is either inherently unsafe, or carries with it the implicit
220 * assumption that all fields of timeptr fall within their usual ranges, and
221 * that the tm_year value falls in the range [-2899,8099] to avoid overflowing
224 * If we take the implicit assumption as given, then the implementation below
225 * is still incorrect for tm_year values < -900, as there will be either
226 * 0-padding and/or a missing negative sign for the year conversion . But given
227 * the ususal use of asctime(), I think it isn't unreasonable to restrict correct
228 * operation to the domain of years between 1000 and 9999.
231 /* This is generally a good thing, but if you're _sure_ any data passed will be
232 * in range, you can #undef this. */
233 #define SAFE_ASCTIME_R 1
235 static const unsigned char at_data[] = {
236 'S', 'u', 'n', 'M', 'o', 'n', 'T', 'u', 'e', 'W', 'e', 'd',
237 'T', 'h', 'u', 'F', 'r', 'i', 'S', 'a', 't',
239 'J', 'a', 'n', 'F', 'e', 'b', 'M', 'a', 'r', 'A', 'p', 'r',
240 'M', 'a', 'y', 'J', 'u', 'n', 'J', 'u', 'l', 'A', 'u', 'g',
241 'S', 'e', 'p', 'O', 'c', 't', 'N', 'o', 'v', 'D', 'e', 'c',
243 #ifdef SAFE_ASCTIME_R
248 offsetof(struct tm, tm_mday),
250 offsetof(struct tm, tm_hour),
252 offsetof(struct tm, tm_min),
254 offsetof(struct tm, tm_sec),
255 ' ', '?', '?', '?', '?', '\n', 0
258 char *asctime_r(register const struct tm *__restrict ptm,
259 register char *__restrict buffer)
266 #ifdef SAFE_ASCTIME_R
267 memcpy(buffer, at_data + 3*(7 + 12), sizeof(at_data) - 3*(7 + 12));
269 if (((unsigned int)(ptm->tm_wday)) <= 6) {
270 memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);
273 if (((unsigned int)(ptm->tm_mon)) <= 11) {
274 memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
277 assert(((unsigned int)(ptm->tm_wday)) <= 6);
278 assert(((unsigned int)(ptm->tm_mon)) <= 11);
280 memcpy(buffer, at_data + 3*(7 + 12) - 3, sizeof(at_data) + 3 - 3*(7 + 12));
282 memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);
283 memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
286 #ifdef SAFE_ASCTIME_R
288 tmp = ptm->tm_year + 1900;
289 if (((unsigned int) tmp) < 10000) {
292 *buffer = '0' + (tmp % 10);
294 } while (*--buffer == '?');
296 #else /* SAFE_ASCTIME_R */
298 tmp = ptm->tm_year + 1900;
299 assert( ((unsigned int) tmp) < 10000 );
301 *buffer = '0' + (tmp % 10);
303 } while (*--buffer == '?');
304 #endif /* SAFE_ASCTIME_R */
308 tmp = *((int *)(((const char *) ptm) + (int) *buffer));
309 #ifdef SAFE_ASCTIME_R
310 if (((unsigned int) tmp) >= 100) { /* Just check 2 digit non-neg. */
311 buffer[-1] = *buffer = '?';
313 #else /* SAFE_ASCTIME_R */
314 assert(((unsigned int) tmp) < 100); /* Just check 2 digit non-neg. */
315 #endif /* SAFE_ASCTIME_R */
317 *buffer = '0' + (tmp % 10);
319 buffer[-1] = '0' + (tmp/10);
321 buffer[-1] += (tmp/10);
324 } while ((buffer -= 2)[-2] == '0');
326 if (*++buffer == '0') { /* Space-pad day of month. */
334 /**********************************************************************/
337 #include <sys/times.h>
339 /* Note: According to glibc...
340 * CAE XSH, Issue 4, Version 2: <time.h>
341 * The value of CLOCKS_PER_SEC is required to be 1 million on all
342 * XSI-conformant systems.
346 #if CLOCKS_PER_SEC != 1000000L
347 #error unexpected value for CLOCKS_PER_SEC!
357 t = ((unsigned long) xtms.tms_utime) + xtms.tms_stime;
359 #ifndef __UCLIBC_CLK_TCK_CONST
360 #error __UCLIBC_CLK_TCK_CONST not defined!
364 #define CLK_TCK __UCLIBC_CLK_TCK_CONST
366 #if CLK_TCK > CLOCKS_PER_SEC
367 #error __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC!
369 #error __UCLIBC_CLK_TCK_CONST < 1!
372 #if (CLK_TCK == CLOCKS_PER_SEC)
373 return (t <= LONG_MAX) ? t : -1;
374 #elif (CLOCKS_PER_SEC % CLK_TCK) == 0
375 return (t <= (LONG_MAX / (CLOCKS_PER_SEC/CLK_TCK)))
376 ? t * (CLOCKS_PER_SEC/CLK_TCK)
379 return (t <= ((LONG_MAX / CLOCKS_PER_SEC) * CLK_TCK
380 + ((LONG_MAX % CLOCKS_PER_SEC) * CLK_TCK) / CLOCKS_PER_SEC))
381 ? (((t / CLK_TCK) * CLOCKS_PER_SEC)
382 + (((t % CLK_TCK) * CLOCKS_PER_SEC) / CLK_TCK))
388 /**********************************************************************/
391 char *ctime(const time_t *clock)
393 /* ANSI/ISO/SUSv3 say that ctime is equivalent to the following. */
394 return asctime(localtime(clock));
398 /**********************************************************************/
401 char *ctime_r(const time_t *clock, char *buf)
405 return asctime_r(localtime_r(clock, &xtms), buf);
409 /**********************************************************************/
415 #error difftime implementation assumptions violated for you arch!
418 double difftime(time_t time1, time_t time0)
420 #if (LONG_MAX >> DBL_MANT_DIG) == 0
422 /* time_t fits in the mantissa of a double. */
423 return ((double) time1) - time0;
425 #elif ((LONG_MAX >> DBL_MANT_DIG) >> DBL_MANT_DIG) == 0
427 /* time_t can overflow the mantissa of a double. */
430 d = ((time_t) 1) << DBL_MANT_DIG;
436 /* Since FLT_RADIX==2 and d is a power of 2, the only possible
437 * rounding error in the expression below would occur from the
439 return (((double) t1) - t0) * d + (((double) time1) - time0);
442 #error difftime needs special implementation on your arch.
447 /**********************************************************************/
450 struct tm *gmtime(const time_t *timer)
452 register struct tm *ptm = &__time_tm;
454 _time_t2tm(timer, 0, ptm); /* Can return NULL... */
460 /**********************************************************************/
463 struct tm *gmtime_r(const time_t *__restrict timer,
464 struct tm *__restrict result)
466 return _time_t2tm(timer, 0, result);
470 /**********************************************************************/
473 struct tm *localtime(const time_t *timer)
475 register struct tm *ptm = &__time_tm;
477 /* In this implementation, tzset() is called by localtime_r(). */
479 localtime_r(timer, ptm); /* Can return NULL... */
485 /**********************************************************************/
488 static const unsigned char day_cor[] = { /* non-leap */
489 31, 31, 34, 34, 35, 35, 36, 36, 36, 37, 37, 38, 38
490 /* 0, 0, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7 */
491 /* 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 */
494 /* Note: timezone locking is done by localtime_r. */
496 static int tm_isdst(register const struct tm *__restrict ptm)
498 register rule_struct *r = _time_tzinfo;
500 int i, isdst, isleap, day, day0, monlen, mday;
501 int oday; /* Note: oday can be uninitialized. */
504 if (r[1].tzname[0] != 0) {
505 /* First, get the current seconds offset from the start of the year.
506 * Fields of ptm are assumed to be in their normal ranges. */
509 + 60 * (long)(ptm->tm_hour
510 + 24 * ptm->tm_yday));
511 /* Do some prep work. */
512 i = (ptm->tm_year % 400) + 1900; /* Make sure we don't overflow. */
513 isleap = __isleap(i);
516 + i /* Normal years increment 1 wday. */
522 day = r->day; /* Common for 'J' and # case. */
523 if (r->rule_type == 'J') {
524 if (!isleap || (day < (31+29))) {
527 } else if (r->rule_type == 'M') {
528 /* Find 0-based day number for 1st of the month. */
529 day = 31*r->month - day_cor[r->month -1];
530 if (isleap && (day >= 59)) {
533 monlen = 31 + day_cor[r->month -1] - day_cor[r->month];
534 if (isleap && (r->month > 1)) {
537 /* Wweekday (0 is Sunday) of 1st of the month
538 * is (day0 + day) % 7. */
539 if ((mday = r->day - ((day0 + day) % 7)) >= 0) {
540 mday -= 7; /* Back up into prev month since r->week>0. */
542 if ((mday += 7 * r->week) >= monlen) {
545 /* So, 0-based day number is... */
550 /* Adjust sec since dst->std change time is in dst. */
551 sec += (r[-1].gmt_offset - r->gmt_offset);
553 ++isdst; /* Year starts in dst. */
558 /* Now convert day to seconds and add offset and compare. */
559 if (sec >= (day * 86400L) + r->dst_offset) {
569 struct tm *localtime_r(register const time_t *__restrict timer,
570 register struct tm *__restrict result)
583 offset = 604800L - _time_tzinfo[dst].gmt_offset;
584 if (*timer > (LONG_MAX - 604800L)) {
588 *x = *timer + offset;
590 _time_t2tm(x, days, result);
593 result->tm_isdst = dst;
597 } while ((result->tm_isdst = tm_isdst(result)) != 0);
605 /**********************************************************************/
608 time_t mktime(struct tm *timeptr)
610 return _time_mktime(timeptr, 1);
614 /**********************************************************************/
617 #define NO_E_MOD 0x80
618 #define NO_O_MOD 0x40
620 #define ILLEGAL_SPEC 0x3f
622 #define INT_SPEC 0x00 /* must be 0x00!! */
623 #define STRING_SPEC 0x10 /* must be 0x10!! */
624 #define CALC_SPEC 0x20
625 #define STACKED_SPEC 0x30
627 #define MASK_SPEC 0x30
631 * No alternate digit (%O?) handling. Always uses 0-9.
632 * Alternate locale format (%E?) handling is broken for nontrivial ERAs.
633 * glibc's %P is currently faked by %p. This means it doesn't do lower case.
634 * glibc's %k, %l, and %s are handled.
635 * glibc apparently allows (and ignores) extraneous 'E' and 'O' modifiers,
636 * while they are flagged as illegal conversions here.
639 /* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
640 static const unsigned char spec[] = {
641 /* A */ 0x03 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
642 /* B */ 0x04 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
643 /* C */ 0x0a | INT_SPEC | NO_O_MOD,
644 /* D */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
645 /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
646 /* F */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
647 /* G */ 0x03 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
648 /* H */ 0x0b | INT_SPEC | NO_E_MOD,
649 /* I */ 0x0c | INT_SPEC | NO_E_MOD,
650 /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
651 /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
652 /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
653 /* M */ 0x0d | INT_SPEC | NO_E_MOD,
654 /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
655 /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
656 /* P */ 0x05 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc ; use %p */
657 /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
658 /* R */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
659 /* S */ 0x0e | INT_SPEC | NO_E_MOD,
660 /* T */ 0x05 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
661 /* U */ 0x04 | CALC_SPEC | NO_E_MOD,
662 /* V */ 0x05 | CALC_SPEC | NO_E_MOD,
663 /* W */ 0x06 | CALC_SPEC | NO_E_MOD,
664 /* X */ 0x0a | STACKED_SPEC | NO_O_MOD,
665 /* Y */ 0x0f | INT_SPEC | NO_O_MOD,
666 /* Z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
673 /* a */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
674 /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
675 /* c */ 0x08 | STACKED_SPEC | NO_O_MOD,
676 /* d */ 0x00 | INT_SPEC | NO_E_MOD,
677 /* e */ 0x01 | INT_SPEC | NO_E_MOD,
678 /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
679 /* g */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
680 /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* same as b */
681 /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
682 /* j */ 0x08 | INT_SPEC | NO_E_MOD | NO_O_MOD,
683 /* k */ 0x03 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
684 /* l */ 0x04 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
685 /* m */ 0x05 | INT_SPEC | NO_E_MOD,
686 /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
687 /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
688 /* p */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
689 /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
690 /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
691 /* s */ 0x07 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
692 /* t */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
693 /* u */ 0x07 | INT_SPEC | NO_E_MOD,
694 /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
695 /* w */ 0x02 | INT_SPEC | NO_E_MOD,
696 /* x */ 0x09 | STACKED_SPEC | NO_O_MOD,
697 /* y */ 0x09 | INT_SPEC,
698 /* z */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
701 /* WARNING!!! These are dependent on the layout of struct tm!!! */
702 #define FIELD_MAX (26+6+26)
703 60 /* 61? */, 59, 23, 31, 11, 0 /* 9999 */, 6, 0 /* 365 */,
705 #define TP_OFFSETS (FIELD_MAX+8)
712 0, /* CURRENTLY UNUSED */
713 /* NOTE: u,j,y order must be preserved as 6,7,5 seq is used in the code! */
714 #define CALC_OFFSETS (TP_OFFSETS + 7)
731 #define TP_CODES (TP_OFFSETS + 16 + 6)
738 0, /* CURRENTLY UNUSED */
741 2 | 128 | 32 | 16 , /* y */
742 2 | 128 | 64 | 32 | 16 , /* C */
744 2 | 32 | 16 | 0, /* I */
755 #define STRINGS_NL_ITEM_START (TP_CODES + 16 + 6)
756 _NL_ITEM_INDEX(ABDAY_1), /* a */
757 _NL_ITEM_INDEX(ABMON_1), /* b, h */
758 _NL_ITEM_INDEX(AM_STR), /* p */
759 _NL_ITEM_INDEX(DAY_1), /* A */
760 _NL_ITEM_INDEX(MON_1), /* B */
761 _NL_ITEM_INDEX(AM_STR), /* P -- wrong! need lower case */
763 #define STACKED_STRINGS_START (STRINGS_NL_ITEM_START+6)
764 6, 7, 8, 16, 24, 29, /* 6 - offsets from offset-count to strings */
767 '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
768 '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
769 '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
770 '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
772 #define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 43)
773 _NL_ITEM_INDEX(D_T_FMT), /* c */
774 _NL_ITEM_INDEX(D_FMT), /* x */
775 _NL_ITEM_INDEX(T_FMT), /* X */
776 _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
777 #ifdef ENABLE_ERA_CODE
778 _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
779 _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */
780 _NL_ITEM_INDEX(ERA_T_FMT), /* EX */
784 static int load_field(int k, const struct tm *__restrict timeptr)
789 r = ((int *) timeptr)[k];
791 r_max = spec[FIELD_MAX + k];
800 if ((((unsigned int) r) > r_max) || ((k == 3) && !r)) {
809 size_t strftime(char *__restrict s, size_t maxsize,
810 const char *__restrict format,
811 const struct tm *__restrict timeptr)
814 register const char *p;
815 register const char *o;
816 const rule_struct *rsp;
817 const char *stack[MAX_PUSH];
820 int field_val, i, j, lvl;
821 int x[3]; /* wday, yday, year */
823 char buf[__UIM_BUFLEN_LONG];
827 tzset(); /* We'll, let's get this out of the way. */
839 *s = 0; /* nul-terminate */
840 return maxsize - count;
847 if ((*(o = p) == '%') && (*++p != '%')) {
850 if ((*p == 'O') || (*p == 'E')) { /* modifier */
851 mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
855 if ((((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
856 || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
864 code &= ILLEGAL_SPEC; /* modifiers are preserved in mod var. */
866 if ((code & MASK_SPEC) == STACKED_SPEC) {
867 if (lvl == MAX_PUSH) {
868 goto OUTPUT; /* Stack full so treat as illegal spec. */
871 if ((code &= 0xf) < 8) {
872 p = ((const char *) spec) + STACKED_STRINGS_START + code;
873 p += *((unsigned char *)p);
876 p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
878 #ifdef ENABLE_ERA_CODE
879 if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
880 && (*(o = nl_langinfo(_NL_ITEM(LC_TIME,
881 (int)(((unsigned char *)p)[4]))
888 p = nl_langinfo(_NL_ITEM(LC_TIME,
889 (int)(*((unsigned char *)p))));
893 o = spec + 26; /* set to "????" */
894 if ((code & MASK_SPEC) == CALC_SPEC) {
899 /* Use a cast to silence the warning since *timeptr won't
901 if ((t = _time_mktime((struct tm *) timeptr, 0))
907 #ifdef TIME_T_IS_UNSIGNED
908 o = _uintmaxtostr(buf + sizeof(buf) - 1,
912 o = _uintmaxtostr(buf + sizeof(buf) - 1,
916 o_count = sizeof(buf);
918 } else if (((*p) | 0x20) == 'z') { /* 'z' or 'Z' */
920 if (timeptr->tm_isdst < 0) {
921 /* SUSv3 specifies this behavior for 'z', but we'll also
922 * treat it as "no timezone info" for 'Z' too. */
930 if (timeptr->tm_isdst > 0) {
938 if (!o) { /* PARANOIA */
939 o = spec+30; /* empty string */
947 if ((tzo = -rsp->gmt_offset) < 0) {
956 field_val = ((i / 60) * 100) + (i % 60);
958 i = 16 + 6; /* 0-fill, width = 4 */
961 /* TODO: don't need year for U, W */
962 for (i=0 ; i < 3 ; i++) {
963 if ((x[i] = load_field(spec[CALC_OFFSETS+i],timeptr)) < 0) {
968 i = 16 + 2; /* 0-fill, width = 2 */
970 if ((*p == 'U') || (*p == 'W')) {
971 field_val = ((x[1] - x[0]) + 7);
976 if ((*p == 'W') && !x[0]) {
979 } else { /* ((*p == 'g') || (*p == 'G') || (*p == 'V')) */
981 isofm = (((x[1] - x[0]) + 11) % 7) - 3; /* [-3,3] */
983 if (x[1] < isofm) { /* belongs to previous year */
985 x[1] += 365 + __isleap(x[2]);
989 field_val = ((x[1] - isofm) / 7) + 1; /* week # */
990 days = 365 + __isleap(x[2]);
991 isofm = ((isofm + 7*53 + 3 - days)) %7 + days - 3; /* next year */
992 if (x[1] >= isofm) { /* next year */
998 if (*p != 'V') { /* need year */
999 field_val = x[2]; /* TODO: what if x[2] now 10000 ?? */
1003 i = 16 + 6; /* 0-fill, width = 4 */
1009 i = TP_OFFSETS + (code & 0x1f);
1010 if ((field_val = load_field(spec[i],timeptr)) < 0) {
1014 i = spec[i+(TP_CODES - TP_OFFSETS)];
1016 j = (i & 128) ? 100: 12;
1022 if (((i&128) + field_val) == 0) { /* mod 12? == 0 */
1023 field_val = j; /* set to 12 */
1026 field_val += (i & 1);
1027 if ((i & 8) && !field_val) {
1032 if ((code & MASK_SPEC) == STRING_SPEC) {
1034 field_val += spec[STRINGS_NL_ITEM_START + (code & 0xf)];
1035 o = nl_langinfo(_NL_ITEM(LC_TIME, field_val));
1037 o_count = ((i >> 1) & 3) + 1;
1040 *(char *)(--o) = '0' + (field_val % 10);
1044 *buf = ' ' + (i & 16);
1051 while (o_count && count && *o) {
1060 /**********************************************************************/
1064 * 1) %l and %k are space-padded, so "%l" by itself fails while " %l" succeeds.
1065 * Both work for glibc. So, should we always strip spaces?
1070 * There are several differences between this strptime and glibc's strptime.
1071 * 1) glibc strips leading space before numeric conversions.
1072 * 2) glibc will read fields without whitespace in between. SUSv3 states
1073 * that you must have whitespace between conversion operators. Besides,
1074 * how do you know how long a number should be if there are leading 0s?
1075 * 3) glibc attempts to compute some the struct tm fields based on the
1076 * data retrieved; tm_wday in particular. I don't as I consider it
1077 * another glibc attempt at mind-reading...
1080 #define NO_E_MOD 0x80
1081 #define NO_O_MOD 0x40
1083 #define ILLEGAL_SPEC 0x3f
1085 #define INT_SPEC 0x00 /* must be 0x00!! */
1086 #define STRING_SPEC 0x10 /* must be 0x10!! */
1087 #define CALC_SPEC 0x20
1088 #define STACKED_SPEC 0x30
1090 #define MASK_SPEC 0x30
1092 /* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
1093 static const unsigned char spec[] = {
1094 /* A */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1095 /* B */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1096 /* C */ 0x08 | INT_SPEC | NO_O_MOD,
1097 /* D */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1098 /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1099 /* F */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1100 /* G */ 0x0f | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1101 /* H */ 0x06 | INT_SPEC | NO_E_MOD,
1102 /* I */ 0x07 | INT_SPEC | NO_E_MOD,
1103 /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1104 /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1105 /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1106 /* M */ 0x04 | INT_SPEC | NO_E_MOD,
1107 /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1108 /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1109 /* P */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1110 /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1111 /* R */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1112 /* S */ 0x05 | INT_SPEC | NO_E_MOD,
1113 /* T */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1114 /* U */ 0x0c | INT_SPEC | NO_E_MOD,
1115 /* V */ 0x0d | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1116 /* W */ 0x0c | INT_SPEC | NO_E_MOD,
1117 /* X */ 0x0a | STACKED_SPEC | NO_O_MOD,
1118 /* Y */ 0x0a | INT_SPEC | NO_O_MOD,
1119 /* Z */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1121 /* WARNING! This assumes orderings:
1123 * ABDAY_1-ABDAY-7,DAY_1-DAY_7
1124 * ABMON_1-ABMON_12,MON_1-MON12
1125 * Also, there are exactly 6 bytes between 'Z' and 'a'.
1127 #define STRINGS_NL_ITEM_START (26)
1128 _NL_ITEM_INDEX(AM_STR), /* p (P) */
1129 _NL_ITEM_INDEX(ABMON_1), /* B, b */
1130 _NL_ITEM_INDEX(ABDAY_1), /* A, a */
1135 /* a */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1136 /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1137 /* c */ 0x08 | STACKED_SPEC | NO_O_MOD,
1138 /* d */ 0x00 | INT_SPEC | NO_E_MOD,
1139 /* e */ 0x00 | INT_SPEC | NO_E_MOD,
1140 /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1141 /* g */ 0x0e | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1142 /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1143 /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1144 /* j */ 0x01 | INT_SPEC | NO_E_MOD | NO_O_MOD,
1145 /* k */ 0x06 | INT_SPEC | NO_E_MOD, /* glibc */
1146 /* l */ 0x07 | INT_SPEC | NO_E_MOD, /* glibc */
1147 /* m */ 0x02 | INT_SPEC | NO_E_MOD,
1148 /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1149 /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1150 /* p */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1151 /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1152 /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1153 /* s */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1154 /* t */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1155 /* u */ 0x0b | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1156 /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1157 /* w */ 0x03 | INT_SPEC | NO_E_MOD,
1158 /* x */ 0x09 | STACKED_SPEC | NO_O_MOD,
1159 /* y */ 0x09 | INT_SPEC,
1160 /* z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1162 #define INT_FIELD_START (26+6+26)
1163 /* (field #) << 3 + lower bound (0|1) + correction 0:none, 2:-1, 4:-1900
1164 * followed by upper bound prior to correction with 1=>366 and 2=>9999. */
1165 /* d, e */ (3 << 3) + 1 + 0, 31,
1166 /* j */ (7 << 3) + 1 + 2, /* 366 */ 1,
1167 /* m */ (4 << 3) + 1 + 2, 12,
1168 /* w */ (6 << 3) + 0 + 0, 6,
1169 /* M */ (1 << 3) + 0 + 0, 59,
1170 /* S */ 0 + 0 + 0, 60,
1171 /* H (k) */ (2 << 3) + 0 + 0, 23,
1172 /* I (l) */ (9 << 3) + 1 + 0, 12, /* goes with 8 -- am/pm */
1173 /* C */ (10<< 3) + 0 + 0, 99,
1174 /* y */ (11<< 3) + 0 + 0, 99,
1175 /* Y */ (5 << 3) + 0 + 4, /* 9999 */ 2,
1176 /* u */ (6 << 3) + 1 + 0, 7,
1177 /* The following are processed and range-checked, but ignored otherwise. */
1178 /* U, W */ (12<< 3) + 0 + 0, 53,
1179 /* V */ (12<< 3) + 1 + 0, 53,
1180 /* g */ (12<< 3) + 0 + 0, 99,
1181 /* G */ (12<< 3) + 0 /*+ 4*/, /* 9999 */ 2, /* Note: -1 or 10000? */
1183 #define STACKED_STRINGS_START (INT_FIELD_START+32)
1184 5, 6, 14, 22, 27, /* 5 - offsets from offset-count to strings */
1185 ' ', 0, /* 2 - %n or %t */
1186 '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
1187 '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
1188 '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
1189 '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
1191 #define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 40)
1192 _NL_ITEM_INDEX(D_T_FMT), /* c */
1193 _NL_ITEM_INDEX(D_FMT), /* x */
1194 _NL_ITEM_INDEX(T_FMT), /* X */
1195 _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
1196 #ifdef ENABLE_ERA_CODE
1197 _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
1198 _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */
1199 _NL_ITEM_INDEX(ERA_T_FMT), /* EX */
1205 char *strptime(const char *__restrict buf, const char *__restrict format,
1206 struct tm *__restrict tm)
1208 register const char *p;
1210 const char *stack[MAX_PUSH];
1218 fields[i] = INT_MIN;
1226 if (lvl == 0) { /* Done. */
1227 if (fields[6] == 7) { /* Cleanup for %u here since just once. */
1228 fields[6] = 0; /* Don't use mod in case unset. */
1232 do { /* Store the values into tm. */
1233 ((int *) tm)[i] = fields[i];
1236 return (char *) buf; /* Success. */
1242 if ((*p == '%') && (*++p != '%')) {
1244 if ((*p == 'O') || (*p == 'E')) { /* Modifier? */
1245 mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
1250 || (((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
1251 || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
1253 return NULL; /* Illegal spec. */
1256 if ((code & MASK_SPEC) == STACKED_SPEC) {
1257 if (lvl == MAX_PUSH) {
1258 return NULL; /* Stack full so treat as illegal spec. */
1261 if ((code &= 0xf) < 8) {
1262 p = ((const char *) spec) + STACKED_STRINGS_START + code;
1263 p += *((unsigned char *)p);
1267 p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
1269 #ifdef ENABLE_ERA_CODE
1270 if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
1271 && (*(o = nl_langinfo(_NL_ITEM(LC_TIME,
1272 (int)(((unsigned char *)p)[4]))
1279 p = nl_langinfo(_NL_ITEM(LC_TIME,
1280 (int)(*((unsigned char *)p))));
1286 if ((code & MASK_SPEC) == STRING_SPEC) {
1288 j = spec[STRINGS_NL_ITEM_START + 3 + code];
1289 i = _NL_ITEM(LC_TIME, spec[STRINGS_NL_ITEM_START + code]);
1290 /* Go backwards to check full names before abreviations. */
1293 o = nl_langinfo(i+j);
1294 if (!strncasecmp(buf,o,strlen(o)) && *o) { /* Found a match. */
1298 if (!code) { /* am/pm */
1300 if (fields[9] >= 0) { /* We have a previous %I or %l. */
1301 fields[2] = fields[9] + fields[8];
1303 } else { /* day (4) or month (6) */
1304 fields[2 + (code << 1)]
1305 = j % (spec[STRINGS_NL_ITEM_START + 3 + code] >> 1);
1310 return NULL; /* Failed to match. */
1313 if ((code & MASK_SPEC) == CALC_SPEC) {
1314 if ((code &= 0xf) < 1) { /* s or z*/
1320 if (!isspace(*buf)) { /* Signal an error if whitespace. */
1321 #ifdef TIME_T_IS_UNSIGNED
1322 t = strtoul(buf, &o, 10);
1324 t = strtol(buf, &o, 10);
1327 if ((o == buf) || errno) { /* Not a number or overflow. */
1330 __set_errno(i); /* Restore errno. */
1333 if (!code) { /* s */
1334 localtime_r(&t, tm); /* TODO: check for failure? */
1336 do { /* Now copy values from tm to fields. */
1337 fields[i] = ((int *) tm)[i];
1341 /* TODO: glibc treats %Z as a nop. For now, do the same. */
1345 assert((code & MASK_SPEC) == INT_SPEC);
1347 register const unsigned char *x;
1349 x = spec + INT_FIELD_START + (code << 1);
1350 if ((j = x[1]) < 3) { /* upper bound (inclusive) */
1351 j = ((j==1) ? 366 : 9999);
1354 while (isdigit(*buf)) {
1358 if ((i = 10*i + (*buf - '0')) > j) { /* Overflow. */
1363 if (i < (*x & 1)) { /* This catches no-digit case too. */
1373 if (*x == (9 << 3) + 1 + 0) { /* %I or %l */
1377 if (fields[8] >= 0) { /* We have a previous %p or %P. */
1378 fields[2] = i + fields[8];
1382 fields[(*x) >> 3] = i;
1384 if (((unsigned char)(*x - (10<< 3) + 0 + 0)) <= 8) { /* %C or %y */
1385 if ((j = fields[10]) < 0) { /* No %C, so i must be %y data. */
1386 if (i <= 68) { /* Map [0-68] to 2000+i */
1389 } else { /* Have %C data, but what about %y? */
1390 if ((i = fields[11]) < 0) { /* No %y data. */
1391 i = 0; /* Treat %y val as 0 following glibc's example. */
1399 } else if (isspace(*p)) {
1401 while (isspace(*buf)) {
1405 } else if (*buf++ == *p++) {
1412 /**********************************************************************/
1416 #error The uClibc version of time is in sysdeps/linux/common.
1419 time_t time(register time_t *tloc)
1422 register struct timeval *p = &tv;
1424 gettimeofday(p, NULL); /* This should never fail... */
1434 /**********************************************************************/
1437 static const char vals[] = {
1438 'T', 'Z', 0, /* 3 */
1439 'U', 'T', 'C', 0, /* 4 */
1440 25, 60, 60, 1, /* 4 */
1443 6, 0, 0, /* Note: overloaded for non-M non-J case... */
1445 ',', 'M', '4', '.', '1', '.', '0',
1446 ',', 'M', '1', '0', '.', '5', '.', '0', 0
1450 #define UTC (vals + 3)
1451 #define RANGE (vals + 7)
1452 #define RULE (vals + 11 - 1)
1453 #define DEFAULT_RULES (vals + 22)
1455 /* Initialize to UTC. */
1458 char *tzname[2] = { (char *) UTC, (char *) (UTC-1) };
1460 #ifdef __UCLIBC_HAS_THREADS__
1461 pthread_mutex_t _time_tzlock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
1464 rule_struct _time_tzinfo[2];
1466 static const char *getoffset(register const char *e, long *pn)
1468 register const char *s = RANGE-1;
1480 f = 10 * f + (*e++ - '0');
1482 if (((unsigned int)f) >= *s) {
1497 static const char *getnumber(register const char *e, int *pn)
1500 /* bcc can optimize the counter if it thinks it is a pointer... */
1501 register const char *n = (const char *) 3;
1505 while (n && isdigit(*e)) {
1506 f = 10 * f + (*e++ - '0');
1511 return (n == (const char *) 3) ? NULL : e;
1517 while (n && isdigit(*e)) {
1518 f = 10 * f + (*e++ - '0');
1523 return (n == 3) ? NULL : e;
1524 #endif /* __BCC__ */
1527 #ifdef __TIME_TZ_FILE
1529 #ifdef __TIME_TZ_FILE_ONCE
1530 static int TZ_file_read; /* Let BSS initialization set this to 0. */
1531 #endif /* __TIME_TZ_FILE_ONCE */
1533 static char *read_TZ_file(char *buf)
1540 if ((fd = open("/etc/TZ", O_RDONLY)) >= 0) {
1544 if ((r = read(fd, p, todo)) < 0) {
1554 if ((p > buf) && (p[-1] == '\n')) { /* Must end with newline. */
1557 #ifdef __TIME_TZ_FILE_ONCE
1559 #endif /* __TIME_TZ_FILE_ONCE */
1569 #endif /* __TIME_TZ_FILE */
1573 register const char *e;
1577 rule_struct new_rules[2];
1580 #ifdef __TIME_TZ_FILE
1581 char buf[TZ_BUFLEN];
1582 #endif /* __TIME_TZ_FILE */
1583 #ifdef __TIME_TZ_OPT_SPEED
1584 static char oldval[TZ_BUFLEN]; /* BSS-zero'd. */
1585 #endif /* __TIME_TZ_OPT_SPEED */
1589 e = getenv(TZ); /* TZ env var always takes precedence. */
1591 #ifdef __TIME_TZ_FILE_ONCE
1592 /* Put this inside the lock to prevent the possiblity of two different
1593 * timezones being used in a threaded app. */
1596 TZ_file_read = 0; /* Reset if the TZ env var is set. */
1597 } else if (TZ_file_read > 0) {
1600 #endif /* __TIME_TZ_FILE_ONCE */
1602 /* Warning!!! Since uClibc doesn't do lib locking, the following is
1603 * potentially unsafe in a multi-threaded program since it is remotely
1604 * possible that another thread could call setenv() for TZ and overwrite
1605 * the string being parsed. So, don't do that... */
1607 if ((!e /* TZ env var not set... */
1608 #ifdef __TIME_TZ_FILE
1609 && !(e = read_TZ_file(buf)) /* and no file or invalid file */
1610 #endif /* __TIME_TZ_FILE */
1611 ) || !*e) { /* or set to empty string. */
1612 ILLEGAL: /* TODO: Clean up the following... */
1613 #ifdef __TIME_TZ_OPT_SPEED
1614 *oldval = 0; /* Set oldval tonnn empty string. */
1615 #endif /* __TIME_TZ_OPT_SPEED */
1616 s = _time_tzinfo[0].tzname;
1621 *_time_tzinfo[1].tzname = 0;
1622 _time_tzinfo[0].gmt_offset = 0;
1626 if (*e == ':') { /* Ignore leading ':'. */
1630 #ifdef __TIME_TZ_OPT_SPEED
1631 if (strcmp(e, oldval) == 0) { /* Same string as last time... */
1632 goto FAST_DONE; /* So nothing to do. */
1634 /* Make a copy of the TZ env string. It won't be nul-terminated if
1635 * it is too long, but it that case it will be illegal and will be reset
1636 * to the empty string anyway. */
1637 strncpy(oldval, e, TZ_BUFLEN);
1638 #endif /* __TIME_TZ_OPT_SPEED */
1641 new_rules[1].tzname[0] = 0;
1643 /* Get std or dst name. */
1650 s = new_rules[count].tzname;
1653 && isascii(*e) /* SUSv3 requires char in portable char set. */
1655 || (c && (isalnum(*e) || (*e == '+') || (*e == '-'))))
1658 if (++n > TZNAME_MAX) {
1664 if ((n < 3) /* Check for minimum length. */
1665 || (c && (*e++ != c)) /* Match any quoting '<'. */
1672 if ((*e != '-') && (*e != '+')) {
1673 if (count && !isdigit(*e)) {
1674 off -= 3600; /* Default to 1 hour ahead of std. */
1681 if (!(e = getoffset(e, &off))) {
1686 off = -off; /* Save off in case needed for dst default. */
1689 new_rules[count].gmt_offset = off;
1696 } else { /* OK, we have dst, so get some rules. */
1698 if (!*e) { /* No rules so default to US rules. */
1709 if ((c = *e++) == 'M') {
1711 } else if (c == 'J') {
1719 *(p = &new_rules[count].rule_type) = c;
1726 if (!(e = getnumber(e, &f))
1727 || (((unsigned int)(f - s[1])) > n)
1728 || (*s && (*e++ != *s))
1733 } while ((n = *(s += 2)) > 0);
1735 off = 2 * 60 * 60; /* Default to 2:00:00 */
1738 if (!(e = getoffset(e, &off))) {
1742 new_rules[count].dst_offset = off;
1743 } while (++count < 2);
1750 memcpy(_time_tzinfo, new_rules, sizeof(new_rules));
1752 tzname[0] = _time_tzinfo[0].tzname;
1753 tzname[1] = _time_tzinfo[1].tzname;
1754 daylight = !!_time_tzinfo[1].tzname[0];
1755 timezone = _time_tzinfo[0].gmt_offset;
1762 /**********************************************************************/
1763 /* #ifdef L_utime */
1765 /* utime is a syscall in both linux and elks. */
1766 /* int utime(const char *path, const struct utimbuf *times) */
1769 /**********************************************************************/
1771 /**********************************************************************/
1775 #error The uClibc version of utimes is in sysdeps/linux/common.
1779 #include <sys/time.h>
1781 int utimes(const char *filename, register const struct timeval *tvp)
1783 register struct utimbuf *p = NULL;
1788 p->actime = tvp[0].tv_sec;
1789 p->modtime = tvp[1].tv_sec;
1791 return utime(filename, p);
1795 /**********************************************************************/
1798 static const uint16_t vals[] = {
1799 60, 60, 24, 7 /* special */, 36524, 1461, 365, 0
1802 static const unsigned char days[] = {
1803 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
1808 * If time_t is 32 bits, then no overflow is possible.
1809 * It time_t is > 32 bits, this needs to be adjusted to deal with overflow.
1812 /* Note: offset is the correction in _days_ to *timer! */
1814 struct tm *_time_t2tm(const time_t *__restrict timer,
1815 int offset, struct tm *__restrict result)
1819 int wday; /* Note: wday can be uninitialized. */
1822 register const uint16_t *vp;
1828 if ((v = *vp) == 7) {
1829 /* Overflow checking, assuming time_t is long int... */
1830 #if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
1831 #if (INT_MAX == 2147483647L) && (LONG_MAX == 9223372036854775807L)
1832 /* Valid range for t is [-784223472856L, 784223421720L].
1833 * Outside of this range, the tm_year field will overflow. */
1834 if (((unsigned long)(t + offset- -784223472856L))
1835 > (784223421720L - -784223472856L)
1840 #error overflow conditions unknown
1844 /* We have days since the epoch, so caluclate the weekday. */
1845 #if defined(__BCC__) && TIME_T_IS_UNSIGNED
1846 wday = (t + 4) % (*vp); /* t is unsigned */
1848 wday = ((int)((t % (*vp)) + 11)) % ((int)(*vp)); /* help bcc */
1850 /* Set divisor to days in 400 years. Be kind to bcc... */
1851 v = ((time_t)(vp[1])) << 2;
1853 /* Change to days since 1/1/1601 so that for 32 bit time_t
1854 * values, we'll have t >= 0. This should be changed for
1855 * archs with larger time_t types.
1856 * Also, correct for offset since a multiple of 7. */
1858 /* TODO: Does this still work on archs with time_t > 32 bits? */
1859 t += (135140L - 366) + offset; /* 146097 - (365*30 + 7) -366 */
1861 #if defined(__BCC__) && TIME_T_IS_UNSIGNED
1862 t -= ((t1 = t / v) * v);
1864 if ((t -= ((t1 = t / v) * v)) < 0) {
1870 if ((*vp == 7) && (t == v-1)) {
1871 --t; /* Correct for 400th year leap case */
1872 ++p[4]; /* Stash the extra day... */
1875 #if defined(__BCC__) && 0
1899 *p += ((int) t); /* result[7] .. tm_yday */
1901 p -= 2; /* at result[5] */
1903 #if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
1904 /* Protect against overflow. TODO: Unecessary if int arith wraps? */
1905 *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + (p[1] - 299); /* tm_year */
1907 *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + p[1] - 299; /* tm_year */
1910 p[1] = wday; /* result[6] .. tm_wday */
1913 register const unsigned char *d = days;
1916 if (__isleap(wday)) {
1920 wday = p[2] + 1; /* result[7] .. tm_yday */
1921 *--p = 0; /* at result[4] .. tm_mon */
1925 d -= 11; /* Backup to non-leap Feb. */
1928 ++*p; /* Increment tm_mon. */
1930 p[-1] = wday; /* result[3] .. tm_mday */
1932 /* TODO -- should this be 0? */
1933 p[4] = 0; /* result[8] .. tm_isdst */
1939 /**********************************************************************/
1942 struct tm __time_tm; /* Global shared by gmtime() and localtime(). */
1945 /**********************************************************************/
1946 #ifdef L__time_mktime
1948 static const unsigned char vals[] = {
1949 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
1953 time_t _time_mktime(struct tm *timeptr, int store_on_success)
1962 /* 0:sec 1:min 2:hour 3:mday 4:mon 5:year 6:wday 7:yday 8:isdst */
1963 register int *p = (int *) &x;
1964 register const unsigned char *s;
1969 memcpy(p, timeptr, sizeof(struct tm));
1972 p[5] = (p[5] - ((p[6] = p[5]/d) * d)) + (p[7] = p[4]/12);
1973 if ((p[4] -= 12 * p[7]) < 0) {
1979 d = (p[5] += 1900); /* Correct year. Now between 1900 and 2300. */
1989 s -= 11; /* Backup to non-leap Feb. */
1997 days = -719163L + ((long)d)*365 + ((d/4) - (d/100) + (d/400) + p[3] + p[7]);
1998 secs = p[0] + 60*( p[1] + 60*((long)(p[2])) )
1999 + _time_tzinfo[timeptr->tm_isdst > 0].gmt_offset;
2004 if ( ((unsigned long)(days + secs/86400L)) > 49710L) {
2007 secs += (days * 86400L);
2011 d = -719163L + d*365 + (d/4) - (d/100) + (d/400);
2013 + _time_tzinfo[timeptr->tm_isdst > 0].gmt_offset
2016 + 24*(((146073L * ((long long)(p[6])) + d)
2019 if (((unsigned long long)(secs - LONG_MIN))
2020 > (((unsigned long long)LONG_MAX) - LONG_MIN)
2028 localtime_r(&t, (struct tm *)p);
2034 if (store_on_success) {
2035 memcpy(timeptr, p, sizeof(struct tm));
2042 /**********************************************************************/