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>
140 /* ":<tzname>+hh:mm:ss<tzname>+hh:mm:ss,Mmm.w.d/hh:mm:ss,Mmm.w.d/hh:mm:ss" + nul */
141 /* 1 + 2*(1+TZNAME_MAX+1 + 9 + 7 + 9) + 1 = 2*TZNAME_MAX + 56 */
142 #else /* __TIME_TZ_FILE */
143 #undef __TIME_TZ_FILE_ONCE
144 #endif /* __TIME_TZ_FILE */
146 /**********************************************************************/
148 extern struct tm __time_tm
;
153 short day
; /* for J or normal */
156 short rule_type
; /* J, M, \0 */
157 char tzname
[TZNAME_MAX
+1];
160 #ifdef __UCLIBC_HAS_THREADS__
164 extern pthread_mutex_t _time_tzlock
;
166 #define TZLOCK pthread_mutex_lock(&_time_tzlock)
167 #define TZUNLOCK pthread_mutex_unlock(&_time_tzlock)
171 #define TZLOCK ((void) 0)
172 #define TZUNLOCK ((void) 0)
176 extern rule_struct _time_tzinfo
[2];
178 extern struct tm
*_time_t2tm(const time_t *__restrict timer
,
179 int offset
, struct tm
*__restrict result
);
181 extern time_t _time_mktime(struct tm
*timeptr
, int store_on_success
);
183 /**********************************************************************/
186 static char __time_str
[26];
188 char *asctime(const struct tm
*__restrict ptm
)
190 return asctime_r(ptm
, __time_str
);
194 /**********************************************************************/
197 /* Strictly speaking, this implementation isn't correct. ANSI/ISO specifies
198 * that the implementation of asctime() be equivalent to
200 * char *asctime(const struct tm *timeptr)
202 * static char wday_name[7][3] = {
203 * "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
205 * static char mon_name[12][3] = {
206 * "Jan", "Feb", "Mar", "Apr", "May", "Jun",
207 * "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
209 * static char result[26];
211 * sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
212 * wday_name[timeptr->tm_wday],
213 * mon_name[timeptr->tm_mon],
214 * timeptr->tm_mday, timeptr->tm_hour,
215 * timeptr->tm_min, timeptr->tm_sec,
216 * 1900 + timeptr->tm_year);
220 * but the above is either inherently unsafe, or carries with it the implicit
221 * assumption that all fields of timeptr fall within their usual ranges, and
222 * that the tm_year value falls in the range [-2899,8099] to avoid overflowing
225 * If we take the implicit assumption as given, then the implementation below
226 * is still incorrect for tm_year values < -900, as there will be either
227 * 0-padding and/or a missing negative sign for the year conversion . But given
228 * the ususal use of asctime(), I think it isn't unreasonable to restrict correct
229 * operation to the domain of years between 1000 and 9999.
232 /* This is generally a good thing, but if you're _sure_ any data passed will be
233 * in range, you can #undef this. */
234 #define SAFE_ASCTIME_R 1
236 static const unsigned char at_data
[] = {
237 'S', 'u', 'n', 'M', 'o', 'n', 'T', 'u', 'e', 'W', 'e', 'd',
238 'T', 'h', 'u', 'F', 'r', 'i', 'S', 'a', 't',
240 'J', 'a', 'n', 'F', 'e', 'b', 'M', 'a', 'r', 'A', 'p', 'r',
241 'M', 'a', 'y', 'J', 'u', 'n', 'J', 'u', 'l', 'A', 'u', 'g',
242 'S', 'e', 'p', 'O', 'c', 't', 'N', 'o', 'v', 'D', 'e', 'c',
244 #ifdef SAFE_ASCTIME_R
249 offsetof(struct tm
, tm_mday
),
251 offsetof(struct tm
, tm_hour
),
253 offsetof(struct tm
, tm_min
),
255 offsetof(struct tm
, tm_sec
),
256 ' ', '?', '?', '?', '?', '\n', 0
259 char *asctime_r(register const struct tm
*__restrict ptm
,
260 register char *__restrict buffer
)
267 #ifdef SAFE_ASCTIME_R
268 memcpy(buffer
, at_data
+ 3*(7 + 12), sizeof(at_data
) - 3*(7 + 12));
270 if (((unsigned int)(ptm
->tm_wday
)) <= 6) {
271 memcpy(buffer
, at_data
+ 3 * ptm
->tm_wday
, 3);
274 if (((unsigned int)(ptm
->tm_mon
)) <= 11) {
275 memcpy(buffer
+ 4, at_data
+ 3*7 + 3 * ptm
->tm_mon
, 3);
278 assert(((unsigned int)(ptm
->tm_wday
)) <= 6);
279 assert(((unsigned int)(ptm
->tm_mon
)) <= 11);
281 memcpy(buffer
, at_data
+ 3*(7 + 12) - 3, sizeof(at_data
) + 3 - 3*(7 + 12));
283 memcpy(buffer
, at_data
+ 3 * ptm
->tm_wday
, 3);
284 memcpy(buffer
+ 4, at_data
+ 3*7 + 3 * ptm
->tm_mon
, 3);
287 #ifdef SAFE_ASCTIME_R
289 tmp
= ptm
->tm_year
+ 1900;
290 if (((unsigned int) tmp
) < 10000) {
293 *buffer
= '0' + (tmp
% 10);
295 } while (*--buffer
== '?');
297 #else /* SAFE_ASCTIME_R */
299 tmp
= ptm
->tm_year
+ 1900;
300 assert( ((unsigned int) tmp
) < 10000 );
302 *buffer
= '0' + (tmp
% 10);
304 } while (*--buffer
== '?');
305 #endif /* SAFE_ASCTIME_R */
309 tmp
= *((int *)(((const char *) ptm
) + (int) *buffer
));
310 #ifdef SAFE_ASCTIME_R
311 if (((unsigned int) tmp
) >= 100) { /* Just check 2 digit non-neg. */
312 buffer
[-1] = *buffer
= '?';
314 #else /* SAFE_ASCTIME_R */
315 assert(((unsigned int) tmp
) < 100); /* Just check 2 digit non-neg. */
316 #endif /* SAFE_ASCTIME_R */
318 *buffer
= '0' + (tmp
% 10);
320 buffer
[-1] = '0' + (tmp
/10);
322 buffer
[-1] += (tmp
/10);
325 } while ((buffer
-= 2)[-2] == '0');
327 if (*++buffer
== '0') { /* Space-pad day of month. */
335 /**********************************************************************/
338 #include <sys/times.h>
340 /* Note: According to glibc...
341 * CAE XSH, Issue 4, Version 2: <time.h>
342 * The value of CLOCKS_PER_SEC is required to be 1 million on all
343 * XSI-conformant systems.
347 #if CLOCKS_PER_SEC != 1000000L
348 #error unexpected value for CLOCKS_PER_SEC!
358 t
= ((unsigned long) xtms
.tms_utime
) + xtms
.tms_stime
;
360 #ifndef __UCLIBC_CLK_TCK_CONST
361 #error __UCLIBC_CLK_TCK_CONST not defined!
365 #define CLK_TCK __UCLIBC_CLK_TCK_CONST
367 #if CLK_TCK > CLOCKS_PER_SEC
368 #error __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC!
370 #error __UCLIBC_CLK_TCK_CONST < 1!
373 #if (CLK_TCK == CLOCKS_PER_SEC)
374 return (t
<= LONG_MAX
) ? t
: -1;
375 #elif (CLOCKS_PER_SEC % CLK_TCK) == 0
376 return (t
<= (LONG_MAX
/ (CLOCKS_PER_SEC
/CLK_TCK
)))
377 ? t
* (CLOCKS_PER_SEC
/CLK_TCK
)
380 return (t
<= ((LONG_MAX
/ CLOCKS_PER_SEC
) * CLK_TCK
381 + ((LONG_MAX
% CLOCKS_PER_SEC
) * CLK_TCK
) / CLOCKS_PER_SEC
))
382 ? (((t
/ CLK_TCK
) * CLOCKS_PER_SEC
)
383 + (((t
% CLK_TCK
) * CLOCKS_PER_SEC
) / CLK_TCK
))
389 /**********************************************************************/
392 char *ctime(const time_t *clock
)
394 /* ANSI/ISO/SUSv3 say that ctime is equivalent to the following. */
395 return asctime(localtime(clock
));
399 /**********************************************************************/
402 char *ctime_r(const time_t *clock
, char *buf
)
406 return asctime_r(localtime_r(clock
, &xtms
), buf
);
410 /**********************************************************************/
416 #error difftime implementation assumptions violated for you arch!
419 double difftime(time_t time1
, time_t time0
)
421 #if (LONG_MAX >> DBL_MANT_DIG) == 0
423 /* time_t fits in the mantissa of a double. */
424 return ((double) time1
) - time0
;
426 #elif ((LONG_MAX >> DBL_MANT_DIG) >> DBL_MANT_DIG) == 0
428 /* time_t can overflow the mantissa of a double. */
431 d
= ((time_t) 1) << DBL_MANT_DIG
;
437 /* Since FLT_RADIX==2 and d is a power of 2, the only possible
438 * rounding error in the expression below would occur from the
440 return (((double) t1
) - t0
) * d
+ (((double) time1
) - time0
);
443 #error difftime needs special implementation on your arch.
448 /**********************************************************************/
451 struct tm
*gmtime(const time_t *timer
)
453 register struct tm
*ptm
= &__time_tm
;
455 _time_t2tm(timer
, 0, ptm
); /* Can return NULL... */
461 /**********************************************************************/
464 struct tm
*gmtime_r(const time_t *__restrict timer
,
465 struct tm
*__restrict result
)
467 return _time_t2tm(timer
, 0, result
);
471 /**********************************************************************/
474 struct tm
*localtime(const time_t *timer
)
476 register struct tm
*ptm
= &__time_tm
;
478 /* In this implementation, tzset() is called by localtime_r(). */
480 localtime_r(timer
, ptm
); /* Can return NULL... */
486 /**********************************************************************/
489 static const unsigned char day_cor
[] = { /* non-leap */
490 31, 31, 34, 34, 35, 35, 36, 36, 36, 37, 37, 38, 38
491 /* 0, 0, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7 */
492 /* 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 */
495 /* Note: timezone locking is done by localtime_r. */
497 static int tm_isdst(register const struct tm
*__restrict ptm
)
499 register rule_struct
*r
= _time_tzinfo
;
501 int i
, isdst
, isleap
, day
, day0
, monlen
, mday
;
502 int oday
; /* Note: oday can be uninitialized. */
505 if (r
[1].tzname
[0] != 0) {
506 /* First, get the current seconds offset from the start of the year.
507 * Fields of ptm are assumed to be in their normal ranges. */
510 + 60 * (long)(ptm
->tm_hour
511 + 24 * ptm
->tm_yday
));
512 /* Do some prep work. */
513 i
= (ptm
->tm_year
% 400) + 1900; /* Make sure we don't overflow. */
514 isleap
= __isleap(i
);
517 + i
/* Normal years increment 1 wday. */
523 day
= r
->day
; /* Common for 'J' and # case. */
524 if (r
->rule_type
== 'J') {
525 if (!isleap
|| (day
< (31+29))) {
528 } else if (r
->rule_type
== 'M') {
529 /* Find 0-based day number for 1st of the month. */
530 day
= 31*r
->month
- day_cor
[r
->month
-1];
531 if (isleap
&& (day
>= 59)) {
534 monlen
= 31 + day_cor
[r
->month
-1] - day_cor
[r
->month
];
535 if (isleap
&& (r
->month
> 1)) {
538 /* Wweekday (0 is Sunday) of 1st of the month
539 * is (day0 + day) % 7. */
540 if ((mday
= r
->day
- ((day0
+ day
) % 7)) >= 0) {
541 mday
-= 7; /* Back up into prev month since r->week>0. */
543 if ((mday
+= 7 * r
->week
) >= monlen
) {
546 /* So, 0-based day number is... */
551 /* Adjust sec since dst->std change time is in dst. */
552 sec
+= (r
[-1].gmt_offset
- r
->gmt_offset
);
554 ++isdst
; /* Year starts in dst. */
559 /* Now convert day to seconds and add offset and compare. */
560 if (sec
>= (day
* 86400L) + r
->dst_offset
) {
570 struct tm
*localtime_r(register const time_t *__restrict timer
,
571 register struct tm
*__restrict result
)
584 offset
= 604800L - _time_tzinfo
[dst
].gmt_offset
;
585 if (*timer
> (LONG_MAX
- 604800L)) {
589 *x
= *timer
+ offset
;
591 _time_t2tm(x
, days
, result
);
594 result
->tm_isdst
= dst
;
598 } while ((result
->tm_isdst
= tm_isdst(result
)) != 0);
606 /**********************************************************************/
609 time_t mktime(struct tm
*timeptr
)
611 return _time_mktime(timeptr
, 1);
615 /**********************************************************************/
618 #define NO_E_MOD 0x80
619 #define NO_O_MOD 0x40
621 #define ILLEGAL_SPEC 0x3f
623 #define INT_SPEC 0x00 /* must be 0x00!! */
624 #define STRING_SPEC 0x10 /* must be 0x10!! */
625 #define CALC_SPEC 0x20
626 #define STACKED_SPEC 0x30
628 #define MASK_SPEC 0x30
632 * No alternate digit (%O?) handling. Always uses 0-9.
633 * Alternate locale format (%E?) handling is broken for nontrivial ERAs.
634 * glibc's %P is currently faked by %p. This means it doesn't do lower case.
635 * glibc's %k, %l, and %s are handled.
636 * glibc apparently allows (and ignores) extraneous 'E' and 'O' modifiers,
637 * while they are flagged as illegal conversions here.
640 /* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
641 static const unsigned char spec
[] = {
642 /* A */ 0x03 | STRING_SPEC
| NO_E_MOD
| NO_O_MOD
,
643 /* B */ 0x04 | STRING_SPEC
| NO_E_MOD
| NO_O_MOD
,
644 /* C */ 0x0a | INT_SPEC
| NO_O_MOD
,
645 /* D */ 0x02 | STACKED_SPEC
| NO_E_MOD
| NO_O_MOD
,
646 /* E */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
647 /* F */ 0x03 | STACKED_SPEC
| NO_E_MOD
| NO_O_MOD
,
648 /* G */ 0x03 | CALC_SPEC
| NO_E_MOD
| NO_O_MOD
,
649 /* H */ 0x0b | INT_SPEC
| NO_E_MOD
,
650 /* I */ 0x0c | INT_SPEC
| NO_E_MOD
,
651 /* J */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
652 /* K */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
653 /* L */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
654 /* M */ 0x0d | INT_SPEC
| NO_E_MOD
,
655 /* N */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
656 /* O */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
657 /* P */ 0x05 | STRING_SPEC
| NO_E_MOD
| NO_O_MOD
, /* glibc ; use %p */
658 /* Q */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
659 /* R */ 0x04 | STACKED_SPEC
| NO_E_MOD
| NO_O_MOD
,
660 /* S */ 0x0e | INT_SPEC
| NO_E_MOD
,
661 /* T */ 0x05 | STACKED_SPEC
| NO_E_MOD
| NO_O_MOD
,
662 /* U */ 0x04 | CALC_SPEC
| NO_E_MOD
,
663 /* V */ 0x05 | CALC_SPEC
| NO_E_MOD
,
664 /* W */ 0x06 | CALC_SPEC
| NO_E_MOD
,
665 /* X */ 0x0a | STACKED_SPEC
| NO_O_MOD
,
666 /* Y */ 0x0f | INT_SPEC
| NO_O_MOD
,
667 /* Z */ 0x01 | CALC_SPEC
| NO_E_MOD
| NO_O_MOD
,
674 /* a */ 0x00 | STRING_SPEC
| NO_E_MOD
| NO_O_MOD
,
675 /* b */ 0x01 | STRING_SPEC
| NO_E_MOD
| NO_O_MOD
,
676 /* c */ 0x08 | STACKED_SPEC
| NO_O_MOD
,
677 /* d */ 0x00 | INT_SPEC
| NO_E_MOD
,
678 /* e */ 0x01 | INT_SPEC
| NO_E_MOD
,
679 /* f */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
680 /* g */ 0x02 | CALC_SPEC
| NO_E_MOD
| NO_O_MOD
,
681 /* h */ 0x01 | STRING_SPEC
| NO_E_MOD
| NO_O_MOD
, /* same as b */
682 /* i */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
683 /* j */ 0x08 | INT_SPEC
| NO_E_MOD
| NO_O_MOD
,
684 /* k */ 0x03 | INT_SPEC
| NO_E_MOD
| NO_O_MOD
, /* glibc */
685 /* l */ 0x04 | INT_SPEC
| NO_E_MOD
| NO_O_MOD
, /* glibc */
686 /* m */ 0x05 | INT_SPEC
| NO_E_MOD
,
687 /* n */ 0x00 | STACKED_SPEC
| NO_E_MOD
| NO_O_MOD
,
688 /* o */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
689 /* p */ 0x02 | STRING_SPEC
| NO_E_MOD
| NO_O_MOD
,
690 /* q */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
691 /* r */ 0x0b | STACKED_SPEC
| NO_E_MOD
| NO_O_MOD
,
692 /* s */ 0x07 | CALC_SPEC
| NO_E_MOD
| NO_O_MOD
, /* glibc */
693 /* t */ 0x01 | STACKED_SPEC
| NO_E_MOD
| NO_O_MOD
,
694 /* u */ 0x07 | INT_SPEC
| NO_E_MOD
,
695 /* v */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
696 /* w */ 0x02 | INT_SPEC
| NO_E_MOD
,
697 /* x */ 0x09 | STACKED_SPEC
| NO_O_MOD
,
698 /* y */ 0x09 | INT_SPEC
,
699 /* z */ 0x00 | CALC_SPEC
| NO_E_MOD
| NO_O_MOD
,
702 /* WARNING!!! These are dependent on the layout of struct tm!!! */
703 #define FIELD_MAX (26+6+26)
704 60 /* 61? */, 59, 23, 31, 11, 0 /* 9999 */, 6, 0 /* 365 */,
706 #define TP_OFFSETS (FIELD_MAX+8)
713 0, /* CURRENTLY UNUSED */
714 /* NOTE: u,j,y order must be preserved as 6,7,5 seq is used in the code! */
715 #define CALC_OFFSETS (TP_OFFSETS + 7)
732 #define TP_CODES (TP_OFFSETS + 16 + 6)
739 0, /* CURRENTLY UNUSED */
742 2 | 128 | 32 | 16 , /* y */
743 2 | 128 | 64 | 32 | 16 , /* C */
745 2 | 32 | 16 | 0, /* I */
756 #define STRINGS_NL_ITEM_START (TP_CODES + 16 + 6)
757 _NL_ITEM_INDEX(ABDAY_1
), /* a */
758 _NL_ITEM_INDEX(ABMON_1
), /* b, h */
759 _NL_ITEM_INDEX(AM_STR
), /* p */
760 _NL_ITEM_INDEX(DAY_1
), /* A */
761 _NL_ITEM_INDEX(MON_1
), /* B */
762 _NL_ITEM_INDEX(AM_STR
), /* P -- wrong! need lower case */
764 #define STACKED_STRINGS_START (STRINGS_NL_ITEM_START+6)
765 6, 7, 8, 16, 24, 29, /* 6 - offsets from offset-count to strings */
768 '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
769 '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
770 '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
771 '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
773 #define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 43)
774 _NL_ITEM_INDEX(D_T_FMT
), /* c */
775 _NL_ITEM_INDEX(D_FMT
), /* x */
776 _NL_ITEM_INDEX(T_FMT
), /* X */
777 _NL_ITEM_INDEX(T_FMT_AMPM
), /* r */
778 #ifdef ENABLE_ERA_CODE
779 _NL_ITEM_INDEX(ERA_D_T_FMT
), /* Ec */
780 _NL_ITEM_INDEX(ERA_D_FMT
), /* Ex */
781 _NL_ITEM_INDEX(ERA_T_FMT
), /* EX */
785 static int load_field(int k
, const struct tm
*__restrict timeptr
)
790 r
= ((int *) timeptr
)[k
];
792 r_max
= spec
[FIELD_MAX
+ k
];
801 if ((((unsigned int) r
) > r_max
) || ((k
== 3) && !r
)) {
810 size_t strftime(char *__restrict s
, size_t maxsize
,
811 const char *__restrict format
,
812 const struct tm
*__restrict timeptr
)
815 register const char *p
;
816 register const char *o
;
817 const rule_struct
*rsp
;
818 const char *stack
[MAX_PUSH
];
821 int field_val
, i
, j
, lvl
;
822 int x
[3]; /* wday, yday, year */
824 char buf
[__UIM_BUFLEN_LONG
];
828 tzset(); /* We'll, let's get this out of the way. */
840 *s
= 0; /* nul-terminate */
841 return maxsize
- count
;
848 if ((*(o
= p
) == '%') && (*++p
!= '%')) {
851 if ((*p
== 'O') || (*p
== 'E')) { /* modifier */
852 mod
|= ((*p
== 'O') ? NO_O_MOD
: NO_E_MOD
);
856 if ((((unsigned char)(((*p
) | 0x20) - 'a')) >= 26)
857 || (((code
= spec
[(int)(*p
- 'A')]) & mod
) >= ILLEGAL_SPEC
)
865 code
&= ILLEGAL_SPEC
; /* modifiers are preserved in mod var. */
867 if ((code
& MASK_SPEC
) == STACKED_SPEC
) {
868 if (lvl
== MAX_PUSH
) {
869 goto OUTPUT
; /* Stack full so treat as illegal spec. */
872 if ((code
&= 0xf) < 8) {
873 p
= ((const char *) spec
) + STACKED_STRINGS_START
+ code
;
874 p
+= *((unsigned char *)p
);
877 p
= ((const char *) spec
) + STACKED_STRINGS_NL_ITEM_START
879 #ifdef ENABLE_ERA_CODE
880 if ((mod
& NO_E_MOD
) /* Actually, this means E modifier present. */
881 && (*(o
= nl_langinfo(_NL_ITEM(LC_TIME
,
882 (int)(((unsigned char *)p
)[4]))
889 p
= nl_langinfo(_NL_ITEM(LC_TIME
,
890 (int)(*((unsigned char *)p
))));
894 o
= spec
+ 26; /* set to "????" */
895 if ((code
& MASK_SPEC
) == CALC_SPEC
) {
900 /* Use a cast to silence the warning since *timeptr won't
902 if ((t
= _time_mktime((struct tm
*) timeptr
, 0))
908 #ifdef TIME_T_IS_UNSIGNED
909 o
= _uintmaxtostr(buf
+ sizeof(buf
) - 1,
913 o
= _uintmaxtostr(buf
+ sizeof(buf
) - 1,
917 o_count
= sizeof(buf
);
919 } else if (((*p
) | 0x20) == 'z') { /* 'z' or 'Z' */
921 if (timeptr
->tm_isdst
< 0) {
922 /* SUSv3 specifies this behavior for 'z', but we'll also
923 * treat it as "no timezone info" for 'Z' too. */
931 if (timeptr
->tm_isdst
> 0) {
939 if (!o
) { /* PARANOIA */
940 o
= spec
+30; /* empty string */
948 if ((tzo
= -rsp
->gmt_offset
) < 0) {
957 field_val
= ((i
/ 60) * 100) + (i
% 60);
959 i
= 16 + 6; /* 0-fill, width = 4 */
962 /* TODO: don't need year for U, W */
963 for (i
=0 ; i
< 3 ; i
++) {
964 if ((x
[i
] = load_field(spec
[CALC_OFFSETS
+i
],timeptr
)) < 0) {
969 i
= 16 + 2; /* 0-fill, width = 2 */
971 if ((*p
== 'U') || (*p
== 'W')) {
972 field_val
= ((x
[1] - x
[0]) + 7);
977 if ((*p
== 'W') && !x
[0]) {
980 } else { /* ((*p == 'g') || (*p == 'G') || (*p == 'V')) */
982 isofm
= (((x
[1] - x
[0]) + 11) % 7) - 3; /* [-3,3] */
984 if (x
[1] < isofm
) { /* belongs to previous year */
986 x
[1] += 365 + __isleap(x
[2]);
990 field_val
= ((x
[1] - isofm
) / 7) + 1; /* week # */
991 days
= 365 + __isleap(x
[2]);
992 isofm
= ((isofm
+ 7*53 + 3 - days
)) %7 + days
- 3; /* next year */
993 if (x
[1] >= isofm
) { /* next year */
999 if (*p
!= 'V') { /* need year */
1000 field_val
= x
[2]; /* TODO: what if x[2] now 10000 ?? */
1004 i
= 16 + 6; /* 0-fill, width = 4 */
1010 i
= TP_OFFSETS
+ (code
& 0x1f);
1011 if ((field_val
= load_field(spec
[i
],timeptr
)) < 0) {
1015 i
= spec
[i
+(TP_CODES
- TP_OFFSETS
)];
1017 j
= (i
& 128) ? 100: 12;
1023 if (((i
&128) + field_val
) == 0) { /* mod 12? == 0 */
1024 field_val
= j
; /* set to 12 */
1027 field_val
+= (i
& 1);
1028 if ((i
& 8) && !field_val
) {
1033 if ((code
& MASK_SPEC
) == STRING_SPEC
) {
1035 field_val
+= spec
[STRINGS_NL_ITEM_START
+ (code
& 0xf)];
1036 o
= nl_langinfo(_NL_ITEM(LC_TIME
, field_val
));
1038 o_count
= ((i
>> 1) & 3) + 1;
1041 *(char *)(--o
) = '0' + (field_val
% 10);
1045 *buf
= ' ' + (i
& 16);
1052 while (o_count
&& count
&& *o
) {
1061 /**********************************************************************/
1065 * 1) %l and %k are space-padded, so "%l" by itself fails while " %l" succeeds.
1066 * Both work for glibc. So, should we always strip spaces?
1071 * There are several differences between this strptime and glibc's strptime.
1072 * 1) glibc strips leading space before numeric conversions.
1073 * 2) glibc will read fields without whitespace in between. SUSv3 states
1074 * that you must have whitespace between conversion operators. Besides,
1075 * how do you know how long a number should be if there are leading 0s?
1076 * 3) glibc attempts to compute some the struct tm fields based on the
1077 * data retrieved; tm_wday in particular. I don't as I consider it
1078 * another glibc attempt at mind-reading...
1081 #define NO_E_MOD 0x80
1082 #define NO_O_MOD 0x40
1084 #define ILLEGAL_SPEC 0x3f
1086 #define INT_SPEC 0x00 /* must be 0x00!! */
1087 #define STRING_SPEC 0x10 /* must be 0x10!! */
1088 #define CALC_SPEC 0x20
1089 #define STACKED_SPEC 0x30
1091 #define MASK_SPEC 0x30
1093 /* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
1094 static const unsigned char spec
[] = {
1095 /* A */ 0x02 | STRING_SPEC
| NO_E_MOD
| NO_O_MOD
,
1096 /* B */ 0x01 | STRING_SPEC
| NO_E_MOD
| NO_O_MOD
,
1097 /* C */ 0x08 | INT_SPEC
| NO_O_MOD
,
1098 /* D */ 0x01 | STACKED_SPEC
| NO_E_MOD
| NO_O_MOD
,
1099 /* E */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
1100 /* F */ 0x02 | STACKED_SPEC
| NO_E_MOD
| NO_O_MOD
, /* glibc */
1101 /* G */ 0x0f | INT_SPEC
| NO_E_MOD
| NO_O_MOD
, /* glibc */
1102 /* H */ 0x06 | INT_SPEC
| NO_E_MOD
,
1103 /* I */ 0x07 | INT_SPEC
| NO_E_MOD
,
1104 /* J */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
1105 /* K */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
1106 /* L */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
1107 /* M */ 0x04 | INT_SPEC
| NO_E_MOD
,
1108 /* N */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
1109 /* O */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
1110 /* P */ 0x00 | STRING_SPEC
| NO_E_MOD
| NO_O_MOD
, /* glibc */
1111 /* Q */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
1112 /* R */ 0x03 | STACKED_SPEC
| NO_E_MOD
| NO_O_MOD
,
1113 /* S */ 0x05 | INT_SPEC
| NO_E_MOD
,
1114 /* T */ 0x04 | STACKED_SPEC
| NO_E_MOD
| NO_O_MOD
,
1115 /* U */ 0x0c | INT_SPEC
| NO_E_MOD
,
1116 /* V */ 0x0d | INT_SPEC
| NO_E_MOD
| NO_O_MOD
, /* glibc */
1117 /* W */ 0x0c | INT_SPEC
| NO_E_MOD
,
1118 /* X */ 0x0a | STACKED_SPEC
| NO_O_MOD
,
1119 /* Y */ 0x0a | INT_SPEC
| NO_O_MOD
,
1120 /* Z */ 0x02 | CALC_SPEC
| NO_E_MOD
| NO_O_MOD
, /* glibc */
1122 /* WARNING! This assumes orderings:
1124 * ABDAY_1-ABDAY-7,DAY_1-DAY_7
1125 * ABMON_1-ABMON_12,MON_1-MON12
1126 * Also, there are exactly 6 bytes between 'Z' and 'a'.
1128 #define STRINGS_NL_ITEM_START (26)
1129 _NL_ITEM_INDEX(AM_STR
), /* p (P) */
1130 _NL_ITEM_INDEX(ABMON_1
), /* B, b */
1131 _NL_ITEM_INDEX(ABDAY_1
), /* A, a */
1136 /* a */ 0x02 | STRING_SPEC
| NO_E_MOD
| NO_O_MOD
,
1137 /* b */ 0x01 | STRING_SPEC
| NO_E_MOD
| NO_O_MOD
,
1138 /* c */ 0x08 | STACKED_SPEC
| NO_O_MOD
,
1139 /* d */ 0x00 | INT_SPEC
| NO_E_MOD
,
1140 /* e */ 0x00 | INT_SPEC
| NO_E_MOD
,
1141 /* f */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
1142 /* g */ 0x0e | INT_SPEC
| NO_E_MOD
| NO_O_MOD
, /* glibc */
1143 /* h */ 0x01 | STRING_SPEC
| NO_E_MOD
| NO_O_MOD
,
1144 /* i */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
1145 /* j */ 0x01 | INT_SPEC
| NO_E_MOD
| NO_O_MOD
,
1146 /* k */ 0x06 | INT_SPEC
| NO_E_MOD
, /* glibc */
1147 /* l */ 0x07 | INT_SPEC
| NO_E_MOD
, /* glibc */
1148 /* m */ 0x02 | INT_SPEC
| NO_E_MOD
,
1149 /* n */ 0x00 | STACKED_SPEC
| NO_E_MOD
| NO_O_MOD
,
1150 /* o */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
1151 /* p */ 0x00 | STRING_SPEC
| NO_E_MOD
| NO_O_MOD
,
1152 /* q */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
1153 /* r */ 0x0b | STACKED_SPEC
| NO_E_MOD
| NO_O_MOD
,
1154 /* s */ 0x00 | CALC_SPEC
| NO_E_MOD
| NO_O_MOD
, /* glibc */
1155 /* t */ 0x00 | STACKED_SPEC
| NO_E_MOD
| NO_O_MOD
,
1156 /* u */ 0x0b | INT_SPEC
| NO_E_MOD
| NO_O_MOD
, /* glibc */
1157 /* v */ ILLEGAL_SPEC
| NO_E_MOD
| NO_O_MOD
,
1158 /* w */ 0x03 | INT_SPEC
| NO_E_MOD
,
1159 /* x */ 0x09 | STACKED_SPEC
| NO_O_MOD
,
1160 /* y */ 0x09 | INT_SPEC
,
1161 /* z */ 0x01 | CALC_SPEC
| NO_E_MOD
| NO_O_MOD
, /* glibc */
1163 #define INT_FIELD_START (26+6+26)
1164 /* (field #) << 3 + lower bound (0|1) + correction 0:none, 2:-1, 4:-1900
1165 * followed by upper bound prior to correction with 1=>366 and 2=>9999. */
1166 /* d, e */ (3 << 3) + 1 + 0, 31,
1167 /* j */ (7 << 3) + 1 + 2, /* 366 */ 1,
1168 /* m */ (4 << 3) + 1 + 2, 12,
1169 /* w */ (6 << 3) + 0 + 0, 6,
1170 /* M */ (1 << 3) + 0 + 0, 59,
1171 /* S */ 0 + 0 + 0, 60,
1172 /* H (k) */ (2 << 3) + 0 + 0, 23,
1173 /* I (l) */ (9 << 3) + 1 + 0, 12, /* goes with 8 -- am/pm */
1174 /* C */ (10<< 3) + 0 + 0, 99,
1175 /* y */ (11<< 3) + 0 + 0, 99,
1176 /* Y */ (5 << 3) + 0 + 4, /* 9999 */ 2,
1177 /* u */ (6 << 3) + 1 + 0, 7,
1178 /* The following are processed and range-checked, but ignored otherwise. */
1179 /* U, W */ (12<< 3) + 0 + 0, 53,
1180 /* V */ (12<< 3) + 1 + 0, 53,
1181 /* g */ (12<< 3) + 0 + 0, 99,
1182 /* G */ (12<< 3) + 0 /*+ 4*/, /* 9999 */ 2, /* Note: -1 or 10000? */
1184 #define STACKED_STRINGS_START (INT_FIELD_START+32)
1185 5, 6, 14, 22, 27, /* 5 - offsets from offset-count to strings */
1186 ' ', 0, /* 2 - %n or %t */
1187 '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
1188 '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
1189 '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
1190 '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
1192 #define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 40)
1193 _NL_ITEM_INDEX(D_T_FMT
), /* c */
1194 _NL_ITEM_INDEX(D_FMT
), /* x */
1195 _NL_ITEM_INDEX(T_FMT
), /* X */
1196 _NL_ITEM_INDEX(T_FMT_AMPM
), /* r */
1197 #ifdef ENABLE_ERA_CODE
1198 _NL_ITEM_INDEX(ERA_D_T_FMT
), /* Ec */
1199 _NL_ITEM_INDEX(ERA_D_FMT
), /* Ex */
1200 _NL_ITEM_INDEX(ERA_T_FMT
), /* EX */
1206 char *strptime(const char *__restrict buf
, const char *__restrict format
,
1207 struct tm
*__restrict tm
)
1209 register const char *p
;
1211 const char *stack
[MAX_PUSH
];
1219 fields
[i
] = INT_MIN
;
1227 if (lvl
== 0) { /* Done. */
1228 if (fields
[6] == 7) { /* Cleanup for %u here since just once. */
1229 fields
[6] = 0; /* Don't use mod in case unset. */
1233 do { /* Store the values into tm. */
1234 ((int *) tm
)[i
] = fields
[i
];
1237 return (char *) buf
; /* Success. */
1243 if ((*p
== '%') && (*++p
!= '%')) {
1245 if ((*p
== 'O') || (*p
== 'E')) { /* Modifier? */
1246 mod
|= ((*p
== 'O') ? NO_O_MOD
: NO_E_MOD
);
1251 || (((unsigned char)(((*p
) | 0x20) - 'a')) >= 26)
1252 || (((code
= spec
[(int)(*p
- 'A')]) & mod
) >= ILLEGAL_SPEC
)
1254 return NULL
; /* Illegal spec. */
1257 if ((code
& MASK_SPEC
) == STACKED_SPEC
) {
1258 if (lvl
== MAX_PUSH
) {
1259 return NULL
; /* Stack full so treat as illegal spec. */
1262 if ((code
&= 0xf) < 8) {
1263 p
= ((const char *) spec
) + STACKED_STRINGS_START
+ code
;
1264 p
+= *((unsigned char *)p
);
1268 p
= ((const char *) spec
) + STACKED_STRINGS_NL_ITEM_START
1270 #ifdef ENABLE_ERA_CODE
1271 if ((mod
& NO_E_MOD
) /* Actually, this means E modifier present. */
1272 && (*(o
= nl_langinfo(_NL_ITEM(LC_TIME
,
1273 (int)(((unsigned char *)p
)[4]))
1280 p
= nl_langinfo(_NL_ITEM(LC_TIME
,
1281 (int)(*((unsigned char *)p
))));
1287 if ((code
& MASK_SPEC
) == STRING_SPEC
) {
1289 j
= spec
[STRINGS_NL_ITEM_START
+ 3 + code
];
1290 i
= _NL_ITEM(LC_TIME
, spec
[STRINGS_NL_ITEM_START
+ code
]);
1291 /* Go backwards to check full names before abreviations. */
1294 o
= nl_langinfo(i
+j
);
1295 if (!strncasecmp(buf
,o
,strlen(o
)) && *o
) { /* Found a match. */
1299 if (!code
) { /* am/pm */
1301 if (fields
[9] >= 0) { /* We have a previous %I or %l. */
1302 fields
[2] = fields
[9] + fields
[8];
1304 } else { /* day (4) or month (6) */
1305 fields
[2 + (code
<< 1)]
1306 = j
% (spec
[STRINGS_NL_ITEM_START
+ 3 + code
] >> 1);
1311 return NULL
; /* Failed to match. */
1314 if ((code
& MASK_SPEC
) == CALC_SPEC
) {
1315 if ((code
&= 0xf) < 1) { /* s or z*/
1321 if (!isspace(*buf
)) { /* Signal an error if whitespace. */
1322 #ifdef TIME_T_IS_UNSIGNED
1323 t
= strtoul(buf
, &o
, 10);
1325 t
= strtol(buf
, &o
, 10);
1328 if ((o
== buf
) || errno
) { /* Not a number or overflow. */
1331 __set_errno(i
); /* Restore errno. */
1334 if (!code
) { /* s */
1335 localtime_r(&t
, tm
); /* TODO: check for failure? */
1337 do { /* Now copy values from tm to fields. */
1338 fields
[i
] = ((int *) tm
)[i
];
1342 /* TODO: glibc treats %Z as a nop. For now, do the same. */
1346 assert((code
& MASK_SPEC
) == INT_SPEC
);
1348 register const unsigned char *x
;
1350 x
= spec
+ INT_FIELD_START
+ (code
<< 1);
1351 if ((j
= x
[1]) < 3) { /* upper bound (inclusive) */
1352 j
= ((j
==1) ? 366 : 9999);
1355 while (isdigit(*buf
)) {
1359 if ((i
= 10*i
+ (*buf
- '0')) > j
) { /* Overflow. */
1364 if (i
< (*x
& 1)) { /* This catches no-digit case too. */
1374 if (*x
== (9 << 3) + 1 + 0) { /* %I or %l */
1378 if (fields
[8] >= 0) { /* We have a previous %p or %P. */
1379 fields
[2] = i
+ fields
[8];
1383 fields
[(*x
) >> 3] = i
;
1385 if (((unsigned char)(*x
- (10<< 3) + 0 + 0)) <= 8) { /* %C or %y */
1386 if ((j
= fields
[10]) < 0) { /* No %C, so i must be %y data. */
1387 if (i
<= 68) { /* Map [0-68] to 2000+i */
1390 } else { /* Have %C data, but what about %y? */
1391 if ((i
= fields
[11]) < 0) { /* No %y data. */
1392 i
= 0; /* Treat %y val as 0 following glibc's example. */
1400 } else if (isspace(*p
)) {
1402 while (isspace(*buf
)) {
1406 } else if (*buf
++ == *p
++) {
1413 /**********************************************************************/
1417 #error The uClibc version of time is in sysdeps/linux/common.
1420 time_t time(register time_t *tloc
)
1423 register struct timeval
*p
= &tv
;
1425 gettimeofday(p
, NULL
); /* This should never fail... */
1435 /**********************************************************************/
1438 static const char vals
[] = {
1439 'T', 'Z', 0, /* 3 */
1440 'U', 'T', 'C', 0, /* 4 */
1441 25, 60, 60, 1, /* 4 */
1444 6, 0, 0, /* Note: overloaded for non-M non-J case... */
1446 ',', 'M', '4', '.', '1', '.', '0',
1447 ',', 'M', '1', '0', '.', '5', '.', '0', 0
1451 #define UTC (vals + 3)
1452 #define RANGE (vals + 7)
1453 #define RULE (vals + 11 - 1)
1454 #define DEFAULT_RULES (vals + 22)
1456 /* Initialize to UTC. */
1459 char *tzname
[2] = { (char *) UTC
, (char *) (UTC
-1) };
1461 #ifdef __UCLIBC_HAS_THREADS__
1462 pthread_mutex_t _time_tzlock
= PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
;
1465 rule_struct _time_tzinfo
[2];
1467 static const char *getoffset(register const char *e
, long *pn
)
1469 register const char *s
= RANGE
-1;
1481 f
= 10 * f
+ (*e
++ - '0');
1483 if (((unsigned int)f
) >= *s
) {
1498 static const char *getnumber(register const char *e
, int *pn
)
1501 /* bcc can optimize the counter if it thinks it is a pointer... */
1502 register const char *n
= (const char *) 3;
1506 while (n
&& isdigit(*e
)) {
1507 f
= 10 * f
+ (*e
++ - '0');
1512 return (n
== (const char *) 3) ? NULL
: e
;
1518 while (n
&& isdigit(*e
)) {
1519 f
= 10 * f
+ (*e
++ - '0');
1524 return (n
== 3) ? NULL
: e
;
1525 #endif /* __BCC__ */
1528 #ifdef __TIME_TZ_FILE
1530 #ifdef __TIME_TZ_FILE_ONCE
1531 static int TZ_file_read
; /* Let BSS initialization set this to 0. */
1532 #endif /* __TIME_TZ_FILE_ONCE */
1534 static char *read_TZ_file(char *buf
)
1541 if ((fd
= open(_PATH_TZ
, O_RDONLY
)) >= 0) {
1545 if ((r
= read(fd
, p
, todo
)) < 0) {
1555 if ((p
> buf
) && (p
[-1] == '\n')) { /* Must end with newline. */
1558 #ifdef __TIME_TZ_FILE_ONCE
1560 #endif /* __TIME_TZ_FILE_ONCE */
1570 #endif /* __TIME_TZ_FILE */
1574 register const char *e
;
1578 rule_struct new_rules
[2];
1581 #ifdef __TIME_TZ_FILE
1582 char buf
[TZ_BUFLEN
];
1583 #endif /* __TIME_TZ_FILE */
1584 #ifdef __TIME_TZ_OPT_SPEED
1585 static char oldval
[TZ_BUFLEN
]; /* BSS-zero'd. */
1586 #endif /* __TIME_TZ_OPT_SPEED */
1590 e
= getenv(TZ
); /* TZ env var always takes precedence. */
1592 #ifdef __TIME_TZ_FILE_ONCE
1593 /* Put this inside the lock to prevent the possiblity of two different
1594 * timezones being used in a threaded app. */
1597 TZ_file_read
= 0; /* Reset if the TZ env var is set. */
1598 } else if (TZ_file_read
> 0) {
1601 #endif /* __TIME_TZ_FILE_ONCE */
1603 /* Warning!!! Since uClibc doesn't do lib locking, the following is
1604 * potentially unsafe in a multi-threaded program since it is remotely
1605 * possible that another thread could call setenv() for TZ and overwrite
1606 * the string being parsed. So, don't do that... */
1608 if ((!e
/* TZ env var not set... */
1609 #ifdef __TIME_TZ_FILE
1610 && !(e
= read_TZ_file(buf
)) /* and no file or invalid file */
1611 #endif /* __TIME_TZ_FILE */
1612 ) || !*e
) { /* or set to empty string. */
1613 ILLEGAL
: /* TODO: Clean up the following... */
1614 #ifdef __TIME_TZ_OPT_SPEED
1615 *oldval
= 0; /* Set oldval tonnn empty string. */
1616 #endif /* __TIME_TZ_OPT_SPEED */
1617 s
= _time_tzinfo
[0].tzname
;
1622 *_time_tzinfo
[1].tzname
= 0;
1623 _time_tzinfo
[0].gmt_offset
= 0;
1627 if (*e
== ':') { /* Ignore leading ':'. */
1631 #ifdef __TIME_TZ_OPT_SPEED
1632 if (strcmp(e
, oldval
) == 0) { /* Same string as last time... */
1633 goto FAST_DONE
; /* So nothing to do. */
1635 /* Make a copy of the TZ env string. It won't be nul-terminated if
1636 * it is too long, but it that case it will be illegal and will be reset
1637 * to the empty string anyway. */
1638 strncpy(oldval
, e
, TZ_BUFLEN
);
1639 #endif /* __TIME_TZ_OPT_SPEED */
1642 new_rules
[1].tzname
[0] = 0;
1644 /* Get std or dst name. */
1651 s
= new_rules
[count
].tzname
;
1654 && isascii(*e
) /* SUSv3 requires char in portable char set. */
1656 || (c
&& (isalnum(*e
) || (*e
== '+') || (*e
== '-'))))
1659 if (++n
> TZNAME_MAX
) {
1665 if ((n
< 3) /* Check for minimum length. */
1666 || (c
&& (*e
++ != c
)) /* Match any quoting '<'. */
1673 if ((*e
!= '-') && (*e
!= '+')) {
1674 if (count
&& !isdigit(*e
)) {
1675 off
-= 3600; /* Default to 1 hour ahead of std. */
1682 if (!(e
= getoffset(e
, &off
))) {
1687 off
= -off
; /* Save off in case needed for dst default. */
1690 new_rules
[count
].gmt_offset
= off
;
1697 } else { /* OK, we have dst, so get some rules. */
1699 if (!*e
) { /* No rules so default to US rules. */
1710 if ((c
= *e
++) == 'M') {
1712 } else if (c
== 'J') {
1720 *(p
= &new_rules
[count
].rule_type
) = c
;
1727 if (!(e
= getnumber(e
, &f
))
1728 || (((unsigned int)(f
- s
[1])) > n
)
1729 || (*s
&& (*e
++ != *s
))
1734 } while ((n
= *(s
+= 2)) > 0);
1736 off
= 2 * 60 * 60; /* Default to 2:00:00 */
1739 if (!(e
= getoffset(e
, &off
))) {
1743 new_rules
[count
].dst_offset
= off
;
1744 } while (++count
< 2);
1751 memcpy(_time_tzinfo
, new_rules
, sizeof(new_rules
));
1753 tzname
[0] = _time_tzinfo
[0].tzname
;
1754 tzname
[1] = _time_tzinfo
[1].tzname
;
1755 daylight
= !!_time_tzinfo
[1].tzname
[0];
1756 timezone
= _time_tzinfo
[0].gmt_offset
;
1763 /**********************************************************************/
1764 /* #ifdef L_utime */
1766 /* utime is a syscall in both linux and elks. */
1767 /* int utime(const char *path, const struct utimbuf *times) */
1770 /**********************************************************************/
1772 /**********************************************************************/
1776 #error The uClibc version of utimes is in sysdeps/linux/common.
1780 #include <sys/time.h>
1782 int utimes(const char *filename
, register const struct timeval
*tvp
)
1784 register struct utimbuf
*p
= NULL
;
1789 p
->actime
= tvp
[0].tv_sec
;
1790 p
->modtime
= tvp
[1].tv_sec
;
1792 return utime(filename
, p
);
1796 /**********************************************************************/
1799 static const uint16_t vals
[] = {
1800 60, 60, 24, 7 /* special */, 36524, 1461, 365, 0
1803 static const unsigned char days
[] = {
1804 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
1809 * If time_t is 32 bits, then no overflow is possible.
1810 * It time_t is > 32 bits, this needs to be adjusted to deal with overflow.
1813 /* Note: offset is the correction in _days_ to *timer! */
1815 struct tm
*_time_t2tm(const time_t *__restrict timer
,
1816 int offset
, struct tm
*__restrict result
)
1820 int wday
; /* Note: wday can be uninitialized. */
1823 register const uint16_t *vp
;
1829 if ((v
= *vp
) == 7) {
1830 /* Overflow checking, assuming time_t is long int... */
1831 #if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
1832 #if (INT_MAX == 2147483647L) && (LONG_MAX == 9223372036854775807L)
1833 /* Valid range for t is [-784223472856L, 784223421720L].
1834 * Outside of this range, the tm_year field will overflow. */
1835 if (((unsigned long)(t
+ offset
- -784223472856L))
1836 > (784223421720L - -784223472856L)
1841 #error overflow conditions unknown
1845 /* We have days since the epoch, so caluclate the weekday. */
1846 #if defined(__BCC__) && TIME_T_IS_UNSIGNED
1847 wday
= (t
+ 4) % (*vp
); /* t is unsigned */
1849 wday
= ((int)((t
% (*vp
)) + 11)) % ((int)(*vp
)); /* help bcc */
1851 /* Set divisor to days in 400 years. Be kind to bcc... */
1852 v
= ((time_t)(vp
[1])) << 2;
1854 /* Change to days since 1/1/1601 so that for 32 bit time_t
1855 * values, we'll have t >= 0. This should be changed for
1856 * archs with larger time_t types.
1857 * Also, correct for offset since a multiple of 7. */
1859 /* TODO: Does this still work on archs with time_t > 32 bits? */
1860 t
+= (135140L - 366) + offset
; /* 146097 - (365*30 + 7) -366 */
1862 #if defined(__BCC__) && TIME_T_IS_UNSIGNED
1863 t
-= ((t1
= t
/ v
) * v
);
1865 if ((t
-= ((t1
= t
/ v
) * v
)) < 0) {
1871 if ((*vp
== 7) && (t
== v
-1)) {
1872 --t
; /* Correct for 400th year leap case */
1873 ++p
[4]; /* Stash the extra day... */
1876 #if defined(__BCC__) && 0
1900 *p
+= ((int) t
); /* result[7] .. tm_yday */
1902 p
-= 2; /* at result[5] */
1904 #if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
1905 /* Protect against overflow. TODO: Unecessary if int arith wraps? */
1906 *p
= ((((p
[-2]<<2) + p
[-1])*25 + p
[0])<< 2) + (p
[1] - 299); /* tm_year */
1908 *p
= ((((p
[-2]<<2) + p
[-1])*25 + p
[0])<< 2) + p
[1] - 299; /* tm_year */
1911 p
[1] = wday
; /* result[6] .. tm_wday */
1914 register const unsigned char *d
= days
;
1917 if (__isleap(wday
)) {
1921 wday
= p
[2] + 1; /* result[7] .. tm_yday */
1922 *--p
= 0; /* at result[4] .. tm_mon */
1926 d
-= 11; /* Backup to non-leap Feb. */
1929 ++*p
; /* Increment tm_mon. */
1931 p
[-1] = wday
; /* result[3] .. tm_mday */
1933 /* TODO -- should this be 0? */
1934 p
[4] = 0; /* result[8] .. tm_isdst */
1940 /**********************************************************************/
1943 struct tm __time_tm
; /* Global shared by gmtime() and localtime(). */
1946 /**********************************************************************/
1947 #ifdef L__time_mktime
1949 static const unsigned char vals
[] = {
1950 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
1954 time_t _time_mktime(struct tm
*timeptr
, int store_on_success
)
1963 /* 0:sec 1:min 2:hour 3:mday 4:mon 5:year 6:wday 7:yday 8:isdst */
1964 register int *p
= (int *) &x
;
1965 register const unsigned char *s
;
1970 memcpy(p
, timeptr
, sizeof(struct tm
));
1973 p
[5] = (p
[5] - ((p
[6] = p
[5]/d
) * d
)) + (p
[7] = p
[4]/12);
1974 if ((p
[4] -= 12 * p
[7]) < 0) {
1980 d
= (p
[5] += 1900); /* Correct year. Now between 1900 and 2300. */
1990 s
-= 11; /* Backup to non-leap Feb. */
1998 days
= -719163L + ((long)d
)*365 + ((d
/4) - (d
/100) + (d
/400) + p
[3] + p
[7]);
1999 secs
= p
[0] + 60*( p
[1] + 60*((long)(p
[2])) )
2000 + _time_tzinfo
[timeptr
->tm_isdst
> 0].gmt_offset
;
2005 if ( ((unsigned long)(days
+ secs
/86400L)) > 49710L) {
2008 secs
+= (days
* 86400L);
2012 d
= -719163L + d
*365 + (d
/4) - (d
/100) + (d
/400);
2014 + _time_tzinfo
[timeptr
->tm_isdst
> 0].gmt_offset
2017 + 24*(((146073L * ((long long)(p
[6])) + d
)
2020 if (((unsigned long long)(secs
- LONG_MIN
))
2021 > (((unsigned long long)LONG_MAX
) - LONG_MIN
)
2029 localtime_r(&t
, (struct tm
*)p
);
2035 if (store_on_success
) {
2036 memcpy(timeptr
, p
, sizeof(struct tm
));
2043 /**********************************************************************/