Introduce time64 support.
[uclibc-ng.git] / libc / misc / time / time.c
blobb6a5b097d9511d376ac954f70866d197145b1157
1 /* Copyright (C) 2002-2004 Manuel Novoa III <mjn3@codepoet.org>
3 * GNU Library General Public License (LGPL) version 2 or later.
5 * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
6 */
8 /* June 15, 2002 Initial Notes:
10 * Note: It is assumed throught that time_t is either long or unsigned long.
11 * Similarly, clock_t is assumed to be long int.
13 * Warning: Assumptions are made about the layout of struct tm! It is
14 * assumed that the initial fields of struct tm are (in order):
15 * tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday
17 * Reached the inital goal of supporting the ANSI/ISO C99 time functions
18 * as well as SUSv3's strptime. All timezone info is obtained from the
19 * TZ env variable.
21 * Differences from glibc worth noting:
23 * Leap seconds are not considered here.
25 * glibc stores additional timezone info the struct tm, whereas we don't.
27 * Alternate digits and era handling are not currently implemented.
28 * The modifiers are accepted, and tested for validity with the following
29 * specifier, but are ignored otherwise.
31 * strftime does not implement glibc extension modifiers or widths for
32 * conversion specifiers. However it does implement the glibc
33 * extension specifiers %l, %k, and %s. It also recognizes %P, but
34 * treats it as a synonym for %p; i.e. doesn't convert to lower case.
36 * strptime implements the glibc extension specifiers. However, it follows
37 * SUSv3 in requiring at least one non-alphanumeric char between
38 * conversion specifiers. Also, strptime only sets struct tm fields
39 * for which format specifiers appear and does not try to infer other
40 * fields (such as wday) as glibc's version does.
42 * TODO - Since glibc's %l and %k can space-pad their output in strftime,
43 * it might be reasonable to eat whitespace first for those specifiers.
44 * This could be done by pushing " %I" and " %H" respectively so that
45 * leading whitespace is consumed. This is really only an issue if %l
46 * or %k occurs at the start of the format string.
48 * TODO - Implement getdate? tzfile? struct tm extensions?
50 * TODO - Rework _time_mktime to remove the dependency on long long.
53 /* Oct 28, 2002
55 * Fixed allowed char check for std and dst TZ fields.
57 * Added several options concerned with timezone support. The names will
58 * probably change once Erik gets the new config system in place.
60 * Defining __TIME_TZ_FILE causes tzset() to attempt to read the TZ value
61 * from the file /etc/TZ if the TZ env variable isn't set. The file contents
62 * must be the intended value of TZ, followed by a newline. No other chars,
63 * spacing, etc is allowed. As an example, an easy way for me to init
64 * /etc/TZ appropriately would be: echo CST6CDT > /etc/TZ
66 * Defining __TIME_TZ_FILE_ONCE will cause all further accesses of /etc/TZ
67 * to be skipped once a legal value has been read.
69 * Defining __TIME_TZ_OPT_SPEED will cause a tzset() to keep a copy of the
70 * last TZ setting string and do a "fast out" if the current string is the
71 * same.
73 * Nov 21, 2002 Fix an error return case in _time_mktime.
75 * Nov 26, 2002 Fix bug in setting daylight and timezone when no (valid) TZ.
76 * Bug reported by Arne Bernin <arne@alamut.de> in regards to freeswan.
78 * July 27, 2003 Adjust the struct tm extension field support.
79 * Change __tm_zone back to a ptr and add the __tm_tzname[] buffer for
80 * __tm_zone to point to. This gets around complaints from g++.
81 * Who knows... it might even fix the PPC timezone init problem.
83 * July 29, 2003 Fix a bug in mktime behavior when tm_isdst was -1.
84 * Bug reported by "Sid Wade" <sid@vivato.net> in regards to busybox.
86 * NOTE: uClibc mktime behavior is different than glibc's when
87 * the struct tm has tm_isdst == -1 and also had fields outside of
88 * the normal ranges.
90 * Apparently, glibc examines (at least) tm_sec and guesses the app's
91 * intention of assuming increasing or decreasing time when entering an
92 * ambiguous time period at the dst<->st boundaries.
94 * The uClibc behavior is to always normalize the struct tm and then
95 * try to determing the dst setting.
97 * As long as tm_isdst != -1 or the time specifiec by struct tm is
98 * unambiguous (not falling in the dst<->st transition region) both
99 * uClibc and glibc should produce the same result for mktime.
101 * Oct 31, 2003 Kill the seperate __tm_zone and __tm_tzname[] and which
102 * doesn't work if you want the memcpy the struct. Sigh... I didn't
103 * think about that. So now, when the extensions are enabled, we
104 * malloc space when necessary and keep the timezone names in a linked
105 * list.
107 * Fix a dst-related bug which resulted in use of uninitialized data.
109 * Nov 15, 2003 I forgot to update the thread locking in the last dst fix.
111 * Dec 14, 2003 Fix some dst issues in _time_mktime().
112 * Normalize the tm_isdst value to -1, 0, or 1.
113 * If no dst for this timezone, then reset tm_isdst to 0.
115 * May 7, 2004
116 * Change clock() to allow wrapping.
117 * Add timegm() function.
118 * Make lookup_tzname() static (as it should have been).
119 * Have strftime() get timezone information from the passed struct
120 * for the %z and %Z conversions when using struct tm extensions.
122 * Jul 24, 2004
123 * Fix 2 bugs in strftime related to glibc struct tm extensions.
124 * 1) Need to negate tm_gmtoff field value when used. (bug 336).
125 * 2) Deal with NULL ptr case for tm_zone field, which was causing
126 * segfaults in both the NIST/PCTS tests and the Python 2.4.1
127 * self-test suite.
128 * NOTE: We set uninitialized timezone names to "???", and this
129 * differs (intentionally) from glibc's behavior.
132 #include <stdio.h>
133 #include <stdlib.h>
134 #include <stddef.h>
135 #include <string.h>
136 #include <time.h>
137 #include <sys/time.h>
138 #include <limits.h>
139 #include <assert.h>
140 #include <errno.h>
141 #include <ctype.h>
142 #include <langinfo.h>
143 #include <locale.h>
144 #include <fcntl.h>
145 #include <unistd.h>
146 #include <bits/uClibc_uintmaxtostr.h>
147 #include <bits/uClibc_mutex.h>
149 #if defined __UCLIBC_HAS_WCHAR__ && (defined L_wcsftime || defined L_wcsftime_l)
150 #include <wchar.h>
151 # define CHAR_T wchar_t
152 # define UCHAR_T unsigned int
153 # ifdef L_wcsftime
154 # define strftime wcsftime
155 # define L_strftime
156 # if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
157 # define strftime_l wcsftime_l
158 # endif
159 # endif
160 # ifdef L_wcsftime_l
161 # define strftime_l wcsftime_l
162 # define L_strftime_l
163 # endif
164 #else
165 # define CHAR_T char
166 # define UCHAR_T unsigned char
167 #endif
169 #ifndef __isleap
170 #define __isleap(y) ( !((y) % 4) && ( ((y) % 100) || !((y) % 400) ) )
171 #endif
173 #ifndef TZNAME_MAX
174 #define TZNAME_MAX _POSIX_TZNAME_MAX
175 #endif
177 #if defined (L_tzset) || defined (L_localtime_r) || defined(L_strftime) || \
178 defined(L__time_mktime) || defined(L__time_mktime_tzi) || \
179 ((defined(L_strftime) || defined(L_strftime_l)) && \
180 defined(__UCLIBC_HAS_XLOCALE__))
182 void _time_tzset(int use_old_rules) attribute_hidden;
184 #ifndef L__time_mktime
186 /* Jan 1, 2007 Z - tm = 0,0,0,1,0,107,1,0,0 */
188 static const time_t new_rule_starts = 1167609600;
190 #endif
191 #endif
193 /**********************************************************************/
194 /* The era code is currently unfinished. */
195 /* #define ENABLE_ERA_CODE */
197 #define TZ_BUFLEN (2*TZNAME_MAX + 56)
199 #ifdef __UCLIBC_HAS_TZ_FILE__
201 #include <sys/stat.h>
202 #include "paths.h"
203 /* ":<tzname>+hh:mm:ss<tzname>+hh:mm:ss,Mmm.w.d/hh:mm:ss,Mmm.w.d/hh:mm:ss" + nul */
204 /* 1 + 2*(1+TZNAME_MAX+1 + 9 + 7 + 9) + 1 = 2*TZNAME_MAX + 56 */
206 #else /* __UCLIBC_HAS_TZ_FILE__ */
208 /* Probably no longer needed. */
209 #undef __UCLIBC_HAS_TZ_FILE_READ_MANY__
211 #endif /* __UCLIBC_HAS_TZ_FILE__ */
213 /**********************************************************************/
215 extern struct tm __time_tm attribute_hidden;
217 typedef struct {
218 long gmt_offset;
219 long dst_offset;
220 short day; /* for J or normal */
221 short week;
222 short month;
223 short rule_type; /* J, M, \0 */
224 char tzname[TZNAME_MAX+1];
225 } rule_struct;
227 __UCLIBC_MUTEX_EXTERN(_time_tzlock) attribute_hidden;
229 extern rule_struct _time_tzinfo[2] attribute_hidden;
231 extern struct tm *_time_t2tm(const time_t *__restrict timer,
232 int offset, struct tm *__restrict result) attribute_hidden;
234 extern time_t _time_mktime(struct tm *timeptr, int store_on_success) attribute_hidden;
236 extern struct tm *__time_localtime_tzi(const time_t *__restrict timer,
237 struct tm *__restrict result,
238 rule_struct *tzi) attribute_hidden;
240 extern time_t _time_mktime_tzi(struct tm *timeptr, int store_on_success,
241 rule_struct *tzi) attribute_hidden;
243 /**********************************************************************/
244 #ifdef L_asctime
246 static char __time_str[26];
248 char *asctime(const struct tm *ptm)
250 return asctime_r(ptm, __time_str);
252 libc_hidden_def(asctime)
254 #endif
255 /**********************************************************************/
256 #ifdef L_asctime_r
258 /* Strictly speaking, this implementation isn't correct. ANSI/ISO specifies
259 * that the implementation of asctime() be equivalent to
261 * char *asctime(const struct tm *timeptr)
263 * static char wday_name[7][3] = {
264 * "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
265 * };
266 * static char mon_name[12][3] = {
267 * "Jan", "Feb", "Mar", "Apr", "May", "Jun",
268 * "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
269 * };
270 * static char result[26];
272 * sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
273 * wday_name[timeptr->tm_wday],
274 * mon_name[timeptr->tm_mon],
275 * timeptr->tm_mday, timeptr->tm_hour,
276 * timeptr->tm_min, timeptr->tm_sec,
277 * 1900 + timeptr->tm_year);
278 * return result;
281 * but the above is either inherently unsafe, or carries with it the implicit
282 * assumption that all fields of timeptr fall within their usual ranges, and
283 * that the tm_year value falls in the range [-2899,8099] to avoid overflowing
284 * the static buffer.
286 * If we take the implicit assumption as given, then the implementation below
287 * is still incorrect for tm_year values < -900, as there will be either
288 * 0-padding and/or a missing negative sign for the year conversion . But given
289 * the usual use of asctime(), I think it isn't unreasonable to restrict correct
290 * operation to the domain of years between 1000 and 9999.
293 /* This is generally a good thing, but if you're _sure_ any data passed will be
294 * in range, you can #undef this. */
295 #define SAFE_ASCTIME_R 1
297 static const unsigned char at_data[] = {
298 'S', 'u', 'n', 'M', 'o', 'n', 'T', 'u', 'e', 'W', 'e', 'd',
299 'T', 'h', 'u', 'F', 'r', 'i', 'S', 'a', 't',
301 'J', 'a', 'n', 'F', 'e', 'b', 'M', 'a', 'r', 'A', 'p', 'r',
302 'M', 'a', 'y', 'J', 'u', 'n', 'J', 'u', 'l', 'A', 'u', 'g',
303 'S', 'e', 'p', 'O', 'c', 't', 'N', 'o', 'v', 'D', 'e', 'c',
305 #ifdef SAFE_ASCTIME_R
306 '?', '?', '?',
307 #endif
308 ' ', '?', '?', '?',
309 ' ', '0',
310 offsetof(struct tm, tm_mday),
311 ' ', '0',
312 offsetof(struct tm, tm_hour),
313 ':', '0',
314 offsetof(struct tm, tm_min),
315 ':', '0',
316 offsetof(struct tm, tm_sec),
317 ' ', '?', '?', '?', '?', '\n', 0
320 char *asctime_r(register const struct tm *__restrict ptm,
321 register char *__restrict buffer)
323 int tmp;
325 assert(ptm);
326 assert(buffer);
328 #ifdef SAFE_ASCTIME_R
329 memcpy(buffer, at_data + 3*(7 + 12), sizeof(at_data) - 3*(7 + 12));
331 if (((unsigned int)(ptm->tm_wday)) <= 6) {
332 memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);
335 if (((unsigned int)(ptm->tm_mon)) <= 11) {
336 memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
338 #else
339 assert(((unsigned int)(ptm->tm_wday)) <= 6);
340 assert(((unsigned int)(ptm->tm_mon)) <= 11);
342 memcpy(buffer, at_data + 3*(7 + 12) - 3, sizeof(at_data) + 3 - 3*(7 + 12));
344 memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);
345 memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
346 #endif
348 #ifdef SAFE_ASCTIME_R
349 buffer += 19;
350 tmp = ptm->tm_year + 1900;
351 if (((unsigned int) tmp) < 10000) {
352 buffer += 4;
353 do {
354 *buffer = '0' + (tmp % 10);
355 tmp /= 10;
356 } while (*--buffer == '?');
358 /* Not sure if we should even bother ...
359 } else {
360 __set_errno(EOVERFLOW);
361 return NULL;
364 #else /* SAFE_ASCTIME_R */
365 buffer += 23;
366 tmp = ptm->tm_year + 1900;
367 assert( ((unsigned int) tmp) < 10000 );
368 /* Not sure if we should even bother ...
369 if ( ((unsigned int) tmp) >= 10000 ) {
370 __set_errno(EOVERFLOW);
371 return NULL;
374 do {
375 *buffer = '0' + (tmp % 10);
376 tmp /= 10;
377 } while (*--buffer == '?');
378 #endif /* SAFE_ASCTIME_R */
380 do {
381 --buffer;
382 tmp = *((int *)(((const char *) ptm) + (int) *buffer));
383 #ifdef SAFE_ASCTIME_R
384 if (((unsigned int) tmp) >= 100) { /* Just check 2 digit non-neg. */
385 buffer[-1] = *buffer = '?';
386 } else
387 #else
388 assert(((unsigned int) tmp) < 100); /* Just check 2 digit non-neg. */
389 #endif
391 *buffer = '0' + (tmp % 10);
392 #ifdef __BCC__
393 buffer[-1] = '0' + (tmp/10);
394 #else
395 buffer[-1] += (tmp/10);
396 #endif
398 } while ((buffer -= 2)[-2] == '0');
400 if (*++buffer == '0') { /* Space-pad day of month. */
401 *buffer = ' ';
404 return buffer - 8;
406 libc_hidden_def(asctime_r)
408 #endif
409 /**********************************************************************/
410 #ifdef L_clock
412 #include <sys/times.h>
414 #ifndef __BCC__
415 #if CLOCKS_PER_SEC != 1000000L
416 #error unexpected value for CLOCKS_PER_SEC!
417 #endif
418 #endif
420 #ifdef __UCLIBC_CLK_TCK_CONST
421 # if __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC
422 # error __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC!
423 # elif __UCLIBC_CLK_TCK_CONST < 1
424 # error __UCLIBC_CLK_TCK_CONST < 1!
425 # endif
426 #endif
428 /* Note: SUSv3 notes
430 * On XSI-conformant systems, CLOCKS_PER_SEC is defined to be one million.
432 * The value returned by clock() may wrap around on some implementations.
433 * For example, on a machine with 32-bit values for clock_t, it wraps
434 * after 2147 seconds.
436 * This implies that we should bitwise and with LONG_MAX.
439 clock_t clock(void)
441 struct tms xtms;
442 unsigned long t;
444 times(&xtms);
446 t = ((unsigned long) xtms.tms_utime) + xtms.tms_stime;
448 #ifndef __UCLIBC_CLK_TCK_CONST
450 # error __UCLIBC_CLK_TCK_CONST not defined!
452 #elif ((CLOCKS_PER_SEC % __UCLIBC_CLK_TCK_CONST) == 0)
454 /* CLOCKS_PER_SEC == k * __UCLIBC_CLK_TCK_CONST for some integer k >= 1. */
455 return ((t * (CLOCKS_PER_SEC/__UCLIBC_CLK_TCK_CONST)) & LONG_MAX);
457 #else
459 /* Unlike the previous case, the scaling factor is not an integer.
460 * So when tms_utime, tms_stime, or their sum wraps, some of the
461 * "visible" bits in the return value are affected. Nothing we
462 * can really do about this though other than handle tms_utime and
463 * tms_stime seperately and then sum. But since that doesn't really
464 * buy us much, we don't bother. */
466 return ((((t / __UCLIBC_CLK_TCK_CONST) * CLOCKS_PER_SEC)
467 + ((((t % __UCLIBC_CLK_TCK_CONST) * CLOCKS_PER_SEC)
468 / __UCLIBC_CLK_TCK_CONST))
469 ) & LONG_MAX);
471 #endif
474 #endif
475 /**********************************************************************/
476 #ifdef L_ctime
478 char *ctime(const time_t *t)
480 /* ANSI/ISO/SUSv3 say that ctime is equivalent to the following:
481 * return asctime(localtime(t));
482 * I don't think "equivalent" means "it uses the same internal buffer",
483 * it means "gives the same resultant string".
485 * I doubt anyone ever uses weird code like:
486 * struct tm *ptm = localtime(t1); ...; ctime(t2); use(ptm);
487 * which relies on the assumption that ctime's and localtime's
488 * internal static struct tm is the same.
490 * Using localtime_r instead of localtime avoids linking in
491 * localtime's static buffer:
493 struct tm xtm;
494 memset(&xtm, 0, sizeof(xtm));
496 return asctime(localtime_r(t, &xtm));
498 libc_hidden_def(ctime)
499 #endif
500 /**********************************************************************/
501 #ifdef L_ctime_r
503 char *ctime_r(const time_t *t, char *buf)
505 struct tm xtm;
507 return asctime_r(localtime_r(t, &xtm), buf);
510 #endif
511 /**********************************************************************/
512 #ifdef L_difftime
514 #include <float.h>
516 #if FLT_RADIX != 2
517 #error difftime implementation assumptions violated for you arch!
518 #endif
520 double difftime(time_t time1, time_t time0)
522 #if (LONG_MAX >> DBL_MANT_DIG) == 0
524 /* time_t fits in the mantissa of a double. */
525 return (double)time1 - (double)time0;
527 #elif ((LONG_MAX >> DBL_MANT_DIG) >> DBL_MANT_DIG) == 0
529 /* time_t can overflow the mantissa of a double. */
530 time_t t1, t0, d;
532 d = ((time_t) 1) << DBL_MANT_DIG;
533 t1 = time1 / d;
534 time1 -= (t1 * d);
535 t0 = time0 / d;
536 time0 -= (t0*d);
538 /* Since FLT_RADIX==2 and d is a power of 2, the only possible
539 * rounding error in the expression below would occur from the
540 * addition. */
541 return (((double) t1) - t0) * d + (((double) time1) - time0);
543 #else
544 #error difftime needs special implementation on your arch.
545 #endif
548 #endif
549 /**********************************************************************/
550 #ifdef L_gmtime
552 struct tm *gmtime(const time_t *timer)
554 register struct tm *ptm = &__time_tm;
556 _time_t2tm(timer, 0, ptm); /* Can return NULL... */
558 return ptm;
561 #endif
562 /**********************************************************************/
563 #ifdef L_gmtime_r
565 struct tm *gmtime_r(const time_t *__restrict timer,
566 struct tm *__restrict result)
568 return _time_t2tm(timer, 0, result);
571 #endif
572 /**********************************************************************/
573 #ifdef L_localtime
575 struct tm *localtime(const time_t *timer)
577 register struct tm *ptm = &__time_tm;
579 /* In this implementation, tzset() is called by localtime_r(). */
581 localtime_r(timer, ptm); /* Can return NULL... */
583 return ptm;
585 libc_hidden_def(localtime)
587 #endif
588 /**********************************************************************/
589 #ifdef L_localtime_r
591 struct tm *localtime_r(register const time_t *__restrict timer,
592 register struct tm *__restrict result)
594 __UCLIBC_MUTEX_LOCK(_time_tzlock);
596 _time_tzset(*timer < new_rule_starts);
598 __time_localtime_tzi(timer, result, _time_tzinfo);
600 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
602 return result;
604 libc_hidden_def(localtime_r)
606 #endif
607 /**********************************************************************/
608 #ifdef L__time_localtime_tzi
610 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
612 struct ll_tzname_item;
614 typedef struct ll_tzname_item {
615 struct ll_tzname_item *next;
616 char tzname[1];
617 } ll_tzname_item_t;
619 /* Structures form a list "UTC" -> "???" -> "tzname1" -> "tzname2"... */
620 static struct {
621 struct ll_tzname_item *next;
622 char tzname[4];
623 } ll_tzname_UNKNOWN = { NULL, "???" };
624 static const struct {
625 struct ll_tzname_item *next;
626 char tzname[4];
627 } ll_tzname_UTC = { (void*)&ll_tzname_UNKNOWN, "UTC" };
629 static const char *lookup_tzname(const char *key)
631 int len;
632 ll_tzname_item_t *p = (void*) &ll_tzname_UTC;
634 do {
635 if (strcmp(p->tzname, key) == 0)
636 return p->tzname;
637 p = p->next;
638 } while (p != NULL);
640 /* Hmm... a new name. */
641 len = strnlen(key, TZNAME_MAX+1);
642 if (len < TZNAME_MAX+1) { /* Verify legal length */
643 p = malloc(sizeof(ll_tzname_item_t) + len);
644 if (p != NULL) {
645 /* Insert as 3rd item in the list. */
646 p->next = ll_tzname_UNKNOWN.next;
647 ll_tzname_UNKNOWN.next = p;
648 return strcpy(p->tzname, key);
652 /* Either invalid or couldn't alloc. */
653 return ll_tzname_UNKNOWN.tzname;
656 #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
658 static const unsigned char day_cor[] = { /* non-leap */
659 31, 31, 34, 34, 35, 35, 36, 36, 36, 37, 37, 38, 38
660 /* 0, 0, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7 */
661 /* 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 */
664 /* Note: timezone locking is done by localtime_r. */
666 static int tm_isdst(register const struct tm *__restrict ptm,
667 register rule_struct *r)
669 long sec;
670 int i, isdst, isleap, day, day0, monlen, mday;
671 int oday = oday; /* ok to be uninitialized, shutting up compiler warning */
673 isdst = 0;
674 if (r[1].tzname[0] != 0) {
675 /* First, get the current seconds offset from the start of the year.
676 * Fields of ptm are assumed to be in their normal ranges. */
677 sec = ptm->tm_sec
678 + 60 * (ptm->tm_min
679 + 60 * (long)(ptm->tm_hour
680 + 24 * ptm->tm_yday));
681 /* Do some prep work. */
682 i = (ptm->tm_year % 400) + 1900; /* Make sure we don't overflow. */
683 isleap = __isleap(i);
684 --i;
685 day0 = (1
686 + i /* Normal years increment 1 wday. */
687 + (i/4)
688 - (i/100)
689 + (i/400) ) % 7;
690 i = 0;
691 do {
692 day = r->day; /* Common for 'J' and # case. */
693 if (r->rule_type == 'J') {
694 if (!isleap || (day < (31+29))) {
695 --day;
697 } else if (r->rule_type == 'M') {
698 /* Find 0-based day number for 1st of the month. */
699 day = 31 * r->month - day_cor[r->month - 1];
700 if (isleap && (day >= 59)) {
701 ++day;
703 monlen = 31 + day_cor[r->month - 1] - day_cor[r->month];
704 if (isleap && (r->month == 2)) {
705 ++monlen;
707 /* Weekday (0 is Sunday) of 1st of the month
708 * is (day0 + day) % 7. */
709 mday = r->day - ((day0 + day) % 7);
710 if (mday >= 0) {
711 mday -= 7; /* Back up into prev month since r->week > 0. */
713 mday += 7 * r->week;
714 if (mday >= monlen) {
715 mday -= 7;
717 /* So, 0-based day number is... */
718 day += mday;
721 if (i != 0) {
722 /* Adjust sec since dst->std change time is in dst. */
723 sec += (r[-1].gmt_offset - r->gmt_offset);
724 if (oday > day) {
725 ++isdst; /* Year starts in dst. */
728 oday = day;
730 /* Now convert day to seconds and add offset and compare. */
731 if (sec >= (day * 86400L) + r->dst_offset) {
732 ++isdst;
734 ++r;
735 } while (++i < 2);
738 return (isdst & 1);
741 struct tm attribute_hidden *__time_localtime_tzi(register const time_t *__restrict timer,
742 register struct tm *__restrict result,
743 rule_struct *tzi)
745 time_t x[1];
746 long offset;
747 int days, dst;
749 dst = 0;
750 do {
751 days = -7;
752 offset = 604800L - tzi[dst].gmt_offset;
753 if (*timer > (LONG_MAX - 604800L)) {
754 days = -days;
755 offset = -offset;
757 *x = *timer + offset;
759 _time_t2tm(x, days, result);
760 result->tm_isdst = dst;
761 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
762 # ifdef __USE_BSD
763 result->tm_gmtoff = - tzi[dst].gmt_offset;
764 result->tm_zone = lookup_tzname(tzi[dst].tzname);
765 # else
766 result->__tm_gmtoff = - tzi[dst].gmt_offset;
767 result->__tm_zone = lookup_tzname(tzi[dst].tzname);
768 # endif
769 #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
770 } while ((++dst < 2)
771 && ((result->tm_isdst = tm_isdst(result, tzi)) != 0));
773 return result;
776 #endif
777 /**********************************************************************/
778 #ifdef L_mktime
780 time_t mktime(struct tm *timeptr)
782 return _time_mktime(timeptr, 1);
785 /* Another name for `mktime'. */
786 /* time_t timelocal(struct tm *tp) */
787 strong_alias(mktime,timelocal)
789 #endif
790 /**********************************************************************/
791 #ifdef L_timegm
792 /* Like `mktime' but timeptr represents Universal Time, not local time. */
794 time_t timegm(struct tm *timeptr)
796 rule_struct gmt_tzinfo[2];
798 memset(gmt_tzinfo, 0, sizeof(gmt_tzinfo));
799 strcpy(gmt_tzinfo[0].tzname, "GMT"); /* Match glibc behavior here. */
801 return _time_mktime_tzi(timeptr, 1, gmt_tzinfo);
804 #endif
805 /**********************************************************************/
806 #if defined(L_strftime) || defined(L_strftime_l) \
807 || defined(L_wcsftime) || defined(L_wcsftime_l)
809 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
811 size_t strftime(CHAR_T *__restrict s, size_t maxsize,
812 const CHAR_T *__restrict format,
813 const struct tm *__restrict timeptr)
815 return strftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE);
818 #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
820 #define NO_E_MOD 0x80
821 #define NO_O_MOD 0x40
823 #define ILLEGAL_SPEC 0x3f
825 #define INT_SPEC 0x00 /* must be 0x00!! */
826 #define STRING_SPEC 0x10 /* must be 0x10!! */
827 #define CALC_SPEC 0x20
828 #define STACKED_SPEC 0x30
830 #define MASK_SPEC 0x30
832 /* Compatibility:
834 * No alternate digit (%O?) handling. Always uses 0-9.
835 * Alternate locale format (%E?) handling is broken for nontrivial ERAs.
836 * glibc's %P is currently faked by %p. This means it doesn't do lower case.
837 * glibc's %k, %l, and %s are handled.
838 * glibc apparently allows (and ignores) extraneous 'E' and 'O' modifiers,
839 * while they are flagged as illegal conversions here.
842 /* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
843 static const unsigned char spec[] = {
844 /* A */ 0x03 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
845 /* B */ 0x04 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
846 /* C */ 0x0a | INT_SPEC | NO_O_MOD,
847 /* D */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
848 /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
849 /* F */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
850 /* G */ 0x03 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
851 /* H */ 0x0b | INT_SPEC | NO_E_MOD,
852 /* I */ 0x0c | INT_SPEC | NO_E_MOD,
853 /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
854 /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
855 /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
856 /* M */ 0x0d | INT_SPEC | NO_E_MOD,
857 /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
858 /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
859 /* P */ 0x05 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc ; use %p */
860 /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
861 /* R */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
862 /* S */ 0x0e | INT_SPEC | NO_E_MOD,
863 /* T */ 0x05 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
864 /* U */ 0x04 | CALC_SPEC | NO_E_MOD,
865 /* V */ 0x05 | CALC_SPEC | NO_E_MOD,
866 /* W */ 0x06 | CALC_SPEC | NO_E_MOD,
867 /* X */ 0x0a | STACKED_SPEC | NO_O_MOD,
868 /* Y */ 0x0f | INT_SPEC | NO_O_MOD,
869 /* Z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
870 '?', /* 26 */
871 '?', /* 27 */
872 '?', /* 28 */
873 '?', /* 29 */
874 0, /* 30 */
875 0, /* 31 */
876 /* a */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
877 /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
878 /* c */ 0x08 | STACKED_SPEC | NO_O_MOD,
879 /* d */ 0x00 | INT_SPEC | NO_E_MOD,
880 /* e */ 0x01 | INT_SPEC | NO_E_MOD,
881 /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
882 /* g */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
883 /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* same as b */
884 /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
885 /* j */ 0x08 | INT_SPEC | NO_E_MOD | NO_O_MOD,
886 /* k */ 0x03 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
887 /* l */ 0x04 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
888 /* m */ 0x05 | INT_SPEC | NO_E_MOD,
889 /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
890 /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
891 /* p */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
892 /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
893 /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
894 /* s */ 0x07 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
895 /* t */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
896 /* u */ 0x07 | INT_SPEC | NO_E_MOD,
897 /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
898 /* w */ 0x02 | INT_SPEC | NO_E_MOD,
899 /* x */ 0x09 | STACKED_SPEC | NO_O_MOD,
900 /* y */ 0x09 | INT_SPEC,
901 /* z */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
904 /* WARNING!!! These are dependent on the layout of struct tm!!! */
905 #define FIELD_MAX (26+6+26)
906 60 /* 61? */, 59, 23, 31, 11, 0 /* 9999 */, 6, 0 /* 365 */,
908 #define TP_OFFSETS (FIELD_MAX+8)
909 3, /* d */
910 3, /* e */
911 6, /* w */
912 2, /* k */
913 2, /* l */
914 4, /* m */
915 0, /* CURRENTLY UNUSED */
916 /* NOTE: u,j,y order must be preserved as 6,7,5 seq is used in the code! */
917 #define CALC_OFFSETS (TP_OFFSETS + 7)
918 6, /* u */
919 7, /* j */
920 5, /* y */
921 5, /* C */
922 2, /* H */
923 2, /* I */
924 1, /* M */
925 0, /* S */
926 5, /* Y */
927 6, /* a */
928 4, /* b, h */
929 2, /* p */
930 6, /* A */
931 4, /* B */
932 2, /* P */
934 #define TP_CODES (TP_OFFSETS + 16 + 6)
935 2 | 16, /* d */
936 2, /* e */
937 0 | 16, /* w */
938 2, /* k */
939 2 | 32 | 0, /* l */
940 2 | 16 | 1, /* m */
941 0, /* CURRENTLY UNUSED */
942 0 | 16 | 8 , /* u */
943 4 | 16 | 1, /* j */
944 2 | 128 | 32 | 16 , /* y */
945 2 | 128 | 64 | 32 | 16 , /* C */
946 2 | 16, /* H */
947 2 | 32 | 16 | 0, /* I */
948 2 | 16, /* M */
949 2 | 16, /* S */
950 6 | 16, /* Y */
951 2, /* a */
952 2, /* b, h */
953 2 | 64, /* p */
954 2, /* A */
955 2, /* B */
956 2 | 64, /* P */
958 #define STRINGS_NL_ITEM_START (TP_CODES + 16 + 6)
959 _NL_ITEM_INDEX(ABDAY_1), /* a */
960 _NL_ITEM_INDEX(ABMON_1), /* b, h */
961 _NL_ITEM_INDEX(AM_STR), /* p */
962 _NL_ITEM_INDEX(DAY_1), /* A */
963 _NL_ITEM_INDEX(MON_1), /* B */
964 _NL_ITEM_INDEX(AM_STR), /* P -- wrong! need lower case */
966 #define STACKED_STRINGS_START (STRINGS_NL_ITEM_START+6)
967 6, 7, 8, 16, 24, 29, /* 6 - offsets from offset-count to strings */
968 '\n', 0, /* 2 */
969 '\t', 0, /* 2 */
970 '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
971 '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
972 '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
973 '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
975 #define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 43)
976 _NL_ITEM_INDEX(D_T_FMT), /* c */
977 _NL_ITEM_INDEX(D_FMT), /* x */
978 _NL_ITEM_INDEX(T_FMT), /* X */
979 _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
980 #ifdef ENABLE_ERA_CODE
981 _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
982 _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */
983 _NL_ITEM_INDEX(ERA_T_FMT), /* EX */
984 #endif
987 static int load_field(int k, const struct tm *__restrict timeptr)
989 int r;
990 int r_max;
992 r = ((int *) timeptr)[k];
994 r_max = spec[FIELD_MAX + k];
996 if (k == 7) {
997 r_max = 365;
998 } else if (k == 5) {
999 r += 1900;
1000 r_max = 9999;
1003 if ((((unsigned int) r) > r_max) || ((k == 3) && !r)) {
1004 r = -1;
1007 return r;
1010 #if defined __UCLIBC_HAS_WCHAR__ && (defined L_wcsftime || defined L_wcsftime_l)
1011 static wchar_t* fmt_to_wc_1(const char *src)
1013 mbstate_t mbstate;
1014 size_t src_len = strlen(src);
1015 wchar_t *dest = (wchar_t *)malloc((src_len + 1) * sizeof(wchar_t));
1016 if (dest == NULL)
1017 return NULL;
1018 mbstate.__mask = 0;
1019 if (mbsrtowcs(dest, &src, src_len + 1, &mbstate) == (size_t) -1) {
1020 free(dest);
1021 return NULL;
1023 return dest;
1025 # define fmt_to_wc(dest, src) \
1026 dest = alloc[++allocno] = fmt_to_wc_1(src)
1027 # define to_wc(dest, src) \
1028 dest = fmt_to_wc_1(src)
1029 #else
1030 # define fmt_to_wc(dest, src) (dest) = (src)
1031 # define to_wc(dest, src) (dest) = (src)
1032 #endif
1034 #define MAX_PUSH 4
1036 size_t __XL_NPP(strftime)(CHAR_T *__restrict s, size_t maxsize,
1037 const CHAR_T *__restrict format,
1038 const struct tm *__restrict timeptr __LOCALE_PARAM )
1040 long tzo;
1041 register const CHAR_T *p;
1042 const CHAR_T *o;
1043 const char *ccp;
1044 #ifndef __UCLIBC_HAS_TM_EXTENSIONS__
1045 const rule_struct *rsp;
1046 #endif
1047 const CHAR_T *stack[MAX_PUSH];
1048 #if defined __UCLIBC_HAS_WCHAR__ && (defined L_wcsftime || defined L_wcsftime_l)
1049 const CHAR_T *alloc[MAX_PUSH];
1050 int allocno = -1;
1051 #endif
1052 size_t count;
1053 size_t o_count;
1054 int field_val = 0, i = 0, j, lvl;
1055 int x[3]; /* wday, yday, year */
1056 int isofm, days;
1057 char buf[__UIM_BUFLEN_LONG] = {0,};
1058 unsigned char mod;
1059 unsigned char code;
1061 /* We'll, let's get this out of the way. */
1062 _time_tzset(_time_mktime((struct tm *) timeptr, 0) < new_rule_starts);
1064 lvl = 0;
1065 p = format;
1066 count = maxsize;
1068 LOOP:
1069 if (!count) {
1070 return 0;
1072 if (!*p) {
1073 if (lvl == 0) {
1074 *s = 0; /* nul-terminate */
1075 return maxsize - count;
1077 p = stack[--lvl];
1078 goto LOOP;
1081 o_count = 1;
1082 if ((*(o = (CHAR_T *)p) == '%') && (*++p != '%')) {
1083 #if 0 /* TODO, same for strptime */
1084 /* POSIX.1-2008 allows %0xY %+nY %-nY etc. for certain formats.
1085 * Just accept these for all (for now) */
1086 const int plus = *p == '+';
1087 CHAR_T *q = (CHAR_T *)p;
1088 long int o_width = __XL_NPP(strtol)(p, &q, 0 __LOCALE_ARG);
1089 if (o_width > 0 && o_width < 256) { /* arbitrary upper limit */
1090 o_count = o_width;
1091 if (plus) {
1092 *s++ = '+';
1093 --count;
1095 p = q;
1096 } else {
1097 o_count = 2;
1099 #else
1100 o_count = 2;
1101 #endif
1102 mod = ILLEGAL_SPEC;
1103 if ((*p == 'O') || (*p == 'E')) { /* modifier */
1104 mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
1105 ++o_count;
1106 ++p;
1108 if ((((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
1109 || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
1111 if (!*p) {
1112 --p;
1113 --o_count;
1115 goto OUTPUT;
1117 code &= ILLEGAL_SPEC; /* modifiers are preserved in mod var. */
1119 if ((code & MASK_SPEC) == STACKED_SPEC) {
1120 if (lvl == MAX_PUSH) {
1121 goto OUTPUT; /* Stack full so treat as illegal spec. */
1123 stack[lvl++] = ++p;
1124 if ((code &= 0xf) < 8) {
1125 ccp = (const char *)(spec + STACKED_STRINGS_START + code);
1126 ccp += *ccp;
1127 fmt_to_wc(p, ccp);
1128 goto LOOP;
1130 ccp = (const char *)spec + STACKED_STRINGS_NL_ITEM_START + (code & 7);
1131 fmt_to_wc(p, ccp);
1132 #ifdef ENABLE_ERA_CODE
1133 if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
1134 && (*(ccp = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1135 (int)(((unsigned char *)p)[4]))
1136 __LOCALE_ARG
1139 fmt_to_wc(p, ccp);
1140 goto LOOP;
1142 #endif
1143 ccp = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1144 (int)(*((unsigned char *)p)))
1145 __LOCALE_ARG
1147 fmt_to_wc(p, ccp);
1148 goto LOOP;
1151 ccp = (const char *)(spec + 26); /* set to "????" */
1152 if ((code & MASK_SPEC) == CALC_SPEC) {
1154 if (*p == 's') {
1155 time_t t;
1157 /* Use a cast to silence the warning since *timeptr won't
1158 * be changed. */
1159 if ((t = _time_mktime((struct tm *) timeptr, 0))
1160 == ((time_t) -1)
1162 o_count = 1;
1163 goto OUTPUT;
1165 #ifdef TIME_T_IS_UNSIGNED
1166 ccp = _uintmaxtostr(buf + sizeof(buf) - 1,
1167 (uintmax_t) t,
1168 10, __UIM_DECIMAL);
1169 #else
1170 ccp = _uintmaxtostr(buf + sizeof(buf) - 1,
1171 (uintmax_t) t,
1172 -10, __UIM_DECIMAL);
1173 #endif
1174 o_count = sizeof(buf);
1175 fmt_to_wc(o, ccp);
1176 goto OUTPUT;
1177 } else if (((*p) | 0x20) == 'z') { /* 'z' or 'Z' */
1179 if (timeptr->tm_isdst < 0) {
1180 /* SUSv3 specifies this behavior for 'z', but we'll also
1181 * treat it as "no timezone info" for 'Z' too. */
1182 o_count = 0;
1183 goto OUTPUT;
1186 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1188 # ifdef __USE_BSD
1189 # define RSP_TZNAME timeptr->tm_zone
1190 # define RSP_GMT_OFFSET (-timeptr->tm_gmtoff)
1191 # else
1192 # define RSP_TZNAME timeptr->__tm_zone
1193 # define RSP_GMT_OFFSET (-timeptr->__tm_gmtoff)
1194 # endif
1196 #else
1198 #define RSP_TZNAME rsp->tzname
1199 #define RSP_GMT_OFFSET rsp->gmt_offset
1201 __UCLIBC_MUTEX_LOCK(_time_tzlock);
1203 rsp = _time_tzinfo;
1204 if (timeptr->tm_isdst > 0) {
1205 ++rsp;
1207 #endif
1209 if (*p == 'Z') {
1210 ccp = RSP_TZNAME;
1211 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1212 /* Sigh... blasted glibc extensions. Of course we can't
1213 * count on the pointer being valid. Best we can do is
1214 * handle NULL, which looks to be all that glibc does.
1215 * At least that catches the memset() with 0 case.
1216 * NOTE: We handle this case differently than glibc!
1217 * It uses system timezone name (based on tm_isdst) in this
1218 * case... although it always seems to use the embedded
1219 * tm_gmtoff value. What we'll do instead is treat the
1220 * timezone name as unknown/invalid and return "???". */
1221 if (!ccp) {
1222 ccp = (const char *)(spec + 27); /* "???" */
1224 #endif
1225 assert(ccp != NULL);
1226 #if 0
1227 if (!ccp) { /* PARANOIA */
1228 ccp = spec+30; /* empty string */
1230 #endif
1231 o_count = SIZE_MAX;
1232 fmt_to_wc(o, ccp);
1233 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1234 goto OUTPUT;
1235 #endif
1236 } else { /* z */
1237 *s = '+';
1238 if ((tzo = -RSP_GMT_OFFSET) < 0) {
1239 tzo = -tzo;
1240 *s = '-';
1242 ++s;
1243 --count;
1245 i = tzo / 60;
1246 field_val = ((i / 60) * 100) + (i % 60);
1248 i = 16 + 6; /* 0-fill, width = 4 */
1250 #ifndef __UCLIBC_HAS_TM_EXTENSIONS__
1251 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
1252 if (*p == 'Z') {
1253 goto OUTPUT;
1255 #endif
1256 } else {
1257 /* TODO: don't need year for U, W */
1258 for (i=0 ; i < 3 ; i++) {
1259 if ((x[i] = load_field(spec[CALC_OFFSETS+i],timeptr)) < 0) {
1260 goto OUTPUT;
1264 i = 16 + 2; /* 0-fill, width = 2 */
1266 if ((*p == 'U') || (*p == 'W')) {
1267 field_val = ((x[1] - x[0]) + 7);
1268 if (*p == 'W') {
1269 ++field_val;
1271 field_val /= 7;
1272 if ((*p == 'W') && !x[0]) {
1273 --field_val;
1275 } else { /* ((*p == 'g') || (*p == 'G') || (*p == 'V')) */
1276 ISO_LOOP:
1277 isofm = (((x[1] - x[0]) + 11) % 7) - 3; /* [-3,3] */
1279 if (x[1] < isofm) { /* belongs to previous year */
1280 --x[2];
1281 x[1] += 365 + __isleap(x[2]);
1282 goto ISO_LOOP;
1285 field_val = ((x[1] - isofm) / 7) + 1; /* week # */
1286 days = 365 + __isleap(x[2]);
1287 isofm = ((isofm + 7*53 + 3 - days)) % 7 + days - 3; /* next year */
1288 if (x[1] >= isofm) { /* next year */
1289 x[1] -= days;
1290 ++x[2];
1291 goto ISO_LOOP;
1294 if (*p != 'V') { /* need year */
1295 field_val = x[2]; /* TODO: what if x[2] now 10000 ?? */
1296 if (*p == 'g') {
1297 field_val %= 100;
1298 } else {
1299 i = 16 + 6; /* 0-fill, width = 4 */
1304 } else {
1305 i = TP_OFFSETS + (code & 0x1f);
1306 if ((field_val = load_field(spec[i], timeptr)) < 0) {
1307 goto OUTPUT;
1310 i = spec[i+(TP_CODES - TP_OFFSETS)];
1312 j = (i & 128) ? 100: 12;
1313 if (i & 64) {
1314 field_val /= j;
1316 if (i & 32) {
1317 field_val %= j;
1318 if (((i & 128) + field_val) == 0) { /* mod 12? == 0 */
1319 field_val = j; /* set to 12 */
1322 field_val += (i & 1);
1323 if ((i & 8) && !field_val) {
1324 field_val += 7;
1328 if ((code & MASK_SPEC) == STRING_SPEC) {
1329 o_count = SIZE_MAX;
1330 field_val += spec[STRINGS_NL_ITEM_START + (code & 0xf)];
1331 ccp = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME, field_val) __LOCALE_ARG);
1332 fmt_to_wc(o, ccp);
1333 } else {
1334 #if 0 /* TODO, same for strptime */
1335 size_t min_count = ((i >> 1) & 3) + 1;
1336 if (o_count < min_count)
1337 o_count = min_count;
1338 #else
1339 o_count = ((i >> 1) & 3) + 1;
1340 #endif
1341 ccp = buf + o_count;
1342 do {
1343 *(char *)(--ccp) = '0' + (field_val % 10);
1344 field_val /= 10;
1345 } while (ccp > buf);
1346 if (*buf == '0') {
1347 *buf = ' ' + (i & 16);
1349 fmt_to_wc(o, ccp);
1353 OUTPUT:
1354 ++p;
1355 while (o_count && count && *o) {
1356 *s++ = *o++;
1357 --o_count;
1358 --count;
1360 #if defined __UCLIBC_HAS_WCHAR__ && (defined L_wcsftime || defined L_wcsftime_l)
1361 if (allocno >= 0)
1362 free((void *)alloc[allocno--]);
1363 #endif
1364 goto LOOP;
1366 # ifdef L_strftime_l
1367 libc_hidden_def(strftime_l)
1368 # endif
1370 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1372 #endif
1373 /**********************************************************************/
1374 #if defined(L_strptime) || defined(L_strptime_l)
1376 #define ISDIGIT(C) __isdigit_char((C))
1378 #ifdef __UCLIBC_DO_XLOCALE
1379 #define ISSPACE(C) isspace_l((C), locale_arg)
1380 #else
1381 #define ISSPACE(C) isspace((C))
1382 #endif
1384 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
1386 char *strptime(const char *__restrict buf, const char *__restrict format,
1387 struct tm *__restrict tm)
1389 return strptime_l(buf, format, tm, __UCLIBC_CURLOCALE);
1392 #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1394 /* TODO:
1395 * 1) %l and %k are space-padded, so "%l" by itself fails while " %l" succeeds.
1396 * Both work for glibc. So, should we always strip spaces?
1397 * 2) %Z
1400 /* Notes:
1401 * There are several differences between this strptime and glibc's strptime.
1402 * 1) glibc strips leading space before numeric conversions.
1403 * 2) glibc will read fields without whitespace in between. SUSv3 states
1404 * that you must have whitespace between conversion operators. Besides,
1405 * how do you know how long a number should be if there are leading 0s?
1406 * 3) glibc attempts to compute some the struct tm fields based on the
1407 * data retrieved; tm_wday in particular. I don't as I consider it
1408 * another glibc attempt at mind-reading...
1411 #define NO_E_MOD 0x80
1412 #define NO_O_MOD 0x40
1414 #define ILLEGAL_SPEC 0x3f
1416 #define INT_SPEC 0x00 /* must be 0x00!! */
1417 #define STRING_SPEC 0x10 /* must be 0x10!! */
1418 #define CALC_SPEC 0x20
1419 #define STACKED_SPEC 0x30
1421 #define MASK_SPEC 0x30
1423 /* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
1424 static const unsigned char spec[] = {
1425 /* A */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1426 /* B */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1427 /* C */ 0x08 | INT_SPEC | NO_O_MOD,
1428 /* D */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1429 /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1430 /* F */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1431 /* G */ 0x0f | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1432 /* H */ 0x06 | INT_SPEC | NO_E_MOD,
1433 /* I */ 0x07 | INT_SPEC | NO_E_MOD,
1434 /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1435 /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1436 /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1437 /* M */ 0x04 | INT_SPEC | NO_E_MOD,
1438 /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1439 /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1440 /* P */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1441 /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1442 /* R */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1443 /* S */ 0x05 | INT_SPEC | NO_E_MOD,
1444 /* T */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1445 /* U */ 0x0c | INT_SPEC | NO_E_MOD,
1446 /* V */ 0x0d | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1447 /* W */ 0x0c | INT_SPEC | NO_E_MOD,
1448 /* X */ 0x0a | STACKED_SPEC | NO_O_MOD,
1449 /* Y */ 0x0a | INT_SPEC | NO_O_MOD,
1450 /* Z */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1452 /* WARNING! This assumes orderings:
1453 * AM,PM
1454 * ABDAY_1-ABDAY-7,DAY_1-DAY_7
1455 * ABMON_1-ABMON_12,MON_1-MON12
1456 * Also, there are exactly 6 bytes between 'Z' and 'a'.
1458 #define STRINGS_NL_ITEM_START (26)
1459 _NL_ITEM_INDEX(AM_STR), /* p (P) */
1460 _NL_ITEM_INDEX(ABMON_1), /* B, b */
1461 _NL_ITEM_INDEX(ABDAY_1), /* A, a */
1466 /* a */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1467 /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1468 /* c */ 0x08 | STACKED_SPEC | NO_O_MOD,
1469 /* d */ 0x00 | INT_SPEC | NO_E_MOD,
1470 /* e */ 0x00 | INT_SPEC | NO_E_MOD,
1471 /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1472 /* g */ 0x0e | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1473 /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1474 /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1475 /* j */ 0x01 | INT_SPEC | NO_E_MOD | NO_O_MOD,
1476 /* k */ 0x06 | INT_SPEC | NO_E_MOD, /* glibc */
1477 /* l */ 0x07 | INT_SPEC | NO_E_MOD, /* glibc */
1478 /* m */ 0x02 | INT_SPEC | NO_E_MOD,
1479 /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1480 /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1481 /* p */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1482 /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1483 /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1484 /* s */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1485 /* t */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1486 /* u */ 0x0b | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1487 /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1488 /* w */ 0x03 | INT_SPEC | NO_E_MOD,
1489 /* x */ 0x09 | STACKED_SPEC | NO_O_MOD,
1490 /* y */ 0x09 | INT_SPEC,
1491 /* z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1493 #define INT_FIELD_START (26+6+26)
1494 /* (field #) << 3 + lower bound (0|1) + correction 0:none, 2:-1, 4:-1900
1495 * followed by upper bound prior to correction with 1=>366 and 2=>9999. */
1496 /* d, e */ (3 << 3) + 1 + 0, 31,
1497 /* j */ (7 << 3) + 1 + 2, /* 366 */ 1,
1498 /* m */ (4 << 3) + 1 + 2, 12,
1499 /* w */ (6 << 3) + 0 + 0, 6,
1500 /* M */ (1 << 3) + 0 + 0, 59,
1501 /* S */ 0 + 0 + 0, 60,
1502 /* H (k) */ (2 << 3) + 0 + 0, 23,
1503 /* I (l) */ (9 << 3) + 1 + 0, 12, /* goes with 8 -- am/pm */
1504 /* C */ (10<< 3) + 0 + 0, 99,
1505 /* y */ (11<< 3) + 0 + 0, 99,
1506 /* Y */ (5 << 3) + 0 + 4, /* 9999 */ 2,
1507 /* u */ (6 << 3) + 1 + 0, 7,
1508 /* The following are processed and range-checked, but ignored otherwise. */
1509 /* U, W */ (12<< 3) + 0 + 0, 53,
1510 /* V */ (12<< 3) + 1 + 0, 53,
1511 /* g */ (12<< 3) + 0 + 0, 99,
1512 /* G */ (12<< 3) + 0 /*+ 4*/, /* 9999 */ 2, /* Note: -1 or 10000? */
1514 #define STACKED_STRINGS_START (INT_FIELD_START+32)
1515 5, 6, 14, 22, 27, /* 5 - offsets from offset-count to strings */
1516 ' ', 0, /* 2 - %n or %t */
1517 '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
1518 '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
1519 '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
1520 '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
1522 #define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 40)
1523 _NL_ITEM_INDEX(D_T_FMT), /* c */
1524 _NL_ITEM_INDEX(D_FMT), /* x */
1525 _NL_ITEM_INDEX(T_FMT), /* X */
1526 _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
1527 #ifdef ENABLE_ERA_CODE
1528 _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
1529 _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */
1530 _NL_ITEM_INDEX(ERA_T_FMT), /* EX */
1531 #endif
1534 #define MAX_PUSH 4
1536 char *__XL_NPP(strptime)(const char *__restrict buf, const char *__restrict format,
1537 struct tm *__restrict tm __LOCALE_PARAM)
1539 register const char *p;
1540 char *o;
1541 const char *stack[MAX_PUSH];
1542 int i, j, lvl;
1543 int fields[13];
1544 unsigned char mod;
1545 unsigned char code;
1547 i = 0;
1548 do {
1549 fields[i] = INT_MIN;
1550 } while (++i < 13);
1552 lvl = 0;
1553 p = format;
1555 LOOP:
1556 if (!*p) {
1557 if (lvl == 0) { /* Done. */
1558 if (fields[6] == 7) { /* Cleanup for %u here since just once. */
1559 fields[6] = 0; /* Don't use mod in case unset. */
1562 i = 0;
1563 do { /* Store the values into tm. */
1564 if (fields[i] != INT_MIN) {
1565 ((int *) tm)[i] = fields[i];
1567 } while (++i < 8);
1569 return (char *) buf; /* Success. */
1571 p = stack[--lvl];
1572 goto LOOP;
1575 if ((*p == '%') && (*++p != '%')) {
1576 mod = ILLEGAL_SPEC;
1577 if ((*p == 'O') || (*p == 'E')) { /* Modifier? */
1578 mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
1579 ++p;
1582 if (!*p
1583 || (((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
1584 || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
1586 return NULL; /* Illegal spec. */
1589 if ((code & MASK_SPEC) == STACKED_SPEC) {
1590 if (lvl == MAX_PUSH) {
1591 return NULL; /* Stack full so treat as illegal spec. */
1593 stack[lvl++] = ++p;
1594 if ((code &= 0xf) < 8) {
1595 p = ((const char *) spec) + STACKED_STRINGS_START + code;
1596 p += *((unsigned char *)p);
1597 goto LOOP;
1600 p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
1601 + (code & 7);
1602 #ifdef ENABLE_ERA_CODE
1603 if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
1604 && (*(o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1605 (int)(((unsigned char *)p)[4]))
1606 __LOCALE_ARG
1609 p = o;
1610 goto LOOP;
1612 #endif
1613 p = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1614 (int)(*((unsigned char *)p)))
1615 __LOCALE_ARG
1617 goto LOOP;
1620 ++p;
1622 if ((code & MASK_SPEC) == STRING_SPEC) {
1623 code &= 0xf;
1624 j = spec[STRINGS_NL_ITEM_START + 3 + code];
1625 i = _NL_ITEM(LC_TIME, spec[STRINGS_NL_ITEM_START + code]);
1626 /* Go backwards to check full names before abreviations. */
1627 do {
1628 --j;
1629 o = __XL_NPP(nl_langinfo)(i+j __LOCALE_ARG);
1630 if (!__XL_NPP(strncasecmp)(buf, o, strlen(o) __LOCALE_ARG) && *o) {
1631 do { /* Found a match. */
1632 ++buf;
1633 } while (*++o);
1634 if (!code) { /* am/pm */
1635 fields[8] = j * 12;
1636 if (fields[9] >= 0) { /* We have a previous %I or %l. */
1637 fields[2] = fields[9] + fields[8];
1639 } else { /* day (4) or month (6) */
1640 fields[2 + (code << 1)]
1641 = j % (spec[STRINGS_NL_ITEM_START + 3 + code] >> 1);
1643 goto LOOP;
1645 } while (j);
1646 return NULL; /* Failed to match. */
1649 if ((code & MASK_SPEC) == CALC_SPEC) {
1650 if ((code &= 0xf) < 1) { /* s or z*/
1651 time_t t;
1653 o = (char *) buf;
1654 i = errno;
1655 __set_errno(0);
1656 if (!ISSPACE(*buf)) { /* Signal an error if whitespace. */
1657 #ifdef TIME_T_IS_UNSIGNED
1658 t = __XL_NPP(strtoul)(buf, &o, 10 __LOCALE_ARG);
1659 #else
1660 t = __XL_NPP(strtol)(buf, &o, 10 __LOCALE_ARG);
1661 #endif
1663 if ((o == buf) || errno) { /* Not a number or overflow. */
1664 return NULL;
1666 __set_errno(i); /* Restore errno. */
1667 buf = o;
1669 if (!code) { /* s */
1670 localtime_r(&t, tm); /* TODO: check for failure? */
1671 i = 0;
1672 do { /* Now copy values from tm to fields. */
1673 fields[i] = ((int *) tm)[i];
1674 } while (++i < 8);
1677 /* TODO: glibc treats %Z as a nop. For now, do the same. */
1678 goto LOOP;
1681 assert((code & MASK_SPEC) == INT_SPEC);
1683 register const unsigned char *x;
1684 code &= 0xf;
1685 x = spec + INT_FIELD_START + (code << 1);
1686 if ((j = x[1]) < 3) { /* upper bound (inclusive) */
1687 j = ((j==1) ? 366 : 9999);
1689 i = -1;
1690 while (ISDIGIT(*buf)) {
1691 if (i < 0) {
1692 i = 0;
1694 if ((i = 10*i + (*buf - '0')) > j) { /* Overflow. */
1695 return NULL;
1697 ++buf;
1699 if (i < (*x & 1)) { /* This catches no-digit case too. */
1700 return NULL;
1702 if (*x & 2) {
1703 --i;
1705 if (*x & 4) {
1706 i -= 1900;
1709 if (*x == (9 << 3) + 1 + 0) { /* %I or %l */
1710 if (i == 12) {
1711 i = 0;
1713 if (fields[8] >= 0) { /* We have a previous %p or %P. */
1714 fields[2] = i + fields[8];
1718 fields[(*x) >> 3] = i;
1720 if (((unsigned char)(*x - (10 << 3) + 0 + 0)) <= 8) { /* %C or %y */
1721 if ((j = fields[10]) < 0) { /* No %C, so i must be %y data. */
1722 if (i <= 68) { /* Map [0-68] to 2000+i */
1723 i += 100;
1725 } else { /* Have %C data, but what about %y? */
1726 if ((i = fields[11]) < 0) { /* No %y data. */
1727 i = 0; /* Treat %y val as 0 following glibc's example. */
1729 i += 100*(j - 19);
1731 fields[5] = i;
1734 goto LOOP;
1735 } else if (ISSPACE(*p)) {
1736 ++p;
1737 while (ISSPACE(*buf)) {
1738 ++buf;
1740 goto LOOP;
1741 } else if (*buf++ == *p++) {
1742 goto LOOP;
1744 return NULL;
1746 # ifdef L_strptime_l
1747 libc_hidden_def(strptime_l)
1748 # endif
1750 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1752 #endif
1753 /**********************************************************************/
1754 #ifdef L_time
1756 #ifndef __BCC__
1757 #error The uClibc version of time is in sysdeps/linux/common.
1758 #endif
1760 time_t time(register time_t *tloc)
1762 struct timeval tv;
1763 register struct timeval *p = &tv;
1765 gettimeofday(p, NULL); /* This should never fail... */
1767 if (tloc) {
1768 *tloc = p->tv_sec;
1771 return p->tv_sec;
1774 #endif
1775 /**********************************************************************/
1776 #ifdef L_tzset
1778 static const char vals[] = {
1779 'T', 'Z', 0, /* 3 */
1780 'U', 'T', 'C', 0, /* 4 */
1781 25, 60, 60, 1, /* 4 */
1782 '.', 1, /* M */
1783 5, '.', 1,
1784 6, 0, 0, /* Note: overloaded for non-M non-J case... */
1785 0, 1, 0, /* J */
1786 ',', 'M', '4', '.', '1', '.', '0',
1787 ',', 'M', '1', '0', '.', '5', '.', '0', 0,
1788 ',', 'M', '3', '.', '2', '.', '0',
1789 ',', 'M', '1', '1', '.', '1', '.', '0', 0
1792 #define TZ vals
1793 #define UTC (vals + 3)
1794 #define RANGE (vals + 7)
1795 #define RULE (vals + 11 - 1)
1796 #define DEFAULT_RULES (vals + 22)
1797 #define DEFAULT_2007_RULES (vals + 38)
1799 /* Initialize to UTC. */
1800 int daylight = 0;
1801 long timezone = 0;
1802 char *tzname[2] = { (char *) UTC, (char *) (UTC-1) };
1804 __UCLIBC_MUTEX_INIT(_time_tzlock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
1806 rule_struct _time_tzinfo[2];
1808 static const char *getoffset(register const char *e, long *pn)
1810 register const char *s = RANGE-1;
1811 long n;
1812 int f;
1814 n = 0;
1815 f = -1;
1816 do {
1817 ++s;
1818 if (__isdigit_char(*e)) {
1819 f = *e++ - '0';
1821 if (__isdigit_char(*e)) {
1822 f = 10 * f + (*e++ - '0');
1824 if (((unsigned int)f) >= *s) {
1825 return NULL;
1827 n = (*s) * n + f;
1828 f = 0;
1829 if (*e == ':') {
1830 ++e;
1831 --f;
1833 } while (*s > 1);
1835 *pn = n;
1836 return e;
1839 static const char *getnumber(register const char *e, int *pn)
1841 #ifdef __BCC__
1842 /* bcc can optimize the counter if it thinks it is a pointer... */
1843 register const char *n = (const char *) 3;
1844 int f;
1846 f = 0;
1847 while (n && __isdigit_char(*e)) {
1848 f = 10 * f + (*e++ - '0');
1849 --n;
1852 *pn = f;
1853 return (n == (const char *) 3) ? NULL : e;
1854 #else /* __BCC__ */
1855 int n, f;
1857 n = 3;
1858 f = 0;
1859 while (n && __isdigit_char(*e)) {
1860 f = 10 * f + (*e++ - '0');
1861 --n;
1864 *pn = f;
1865 return (n == 3) ? NULL : e;
1866 #endif /* __BCC__ */
1870 #ifdef __UCLIBC_HAS_TZ_FILE__
1872 #ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1873 static smallint TZ_file_read; /* Let BSS initialization set this to 0. */
1874 #endif
1876 static char *read_TZ_file(char *buf)
1878 int r;
1879 int fd;
1880 char *p = NULL;
1882 fd = open(__UCLIBC_TZ_FILE_PATH__, O_RDONLY);
1883 if (fd >= 0) {
1884 #if 0
1885 /* TZ are small *files*. On files, short reads
1886 * only occur on EOF (unlike, say, pipes).
1887 * The code below is pedanticallly more correct,
1888 * but this way we always read at least twice:
1889 * 1st read is short, 2nd one is zero bytes.
1891 size_t todo = TZ_BUFLEN;
1892 p = buf;
1893 do {
1894 r = read(fd, p, todo);
1895 if (r < 0)
1896 goto ERROR;
1897 if (r == 0)
1898 break;
1899 p += r;
1900 todo -= r;
1901 } while (todo);
1902 #else
1903 /* Shorter, and does one fewer read syscall */
1904 r = read(fd, buf, TZ_BUFLEN);
1905 if (r < 0)
1906 goto ERROR;
1907 p = buf + r;
1908 #endif
1909 if ((p > buf) && (p[-1] == '\n')) { /* Must end with newline */
1910 p[-1] = 0;
1911 p = buf;
1912 #ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1913 TZ_file_read = 1;
1914 #endif
1915 } else {
1916 ERROR:
1917 p = NULL;
1919 close(fd);
1921 #ifdef __UCLIBC_FALLBACK_TO_ETC_LOCALTIME__
1922 else {
1923 fd = open("/etc/localtime", O_RDONLY);
1924 if (fd >= 0) {
1925 r = read(fd, buf, TZ_BUFLEN);
1926 if (r != TZ_BUFLEN
1927 || strncmp(buf, "TZif", 4) != 0
1928 || (unsigned char)buf[4] < 2
1929 || lseek(fd, -TZ_BUFLEN, SEEK_END) < 0
1931 goto ERROR;
1933 /* tzfile.h from tzcode database says about TZif2+ files:
1935 ** If tzh_version is '2' or greater, the above is followed by a second instance
1936 ** of tzhead and a second instance of the data in which each coded transition
1937 ** time uses 8 rather than 4 chars,
1938 ** then a POSIX-TZ-environment-variable-style string for use in handling
1939 ** instants after the last transition time stored in the file
1940 ** (with nothing between the newlines if there is no POSIX representation for
1941 ** such instants).
1943 r = read(fd, buf, TZ_BUFLEN);
1944 if (r <= 0 || buf[--r] != '\n')
1945 goto ERROR;
1946 buf[r] = 0;
1947 while (r != 0) {
1948 if (buf[--r] == '\n') {
1949 p = buf + r + 1;
1950 #ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1951 TZ_file_read = 1;
1952 #endif
1953 break;
1955 } /* else ('\n' not found): p remains NULL */
1956 close(fd);
1959 #endif /* __UCLIBC_FALLBACK_TO_ETC_LOCALTIME__ */
1960 return p;
1963 #endif /* __UCLIBC_HAS_TZ_FILE__ */
1965 void tzset(void)
1967 _time_tzset((time(NULL)) < new_rule_starts);
1970 void _time_tzset(int use_old_rules)
1972 register const char *e;
1973 register char *s;
1974 long off = 0;
1975 short *p;
1976 rule_struct new_rules[2];
1977 int n, count, f;
1978 char c;
1979 #ifdef __UCLIBC_HAS_TZ_FILE__
1980 char buf[TZ_BUFLEN];
1981 #endif
1982 #ifdef __UCLIBC_HAS_TZ_CACHING__
1983 static char oldval[TZ_BUFLEN]; /* BSS-zero'd. */
1984 #endif
1986 /* Put this inside the lock to prevent the possibility of two different
1987 * timezones being used in a threaded app. */
1988 __UCLIBC_MUTEX_LOCK(_time_tzlock);
1990 e = getenv(TZ); /* TZ env var always takes precedence. */
1992 #if defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__)
1993 if (e) {
1994 /* Never use TZfile if TZ env var is set. */
1995 TZ_file_read = 0;
1997 if (TZ_file_read) {
1998 /* We already parsed TZfile before, skip everything. */
1999 goto FAST_DONE;
2001 #endif
2003 /* Warning!!! Since uClibc doesn't do lib locking, the following is
2004 * potentially unsafe in a multi-threaded program since it is remotely
2005 * possible that another thread could call setenv() for TZ and overwrite
2006 * the string being parsed. So, don't do that... */
2008 #ifdef __UCLIBC_HAS_TZ_FILE__
2009 if (!e)
2010 e = read_TZ_file(buf);
2011 #endif
2012 if (!e /* TZ env var not set and no TZfile (or bad TZfile) */
2013 || !*e /* or set to empty string. */
2015 goto ILLEGAL;
2018 if (*e == ':') { /* Ignore leading ':'. */
2019 ++e;
2022 #ifdef __UCLIBC_HAS_TZ_CACHING__
2023 if (strcmp(e, oldval) == 0) {
2024 /* Same string as last time... nothing to do. */
2025 goto FAST_DONE;
2027 /* Make a copy of the TZ env string. It won't be nul-terminated if
2028 * it is too long, but it that case it will be illegal and will be reset
2029 * to the empty string anyway. */
2030 strncpy(oldval, e, TZ_BUFLEN);
2031 #endif
2033 count = 0;
2034 new_rules[1].tzname[0] = 0;
2035 LOOP:
2036 /* Get std or dst name. */
2037 c = 0;
2038 if (*e == '<') {
2039 ++e;
2040 c = '>';
2043 s = new_rules[count].tzname;
2044 n = 0;
2045 while (*e
2046 && isascii(*e) /* SUSv3 requires char in portable char set. */
2047 && (isalpha(*e)
2048 || (c && (isalnum(*e) || (*e == '+') || (*e == '-')))
2051 *s++ = *e++;
2052 if (++n > TZNAME_MAX) {
2053 goto ILLEGAL;
2056 *s = 0;
2058 if ((n < 3) /* Check for minimum length. */
2059 || (c && (*e++ != c)) /* Match any quoting '<'. */
2061 goto ILLEGAL;
2064 /* Get offset */
2065 s = (char *) e;
2066 if ((*e != '-') && (*e != '+')) {
2067 if (count && !__isdigit_char(*e)) {
2068 off -= 3600; /* Default to 1 hour ahead of std. */
2069 goto SKIP_OFFSET;
2071 --e;
2074 ++e;
2075 e = getoffset(e, &off);
2076 if (!e) {
2077 goto ILLEGAL;
2080 if (*s == '-') {
2081 off = -off; /* Save off in case needed for dst default. */
2083 SKIP_OFFSET:
2084 new_rules[count].gmt_offset = off;
2086 if (!count) {
2087 new_rules[1].gmt_offset = off; /* Shouldn't be needed... */
2088 if (*e) {
2089 ++count;
2090 goto LOOP;
2092 } else { /* OK, we have dst, so get some rules. */
2093 count = 0;
2094 if (!*e) { /* No rules so default to US rules. */
2095 e = use_old_rules ? DEFAULT_RULES : DEFAULT_2007_RULES;
2096 #ifdef DEBUG_TZSET
2097 if (e == DEFAULT_RULES)
2098 printf("tzset: Using old rules.\n");
2099 else if (e == DEFAULT_2007_RULES)
2100 printf("tzset: Using new rules\n");
2101 else
2102 printf("tzset: Using undefined rules\n");
2103 #endif
2106 do {
2107 if (*e++ != ',') {
2108 goto ILLEGAL;
2111 n = 365;
2112 s = (char *) RULE;
2113 c = *e++;
2114 if (c == 'M') {
2115 n = 12;
2116 } else if (c == 'J') {
2117 s += 8;
2118 } else {
2119 --e;
2120 c = 0;
2121 s += 6;
2124 p = &new_rules[count].rule_type;
2125 *p = c;
2126 if (c != 'M') {
2127 p -= 2;
2130 do {
2131 ++s;
2132 e = getnumber(e, &f);
2133 if (!e
2134 || ((unsigned int)(f - s[1]) > n)
2135 || (*s && (*e++ != *s))
2137 goto ILLEGAL;
2139 *--p = f;
2140 s += 2;
2141 n = *s;
2142 } while (n > 0);
2144 off = 2 * 60 * 60; /* Default to 2:00:00 */
2145 if (*e == '/') {
2146 ++e;
2147 e = getoffset(e, &off);
2148 if (!e) {
2149 goto ILLEGAL;
2152 new_rules[count].dst_offset = off;
2153 } while (++count < 2);
2155 if (*e) {
2156 ILLEGAL:
2157 #ifdef __UCLIBC_HAS_TZ_CACHING__
2158 oldval[0] = 0; /* oldval = "" */
2159 #endif
2160 memset(_time_tzinfo, 0, sizeof(_time_tzinfo));
2161 strcpy(_time_tzinfo[0].tzname, UTC);
2162 goto DONE;
2166 memcpy(_time_tzinfo, new_rules, sizeof(new_rules));
2167 DONE:
2168 tzname[0] = _time_tzinfo[0].tzname;
2169 tzname[1] = _time_tzinfo[1].tzname;
2170 daylight = !!_time_tzinfo[1].tzname[0];
2171 timezone = _time_tzinfo[0].gmt_offset;
2173 #if (defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__)) || \
2174 defined(__UCLIBC_HAS_TZ_CACHING__)
2175 FAST_DONE:
2176 #endif
2177 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
2179 libc_hidden_def(tzset)
2180 #endif
2181 /**********************************************************************/
2182 /* #ifdef L_utime */
2184 /* utime is a syscall in both linux and elks. */
2185 /* int utime(const char *path, const struct utimbuf *times) */
2187 /* #endif */
2188 /**********************************************************************/
2189 /* Non-SUSv3 */
2190 /**********************************************************************/
2191 #ifdef L_utimes
2193 #ifndef __BCC__
2194 #error The uClibc version of utimes is in sysdeps/linux/common.
2195 #endif
2197 #include <utime.h>
2199 int utimes(const char *filename, register const struct timeval *tvp)
2201 register struct utimbuf *p = NULL;
2202 struct utimbuf utb;
2204 if (tvp) {
2205 p = &utb;
2206 p->actime = tvp[0].tv_sec;
2207 p->modtime = tvp[1].tv_sec;
2209 return utime(filename, p);
2212 #endif
2213 /**********************************************************************/
2214 #ifdef L__time_t2tm
2216 static const uint16_t _vals[] = {
2217 60, 60, 24, 7 /* special */, 36524, 1461, 365, 0
2220 static const unsigned char days[] = {
2221 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
2225 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
2226 static const char utc_string[] = "UTC";
2227 #endif
2229 /* Notes:
2230 * If time_t is 32 bits, then no overflow is possible.
2231 * It time_t is > 32 bits, this needs to be adjusted to deal with overflow.
2234 /* Note: offset is the correction in _days_ to *timer! */
2236 struct tm attribute_hidden *_time_t2tm(const time_t *__restrict timer,
2237 int offset, struct tm *__restrict result)
2239 register int *p;
2240 time_t t1, t, v;
2241 int wday = wday; /* ok to be uninitialized, shutting up warning */
2244 register const uint16_t *vp;
2245 t = *timer;
2246 p = (int *) result;
2247 p[7] = 0;
2248 vp = _vals;
2249 do {
2250 if ((v = *vp) == 7) {
2251 /* Overflow checking, assuming time_t is long int... */
2252 #if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
2253 #if (INT_MAX == 2147483647L) && (LONG_MAX == 9223372036854775807L)
2254 /* Valid range for t is [-784223472856L, 784223421720L].
2255 * Outside of this range, the tm_year field will overflow. */
2256 if (((unsigned long)(t + offset- -784223472856L))
2257 > (784223421720L - -784223472856L)
2259 return NULL;
2261 #else
2262 #error overflow conditions unknown
2263 #endif
2264 #endif
2266 /* We have days since the epoch, so caluclate the weekday. */
2267 #if defined(__BCC__) && TIME_T_IS_UNSIGNED
2268 wday = (t + 4) % (*vp); /* t is unsigned */
2269 #else
2270 wday = ((int)((t % (*vp)) + 11)) % ((int)(*vp)); /* help bcc */
2271 #endif
2272 /* Set divisor to days in 400 years. Be kind to bcc... */
2273 v = ((time_t)(vp[1])) << 2;
2274 ++v;
2275 /* Change to days since 1/1/1601 so that for 32 bit time_t
2276 * values, we'll have t >= 0. This should be changed for
2277 * archs with larger time_t types.
2278 * Also, correct for offset since a multiple of 7. */
2280 /* TODO: Does this still work on archs with time_t > 32 bits? */
2281 t += (135140L - 366) + offset; /* 146097 - (365*30 + 7) -366 */
2283 #if defined(__BCC__) && TIME_T_IS_UNSIGNED
2284 t -= ((t1 = t / v) * v);
2285 #else
2286 if ((t -= ((t1 = t / v) * v)) < 0) {
2287 t += v;
2288 --t1;
2290 #endif
2292 if ((*vp == 7) && (t == v-1)) {
2293 --t; /* Correct for 400th year leap case */
2294 ++p[4]; /* Stash the extra day... */
2297 #if defined(__BCC__) && 0
2298 *p = t1;
2299 if (v <= 60) {
2300 *p = t;
2301 t = t1;
2303 ++p;
2304 #else
2305 if (v <= 60) {
2306 *p++ = t;
2307 t = t1;
2308 } else {
2309 *p++ = t1;
2311 #endif
2312 } while (*++vp);
2315 if (p[-1] == 4) {
2316 --p[-1];
2317 t = 365;
2320 *p += ((int) t); /* result[7] .. tm_yday */
2322 p -= 2; /* at result[5] */
2324 #if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
2325 /* Protect against overflow. TODO: Unecessary if int arith wraps? */
2326 *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + (p[1] - 299); /* tm_year */
2327 #else
2328 *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + p[1] - 299; /* tm_year */
2329 #endif
2331 p[1] = wday; /* result[6] .. tm_wday */
2334 register const unsigned char *d = days;
2336 wday = 1900 + *p;
2337 if (__isleap(wday)) {
2338 d += 11;
2341 wday = p[2] + 1; /* result[7] .. tm_yday */
2342 *--p = 0; /* at result[4] .. tm_mon */
2343 while (wday > *d) {
2344 wday -= *d;
2345 if (*d == 29) {
2346 d -= 11; /* Backup to non-leap Feb. */
2348 ++d;
2349 ++*p; /* Increment tm_mon. */
2351 p[-1] = wday; /* result[3] .. tm_mday */
2353 /* TODO -- should this be 0? */
2354 p[4] = 0; /* result[8] .. tm_isdst */
2355 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
2356 # ifdef __USE_BSD
2357 result->tm_gmtoff = 0;
2358 result->tm_zone = utc_string;
2359 # else
2360 result->__tm_gmtoff = 0;
2361 result->__tm_zone = utc_string;
2362 # endif
2363 #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
2365 return result;
2368 #endif
2369 /**********************************************************************/
2370 #ifdef L___time_tm
2372 struct tm __time_tm; /* Global shared by gmtime() and localtime(). */
2374 #endif
2375 /**********************************************************************/
2376 #ifdef L__time_mktime
2378 time_t attribute_hidden _time_mktime(struct tm *timeptr, int store_on_success)
2380 time_t t;
2382 __UCLIBC_MUTEX_LOCK(_time_tzlock);
2384 tzset();
2386 t = _time_mktime_tzi(timeptr, store_on_success, _time_tzinfo);
2388 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
2390 return t;
2393 #endif
2394 /**********************************************************************/
2395 #ifdef L__time_mktime_tzi
2397 static const unsigned char __vals[] = {
2398 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
2402 time_t attribute_hidden _time_mktime_tzi(struct tm *timeptr, int store_on_success,
2403 rule_struct *tzi)
2405 #ifdef __BCC__
2406 long days, secs;
2407 #else
2408 long long secs;
2409 #endif
2410 time_t t;
2411 struct tm x;
2412 /* 0:sec 1:min 2:hour 3:mday 4:mon 5:year 6:wday 7:yday 8:isdst */
2413 register int *p = (int *) &x;
2414 register const unsigned char *s;
2415 int d, default_dst;
2417 memcpy(p, timeptr, sizeof(struct tm));
2419 if (!tzi[1].tzname[0]) { /* No dst in this timezone, */
2420 p[8] = 0; /* so set tm_isdst to 0. */
2423 default_dst = 0;
2424 if (p[8]) { /* Either dst or unknown? */
2425 default_dst = 1; /* Assume advancing (even if unknown). */
2426 p[8] = ((p[8] > 0) ? 1 : -1); /* Normalize so abs() <= 1. */
2429 d = 400;
2430 p[5] = (p[5] - ((p[6] = p[5]/d) * d)) + (p[7] = p[4]/12);
2431 if ((p[4] -= 12 * p[7]) < 0) {
2432 p[4] += 12;
2433 --p[5];
2436 s = __vals;
2437 d = (p[5] += 1900); /* Correct year. Now between 1900 and 2300. */
2438 if (__isleap(d)) {
2439 s += 11;
2442 p[7] = 0;
2443 d = p[4];
2444 while (d) {
2445 p[7] += *s;
2446 if (*s == 29) {
2447 s -= 11; /* Backup to non-leap Feb. */
2449 ++s;
2450 --d;
2453 _time_tzset (x.tm_year < 2007); /* tm_year was expanded above */
2455 #ifdef __BCC__
2456 d = p[5] - 1;
2457 days = -719163L + ((long)d)*365 + ((d/4) - (d/100) + (d/400) + p[3] + p[7]);
2458 secs = p[0] + 60*( p[1] + 60*((long)(p[2])) )
2459 + tzi[default_dst].gmt_offset;
2460 DST_CORRECT:
2461 if (secs < 0) {
2462 secs += 120009600L;
2463 days -= 1389;
2465 if ( ((unsigned long)(days + secs/86400L)) > 49710L) {
2466 t = ((time_t)(-1));
2467 goto DONE;
2469 secs += (days * 86400L);
2470 #else
2471 d = p[5] - 1;
2472 d = -719163L + d*365 + (d/4) - (d/100) + (d/400);
2473 secs = p[0]
2474 + tzi[default_dst].gmt_offset
2475 + 60*( p[1]
2476 + 60*(p[2]
2477 + 24*(((146073L * ((long long)(p[6])) + d)
2478 + p[3]) + p[7])));
2480 DST_CORRECT:
2481 #if defined(__UCLIBC_USE_TIME64__)
2482 if (((unsigned long long)(secs - LLONG_MIN))
2483 > (((unsigned long long)LLONG_MAX) - LLONG_MIN)
2485 #else
2486 if (((unsigned long long)(secs - LONG_MIN))
2487 > (((unsigned long long)LONG_MAX) - LONG_MIN)
2489 #endif
2491 t = ((time_t)(-1));
2492 goto DONE;
2494 #endif
2496 d = ((struct tm *)p)->tm_isdst;
2497 t = secs;
2499 __time_localtime_tzi(&t, (struct tm *)p, tzi);
2501 if (t == ((time_t)(-1))) { /* Remember, time_t can be unsigned. */
2502 goto DONE;
2505 if ((d < 0) && (((struct tm *)p)->tm_isdst != default_dst)) {
2506 #ifdef __BCC__
2507 secs -= (days * 86400L);
2508 #endif
2509 secs += (tzi[1-default_dst].gmt_offset
2510 - tzi[default_dst].gmt_offset);
2511 goto DST_CORRECT;
2515 if (store_on_success) {
2516 memcpy(timeptr, p, sizeof(struct tm));
2520 DONE:
2521 return t;
2524 #endif
2525 /**********************************************************************/
2526 #if (defined(L_wcsftime) || defined(L_wcsftime_l))
2528 /* Implemented via strftime / strftime_l wchar_t variants */
2530 #endif
2531 /**********************************************************************/
2532 #ifdef L_dysize
2533 /* Return the number of days in YEAR. */
2535 int dysize(int year)
2537 return __isleap(year) ? 366 : 365;
2540 #endif
2541 /**********************************************************************/