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.
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
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.
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
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
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
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.
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.
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
128 * NOTE: We set uninitialized timezone names to "???", and this
129 * differs (intentionally) from glibc's behavior.
137 #include <sys/time.h>
142 #include <langinfo.h>
146 #include <bits/uClibc_uintmaxtostr.h>
147 #include <bits/uClibc_mutex.h>
149 #ifdef __UCLIBC_HAS_WCHAR__
154 #define __isleap(y) ( !((y) % 4) && ( ((y) % 100) || !((y) % 400) ) )
158 #define TZNAME_MAX _POSIX_TZNAME_MAX
161 #if defined (L_tzset) || defined (L_localtime_r) || defined(L_strftime) || \
162 defined(L__time_mktime) || defined(L__time_mktime_tzi) || \
163 ((defined(L_strftime) || defined(L_strftime_l)) && \
164 defined(__UCLIBC_HAS_XLOCALE__))
166 void _time_tzset(int use_old_rules) attribute_hidden;
168 #ifndef L__time_mktime
170 /* Jan 1, 2007 Z - tm = 0,0,0,1,0,107,1,0,0 */
172 static const time_t new_rule_starts = 1167609600;
177 /**********************************************************************/
178 /* The era code is currently unfinished. */
179 /* #define ENABLE_ERA_CODE */
181 #define TZ_BUFLEN (2*TZNAME_MAX + 56)
183 #ifdef __UCLIBC_HAS_TZ_FILE__
185 #include <sys/stat.h>
187 /* ":<tzname>+hh:mm:ss<tzname>+hh:mm:ss,Mmm.w.d/hh:mm:ss,Mmm.w.d/hh:mm:ss" + nul */
188 /* 1 + 2*(1+TZNAME_MAX+1 + 9 + 7 + 9) + 1 = 2*TZNAME_MAX + 56 */
190 #else /* __UCLIBC_HAS_TZ_FILE__ */
192 /* Probably no longer needed. */
193 #undef __UCLIBC_HAS_TZ_FILE_READ_MANY__
195 #endif /* __UCLIBC_HAS_TZ_FILE__ */
197 /**********************************************************************/
199 extern struct tm __time_tm attribute_hidden;
204 short day; /* for J or normal */
207 short rule_type; /* J, M, \0 */
208 char tzname[TZNAME_MAX+1];
211 __UCLIBC_MUTEX_EXTERN(_time_tzlock) attribute_hidden;
213 extern rule_struct _time_tzinfo[2] attribute_hidden;
215 extern struct tm *_time_t2tm(const time_t *__restrict timer,
216 int offset, struct tm *__restrict result) attribute_hidden;
218 extern time_t _time_mktime(struct tm *timeptr, int store_on_success) attribute_hidden;
220 extern struct tm *__time_localtime_tzi(const time_t *__restrict timer,
221 struct tm *__restrict result,
222 rule_struct *tzi) attribute_hidden;
224 extern time_t _time_mktime_tzi(struct tm *timeptr, int store_on_success,
225 rule_struct *tzi) attribute_hidden;
227 /**********************************************************************/
230 static char __time_str[26];
232 char *asctime(const struct tm *ptm)
234 return asctime_r(ptm, __time_str);
236 libc_hidden_def(asctime)
239 /**********************************************************************/
242 /* Strictly speaking, this implementation isn't correct. ANSI/ISO specifies
243 * that the implementation of asctime() be equivalent to
245 * char *asctime(const struct tm *timeptr)
247 * static char wday_name[7][3] = {
248 * "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
250 * static char mon_name[12][3] = {
251 * "Jan", "Feb", "Mar", "Apr", "May", "Jun",
252 * "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
254 * static char result[26];
256 * sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
257 * wday_name[timeptr->tm_wday],
258 * mon_name[timeptr->tm_mon],
259 * timeptr->tm_mday, timeptr->tm_hour,
260 * timeptr->tm_min, timeptr->tm_sec,
261 * 1900 + timeptr->tm_year);
265 * but the above is either inherently unsafe, or carries with it the implicit
266 * assumption that all fields of timeptr fall within their usual ranges, and
267 * that the tm_year value falls in the range [-2899,8099] to avoid overflowing
270 * If we take the implicit assumption as given, then the implementation below
271 * is still incorrect for tm_year values < -900, as there will be either
272 * 0-padding and/or a missing negative sign for the year conversion . But given
273 * the usual use of asctime(), I think it isn't unreasonable to restrict correct
274 * operation to the domain of years between 1000 and 9999.
277 /* This is generally a good thing, but if you're _sure_ any data passed will be
278 * in range, you can #undef this. */
279 #define SAFE_ASCTIME_R 1
281 static const unsigned char at_data[] = {
282 'S', 'u', 'n', 'M', 'o', 'n', 'T', 'u', 'e', 'W', 'e', 'd',
283 'T', 'h', 'u', 'F', 'r', 'i', 'S', 'a', 't',
285 'J', 'a', 'n', 'F', 'e', 'b', 'M', 'a', 'r', 'A', 'p', 'r',
286 'M', 'a', 'y', 'J', 'u', 'n', 'J', 'u', 'l', 'A', 'u', 'g',
287 'S', 'e', 'p', 'O', 'c', 't', 'N', 'o', 'v', 'D', 'e', 'c',
289 #ifdef SAFE_ASCTIME_R
294 offsetof(struct tm, tm_mday),
296 offsetof(struct tm, tm_hour),
298 offsetof(struct tm, tm_min),
300 offsetof(struct tm, tm_sec),
301 ' ', '?', '?', '?', '?', '\n', 0
304 char *asctime_r(register const struct tm *__restrict ptm,
305 register char *__restrict buffer)
312 #ifdef SAFE_ASCTIME_R
313 memcpy(buffer, at_data + 3*(7 + 12), sizeof(at_data) - 3*(7 + 12));
315 if (((unsigned int)(ptm->tm_wday)) <= 6) {
316 memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);
319 if (((unsigned int)(ptm->tm_mon)) <= 11) {
320 memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
323 assert(((unsigned int)(ptm->tm_wday)) <= 6);
324 assert(((unsigned int)(ptm->tm_mon)) <= 11);
326 memcpy(buffer, at_data + 3*(7 + 12) - 3, sizeof(at_data) + 3 - 3*(7 + 12));
328 memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);
329 memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
332 #ifdef SAFE_ASCTIME_R
334 tmp = ptm->tm_year + 1900;
335 if (((unsigned int) tmp) < 10000) {
338 *buffer = '0' + (tmp % 10);
340 } while (*--buffer == '?');
342 /* Not sure if we should even bother ...
344 __set_errno(EOVERFLOW);
348 #else /* SAFE_ASCTIME_R */
350 tmp = ptm->tm_year + 1900;
351 assert( ((unsigned int) tmp) < 10000 );
352 /* Not sure if we should even bother ...
353 if ( ((unsigned int) tmp) >= 10000 ) {
354 __set_errno(EOVERFLOW);
359 *buffer = '0' + (tmp % 10);
361 } while (*--buffer == '?');
362 #endif /* SAFE_ASCTIME_R */
366 tmp = *((int *)(((const char *) ptm) + (int) *buffer));
367 #ifdef SAFE_ASCTIME_R
368 if (((unsigned int) tmp) >= 100) { /* Just check 2 digit non-neg. */
369 buffer[-1] = *buffer = '?';
372 assert(((unsigned int) tmp) < 100); /* Just check 2 digit non-neg. */
375 *buffer = '0' + (tmp % 10);
377 buffer[-1] = '0' + (tmp/10);
379 buffer[-1] += (tmp/10);
382 } while ((buffer -= 2)[-2] == '0');
384 if (*++buffer == '0') { /* Space-pad day of month. */
390 libc_hidden_def(asctime_r)
393 /**********************************************************************/
396 #include <sys/times.h>
399 #if CLOCKS_PER_SEC != 1000000L
400 #error unexpected value for CLOCKS_PER_SEC!
404 #ifdef __UCLIBC_CLK_TCK_CONST
405 # if __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC
406 # error __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC!
407 # elif __UCLIBC_CLK_TCK_CONST < 1
408 # error __UCLIBC_CLK_TCK_CONST < 1!
414 * On XSI-conformant systems, CLOCKS_PER_SEC is defined to be one million.
416 * The value returned by clock() may wrap around on some implementations.
417 * For example, on a machine with 32-bit values for clock_t, it wraps
418 * after 2147 seconds.
420 * This implies that we should bitwise and with LONG_MAX.
430 t = ((unsigned long) xtms.tms_utime) + xtms.tms_stime;
432 #ifndef __UCLIBC_CLK_TCK_CONST
434 # error __UCLIBC_CLK_TCK_CONST not defined!
436 #elif ((CLOCKS_PER_SEC % __UCLIBC_CLK_TCK_CONST) == 0)
438 /* CLOCKS_PER_SEC == k * __UCLIBC_CLK_TCK_CONST for some integer k >= 1. */
439 return ((t * (CLOCKS_PER_SEC/__UCLIBC_CLK_TCK_CONST)) & LONG_MAX);
443 /* Unlike the previous case, the scaling factor is not an integer.
444 * So when tms_utime, tms_stime, or their sum wraps, some of the
445 * "visible" bits in the return value are affected. Nothing we
446 * can really do about this though other than handle tms_utime and
447 * tms_stime seperately and then sum. But since that doesn't really
448 * buy us much, we don't bother. */
450 return ((((t / __UCLIBC_CLK_TCK_CONST) * CLOCKS_PER_SEC)
451 + ((((t % __UCLIBC_CLK_TCK_CONST) * CLOCKS_PER_SEC)
452 / __UCLIBC_CLK_TCK_CONST))
459 /**********************************************************************/
462 char *ctime(const time_t *t)
464 /* ANSI/ISO/SUSv3 say that ctime is equivalent to the following:
465 * return asctime(localtime(t));
466 * I don't think "equivalent" means "it uses the same internal buffer",
467 * it means "gives the same resultant string".
469 * I doubt anyone ever uses weird code like:
470 * struct tm *ptm = localtime(t1); ...; ctime(t2); use(ptm);
471 * which relies on the assumption that ctime's and localtime's
472 * internal static struct tm is the same.
474 * Using localtime_r instead of localtime avoids linking in
475 * localtime's static buffer:
478 memset(&xtm, 0, sizeof(xtm));
480 return asctime(localtime_r(t, &xtm));
482 libc_hidden_def(ctime)
484 /**********************************************************************/
487 char *ctime_r(const time_t *t, char *buf)
491 return asctime_r(localtime_r(t, &xtm), buf);
495 /**********************************************************************/
501 #error difftime implementation assumptions violated for you arch!
504 double difftime(time_t time1, time_t time0)
506 #if (LONG_MAX >> DBL_MANT_DIG) == 0
508 /* time_t fits in the mantissa of a double. */
509 return (double)time1 - (double)time0;
511 #elif ((LONG_MAX >> DBL_MANT_DIG) >> DBL_MANT_DIG) == 0
513 /* time_t can overflow the mantissa of a double. */
516 d = ((time_t) 1) << DBL_MANT_DIG;
522 /* Since FLT_RADIX==2 and d is a power of 2, the only possible
523 * rounding error in the expression below would occur from the
525 return (((double) t1) - t0) * d + (((double) time1) - time0);
528 #error difftime needs special implementation on your arch.
533 /**********************************************************************/
536 struct tm *gmtime(const time_t *timer)
538 register struct tm *ptm = &__time_tm;
540 _time_t2tm(timer, 0, ptm); /* Can return NULL... */
546 /**********************************************************************/
549 struct tm *gmtime_r(const time_t *__restrict timer,
550 struct tm *__restrict result)
552 return _time_t2tm(timer, 0, result);
556 /**********************************************************************/
559 struct tm *localtime(const time_t *timer)
561 register struct tm *ptm = &__time_tm;
563 /* In this implementation, tzset() is called by localtime_r(). */
565 localtime_r(timer, ptm); /* Can return NULL... */
569 libc_hidden_def(localtime)
572 /**********************************************************************/
575 struct tm *localtime_r(register const time_t *__restrict timer,
576 register struct tm *__restrict result)
578 __UCLIBC_MUTEX_LOCK(_time_tzlock);
580 _time_tzset(*timer < new_rule_starts);
582 __time_localtime_tzi(timer, result, _time_tzinfo);
584 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
588 libc_hidden_def(localtime_r)
591 /**********************************************************************/
592 #ifdef L__time_localtime_tzi
594 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
596 struct ll_tzname_item;
598 typedef struct ll_tzname_item {
599 struct ll_tzname_item *next;
603 /* Structures form a list "UTC" -> "???" -> "tzname1" -> "tzname2"... */
605 struct ll_tzname_item *next;
607 } ll_tzname_UNKNOWN = { NULL, "???" };
608 static const struct {
609 struct ll_tzname_item *next;
611 } ll_tzname_UTC = { (void*)&ll_tzname_UNKNOWN, "UTC" };
613 static const char *lookup_tzname(const char *key)
616 ll_tzname_item_t *p = (void*) &ll_tzname_UTC;
619 if (strcmp(p->tzname, key) == 0)
624 /* Hmm... a new name. */
625 len = strnlen(key, TZNAME_MAX+1);
626 if (len < TZNAME_MAX+1) { /* Verify legal length */
627 p = malloc(sizeof(ll_tzname_item_t) + len);
629 /* Insert as 3rd item in the list. */
630 p->next = ll_tzname_UNKNOWN.next;
631 ll_tzname_UNKNOWN.next = p;
632 return strcpy(p->tzname, key);
636 /* Either invalid or couldn't alloc. */
637 return ll_tzname_UNKNOWN.tzname;
640 #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
642 static const unsigned char day_cor[] = { /* non-leap */
643 31, 31, 34, 34, 35, 35, 36, 36, 36, 37, 37, 38, 38
644 /* 0, 0, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7 */
645 /* 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 */
648 /* Note: timezone locking is done by localtime_r. */
650 static int tm_isdst(register const struct tm *__restrict ptm,
651 register rule_struct *r)
654 int i, isdst, isleap, day, day0, monlen, mday;
655 int oday = oday; /* ok to be uninitialized, shutting up compiler warning */
658 if (r[1].tzname[0] != 0) {
659 /* First, get the current seconds offset from the start of the year.
660 * Fields of ptm are assumed to be in their normal ranges. */
663 + 60 * (long)(ptm->tm_hour
664 + 24 * ptm->tm_yday));
665 /* Do some prep work. */
666 i = (ptm->tm_year % 400) + 1900; /* Make sure we don't overflow. */
667 isleap = __isleap(i);
670 + i /* Normal years increment 1 wday. */
676 day = r->day; /* Common for 'J' and # case. */
677 if (r->rule_type == 'J') {
678 if (!isleap || (day < (31+29))) {
681 } else if (r->rule_type == 'M') {
682 /* Find 0-based day number for 1st of the month. */
683 day = 31 * r->month - day_cor[r->month - 1];
684 if (isleap && (day >= 59)) {
687 monlen = 31 + day_cor[r->month - 1] - day_cor[r->month];
688 if (isleap && (r->month == 2)) {
691 /* Weekday (0 is Sunday) of 1st of the month
692 * is (day0 + day) % 7. */
693 mday = r->day - ((day0 + day) % 7);
695 mday -= 7; /* Back up into prev month since r->week > 0. */
698 if (mday >= monlen) {
701 /* So, 0-based day number is... */
706 /* Adjust sec since dst->std change time is in dst. */
707 sec += (r[-1].gmt_offset - r->gmt_offset);
709 ++isdst; /* Year starts in dst. */
714 /* Now convert day to seconds and add offset and compare. */
715 if (sec >= (day * 86400L) + r->dst_offset) {
725 struct tm attribute_hidden *__time_localtime_tzi(register const time_t *__restrict timer,
726 register struct tm *__restrict result,
736 offset = 604800L - tzi[dst].gmt_offset;
737 if (*timer > (LONG_MAX - 604800L)) {
741 *x = *timer + offset;
743 _time_t2tm(x, days, result);
744 result->tm_isdst = dst;
745 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
747 result->tm_gmtoff = - tzi[dst].gmt_offset;
748 result->tm_zone = lookup_tzname(tzi[dst].tzname);
750 result->__tm_gmtoff = - tzi[dst].gmt_offset;
751 result->__tm_zone = lookup_tzname(tzi[dst].tzname);
753 #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
755 && ((result->tm_isdst = tm_isdst(result, tzi)) != 0));
761 /**********************************************************************/
764 time_t mktime(struct tm *timeptr)
766 return _time_mktime(timeptr, 1);
769 /* Another name for `mktime'. */
770 /* time_t timelocal(struct tm *tp) */
771 strong_alias(mktime,timelocal)
774 /**********************************************************************/
776 /* Like `mktime' but timeptr represents Universal Time, not local time. */
778 time_t timegm(struct tm *timeptr)
780 rule_struct gmt_tzinfo[2];
782 memset(gmt_tzinfo, 0, sizeof(gmt_tzinfo));
783 strcpy(gmt_tzinfo[0].tzname, "GMT"); /* Match glibc behavior here. */
785 return _time_mktime_tzi(timeptr, 1, gmt_tzinfo);
789 /**********************************************************************/
790 #if defined(L_strftime) || defined(L_strftime_l)
792 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
794 size_t strftime(char *__restrict s, size_t maxsize,
795 const char *__restrict format,
796 const struct tm *__restrict timeptr)
798 return strftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE);
801 #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
803 #define NO_E_MOD 0x80
804 #define NO_O_MOD 0x40
806 #define ILLEGAL_SPEC 0x3f
808 #define INT_SPEC 0x00 /* must be 0x00!! */
809 #define STRING_SPEC 0x10 /* must be 0x10!! */
810 #define CALC_SPEC 0x20
811 #define STACKED_SPEC 0x30
813 #define MASK_SPEC 0x30
817 * No alternate digit (%O?) handling. Always uses 0-9.
818 * Alternate locale format (%E?) handling is broken for nontrivial ERAs.
819 * glibc's %P is currently faked by %p. This means it doesn't do lower case.
820 * glibc's %k, %l, and %s are handled.
821 * glibc apparently allows (and ignores) extraneous 'E' and 'O' modifiers,
822 * while they are flagged as illegal conversions here.
825 /* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
826 static const unsigned char spec[] = {
827 /* A */ 0x03 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
828 /* B */ 0x04 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
829 /* C */ 0x0a | INT_SPEC | NO_O_MOD,
830 /* D */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
831 /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
832 /* F */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
833 /* G */ 0x03 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
834 /* H */ 0x0b | INT_SPEC | NO_E_MOD,
835 /* I */ 0x0c | INT_SPEC | NO_E_MOD,
836 /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
837 /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
838 /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
839 /* M */ 0x0d | INT_SPEC | NO_E_MOD,
840 /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
841 /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
842 /* P */ 0x05 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc ; use %p */
843 /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
844 /* R */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
845 /* S */ 0x0e | INT_SPEC | NO_E_MOD,
846 /* T */ 0x05 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
847 /* U */ 0x04 | CALC_SPEC | NO_E_MOD,
848 /* V */ 0x05 | CALC_SPEC | NO_E_MOD,
849 /* W */ 0x06 | CALC_SPEC | NO_E_MOD,
850 /* X */ 0x0a | STACKED_SPEC | NO_O_MOD,
851 /* Y */ 0x0f | INT_SPEC | NO_O_MOD,
852 /* Z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
859 /* a */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
860 /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
861 /* c */ 0x08 | STACKED_SPEC | NO_O_MOD,
862 /* d */ 0x00 | INT_SPEC | NO_E_MOD,
863 /* e */ 0x01 | INT_SPEC | NO_E_MOD,
864 /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
865 /* g */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
866 /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* same as b */
867 /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
868 /* j */ 0x08 | INT_SPEC | NO_E_MOD | NO_O_MOD,
869 /* k */ 0x03 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
870 /* l */ 0x04 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
871 /* m */ 0x05 | INT_SPEC | NO_E_MOD,
872 /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
873 /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
874 /* p */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
875 /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
876 /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
877 /* s */ 0x07 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
878 /* t */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
879 /* u */ 0x07 | INT_SPEC | NO_E_MOD,
880 /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
881 /* w */ 0x02 | INT_SPEC | NO_E_MOD,
882 /* x */ 0x09 | STACKED_SPEC | NO_O_MOD,
883 /* y */ 0x09 | INT_SPEC,
884 /* z */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
887 /* WARNING!!! These are dependent on the layout of struct tm!!! */
888 #define FIELD_MAX (26+6+26)
889 60 /* 61? */, 59, 23, 31, 11, 0 /* 9999 */, 6, 0 /* 365 */,
891 #define TP_OFFSETS (FIELD_MAX+8)
898 0, /* CURRENTLY UNUSED */
899 /* NOTE: u,j,y order must be preserved as 6,7,5 seq is used in the code! */
900 #define CALC_OFFSETS (TP_OFFSETS + 7)
917 #define TP_CODES (TP_OFFSETS + 16 + 6)
924 0, /* CURRENTLY UNUSED */
927 2 | 128 | 32 | 16 , /* y */
928 2 | 128 | 64 | 32 | 16 , /* C */
930 2 | 32 | 16 | 0, /* I */
941 #define STRINGS_NL_ITEM_START (TP_CODES + 16 + 6)
942 _NL_ITEM_INDEX(ABDAY_1), /* a */
943 _NL_ITEM_INDEX(ABMON_1), /* b, h */
944 _NL_ITEM_INDEX(AM_STR), /* p */
945 _NL_ITEM_INDEX(DAY_1), /* A */
946 _NL_ITEM_INDEX(MON_1), /* B */
947 _NL_ITEM_INDEX(AM_STR), /* P -- wrong! need lower case */
949 #define STACKED_STRINGS_START (STRINGS_NL_ITEM_START+6)
950 6, 7, 8, 16, 24, 29, /* 6 - offsets from offset-count to strings */
953 '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
954 '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
955 '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
956 '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
958 #define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 43)
959 _NL_ITEM_INDEX(D_T_FMT), /* c */
960 _NL_ITEM_INDEX(D_FMT), /* x */
961 _NL_ITEM_INDEX(T_FMT), /* X */
962 _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
963 #ifdef ENABLE_ERA_CODE
964 _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
965 _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */
966 _NL_ITEM_INDEX(ERA_T_FMT), /* EX */
970 static int load_field(int k, const struct tm *__restrict timeptr)
975 r = ((int *) timeptr)[k];
977 r_max = spec[FIELD_MAX + k];
986 if ((((unsigned int) r) > r_max) || ((k == 3) && !r)) {
995 #ifdef __UCLIBC_MJN3_ONLY__
996 #warning TODO: Check multibyte format string validity.
999 size_t __XL_NPP(strftime)(char *__restrict s, size_t maxsize,
1000 const char *__restrict format,
1001 const struct tm *__restrict timeptr __LOCALE_PARAM )
1004 register const char *p;
1005 register const char *o;
1006 #ifndef __UCLIBC_HAS_TM_EXTENSIONS__
1007 const rule_struct *rsp;
1009 const char *stack[MAX_PUSH];
1012 int field_val = 0, i = 0, j, lvl;
1013 int x[3]; /* wday, yday, year */
1015 char buf[__UIM_BUFLEN_LONG];
1019 /* We'll, let's get this out of the way. */
1020 _time_tzset(_time_mktime((struct tm *) timeptr, 0) < new_rule_starts);
1032 *s = 0; /* nul-terminate */
1033 return maxsize - count;
1040 if ((*(o = p) == '%') && (*++p != '%')) {
1043 if ((*p == 'O') || (*p == 'E')) { /* modifier */
1044 mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
1048 if ((((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
1049 || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
1057 code &= ILLEGAL_SPEC; /* modifiers are preserved in mod var. */
1059 if ((code & MASK_SPEC) == STACKED_SPEC) {
1060 if (lvl == MAX_PUSH) {
1061 goto OUTPUT; /* Stack full so treat as illegal spec. */
1064 if ((code &= 0xf) < 8) {
1065 p = ((const char *) spec) + STACKED_STRINGS_START + code;
1066 p += *((unsigned char *)p);
1069 p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
1071 #ifdef ENABLE_ERA_CODE
1072 if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
1073 && (*(o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1074 (int)(((unsigned char *)p)[4]))
1082 p = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1083 (int)(*((unsigned char *)p)))
1089 o = ((const char *) spec) + 26; /* set to "????" */
1090 if ((code & MASK_SPEC) == CALC_SPEC) {
1095 /* Use a cast to silence the warning since *timeptr won't
1097 if ((t = _time_mktime((struct tm *) timeptr, 0))
1103 #ifdef TIME_T_IS_UNSIGNED
1104 o = _uintmaxtostr(buf + sizeof(buf) - 1,
1108 o = _uintmaxtostr(buf + sizeof(buf) - 1,
1110 -10, __UIM_DECIMAL);
1112 o_count = sizeof(buf);
1114 } else if (((*p) | 0x20) == 'z') { /* 'z' or 'Z' */
1116 if (timeptr->tm_isdst < 0) {
1117 /* SUSv3 specifies this behavior for 'z', but we'll also
1118 * treat it as "no timezone info" for 'Z' too. */
1123 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1126 # define RSP_TZNAME timeptr->tm_zone
1127 # define RSP_GMT_OFFSET (-timeptr->tm_gmtoff)
1129 # define RSP_TZNAME timeptr->__tm_zone
1130 # define RSP_GMT_OFFSET (-timeptr->__tm_gmtoff)
1135 #define RSP_TZNAME rsp->tzname
1136 #define RSP_GMT_OFFSET rsp->gmt_offset
1138 __UCLIBC_MUTEX_LOCK(_time_tzlock);
1141 if (timeptr->tm_isdst > 0) {
1148 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1149 /* Sigh... blasted glibc extensions. Of course we can't
1150 * count on the pointer being valid. Best we can do is
1151 * handle NULL, which looks to be all that glibc does.
1152 * At least that catches the memset() with 0 case.
1153 * NOTE: We handle this case differently than glibc!
1154 * It uses system timezone name (based on tm_isdst) in this
1155 * case... although it always seems to use the embedded
1156 * tm_gmtoff value. What we'll do instead is treat the
1157 * timezone name as unknown/invalid and return "???". */
1164 if (!o) { /* PARANOIA */
1165 o = spec+30; /* empty string */
1169 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1174 if ((tzo = -RSP_GMT_OFFSET) < 0) {
1182 field_val = ((i / 60) * 100) + (i % 60);
1184 i = 16 + 6; /* 0-fill, width = 4 */
1186 #ifndef __UCLIBC_HAS_TM_EXTENSIONS__
1187 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
1193 /* TODO: don't need year for U, W */
1194 for (i=0 ; i < 3 ; i++) {
1195 if ((x[i] = load_field(spec[CALC_OFFSETS+i],timeptr)) < 0) {
1200 i = 16 + 2; /* 0-fill, width = 2 */
1202 if ((*p == 'U') || (*p == 'W')) {
1203 field_val = ((x[1] - x[0]) + 7);
1208 if ((*p == 'W') && !x[0]) {
1211 } else { /* ((*p == 'g') || (*p == 'G') || (*p == 'V')) */
1213 isofm = (((x[1] - x[0]) + 11) % 7) - 3; /* [-3,3] */
1215 if (x[1] < isofm) { /* belongs to previous year */
1217 x[1] += 365 + __isleap(x[2]);
1221 field_val = ((x[1] - isofm) / 7) + 1; /* week # */
1222 days = 365 + __isleap(x[2]);
1223 isofm = ((isofm + 7*53 + 3 - days)) % 7 + days - 3; /* next year */
1224 if (x[1] >= isofm) { /* next year */
1230 if (*p != 'V') { /* need year */
1231 field_val = x[2]; /* TODO: what if x[2] now 10000 ?? */
1235 i = 16 + 6; /* 0-fill, width = 4 */
1241 i = TP_OFFSETS + (code & 0x1f);
1242 if ((field_val = load_field(spec[i], timeptr)) < 0) {
1246 i = spec[i+(TP_CODES - TP_OFFSETS)];
1248 j = (i & 128) ? 100: 12;
1254 if (((i & 128) + field_val) == 0) { /* mod 12? == 0 */
1255 field_val = j; /* set to 12 */
1258 field_val += (i & 1);
1259 if ((i & 8) && !field_val) {
1264 if ((code & MASK_SPEC) == STRING_SPEC) {
1266 field_val += spec[STRINGS_NL_ITEM_START + (code & 0xf)];
1267 o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME, field_val) __LOCALE_ARG);
1269 o_count = ((i >> 1) & 3) + 1;
1272 *(char *)(--o) = '0' + (field_val % 10);
1276 *buf = ' ' + (i & 16);
1283 while (o_count && count && *o) {
1290 # ifdef L_strftime_l
1291 libc_hidden_def(strftime_l)
1294 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1297 /**********************************************************************/
1298 #if defined(L_strptime) || defined(L_strptime_l)
1300 #define ISDIGIT(C) __isdigit_char((C))
1302 #ifdef __UCLIBC_DO_XLOCALE
1303 #define ISSPACE(C) isspace_l((C), locale_arg)
1305 #define ISSPACE(C) isspace((C))
1308 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
1310 char *strptime(const char *__restrict buf, const char *__restrict format,
1311 struct tm *__restrict tm)
1313 return strptime_l(buf, format, tm, __UCLIBC_CURLOCALE);
1316 #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1319 * 1) %l and %k are space-padded, so "%l" by itself fails while " %l" succeeds.
1320 * Both work for glibc. So, should we always strip spaces?
1325 * There are several differences between this strptime and glibc's strptime.
1326 * 1) glibc strips leading space before numeric conversions.
1327 * 2) glibc will read fields without whitespace in between. SUSv3 states
1328 * that you must have whitespace between conversion operators. Besides,
1329 * how do you know how long a number should be if there are leading 0s?
1330 * 3) glibc attempts to compute some the struct tm fields based on the
1331 * data retrieved; tm_wday in particular. I don't as I consider it
1332 * another glibc attempt at mind-reading...
1335 #define NO_E_MOD 0x80
1336 #define NO_O_MOD 0x40
1338 #define ILLEGAL_SPEC 0x3f
1340 #define INT_SPEC 0x00 /* must be 0x00!! */
1341 #define STRING_SPEC 0x10 /* must be 0x10!! */
1342 #define CALC_SPEC 0x20
1343 #define STACKED_SPEC 0x30
1345 #define MASK_SPEC 0x30
1347 /* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
1348 static const unsigned char spec[] = {
1349 /* A */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1350 /* B */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1351 /* C */ 0x08 | INT_SPEC | NO_O_MOD,
1352 /* D */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1353 /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1354 /* F */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1355 /* G */ 0x0f | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1356 /* H */ 0x06 | INT_SPEC | NO_E_MOD,
1357 /* I */ 0x07 | INT_SPEC | NO_E_MOD,
1358 /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1359 /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1360 /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1361 /* M */ 0x04 | INT_SPEC | NO_E_MOD,
1362 /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1363 /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1364 /* P */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1365 /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1366 /* R */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1367 /* S */ 0x05 | INT_SPEC | NO_E_MOD,
1368 /* T */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1369 /* U */ 0x0c | INT_SPEC | NO_E_MOD,
1370 /* V */ 0x0d | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1371 /* W */ 0x0c | INT_SPEC | NO_E_MOD,
1372 /* X */ 0x0a | STACKED_SPEC | NO_O_MOD,
1373 /* Y */ 0x0a | INT_SPEC | NO_O_MOD,
1374 /* Z */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1376 /* WARNING! This assumes orderings:
1378 * ABDAY_1-ABDAY-7,DAY_1-DAY_7
1379 * ABMON_1-ABMON_12,MON_1-MON12
1380 * Also, there are exactly 6 bytes between 'Z' and 'a'.
1382 #define STRINGS_NL_ITEM_START (26)
1383 _NL_ITEM_INDEX(AM_STR), /* p (P) */
1384 _NL_ITEM_INDEX(ABMON_1), /* B, b */
1385 _NL_ITEM_INDEX(ABDAY_1), /* A, a */
1390 /* a */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1391 /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1392 /* c */ 0x08 | STACKED_SPEC | NO_O_MOD,
1393 /* d */ 0x00 | INT_SPEC | NO_E_MOD,
1394 /* e */ 0x00 | INT_SPEC | NO_E_MOD,
1395 /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1396 /* g */ 0x0e | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1397 /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1398 /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1399 /* j */ 0x01 | INT_SPEC | NO_E_MOD | NO_O_MOD,
1400 /* k */ 0x06 | INT_SPEC | NO_E_MOD, /* glibc */
1401 /* l */ 0x07 | INT_SPEC | NO_E_MOD, /* glibc */
1402 /* m */ 0x02 | INT_SPEC | NO_E_MOD,
1403 /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1404 /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1405 /* p */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1406 /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1407 /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1408 /* s */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1409 /* t */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1410 /* u */ 0x0b | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1411 /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1412 /* w */ 0x03 | INT_SPEC | NO_E_MOD,
1413 /* x */ 0x09 | STACKED_SPEC | NO_O_MOD,
1414 /* y */ 0x09 | INT_SPEC,
1415 /* z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1417 #define INT_FIELD_START (26+6+26)
1418 /* (field #) << 3 + lower bound (0|1) + correction 0:none, 2:-1, 4:-1900
1419 * followed by upper bound prior to correction with 1=>366 and 2=>9999. */
1420 /* d, e */ (3 << 3) + 1 + 0, 31,
1421 /* j */ (7 << 3) + 1 + 2, /* 366 */ 1,
1422 /* m */ (4 << 3) + 1 + 2, 12,
1423 /* w */ (6 << 3) + 0 + 0, 6,
1424 /* M */ (1 << 3) + 0 + 0, 59,
1425 /* S */ 0 + 0 + 0, 60,
1426 /* H (k) */ (2 << 3) + 0 + 0, 23,
1427 /* I (l) */ (9 << 3) + 1 + 0, 12, /* goes with 8 -- am/pm */
1428 /* C */ (10<< 3) + 0 + 0, 99,
1429 /* y */ (11<< 3) + 0 + 0, 99,
1430 /* Y */ (5 << 3) + 0 + 4, /* 9999 */ 2,
1431 /* u */ (6 << 3) + 1 + 0, 7,
1432 /* The following are processed and range-checked, but ignored otherwise. */
1433 /* U, W */ (12<< 3) + 0 + 0, 53,
1434 /* V */ (12<< 3) + 1 + 0, 53,
1435 /* g */ (12<< 3) + 0 + 0, 99,
1436 /* G */ (12<< 3) + 0 /*+ 4*/, /* 9999 */ 2, /* Note: -1 or 10000? */
1438 #define STACKED_STRINGS_START (INT_FIELD_START+32)
1439 5, 6, 14, 22, 27, /* 5 - offsets from offset-count to strings */
1440 ' ', 0, /* 2 - %n or %t */
1441 '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
1442 '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
1443 '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
1444 '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
1446 #define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 40)
1447 _NL_ITEM_INDEX(D_T_FMT), /* c */
1448 _NL_ITEM_INDEX(D_FMT), /* x */
1449 _NL_ITEM_INDEX(T_FMT), /* X */
1450 _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
1451 #ifdef ENABLE_ERA_CODE
1452 _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
1453 _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */
1454 _NL_ITEM_INDEX(ERA_T_FMT), /* EX */
1460 char *__XL_NPP(strptime)(const char *__restrict buf, const char *__restrict format,
1461 struct tm *__restrict tm __LOCALE_PARAM)
1463 register const char *p;
1465 const char *stack[MAX_PUSH];
1473 fields[i] = INT_MIN;
1481 if (lvl == 0) { /* Done. */
1482 if (fields[6] == 7) { /* Cleanup for %u here since just once. */
1483 fields[6] = 0; /* Don't use mod in case unset. */
1487 do { /* Store the values into tm. */
1488 if (fields[i] != INT_MIN) {
1489 ((int *) tm)[i] = fields[i];
1493 return (char *) buf; /* Success. */
1499 if ((*p == '%') && (*++p != '%')) {
1501 if ((*p == 'O') || (*p == 'E')) { /* Modifier? */
1502 mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
1507 || (((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
1508 || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
1510 return NULL; /* Illegal spec. */
1513 if ((code & MASK_SPEC) == STACKED_SPEC) {
1514 if (lvl == MAX_PUSH) {
1515 return NULL; /* Stack full so treat as illegal spec. */
1518 if ((code &= 0xf) < 8) {
1519 p = ((const char *) spec) + STACKED_STRINGS_START + code;
1520 p += *((unsigned char *)p);
1524 p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
1526 #ifdef ENABLE_ERA_CODE
1527 if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
1528 && (*(o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1529 (int)(((unsigned char *)p)[4]))
1537 p = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1538 (int)(*((unsigned char *)p)))
1546 if ((code & MASK_SPEC) == STRING_SPEC) {
1548 j = spec[STRINGS_NL_ITEM_START + 3 + code];
1549 i = _NL_ITEM(LC_TIME, spec[STRINGS_NL_ITEM_START + code]);
1550 /* Go backwards to check full names before abreviations. */
1553 o = __XL_NPP(nl_langinfo)(i+j __LOCALE_ARG);
1554 if (!__XL_NPP(strncasecmp)(buf, o, strlen(o) __LOCALE_ARG) && *o) {
1555 do { /* Found a match. */
1558 if (!code) { /* am/pm */
1560 if (fields[9] >= 0) { /* We have a previous %I or %l. */
1561 fields[2] = fields[9] + fields[8];
1563 } else { /* day (4) or month (6) */
1564 fields[2 + (code << 1)]
1565 = j % (spec[STRINGS_NL_ITEM_START + 3 + code] >> 1);
1570 return NULL; /* Failed to match. */
1573 if ((code & MASK_SPEC) == CALC_SPEC) {
1574 if ((code &= 0xf) < 1) { /* s or z*/
1580 if (!ISSPACE(*buf)) { /* Signal an error if whitespace. */
1581 #ifdef TIME_T_IS_UNSIGNED
1582 t = __XL_NPP(strtoul)(buf, &o, 10 __LOCALE_ARG);
1584 t = __XL_NPP(strtol)(buf, &o, 10 __LOCALE_ARG);
1587 if ((o == buf) || errno) { /* Not a number or overflow. */
1590 __set_errno(i); /* Restore errno. */
1593 if (!code) { /* s */
1594 localtime_r(&t, tm); /* TODO: check for failure? */
1596 do { /* Now copy values from tm to fields. */
1597 fields[i] = ((int *) tm)[i];
1601 /* TODO: glibc treats %Z as a nop. For now, do the same. */
1605 assert((code & MASK_SPEC) == INT_SPEC);
1607 register const unsigned char *x;
1609 x = spec + INT_FIELD_START + (code << 1);
1610 if ((j = x[1]) < 3) { /* upper bound (inclusive) */
1611 j = ((j==1) ? 366 : 9999);
1614 while (ISDIGIT(*buf)) {
1618 if ((i = 10*i + (*buf - '0')) > j) { /* Overflow. */
1623 if (i < (*x & 1)) { /* This catches no-digit case too. */
1633 if (*x == (9 << 3) + 1 + 0) { /* %I or %l */
1637 if (fields[8] >= 0) { /* We have a previous %p or %P. */
1638 fields[2] = i + fields[8];
1642 fields[(*x) >> 3] = i;
1644 if (((unsigned char)(*x - (10 << 3) + 0 + 0)) <= 8) { /* %C or %y */
1645 if ((j = fields[10]) < 0) { /* No %C, so i must be %y data. */
1646 if (i <= 68) { /* Map [0-68] to 2000+i */
1649 } else { /* Have %C data, but what about %y? */
1650 if ((i = fields[11]) < 0) { /* No %y data. */
1651 i = 0; /* Treat %y val as 0 following glibc's example. */
1659 } else if (ISSPACE(*p)) {
1661 while (ISSPACE(*buf)) {
1665 } else if (*buf++ == *p++) {
1670 # ifdef L_strptime_l
1671 libc_hidden_def(strptime_l)
1674 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1677 /**********************************************************************/
1681 #error The uClibc version of time is in sysdeps/linux/common.
1684 time_t time(register time_t *tloc)
1687 register struct timeval *p = &tv;
1689 gettimeofday(p, NULL); /* This should never fail... */
1699 /**********************************************************************/
1702 static const char vals[] = {
1703 'T', 'Z', 0, /* 3 */
1704 'U', 'T', 'C', 0, /* 4 */
1705 25, 60, 60, 1, /* 4 */
1708 6, 0, 0, /* Note: overloaded for non-M non-J case... */
1710 ',', 'M', '4', '.', '1', '.', '0',
1711 ',', 'M', '1', '0', '.', '5', '.', '0', 0,
1712 ',', 'M', '3', '.', '2', '.', '0',
1713 ',', 'M', '1', '1', '.', '1', '.', '0', 0
1717 #define UTC (vals + 3)
1718 #define RANGE (vals + 7)
1719 #define RULE (vals + 11 - 1)
1720 #define DEFAULT_RULES (vals + 22)
1721 #define DEFAULT_2007_RULES (vals + 38)
1723 /* Initialize to UTC. */
1726 char *tzname[2] = { (char *) UTC, (char *) (UTC-1) };
1728 __UCLIBC_MUTEX_INIT(_time_tzlock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
1730 rule_struct _time_tzinfo[2];
1732 static const char *getoffset(register const char *e, long *pn)
1734 register const char *s = RANGE-1;
1742 if (__isdigit_char(*e)) {
1745 if (__isdigit_char(*e)) {
1746 f = 10 * f + (*e++ - '0');
1748 if (((unsigned int)f) >= *s) {
1763 static const char *getnumber(register const char *e, int *pn)
1766 /* bcc can optimize the counter if it thinks it is a pointer... */
1767 register const char *n = (const char *) 3;
1771 while (n && __isdigit_char(*e)) {
1772 f = 10 * f + (*e++ - '0');
1777 return (n == (const char *) 3) ? NULL : e;
1783 while (n && __isdigit_char(*e)) {
1784 f = 10 * f + (*e++ - '0');
1789 return (n == 3) ? NULL : e;
1790 #endif /* __BCC__ */
1794 #ifdef __UCLIBC_MJN3_ONLY__
1795 #warning CONSIDER: Should we preserve errno from open/read/close errors re TZ file?
1798 #ifdef __UCLIBC_HAS_TZ_FILE__
1800 #ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1801 static smallint TZ_file_read; /* Let BSS initialization set this to 0. */
1804 static char *read_TZ_file(char *buf)
1810 fd = open(__UCLIBC_TZ_FILE_PATH__, O_RDONLY);
1813 /* TZ are small *files*. On files, short reads
1814 * only occur on EOF (unlike, say, pipes).
1815 * The code below is pedanticallly more correct,
1816 * but this way we always read at least twice:
1817 * 1st read is short, 2nd one is zero bytes.
1819 size_t todo = TZ_BUFLEN;
1822 r = read(fd, p, todo);
1831 /* Shorter, and does one fewer read syscall */
1832 r = read(fd, buf, TZ_BUFLEN);
1837 if ((p > buf) && (p[-1] == '\n')) { /* Must end with newline */
1840 #ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1849 #ifdef __UCLIBC_FALLBACK_TO_ETC_LOCALTIME__
1851 fd = open("/etc/localtime", O_RDONLY);
1853 r = read(fd, buf, TZ_BUFLEN);
1855 || strncmp(buf, "TZif", 4) != 0
1856 || (unsigned char)buf[4] < 2
1857 || lseek(fd, -TZ_BUFLEN, SEEK_END) < 0
1861 /* tzfile.h from tzcode database says about TZif2+ files:
1863 ** If tzh_version is '2' or greater, the above is followed by a second instance
1864 ** of tzhead and a second instance of the data in which each coded transition
1865 ** time uses 8 rather than 4 chars,
1866 ** then a POSIX-TZ-environment-variable-style string for use in handling
1867 ** instants after the last transition time stored in the file
1868 ** (with nothing between the newlines if there is no POSIX representation for
1871 r = read(fd, buf, TZ_BUFLEN);
1872 if (r <= 0 || buf[--r] != '\n')
1876 if (buf[--r] == '\n') {
1878 #ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1883 } /* else ('\n' not found): p remains NULL */
1887 #endif /* __UCLIBC_FALLBACK_TO_ETC_LOCALTIME__ */
1891 #endif /* __UCLIBC_HAS_TZ_FILE__ */
1895 _time_tzset((time(NULL)) < new_rule_starts);
1898 void _time_tzset(int use_old_rules)
1900 register const char *e;
1904 rule_struct new_rules[2];
1907 #ifdef __UCLIBC_HAS_TZ_FILE__
1908 char buf[TZ_BUFLEN];
1910 #ifdef __UCLIBC_HAS_TZ_CACHING__
1911 static char oldval[TZ_BUFLEN]; /* BSS-zero'd. */
1914 /* Put this inside the lock to prevent the possibility of two different
1915 * timezones being used in a threaded app. */
1916 __UCLIBC_MUTEX_LOCK(_time_tzlock);
1918 e = getenv(TZ); /* TZ env var always takes precedence. */
1920 #if defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__)
1922 /* Never use TZfile if TZ env var is set. */
1926 /* We already parsed TZfile before, skip everything. */
1931 /* Warning!!! Since uClibc doesn't do lib locking, the following is
1932 * potentially unsafe in a multi-threaded program since it is remotely
1933 * possible that another thread could call setenv() for TZ and overwrite
1934 * the string being parsed. So, don't do that... */
1936 #ifdef __UCLIBC_HAS_TZ_FILE__
1938 e = read_TZ_file(buf);
1940 if (!e /* TZ env var not set and no TZfile (or bad TZfile) */
1941 || !*e /* or set to empty string. */
1946 if (*e == ':') { /* Ignore leading ':'. */
1950 #ifdef __UCLIBC_HAS_TZ_CACHING__
1951 if (strcmp(e, oldval) == 0) {
1952 /* Same string as last time... nothing to do. */
1955 /* Make a copy of the TZ env string. It won't be nul-terminated if
1956 * it is too long, but it that case it will be illegal and will be reset
1957 * to the empty string anyway. */
1958 strncpy(oldval, e, TZ_BUFLEN);
1962 new_rules[1].tzname[0] = 0;
1964 /* Get std or dst name. */
1971 s = new_rules[count].tzname;
1974 && isascii(*e) /* SUSv3 requires char in portable char set. */
1976 || (c && (isalnum(*e) || (*e == '+') || (*e == '-')))
1980 if (++n > TZNAME_MAX) {
1986 if ((n < 3) /* Check for minimum length. */
1987 || (c && (*e++ != c)) /* Match any quoting '<'. */
1994 if ((*e != '-') && (*e != '+')) {
1995 if (count && !__isdigit_char(*e)) {
1996 off -= 3600; /* Default to 1 hour ahead of std. */
2003 e = getoffset(e, &off);
2009 off = -off; /* Save off in case needed for dst default. */
2012 new_rules[count].gmt_offset = off;
2015 new_rules[1].gmt_offset = off; /* Shouldn't be needed... */
2020 } else { /* OK, we have dst, so get some rules. */
2022 if (!*e) { /* No rules so default to US rules. */
2023 e = use_old_rules ? DEFAULT_RULES : DEFAULT_2007_RULES;
2025 if (e == DEFAULT_RULES)
2026 printf("tzset: Using old rules.\n");
2027 else if (e == DEFAULT_2007_RULES)
2028 printf("tzset: Using new rules\n");
2030 printf("tzset: Using undefined rules\n");
2044 } else if (c == 'J') {
2052 p = &new_rules[count].rule_type;
2060 e = getnumber(e, &f);
2062 || ((unsigned int)(f - s[1]) > n)
2063 || (*s && (*e++ != *s))
2072 off = 2 * 60 * 60; /* Default to 2:00:00 */
2075 e = getoffset(e, &off);
2080 new_rules[count].dst_offset = off;
2081 } while (++count < 2);
2085 #ifdef __UCLIBC_HAS_TZ_CACHING__
2086 oldval[0] = 0; /* oldval = "" */
2088 memset(_time_tzinfo, 0, sizeof(_time_tzinfo));
2089 strcpy(_time_tzinfo[0].tzname, UTC);
2094 memcpy(_time_tzinfo, new_rules, sizeof(new_rules));
2096 tzname[0] = _time_tzinfo[0].tzname;
2097 tzname[1] = _time_tzinfo[1].tzname;
2098 daylight = !!_time_tzinfo[1].tzname[0];
2099 timezone = _time_tzinfo[0].gmt_offset;
2101 #if (defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__)) || \
2102 defined(__UCLIBC_HAS_TZ_CACHING__)
2105 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
2107 libc_hidden_def(tzset)
2109 /**********************************************************************/
2110 /* #ifdef L_utime */
2112 /* utime is a syscall in both linux and elks. */
2113 /* int utime(const char *path, const struct utimbuf *times) */
2116 /**********************************************************************/
2118 /**********************************************************************/
2122 #error The uClibc version of utimes is in sysdeps/linux/common.
2127 int utimes(const char *filename, register const struct timeval *tvp)
2129 register struct utimbuf *p = NULL;
2134 p->actime = tvp[0].tv_sec;
2135 p->modtime = tvp[1].tv_sec;
2137 return utime(filename, p);
2141 /**********************************************************************/
2144 static const uint16_t _vals[] = {
2145 60, 60, 24, 7 /* special */, 36524, 1461, 365, 0
2148 static const unsigned char days[] = {
2149 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
2153 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
2154 static const char utc_string[] = "UTC";
2158 * If time_t is 32 bits, then no overflow is possible.
2159 * It time_t is > 32 bits, this needs to be adjusted to deal with overflow.
2162 /* Note: offset is the correction in _days_ to *timer! */
2164 struct tm attribute_hidden *_time_t2tm(const time_t *__restrict timer,
2165 int offset, struct tm *__restrict result)
2169 int wday = wday; /* ok to be uninitialized, shutting up warning */
2172 register const uint16_t *vp;
2178 if ((v = *vp) == 7) {
2179 /* Overflow checking, assuming time_t is long int... */
2180 #if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
2181 #if (INT_MAX == 2147483647L) && (LONG_MAX == 9223372036854775807L)
2182 /* Valid range for t is [-784223472856L, 784223421720L].
2183 * Outside of this range, the tm_year field will overflow. */
2184 if (((unsigned long)(t + offset- -784223472856L))
2185 > (784223421720L - -784223472856L)
2190 #error overflow conditions unknown
2194 /* We have days since the epoch, so caluclate the weekday. */
2195 #if defined(__BCC__) && TIME_T_IS_UNSIGNED
2196 wday = (t + 4) % (*vp); /* t is unsigned */
2198 wday = ((int)((t % (*vp)) + 11)) % ((int)(*vp)); /* help bcc */
2200 /* Set divisor to days in 400 years. Be kind to bcc... */
2201 v = ((time_t)(vp[1])) << 2;
2203 /* Change to days since 1/1/1601 so that for 32 bit time_t
2204 * values, we'll have t >= 0. This should be changed for
2205 * archs with larger time_t types.
2206 * Also, correct for offset since a multiple of 7. */
2208 /* TODO: Does this still work on archs with time_t > 32 bits? */
2209 t += (135140L - 366) + offset; /* 146097 - (365*30 + 7) -366 */
2211 #if defined(__BCC__) && TIME_T_IS_UNSIGNED
2212 t -= ((t1 = t / v) * v);
2214 if ((t -= ((t1 = t / v) * v)) < 0) {
2220 if ((*vp == 7) && (t == v-1)) {
2221 --t; /* Correct for 400th year leap case */
2222 ++p[4]; /* Stash the extra day... */
2225 #if defined(__BCC__) && 0
2248 *p += ((int) t); /* result[7] .. tm_yday */
2250 p -= 2; /* at result[5] */
2252 #if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
2253 /* Protect against overflow. TODO: Unecessary if int arith wraps? */
2254 *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + (p[1] - 299); /* tm_year */
2256 *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + p[1] - 299; /* tm_year */
2259 p[1] = wday; /* result[6] .. tm_wday */
2262 register const unsigned char *d = days;
2265 if (__isleap(wday)) {
2269 wday = p[2] + 1; /* result[7] .. tm_yday */
2270 *--p = 0; /* at result[4] .. tm_mon */
2274 d -= 11; /* Backup to non-leap Feb. */
2277 ++*p; /* Increment tm_mon. */
2279 p[-1] = wday; /* result[3] .. tm_mday */
2281 /* TODO -- should this be 0? */
2282 p[4] = 0; /* result[8] .. tm_isdst */
2283 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
2285 result->tm_gmtoff = 0;
2286 result->tm_zone = utc_string;
2288 result->__tm_gmtoff = 0;
2289 result->__tm_zone = utc_string;
2291 #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
2297 /**********************************************************************/
2300 struct tm __time_tm; /* Global shared by gmtime() and localtime(). */
2303 /**********************************************************************/
2304 #ifdef L__time_mktime
2306 time_t attribute_hidden _time_mktime(struct tm *timeptr, int store_on_success)
2310 __UCLIBC_MUTEX_LOCK(_time_tzlock);
2314 t = _time_mktime_tzi(timeptr, store_on_success, _time_tzinfo);
2316 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
2322 /**********************************************************************/
2323 #ifdef L__time_mktime_tzi
2325 static const unsigned char __vals[] = {
2326 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
2330 time_t attribute_hidden _time_mktime_tzi(struct tm *timeptr, int store_on_success,
2340 /* 0:sec 1:min 2:hour 3:mday 4:mon 5:year 6:wday 7:yday 8:isdst */
2341 register int *p = (int *) &x;
2342 register const unsigned char *s;
2345 memcpy(p, timeptr, sizeof(struct tm));
2347 if (!tzi[1].tzname[0]) { /* No dst in this timezone, */
2348 p[8] = 0; /* so set tm_isdst to 0. */
2352 if (p[8]) { /* Either dst or unknown? */
2353 default_dst = 1; /* Assume advancing (even if unknown). */
2354 p[8] = ((p[8] > 0) ? 1 : -1); /* Normalize so abs() <= 1. */
2358 p[5] = (p[5] - ((p[6] = p[5]/d) * d)) + (p[7] = p[4]/12);
2359 if ((p[4] -= 12 * p[7]) < 0) {
2365 d = (p[5] += 1900); /* Correct year. Now between 1900 and 2300. */
2375 s -= 11; /* Backup to non-leap Feb. */
2381 _time_tzset (x.tm_year < 2007); /* tm_year was expanded above */
2385 days = -719163L + ((long)d)*365 + ((d/4) - (d/100) + (d/400) + p[3] + p[7]);
2386 secs = p[0] + 60*( p[1] + 60*((long)(p[2])) )
2387 + tzi[default_dst].gmt_offset;
2393 if ( ((unsigned long)(days + secs/86400L)) > 49710L) {
2397 secs += (days * 86400L);
2400 d = -719163L + d*365 + (d/4) - (d/100) + (d/400);
2402 + tzi[default_dst].gmt_offset
2405 + 24*(((146073L * ((long long)(p[6])) + d)
2409 if (((unsigned long long)(secs - LONG_MIN))
2410 > (((unsigned long long)LONG_MAX) - LONG_MIN)
2417 d = ((struct tm *)p)->tm_isdst;
2420 __time_localtime_tzi(&t, (struct tm *)p, tzi);
2422 if (t == ((time_t)(-1))) { /* Remember, time_t can be unsigned. */
2426 if ((d < 0) && (((struct tm *)p)->tm_isdst != default_dst)) {
2428 secs -= (days * 86400L);
2430 secs += (tzi[1-default_dst].gmt_offset
2431 - tzi[default_dst].gmt_offset);
2436 if (store_on_success) {
2437 memcpy(timeptr, p, sizeof(struct tm));
2446 /**********************************************************************/
2447 #if defined(L_wcsftime) || defined(L_wcsftime_l)
2449 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
2451 size_t wcsftime(wchar_t *__restrict s, size_t maxsize,
2452 const wchar_t *__restrict format,
2453 const struct tm *__restrict timeptr)
2455 return wcsftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE);
2458 #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
2460 size_t __XL_NPP(wcsftime)(wchar_t *__restrict s, size_t maxsize,
2461 const wchar_t *__restrict format,
2462 const struct tm *__restrict timeptr __LOCALE_PARAM )
2464 #warning wcsftime always fails
2465 return 0; /* always fail */
2468 libc_hidden_def(wcsftime_l)
2471 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
2474 /**********************************************************************/
2476 /* Return the number of days in YEAR. */
2478 int dysize(int year)
2480 return __isleap(year) ? 366 : 365;
2484 /**********************************************************************/