blob: 8e2ebf12e09759bfabe5b77fe6db00c5a86dd15f [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* Copyright (C) 2002-2004 Manuel Novoa III <mjn3@codepoet.org>
2 *
3 * GNU Library General Public License (LGPL) version 2 or later.
4 *
5 * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
6 */
7
8/* June 15, 2002 Initial Notes:
9 *
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.
12 *
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
16 *
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.
20 *
21 * Differences from glibc worth noting:
22 *
23 * Leap seconds are not considered here.
24 *
25 * glibc stores additional timezone info the struct tm, whereas we don't.
26 *
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.
30 *
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.
35 *
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.
41 *
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.
47 *
48 * TODO - Implement getdate? tzfile? struct tm extensions?
49 *
50 * TODO - Rework _time_mktime to remove the dependency on long long.
51 */
52
53/* Oct 28, 2002
54 *
55 * Fixed allowed char check for std and dst TZ fields.
56 *
57 * Added several options concerned with timezone support. The names will
58 * probably change once Erik gets the new config system in place.
59 *
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
65 *
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.
68 *
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.
72 *
73 * Nov 21, 2002 Fix an error return case in _time_mktime.
74 *
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.
77 *
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.
82 *
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.
85 *
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.
89 *
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.
93 *
94 * The uClibc behavior is to always normalize the struct tm and then
95 * try to determing the dst setting.
96 *
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.
100 *
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.
106 *
107 * Fix a dst-related bug which resulted in use of uninitialized data.
108 *
109 * Nov 15, 2003 I forgot to update the thread locking in the last dst fix.
110 *
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.
114 *
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.
121 *
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.
130 */
131
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>
148
149#ifdef __UCLIBC_HAS_WCHAR__
150#include <wchar.h>
151#endif
152#ifdef __UCLIBC_HAS_XLOCALE__
153#include <xlocale.h>
154#endif
155
156
157#ifndef __isleap
158#define __isleap(y) ( !((y) % 4) && ( ((y) % 100) || !((y) % 400) ) )
159#endif
160
161#ifndef TZNAME_MAX
162#define TZNAME_MAX _POSIX_TZNAME_MAX
163#endif
164
165#if defined (L_tzset) || defined (L_localtime_r) || defined(L_strftime) || \
166 defined(L__time_mktime) || defined(L__time_mktime_tzi) || \
167 ((defined(L_strftime) || defined(L_strftime_l)) && \
168 defined(__UCLIBC_HAS_XLOCALE__))
169
170void _time_tzset(int use_old_rules) attribute_hidden;
171
172#ifndef L__time_mktime
173
174 /* Jan 1, 2007 Z - tm = 0,0,0,1,0,107,1,0,0 */
175
176static const time_t new_rule_starts = 1167609600;
177
178#endif
179#endif
180
181/**********************************************************************/
182/* The era code is currently unfinished. */
183/* #define ENABLE_ERA_CODE */
184
185#define TZ_BUFLEN (2*TZNAME_MAX + 56)
186
187#ifdef __UCLIBC_HAS_TZ_FILE__
188
189#include <sys/stat.h>
190#include "paths.h"
191/* ":<tzname>+hh:mm:ss<tzname>+hh:mm:ss,Mmm.w.d/hh:mm:ss,Mmm.w.d/hh:mm:ss" + nul */
192/* 1 + 2*(1+TZNAME_MAX+1 + 9 + 7 + 9) + 1 = 2*TZNAME_MAX + 56 */
193
194#else /* __UCLIBC_HAS_TZ_FILE__ */
195
196/* Probably no longer needed. */
197#undef __UCLIBC_HAS_TZ_FILE_READ_MANY__
198
199#endif /* __UCLIBC_HAS_TZ_FILE__ */
200
201/**********************************************************************/
202
203extern struct tm __time_tm attribute_hidden;
204
205typedef struct {
206 long gmt_offset;
207 long dst_offset;
208 short day; /* for J or normal */
209 short week;
210 short month;
211 short rule_type; /* J, M, \0 */
212 char tzname[TZNAME_MAX+1];
213} rule_struct;
214
215__UCLIBC_MUTEX_EXTERN(_time_tzlock);
216
217extern rule_struct _time_tzinfo[2] attribute_hidden;
218
219extern struct tm *_time_t2tm(const time_t *__restrict timer,
220 int offset, struct tm *__restrict result) attribute_hidden;
221
222extern time_t _time_mktime(struct tm *timeptr, int store_on_success) attribute_hidden;
223
224extern struct tm *__time_localtime_tzi(const time_t *__restrict timer,
225 struct tm *__restrict result,
226 rule_struct *tzi) attribute_hidden;
227
228extern time_t _time_mktime_tzi(struct tm *timeptr, int store_on_success,
229 rule_struct *tzi) attribute_hidden;
230
231/**********************************************************************/
232#ifdef L_asctime
233
234static char __time_str[26];
235
236char *asctime(const struct tm *ptm)
237{
238 return asctime_r(ptm, __time_str);
239}
240libc_hidden_def(asctime)
241
242#endif
243/**********************************************************************/
244#ifdef L_asctime_r
245
246/* Strictly speaking, this implementation isn't correct. ANSI/ISO specifies
247 * that the implementation of asctime() be equivalent to
248 *
249 * char *asctime(const struct tm *timeptr)
250 * {
251 * static char wday_name[7][3] = {
252 * "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
253 * };
254 * static char mon_name[12][3] = {
255 * "Jan", "Feb", "Mar", "Apr", "May", "Jun",
256 * "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
257 * };
258 * static char result[26];
259 *
260 * sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
261 * wday_name[timeptr->tm_wday],
262 * mon_name[timeptr->tm_mon],
263 * timeptr->tm_mday, timeptr->tm_hour,
264 * timeptr->tm_min, timeptr->tm_sec,
265 * 1900 + timeptr->tm_year);
266 * return result;
267 * }
268 *
269 * but the above is either inherently unsafe, or carries with it the implicit
270 * assumption that all fields of timeptr fall within their usual ranges, and
271 * that the tm_year value falls in the range [-2899,8099] to avoid overflowing
272 * the static buffer.
273 *
274 * If we take the implicit assumption as given, then the implementation below
275 * is still incorrect for tm_year values < -900, as there will be either
276 * 0-padding and/or a missing negative sign for the year conversion . But given
277 * the usual use of asctime(), I think it isn't unreasonable to restrict correct
278 * operation to the domain of years between 1000 and 9999.
279 */
280
281/* This is generally a good thing, but if you're _sure_ any data passed will be
282 * in range, you can #undef this. */
283#define SAFE_ASCTIME_R 1
284
285static const unsigned char at_data[] = {
286 'S', 'u', 'n', 'M', 'o', 'n', 'T', 'u', 'e', 'W', 'e', 'd',
287 'T', 'h', 'u', 'F', 'r', 'i', 'S', 'a', 't',
288
289 'J', 'a', 'n', 'F', 'e', 'b', 'M', 'a', 'r', 'A', 'p', 'r',
290 'M', 'a', 'y', 'J', 'u', 'n', 'J', 'u', 'l', 'A', 'u', 'g',
291 'S', 'e', 'p', 'O', 'c', 't', 'N', 'o', 'v', 'D', 'e', 'c',
292
293#ifdef SAFE_ASCTIME_R
294 '?', '?', '?',
295#endif
296 ' ', '?', '?', '?',
297 ' ', '0',
298 offsetof(struct tm, tm_mday),
299 ' ', '0',
300 offsetof(struct tm, tm_hour),
301 ':', '0',
302 offsetof(struct tm, tm_min),
303 ':', '0',
304 offsetof(struct tm, tm_sec),
305 ' ', '?', '?', '?', '?', '\n', 0
306};
307
308char *asctime_r(register const struct tm *__restrict ptm,
309 register char *__restrict buffer)
310{
311 int tmp;
312
313 assert(ptm);
314 assert(buffer);
315
316#ifdef SAFE_ASCTIME_R
317 memcpy(buffer, at_data + 3*(7 + 12), sizeof(at_data) - 3*(7 + 12));
318
319 if (((unsigned int)(ptm->tm_wday)) <= 6) {
320 memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);
321 }
322
323 if (((unsigned int)(ptm->tm_mon)) <= 11) {
324 memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
325 }
326#else
327 assert(((unsigned int)(ptm->tm_wday)) <= 6);
328 assert(((unsigned int)(ptm->tm_mon)) <= 11);
329
330 memcpy(buffer, at_data + 3*(7 + 12) - 3, sizeof(at_data) + 3 - 3*(7 + 12));
331
332 memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);
333 memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
334#endif
335
336#ifdef SAFE_ASCTIME_R
337 buffer += 19;
338 tmp = ptm->tm_year + 1900;
339 if (((unsigned int) tmp) < 10000) {
340 buffer += 4;
341 do {
342 *buffer = '0' + (tmp % 10);
343 tmp /= 10;
344 } while (*--buffer == '?');
345 }
346/* Not sure if we should even bother ...
347 } else {
348 __set_errno(EOVERFLOW);
349 return NULL;
350 }
351*/
352#else /* SAFE_ASCTIME_R */
353 buffer += 23;
354 tmp = ptm->tm_year + 1900;
355 assert( ((unsigned int) tmp) < 10000 );
356/* Not sure if we should even bother ...
357 if ( ((unsigned int) tmp) >= 10000 ) {
358 __set_errno(EOVERFLOW);
359 return NULL;
360 }
361*/
362 do {
363 *buffer = '0' + (tmp % 10);
364 tmp /= 10;
365 } while (*--buffer == '?');
366#endif /* SAFE_ASCTIME_R */
367
368 do {
369 --buffer;
370 tmp = *((int *)(((const char *) ptm) + (int) *buffer));
371#ifdef SAFE_ASCTIME_R
372 if (((unsigned int) tmp) >= 100) { /* Just check 2 digit non-neg. */
373 buffer[-1] = *buffer = '?';
374 } else
375#else
376 assert(((unsigned int) tmp) < 100); /* Just check 2 digit non-neg. */
377#endif
378 {
379 *buffer = '0' + (tmp % 10);
380#ifdef __BCC__
381 buffer[-1] = '0' + (tmp/10);
382#else
383 buffer[-1] += (tmp/10);
384#endif
385 }
386 } while ((buffer -= 2)[-2] == '0');
387
388 if (*++buffer == '0') { /* Space-pad day of month. */
389 *buffer = ' ';
390 }
391
392 return buffer - 8;
393}
394libc_hidden_def(asctime_r)
395
396#endif
397/**********************************************************************/
398#ifdef L_clock
399
400#include <sys/times.h>
401
402#ifndef __BCC__
403#if CLOCKS_PER_SEC != 1000000L
404#error unexpected value for CLOCKS_PER_SEC!
405#endif
406#endif
407
408#ifdef __UCLIBC_CLK_TCK_CONST
409# if __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC
410# error __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC!
411# elif __UCLIBC_CLK_TCK_CONST < 1
412# error __UCLIBC_CLK_TCK_CONST < 1!
413# endif
414#endif
415
416/* Note: SUSv3 notes
417 *
418 * On XSI-conformant systems, CLOCKS_PER_SEC is defined to be one million.
419 *
420 * The value returned by clock() may wrap around on some implementations.
421 * For example, on a machine with 32-bit values for clock_t, it wraps
422 * after 2147 seconds.
423 *
424 * This implies that we should bitwise and with LONG_MAX.
425 */
426
427clock_t clock(void)
428{
429 struct tms xtms;
430 unsigned long t;
431
432 times(&xtms);
433
434 t = ((unsigned long) xtms.tms_utime) + xtms.tms_stime;
435
436#ifndef __UCLIBC_CLK_TCK_CONST
437
438# error __UCLIBC_CLK_TCK_CONST not defined!
439
440#elif ((CLOCKS_PER_SEC % __UCLIBC_CLK_TCK_CONST) == 0)
441
442 /* CLOCKS_PER_SEC == k * __UCLIBC_CLK_TCK_CONST for some integer k >= 1. */
443 return ((t * (CLOCKS_PER_SEC/__UCLIBC_CLK_TCK_CONST)) & LONG_MAX);
444
445#else
446
447 /* Unlike the previous case, the scaling factor is not an integer.
448 * So when tms_utime, tms_stime, or their sum wraps, some of the
449 * "visible" bits in the return value are affected. Nothing we
450 * can really do about this though other than handle tms_utime and
451 * tms_stime seperately and then sum. But since that doesn't really
452 * buy us much, we don't bother. */
453
454 return ((((t / __UCLIBC_CLK_TCK_CONST) * CLOCKS_PER_SEC)
455 + ((((t % __UCLIBC_CLK_TCK_CONST) * CLOCKS_PER_SEC)
456 / __UCLIBC_CLK_TCK_CONST))
457 ) & LONG_MAX);
458
459#endif
460}
461
462#endif
463/**********************************************************************/
464#ifdef L_ctime
465
466char *ctime(const time_t *t)
467{
468 /* ANSI/ISO/SUSv3 say that ctime is equivalent to the following:
469 * return asctime(localtime(t));
470 * I don't think "equivalent" means "it uses the same internal buffer",
471 * it means "gives the same resultant string".
472 *
473 * I doubt anyone ever uses weird code like:
474 * struct tm *ptm = localtime(t1); ...; ctime(t2); use(ptm);
475 * which relies on the assumption that ctime's and localtime's
476 * internal static struct tm is the same.
477 *
478 * Using localtime_r instead of localtime avoids linking in
479 * localtime's static buffer:
480 */
481 struct tm xtm;
482 memset(&xtm, 0, sizeof(xtm));
483
484 return asctime(localtime_r(t, &xtm));
485}
486libc_hidden_def(ctime)
487#endif
488/**********************************************************************/
489#ifdef L_ctime_r
490
491char *ctime_r(const time_t *t, char *buf)
492{
493 struct tm xtm;
494
495 return asctime_r(localtime_r(t, &xtm), buf);
496}
497
498#endif
499/**********************************************************************/
500#ifdef L_difftime
501
502#include <float.h>
503
504#if FLT_RADIX != 2
505#error difftime implementation assumptions violated for you arch!
506#endif
507
508double difftime(time_t time1, time_t time0)
509{
510#if (LONG_MAX >> DBL_MANT_DIG) == 0
511
512 /* time_t fits in the mantissa of a double. */
513 return (double)time1 - (double)time0;
514
515#elif ((LONG_MAX >> DBL_MANT_DIG) >> DBL_MANT_DIG) == 0
516
517 /* time_t can overflow the mantissa of a double. */
518 time_t t1, t0, d;
519
520 d = ((time_t) 1) << DBL_MANT_DIG;
521 t1 = time1 / d;
522 time1 -= (t1 * d);
523 t0 = time0 / d;
524 time0 -= (t0*d);
525
526 /* Since FLT_RADIX==2 and d is a power of 2, the only possible
527 * rounding error in the expression below would occur from the
528 * addition. */
529 return (((double) t1) - t0) * d + (((double) time1) - time0);
530
531#else
532#error difftime needs special implementation on your arch.
533#endif
534}
535
536#endif
537/**********************************************************************/
538#ifdef L_gmtime
539
540struct tm *gmtime(const time_t *timer)
541{
542 register struct tm *ptm = &__time_tm;
543
544 _time_t2tm(timer, 0, ptm); /* Can return NULL... */
545
546 return ptm;
547}
548
549#endif
550/**********************************************************************/
551#ifdef L_gmtime_r
552
553struct tm *gmtime_r(const time_t *__restrict timer,
554 struct tm *__restrict result)
555{
556 return _time_t2tm(timer, 0, result);
557}
558
559#endif
560/**********************************************************************/
561#ifdef L_localtime
562
563struct tm *localtime(const time_t *timer)
564{
565 register struct tm *ptm = &__time_tm;
566
567 /* In this implementation, tzset() is called by localtime_r(). */
568
569 localtime_r(timer, ptm); /* Can return NULL... */
570
571 return ptm;
572}
573libc_hidden_def(localtime)
574
575#endif
576/**********************************************************************/
577#ifdef L_localtime_r
578
579struct tm *localtime_r(register const time_t *__restrict timer,
580 register struct tm *__restrict result)
581{
582 __UCLIBC_MUTEX_LOCK(_time_tzlock);
583
584 _time_tzset(*timer < new_rule_starts);
585
586 __time_localtime_tzi(timer, result, _time_tzinfo);
587
588 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
589
590 return result;
591}
592libc_hidden_def(localtime_r)
593
594#endif
595/**********************************************************************/
596#ifdef L__time_localtime_tzi
597
598#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
599
600struct ll_tzname_item;
601
602typedef struct ll_tzname_item {
603 struct ll_tzname_item *next;
604 char tzname[1];
605} ll_tzname_item_t;
606
607/* Structures form a list "UTC" -> "???" -> "tzname1" -> "tzname2"... */
608struct {
609 struct ll_tzname_item *next;
610 char tzname[4];
611} ll_tzname_UNKNOWN = { NULL, "???" };
612const struct {
613 struct ll_tzname_item *next;
614 char tzname[4];
615} ll_tzname_UTC = { (void*)&ll_tzname_UNKNOWN, "UTC" };
616
617static const char *lookup_tzname(const char *key)
618{
619 int len;
620 ll_tzname_item_t *p = (void*) &ll_tzname_UTC;
621
622 do {
623 if (strcmp(p->tzname, key) == 0)
624 return p->tzname;
625 p = p->next;
626 } while (p != NULL);
627
628 /* Hmm... a new name. */
629 len = strnlen(key, TZNAME_MAX+1);
630 if (len < TZNAME_MAX+1) { /* Verify legal length */
631 p = malloc(sizeof(ll_tzname_item_t) + len);
632 if (p != NULL) {
633 /* Insert as 3rd item in the list. */
634 p->next = ll_tzname_UNKNOWN.next;
635 ll_tzname_UNKNOWN.next = p;
636 return strcpy(p->tzname, key);
637 }
638 }
639
640 /* Either invalid or couldn't alloc. */
641 return ll_tzname_UNKNOWN.tzname;
642}
643
644#endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
645
646static const unsigned char day_cor[] = { /* non-leap */
647 31, 31, 34, 34, 35, 35, 36, 36, 36, 37, 37, 38, 38
648/* 0, 0, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7 */
649/* 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 */
650};
651
652/* Note: timezone locking is done by localtime_r. */
653
654static int tm_isdst(register const struct tm *__restrict ptm,
655 register rule_struct *r)
656{
657 long sec;
658 int i, isdst, isleap, day, day0, monlen, mday;
659 int oday = oday; /* ok to be uninitialized, shutting up compiler warning */
660
661 isdst = 0;
662 if (r[1].tzname[0] != 0) {
663 /* First, get the current seconds offset from the start of the year.
664 * Fields of ptm are assumed to be in their normal ranges. */
665 sec = ptm->tm_sec
666 + 60 * (ptm->tm_min
667 + 60 * (long)(ptm->tm_hour
668 + 24 * ptm->tm_yday));
669 /* Do some prep work. */
670 i = (ptm->tm_year % 400) + 1900; /* Make sure we don't overflow. */
671 isleap = __isleap(i);
672 --i;
673 day0 = (1
674 + i /* Normal years increment 1 wday. */
675 + (i/4)
676 - (i/100)
677 + (i/400) ) % 7;
678 i = 0;
679 do {
680 day = r->day; /* Common for 'J' and # case. */
681 if (r->rule_type == 'J') {
682 if (!isleap || (day < (31+29))) {
683 --day;
684 }
685 } else if (r->rule_type == 'M') {
686 /* Find 0-based day number for 1st of the month. */
687 day = 31*r->month - day_cor[r->month -1];
688 if (isleap && (day >= 59)) {
689 ++day;
690 }
691 monlen = 31 + day_cor[r->month -1] - day_cor[r->month];
692 if (isleap && (r->month == 2)) {
693 ++monlen;
694 }
695 /* Wweekday (0 is Sunday) of 1st of the month
696 * is (day0 + day) % 7. */
697 if ((mday = r->day - ((day0 + day) % 7)) >= 0) {
698 mday -= 7; /* Back up into prev month since r->week>0. */
699 }
700 if ((mday += 7 * r->week) >= monlen) {
701 mday -= 7;
702 }
703 /* So, 0-based day number is... */
704 day += mday;
705 }
706
707 if (i != 0) {
708 /* Adjust sec since dst->std change time is in dst. */
709 sec += (r[-1].gmt_offset - r->gmt_offset);
710 if (oday > day) {
711 ++isdst; /* Year starts in dst. */
712 }
713 }
714 oday = day;
715
716 /* Now convert day to seconds and add offset and compare. */
717 if (sec >= (day * 86400L) + r->dst_offset) {
718 ++isdst;
719 }
720 ++r;
721 } while (++i < 2);
722 }
723
724 return (isdst & 1);
725}
726
727struct tm attribute_hidden *__time_localtime_tzi(register const time_t *__restrict timer,
728 register struct tm *__restrict result,
729 rule_struct *tzi)
730{
731 time_t x[1];
732 long offset;
733 int days, dst;
734
735 dst = 0;
736 do {
737 days = -7;
738 offset = 604800L - tzi[dst].gmt_offset;
739 if (*timer > (LONG_MAX - 604800L)) {
740 days = -days;
741 offset = -offset;
742 }
743 *x = *timer + offset;
744
745 _time_t2tm(x, days, result);
746 result->tm_isdst = dst;
747#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
748# ifdef __USE_BSD
749 result->tm_gmtoff = - tzi[dst].gmt_offset;
750 result->tm_zone = lookup_tzname(tzi[dst].tzname);
751# else
752 result->__tm_gmtoff = - tzi[dst].gmt_offset;
753 result->__tm_zone = lookup_tzname(tzi[dst].tzname);
754# endif
755#endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
756 } while ((++dst < 2)
757 && ((result->tm_isdst = tm_isdst(result, tzi)) != 0));
758
759 return result;
760}
761
762#endif
763/**********************************************************************/
764#ifdef L_mktime
765
766time_t mktime(struct tm *timeptr)
767{
768 return _time_mktime(timeptr, 1);
769}
770
771/* Another name for `mktime'. */
772/* time_t timelocal(struct tm *tp) */
773strong_alias(mktime,timelocal)
774
775#endif
776/**********************************************************************/
777#ifdef L_timegm
778/* Like `mktime' but timeptr represents Universal Time, not local time. */
779
780time_t timegm(struct tm *timeptr)
781{
782 rule_struct gmt_tzinfo[2];
783
784 memset(gmt_tzinfo, 0, sizeof(gmt_tzinfo));
785 strcpy(gmt_tzinfo[0].tzname, "GMT"); /* Match glibc behavior here. */
786
787 return _time_mktime_tzi(timeptr, 1, gmt_tzinfo);
788}
789
790#endif
791/**********************************************************************/
792#if defined(L_strftime) || defined(L_strftime_l)
793
794#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
795
796size_t strftime(char *__restrict s, size_t maxsize,
797 const char *__restrict format,
798 const struct tm *__restrict timeptr)
799{
800 return strftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE);
801}
802
803#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
804
805#define NO_E_MOD 0x80
806#define NO_O_MOD 0x40
807
808#define ILLEGAL_SPEC 0x3f
809
810#define INT_SPEC 0x00 /* must be 0x00!! */
811#define STRING_SPEC 0x10 /* must be 0x10!! */
812#define CALC_SPEC 0x20
813#define STACKED_SPEC 0x30
814
815#define MASK_SPEC 0x30
816
817/* Compatibility:
818 *
819 * No alternate digit (%O?) handling. Always uses 0-9.
820 * Alternate locale format (%E?) handling is broken for nontrivial ERAs.
821 * glibc's %P is currently faked by %p. This means it doesn't do lower case.
822 * glibc's %k, %l, and %s are handled.
823 * glibc apparently allows (and ignores) extraneous 'E' and 'O' modifiers,
824 * while they are flagged as illegal conversions here.
825 */
826
827/* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
828static const unsigned char spec[] = {
829 /* A */ 0x03 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
830 /* B */ 0x04 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
831 /* C */ 0x0a | INT_SPEC | NO_O_MOD,
832 /* D */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
833 /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
834 /* F */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
835 /* G */ 0x03 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
836 /* H */ 0x0b | INT_SPEC | NO_E_MOD,
837 /* I */ 0x0c | INT_SPEC | NO_E_MOD,
838 /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
839 /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
840 /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
841 /* M */ 0x0d | INT_SPEC | NO_E_MOD,
842 /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
843 /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
844 /* P */ 0x05 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc ; use %p */
845 /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
846 /* R */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
847 /* S */ 0x0e | INT_SPEC | NO_E_MOD,
848 /* T */ 0x05 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
849 /* U */ 0x04 | CALC_SPEC | NO_E_MOD,
850 /* V */ 0x05 | CALC_SPEC | NO_E_MOD,
851 /* W */ 0x06 | CALC_SPEC | NO_E_MOD,
852 /* X */ 0x0a | STACKED_SPEC | NO_O_MOD,
853 /* Y */ 0x0f | INT_SPEC | NO_O_MOD,
854 /* Z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
855 '?', /* 26 */
856 '?', /* 27 */
857 '?', /* 28 */
858 '?', /* 29 */
859 0, /* 30 */
860 0, /* 31 */
861 /* a */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
862 /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
863 /* c */ 0x08 | STACKED_SPEC | NO_O_MOD,
864 /* d */ 0x00 | INT_SPEC | NO_E_MOD,
865 /* e */ 0x01 | INT_SPEC | NO_E_MOD,
866 /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
867 /* g */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
868 /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* same as b */
869 /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
870 /* j */ 0x08 | INT_SPEC | NO_E_MOD | NO_O_MOD,
871 /* k */ 0x03 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
872 /* l */ 0x04 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
873 /* m */ 0x05 | INT_SPEC | NO_E_MOD,
874 /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
875 /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
876 /* p */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
877 /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
878 /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
879 /* s */ 0x07 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
880 /* t */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
881 /* u */ 0x07 | INT_SPEC | NO_E_MOD,
882 /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
883 /* w */ 0x02 | INT_SPEC | NO_E_MOD,
884 /* x */ 0x09 | STACKED_SPEC | NO_O_MOD,
885 /* y */ 0x09 | INT_SPEC,
886 /* z */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
887
888
889 /* WARNING!!! These are dependent on the layout of struct tm!!! */
890#define FIELD_MAX (26+6+26)
891 60 /* 61? */, 59, 23, 31, 11, 0 /* 9999 */, 6, 0 /* 365 */,
892
893#define TP_OFFSETS (FIELD_MAX+8)
894 3, /* d */
895 3, /* e */
896 6, /* w */
897 2, /* k */
898 2, /* l */
899 4, /* m */
900 0, /* CURRENTLY UNUSED */
901 /* NOTE: u,j,y order must be preserved as 6,7,5 seq is used in the code! */
902#define CALC_OFFSETS (TP_OFFSETS + 7)
903 6, /* u */
904 7, /* j */
905 5, /* y */
906 5, /* C */
907 2, /* H */
908 2, /* I */
909 1, /* M */
910 0, /* S */
911 5, /* Y */
912 6, /* a */
913 4, /* b, h */
914 2, /* p */
915 6, /* A */
916 4, /* B */
917 2, /* P */
918
919#define TP_CODES (TP_OFFSETS + 16 + 6)
920 2 | 16, /* d */
921 2, /* e */
922 0 | 16, /* w */
923 2, /* k */
924 2 | 32 | 0, /* l */
925 2 | 16 | 1, /* m */
926 0, /* CURRENTLY UNUSED */
927 0 | 16 | 8 , /* u */
928 4 | 16 | 1, /* j */
929 2 | 128 | 32 | 16 , /* y */
930 2 | 128 | 64 | 32 | 16 , /* C */
931 2 | 16, /* H */
932 2 | 32 | 16 | 0, /* I */
933 2 | 16, /* M */
934 2 | 16, /* S */
935 6 | 16, /* Y */
936 2, /* a */
937 2, /* b, h */
938 2 | 64, /* p */
939 2, /* A */
940 2, /* B */
941 2 | 64, /* P */
942
943#define STRINGS_NL_ITEM_START (TP_CODES + 16 + 6)
944 _NL_ITEM_INDEX(ABDAY_1), /* a */
945 _NL_ITEM_INDEX(ABMON_1), /* b, h */
946 _NL_ITEM_INDEX(AM_STR), /* p */
947 _NL_ITEM_INDEX(DAY_1), /* A */
948 _NL_ITEM_INDEX(MON_1), /* B */
949 _NL_ITEM_INDEX(AM_STR), /* P -- wrong! need lower case */
950
951#define STACKED_STRINGS_START (STRINGS_NL_ITEM_START+6)
952 6, 7, 8, 16, 24, 29, /* 6 - offsets from offset-count to strings */
953 '\n', 0, /* 2 */
954 '\t', 0, /* 2 */
955 '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
956 '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
957 '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
958 '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
959
960#define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 43)
961 _NL_ITEM_INDEX(D_T_FMT), /* c */
962 _NL_ITEM_INDEX(D_FMT), /* x */
963 _NL_ITEM_INDEX(T_FMT), /* X */
964 _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
965#ifdef ENABLE_ERA_CODE
966 _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
967 _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */
968 _NL_ITEM_INDEX(ERA_T_FMT), /* EX */
969#endif
970};
971
972static int load_field(int k, const struct tm *__restrict timeptr)
973{
974 int r;
975 int r_max;
976
977 r = ((int *) timeptr)[k];
978
979 r_max = spec[FIELD_MAX + k];
980
981 if (k == 7) {
982 r_max = 365;
983 } else if (k == 5) {
984 r += 1900;
985 r_max = 9999;
986 }
987
988 if ((((unsigned int) r) > r_max) || ((k == 3) && !r)) {
989 r = -1;
990 }
991
992 return r;
993}
994
995#define MAX_PUSH 4
996
997#ifdef __UCLIBC_MJN3_ONLY__
998#warning TODO: Check multibyte format string validity.
999#endif
1000
1001size_t __XL_NPP(strftime)(char *__restrict s, size_t maxsize,
1002 const char *__restrict format,
1003 const struct tm *__restrict timeptr __LOCALE_PARAM )
1004{
1005 long tzo;
1006 register const char *p;
1007 register const char *o;
1008#ifndef __UCLIBC_HAS_TM_EXTENSIONS__
1009 const rule_struct *rsp;
1010#endif
1011 const char *stack[MAX_PUSH];
1012 size_t count;
1013 size_t o_count;
1014 int field_val = 0, i = 0, j, lvl;
1015 int x[3]; /* wday, yday, year */
1016 int isofm, days;
1017 char buf[__UIM_BUFLEN_LONG];
1018 unsigned char mod;
1019 unsigned char code;
1020
1021 /* We'll, let's get this out of the way. */
1022 _time_tzset(_time_mktime((struct tm *) timeptr, 0) < new_rule_starts);
1023
1024 lvl = 0;
1025 p = format;
1026 count = maxsize;
1027
1028LOOP:
1029 if (!count) {
1030 return 0;
1031 }
1032 if (!*p) {
1033 if (lvl == 0) {
1034 *s = 0; /* nul-terminate */
1035 return maxsize - count;
1036 }
1037 p = stack[--lvl];
1038 goto LOOP;
1039 }
1040
1041 o_count = 1;
1042 if ((*(o = p) == '%') && (*++p != '%')) {
1043 o_count = 2;
1044 mod = ILLEGAL_SPEC;
1045 if ((*p == 'O') || (*p == 'E')) { /* modifier */
1046 mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
1047 ++o_count;
1048 ++p;
1049 }
1050 if ((((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
1051 || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
1052 ) {
1053 if (!*p) {
1054 --p;
1055 --o_count;
1056 }
1057 goto OUTPUT;
1058 }
1059 code &= ILLEGAL_SPEC; /* modifiers are preserved in mod var. */
1060
1061 if ((code & MASK_SPEC) == STACKED_SPEC) {
1062 if (lvl == MAX_PUSH) {
1063 goto OUTPUT; /* Stack full so treat as illegal spec. */
1064 }
1065 stack[lvl++] = ++p;
1066 if ((code &= 0xf) < 8) {
1067 p = ((const char *) spec) + STACKED_STRINGS_START + code;
1068 p += *((unsigned char *)p);
1069 goto LOOP;
1070 }
1071 p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
1072 + (code & 7);
1073#ifdef ENABLE_ERA_CODE
1074 if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
1075 && (*(o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1076 (int)(((unsigned char *)p)[4]))
1077 __LOCALE_ARG
1078 )))
1079 ) {
1080 p = o;
1081 goto LOOP;
1082 }
1083#endif
1084 p = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1085 (int)(*((unsigned char *)p)))
1086 __LOCALE_ARG
1087 );
1088 goto LOOP;
1089 }
1090
1091 o = ((const char *) spec) + 26; /* set to "????" */
1092 if ((code & MASK_SPEC) == CALC_SPEC) {
1093
1094 if (*p == 's') {
1095 time_t t;
1096
1097 /* Use a cast to silence the warning since *timeptr won't
1098 * be changed. */
1099 if ((t = _time_mktime((struct tm *) timeptr, 0))
1100 == ((time_t) -1)
1101 ) {
1102 o_count = 1;
1103 goto OUTPUT;
1104 }
1105#ifdef TIME_T_IS_UNSIGNED
1106 o = _uintmaxtostr(buf + sizeof(buf) - 1,
1107 (uintmax_t) t,
1108 10, __UIM_DECIMAL);
1109#else
1110 o = _uintmaxtostr(buf + sizeof(buf) - 1,
1111 (uintmax_t) t,
1112 -10, __UIM_DECIMAL);
1113#endif
1114 o_count = sizeof(buf);
1115 goto OUTPUT;
1116 } else if (((*p) | 0x20) == 'z') { /* 'z' or 'Z' */
1117
1118 if (timeptr->tm_isdst < 0) {
1119 /* SUSv3 specifies this behavior for 'z', but we'll also
1120 * treat it as "no timezone info" for 'Z' too. */
1121 o_count = 0;
1122 goto OUTPUT;
1123 }
1124
1125#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1126
1127# ifdef __USE_BSD
1128# define RSP_TZNAME timeptr->tm_zone
1129# define RSP_GMT_OFFSET (-timeptr->tm_gmtoff)
1130# else
1131# define RSP_TZNAME timeptr->__tm_zone
1132# define RSP_GMT_OFFSET (-timeptr->__tm_gmtoff)
1133# endif
1134
1135#else
1136
1137#define RSP_TZNAME rsp->tzname
1138#define RSP_GMT_OFFSET rsp->gmt_offset
1139
1140 __UCLIBC_MUTEX_LOCK(_time_tzlock);
1141
1142 rsp = _time_tzinfo;
1143 if (timeptr->tm_isdst > 0) {
1144 ++rsp;
1145 }
1146#endif
1147
1148 if (*p == 'Z') {
1149 o = RSP_TZNAME;
1150#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1151 /* Sigh... blasted glibc extensions. Of course we can't
1152 * count on the pointer being valid. Best we can do is
1153 * handle NULL, which looks to be all that glibc does.
1154 * At least that catches the memset() with 0 case.
1155 * NOTE: We handle this case differently than glibc!
1156 * It uses system timezone name (based on tm_isdst) in this
1157 * case... although it always seems to use the embedded
1158 * tm_gmtoff value. What we'll do instead is treat the
1159 * timezone name as unknown/invalid and return "???". */
1160 if (!o) {
1161 o = "???";
1162 }
1163#endif
1164 assert(o != NULL);
1165#if 0
1166 if (!o) { /* PARANOIA */
1167 o = spec+30; /* empty string */
1168 }
1169#endif
1170 o_count = SIZE_MAX;
1171#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1172 goto OUTPUT;
1173#endif
1174 } else { /* z */
1175 *s = '+';
1176 if ((tzo = -RSP_GMT_OFFSET) < 0) {
1177 tzo = -tzo;
1178 *s = '-';
1179 }
1180 ++s;
1181 --count;
1182
1183 i = tzo / 60;
1184 field_val = ((i / 60) * 100) + (i % 60);
1185
1186 i = 16 + 6; /* 0-fill, width = 4 */
1187 }
1188#ifndef __UCLIBC_HAS_TM_EXTENSIONS__
1189 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
1190 if (*p == 'Z') {
1191 goto OUTPUT;
1192 }
1193#endif
1194 } else {
1195 /* TODO: don't need year for U, W */
1196 for (i=0 ; i < 3 ; i++) {
1197 if ((x[i] = load_field(spec[CALC_OFFSETS+i],timeptr)) < 0) {
1198 goto OUTPUT;
1199 }
1200 }
1201
1202 i = 16 + 2; /* 0-fill, width = 2 */
1203
1204 if ((*p == 'U') || (*p == 'W')) {
1205 field_val = ((x[1] - x[0]) + 7);
1206 if (*p == 'W') {
1207 ++field_val;
1208 }
1209 field_val /= 7;
1210 if ((*p == 'W') && !x[0]) {
1211 --field_val;
1212 }
1213 } else { /* ((*p == 'g') || (*p == 'G') || (*p == 'V')) */
1214ISO_LOOP:
1215 isofm = (((x[1] - x[0]) + 11) % 7) - 3; /* [-3,3] */
1216
1217 if (x[1] < isofm) { /* belongs to previous year */
1218 --x[2];
1219 x[1] += 365 + __isleap(x[2]);
1220 goto ISO_LOOP;
1221 }
1222
1223 field_val = ((x[1] - isofm) / 7) + 1; /* week # */
1224 days = 365 + __isleap(x[2]);
1225 isofm = ((isofm + 7*53 + 3 - days)) % 7 + days - 3; /* next year */
1226 if (x[1] >= isofm) { /* next year */
1227 x[1] -= days;
1228 ++x[2];
1229 goto ISO_LOOP;
1230 }
1231
1232 if (*p != 'V') { /* need year */
1233 field_val = x[2]; /* TODO: what if x[2] now 10000 ?? */
1234 if (*p == 'g') {
1235 field_val %= 100;
1236 } else {
1237 i = 16 + 6; /* 0-fill, width = 4 */
1238 }
1239 }
1240 }
1241 }
1242 } else {
1243 i = TP_OFFSETS + (code & 0x1f);
1244 if ((field_val = load_field(spec[i], timeptr)) < 0) {
1245 goto OUTPUT;
1246 }
1247
1248 i = spec[i+(TP_CODES - TP_OFFSETS)];
1249
1250 j = (i & 128) ? 100: 12;
1251 if (i & 64) {
1252 field_val /= j;;
1253 }
1254 if (i & 32) {
1255 field_val %= j;
1256 if (((i & 128) + field_val) == 0) { /* mod 12? == 0 */
1257 field_val = j; /* set to 12 */
1258 }
1259 }
1260 field_val += (i & 1);
1261 if ((i & 8) && !field_val) {
1262 field_val += 7;
1263 }
1264 }
1265
1266 if ((code & MASK_SPEC) == STRING_SPEC) {
1267 o_count = SIZE_MAX;
1268 field_val += spec[STRINGS_NL_ITEM_START + (code & 0xf)];
1269 o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME, field_val) __LOCALE_ARG);
1270 } else {
1271 o_count = ((i >> 1) & 3) + 1;
1272 o = buf + o_count;
1273 do {
1274 *(char *)(--o) = '0' + (field_val % 10);
1275 field_val /= 10;
1276 } while (o > buf);
1277 if (*buf == '0') {
1278 *buf = ' ' + (i & 16);
1279 }
1280 }
1281 }
1282
1283OUTPUT:
1284 ++p;
1285 while (o_count && count && *o) {
1286 *s++ = *o++;
1287 --o_count;
1288 --count;
1289 }
1290 goto LOOP;
1291}
1292# ifdef L_strftime_l
1293libc_hidden_def(strftime_l)
1294# endif
1295
1296#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1297
1298#endif
1299/**********************************************************************/
1300#if defined(L_strptime) || defined(L_strptime_l)
1301
1302#define ISDIGIT(C) __isdigit_char((C))
1303
1304#ifdef __UCLIBC_DO_XLOCALE
1305#define ISSPACE(C) isspace_l((C), locale_arg)
1306#else
1307#define ISSPACE(C) isspace((C))
1308#endif
1309
1310#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
1311
1312char *strptime(const char *__restrict buf, const char *__restrict format,
1313 struct tm *__restrict tm)
1314{
1315 return strptime_l(buf, format, tm, __UCLIBC_CURLOCALE);
1316}
1317
1318#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1319
1320/* TODO:
1321 * 1) %l and %k are space-padded, so "%l" by itself fails while " %l" succeeds.
1322 * Both work for glibc. So, should we always strip spaces?
1323 * 2) %Z
1324 */
1325
1326/* Notes:
1327 * There are several differences between this strptime and glibc's strptime.
1328 * 1) glibc strips leading space before numeric conversions.
1329 * 2) glibc will read fields without whitespace in between. SUSv3 states
1330 * that you must have whitespace between conversion operators. Besides,
1331 * how do you know how long a number should be if there are leading 0s?
1332 * 3) glibc attempts to compute some the struct tm fields based on the
1333 * data retrieved; tm_wday in particular. I don't as I consider it
1334 * another glibc attempt at mind-reading...
1335 */
1336
1337#define NO_E_MOD 0x80
1338#define NO_O_MOD 0x40
1339
1340#define ILLEGAL_SPEC 0x3f
1341
1342#define INT_SPEC 0x00 /* must be 0x00!! */
1343#define STRING_SPEC 0x10 /* must be 0x10!! */
1344#define CALC_SPEC 0x20
1345#define STACKED_SPEC 0x30
1346
1347#define MASK_SPEC 0x30
1348
1349/* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
1350static const unsigned char spec[] = {
1351 /* A */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1352 /* B */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1353 /* C */ 0x08 | INT_SPEC | NO_O_MOD,
1354 /* D */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1355 /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1356 /* F */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1357 /* G */ 0x0f | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1358 /* H */ 0x06 | INT_SPEC | NO_E_MOD,
1359 /* I */ 0x07 | INT_SPEC | NO_E_MOD,
1360 /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1361 /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1362 /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1363 /* M */ 0x04 | INT_SPEC | NO_E_MOD,
1364 /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1365 /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1366 /* P */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1367 /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1368 /* R */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1369 /* S */ 0x05 | INT_SPEC | NO_E_MOD,
1370 /* T */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1371 /* U */ 0x0c | INT_SPEC | NO_E_MOD,
1372 /* V */ 0x0d | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1373 /* W */ 0x0c | INT_SPEC | NO_E_MOD,
1374 /* X */ 0x0a | STACKED_SPEC | NO_O_MOD,
1375 /* Y */ 0x0a | INT_SPEC | NO_O_MOD,
1376 /* Z */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1377
1378 /* WARNING! This assumes orderings:
1379 * AM,PM
1380 * ABDAY_1-ABDAY-7,DAY_1-DAY_7
1381 * ABMON_1-ABMON_12,MON_1-MON12
1382 * Also, there are exactly 6 bytes between 'Z' and 'a'.
1383 */
1384#define STRINGS_NL_ITEM_START (26)
1385 _NL_ITEM_INDEX(AM_STR), /* p (P) */
1386 _NL_ITEM_INDEX(ABMON_1), /* B, b */
1387 _NL_ITEM_INDEX(ABDAY_1), /* A, a */
1388 2,
1389 24,
1390 14,
1391
1392 /* a */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1393 /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1394 /* c */ 0x08 | STACKED_SPEC | NO_O_MOD,
1395 /* d */ 0x00 | INT_SPEC | NO_E_MOD,
1396 /* e */ 0x00 | INT_SPEC | NO_E_MOD,
1397 /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1398 /* g */ 0x0e | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1399 /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1400 /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1401 /* j */ 0x01 | INT_SPEC | NO_E_MOD | NO_O_MOD,
1402 /* k */ 0x06 | INT_SPEC | NO_E_MOD, /* glibc */
1403 /* l */ 0x07 | INT_SPEC | NO_E_MOD, /* glibc */
1404 /* m */ 0x02 | INT_SPEC | NO_E_MOD,
1405 /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1406 /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1407 /* p */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1408 /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1409 /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1410 /* s */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1411 /* t */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1412 /* u */ 0x0b | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1413 /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1414 /* w */ 0x03 | INT_SPEC | NO_E_MOD,
1415 /* x */ 0x09 | STACKED_SPEC | NO_O_MOD,
1416 /* y */ 0x09 | INT_SPEC,
1417 /* z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1418
1419#define INT_FIELD_START (26+6+26)
1420 /* (field #) << 3 + lower bound (0|1) + correction 0:none, 2:-1, 4:-1900
1421 * followed by upper bound prior to correction with 1=>366 and 2=>9999. */
1422 /* d, e */ (3 << 3) + 1 + 0, 31,
1423 /* j */ (7 << 3) + 1 + 2, /* 366 */ 1,
1424 /* m */ (4 << 3) + 1 + 2, 12,
1425 /* w */ (6 << 3) + 0 + 0, 6,
1426 /* M */ (1 << 3) + 0 + 0, 59,
1427 /* S */ 0 + 0 + 0, 60,
1428 /* H (k) */ (2 << 3) + 0 + 0, 23,
1429 /* I (l) */ (9 << 3) + 1 + 0, 12, /* goes with 8 -- am/pm */
1430 /* C */ (10<< 3) + 0 + 0, 99,
1431 /* y */ (11<< 3) + 0 + 0, 99,
1432 /* Y */ (5 << 3) + 0 + 4, /* 9999 */ 2,
1433 /* u */ (6 << 3) + 1 + 0, 7,
1434 /* The following are processed and range-checked, but ignored otherwise. */
1435 /* U, W */ (12<< 3) + 0 + 0, 53,
1436 /* V */ (12<< 3) + 1 + 0, 53,
1437 /* g */ (12<< 3) + 0 + 0, 99,
1438 /* G */ (12<< 3) + 0 /*+ 4*/, /* 9999 */ 2, /* Note: -1 or 10000? */
1439
1440#define STACKED_STRINGS_START (INT_FIELD_START+32)
1441 5, 6, 14, 22, 27, /* 5 - offsets from offset-count to strings */
1442 ' ', 0, /* 2 - %n or %t */
1443 '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
1444 '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
1445 '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
1446 '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
1447
1448#define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 40)
1449 _NL_ITEM_INDEX(D_T_FMT), /* c */
1450 _NL_ITEM_INDEX(D_FMT), /* x */
1451 _NL_ITEM_INDEX(T_FMT), /* X */
1452 _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
1453#ifdef ENABLE_ERA_CODE
1454 _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
1455 _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */
1456 _NL_ITEM_INDEX(ERA_T_FMT), /* EX */
1457#endif
1458};
1459
1460#define MAX_PUSH 4
1461
1462char *__XL_NPP(strptime)(const char *__restrict buf, const char *__restrict format,
1463 struct tm *__restrict tm __LOCALE_PARAM)
1464{
1465 register const char *p;
1466 char *o;
1467 const char *stack[MAX_PUSH];
1468 int i, j, lvl;
1469 int fields[13];
1470 unsigned char mod;
1471 unsigned char code;
1472
1473 i = 0;
1474 do {
1475 fields[i] = INT_MIN;
1476 } while (++i < 13);
1477
1478 lvl = 0;
1479 p = format;
1480
1481LOOP:
1482 if (!*p) {
1483 if (lvl == 0) { /* Done. */
1484 if (fields[6] == 7) { /* Cleanup for %u here since just once. */
1485 fields[6] = 0; /* Don't use mod in case unset. */
1486 }
1487
1488 i = 0;
1489 do { /* Store the values into tm. */
1490 if (fields[i] != INT_MIN) {
1491 ((int *) tm)[i] = fields[i];
1492 }
1493 } while (++i < 8);
1494
1495 return (char *) buf; /* Success. */
1496 }
1497 p = stack[--lvl];
1498 goto LOOP;
1499 }
1500
1501 if ((*p == '%') && (*++p != '%')) {
1502 mod = ILLEGAL_SPEC;
1503 if ((*p == 'O') || (*p == 'E')) { /* Modifier? */
1504 mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
1505 ++p;
1506 }
1507
1508 if (!*p
1509 || (((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
1510 || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
1511 ) {
1512 return NULL; /* Illegal spec. */
1513 }
1514
1515 if ((code & MASK_SPEC) == STACKED_SPEC) {
1516 if (lvl == MAX_PUSH) {
1517 return NULL; /* Stack full so treat as illegal spec. */
1518 }
1519 stack[lvl++] = ++p;
1520 if ((code &= 0xf) < 8) {
1521 p = ((const char *) spec) + STACKED_STRINGS_START + code;
1522 p += *((unsigned char *)p);
1523 goto LOOP;
1524 }
1525
1526 p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
1527 + (code & 7);
1528#ifdef ENABLE_ERA_CODE
1529 if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
1530 && (*(o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1531 (int)(((unsigned char *)p)[4]))
1532 __LOCALE_ARG
1533 )))
1534 ) {
1535 p = o;
1536 goto LOOP;
1537 }
1538#endif
1539 p = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1540 (int)(*((unsigned char *)p)))
1541 __LOCALE_ARG
1542 );
1543 goto LOOP;
1544 }
1545
1546 ++p;
1547
1548 if ((code & MASK_SPEC) == STRING_SPEC) {
1549 code &= 0xf;
1550 j = spec[STRINGS_NL_ITEM_START + 3 + code];
1551 i = _NL_ITEM(LC_TIME, spec[STRINGS_NL_ITEM_START + code]);
1552 /* Go backwards to check full names before abreviations. */
1553 do {
1554 --j;
1555 o = __XL_NPP(nl_langinfo)(i+j __LOCALE_ARG);
1556 if (!__XL_NPP(strncasecmp)(buf, o, strlen(o) __LOCALE_ARG) && *o) {
1557 do { /* Found a match. */
1558 ++buf;
1559 } while (*++o);
1560 if (!code) { /* am/pm */
1561 fields[8] = j * 12;
1562 if (fields[9] >= 0) { /* We have a previous %I or %l. */
1563 fields[2] = fields[9] + fields[8];
1564 }
1565 } else { /* day (4) or month (6) */
1566 fields[2 + (code << 1)]
1567 = j % (spec[STRINGS_NL_ITEM_START + 3 + code] >> 1);
1568 }
1569 goto LOOP;
1570 }
1571 } while (j);
1572 return NULL; /* Failed to match. */
1573 }
1574
1575 if ((code & MASK_SPEC) == CALC_SPEC) {
1576 if ((code &= 0xf) < 1) { /* s or z*/
1577 time_t t;
1578
1579 o = (char *) buf;
1580 i = errno;
1581 __set_errno(0);
1582 if (!ISSPACE(*buf)) { /* Signal an error if whitespace. */
1583#ifdef TIME_T_IS_UNSIGNED
1584 t = __XL_NPP(strtoul)(buf, &o, 10 __LOCALE_ARG);
1585#else
1586 t = __XL_NPP(strtol)(buf, &o, 10 __LOCALE_ARG);
1587#endif
1588 }
1589 if ((o == buf) || errno) { /* Not a number or overflow. */
1590 return NULL;
1591 }
1592 __set_errno(i); /* Restore errno. */
1593 buf = o;
1594
1595 if (!code) { /* s */
1596 localtime_r(&t, tm); /* TODO: check for failure? */
1597 i = 0;
1598 do { /* Now copy values from tm to fields. */
1599 fields[i] = ((int *) tm)[i];
1600 } while (++i < 8);
1601 }
1602 }
1603 /* TODO: glibc treats %Z as a nop. For now, do the same. */
1604 goto LOOP;
1605 }
1606
1607 assert((code & MASK_SPEC) == INT_SPEC);
1608 {
1609 register const unsigned char *x;
1610 code &= 0xf;
1611 x = spec + INT_FIELD_START + (code << 1);
1612 if ((j = x[1]) < 3) { /* upper bound (inclusive) */
1613 j = ((j==1) ? 366 : 9999);
1614 }
1615 i = -1;
1616 while (ISDIGIT(*buf)) {
1617 if (i < 0) {
1618 i = 0;
1619 }
1620 if ((i = 10*i + (*buf - '0')) > j) { /* Overflow. */
1621 return NULL;
1622 }
1623 ++buf;
1624 }
1625 if (i < (*x & 1)) { /* This catches no-digit case too. */
1626 return NULL;
1627 }
1628 if (*x & 2) {
1629 --i;
1630 }
1631 if (*x & 4) {
1632 i -= 1900;
1633 }
1634
1635 if (*x == (9 << 3) + 1 + 0) { /* %I or %l */
1636 if (i == 12) {
1637 i = 0;
1638 }
1639 if (fields[8] >= 0) { /* We have a previous %p or %P. */
1640 fields[2] = i + fields[8];
1641 }
1642 }
1643
1644 fields[(*x) >> 3] = i;
1645
1646 if (((unsigned char)(*x - (10 << 3) + 0 + 0)) <= 8) { /* %C or %y */
1647 if ((j = fields[10]) < 0) { /* No %C, so i must be %y data. */
1648 if (i <= 68) { /* Map [0-68] to 2000+i */
1649 i += 100;
1650 }
1651 } else { /* Have %C data, but what about %y? */
1652 if ((i = fields[11]) < 0) { /* No %y data. */
1653 i = 0; /* Treat %y val as 0 following glibc's example. */
1654 }
1655 i += 100*(j - 19);
1656 }
1657 fields[5] = i;
1658 }
1659 }
1660 goto LOOP;
1661 } else if (ISSPACE(*p)) {
1662 ++p;
1663 while (ISSPACE(*buf)) {
1664 ++buf;
1665 }
1666 goto LOOP;
1667 } else if (*buf++ == *p++) {
1668 goto LOOP;
1669 }
1670 return NULL;
1671}
1672# ifdef L_strptime_l
1673libc_hidden_def(strptime_l)
1674# endif
1675
1676#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1677
1678#endif
1679/**********************************************************************/
1680#ifdef L_time
1681
1682#ifndef __BCC__
1683#error The uClibc version of time is in sysdeps/linux/common.
1684#endif
1685
1686time_t time(register time_t *tloc)
1687{
1688 struct timeval tv;
1689 register struct timeval *p = &tv;
1690
1691 gettimeofday(p, NULL); /* This should never fail... */
1692
1693 if (tloc) {
1694 *tloc = p->tv_sec;
1695 }
1696
1697 return p->tv_sec;
1698}
1699
1700#endif
1701/**********************************************************************/
1702#ifdef L_tzset
1703
1704static const char vals[] = {
1705 'T', 'Z', 0, /* 3 */
1706 'U', 'T', 'C', 0, /* 4 */
1707 25, 60, 60, 1, /* 4 */
1708 '.', 1, /* M */
1709 5, '.', 1,
1710 6, 0, 0, /* Note: overloaded for non-M non-J case... */
1711 0, 1, 0, /* J */
1712 ',', 'M', '4', '.', '1', '.', '0',
1713 ',', 'M', '1', '0', '.', '5', '.', '0', 0,
1714 ',', 'M', '3', '.', '2', '.', '0',
1715 ',', 'M', '1', '1', '.', '1', '.', '0', 0
1716};
1717
1718#define TZ vals
1719#define UTC (vals + 3)
1720#define RANGE (vals + 7)
1721#define RULE (vals + 11 - 1)
1722#define DEFAULT_RULES (vals + 22)
1723#define DEFAULT_2007_RULES (vals + 38)
1724
1725/* Initialize to UTC. */
1726int daylight = 0;
1727long timezone = 0;
1728char *tzname[2] = { (char *) UTC, (char *) (UTC-1) };
1729
1730__UCLIBC_MUTEX_INIT(_time_tzlock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
1731
1732rule_struct _time_tzinfo[2];
1733
1734static const char *getoffset(register const char *e, long *pn)
1735{
1736 register const char *s = RANGE-1;
1737 long n;
1738 int f;
1739
1740 n = 0;
1741 f = -1;
1742 do {
1743 ++s;
1744 if (__isdigit_char(*e)) {
1745 f = *e++ - '0';
1746 }
1747 if (__isdigit_char(*e)) {
1748 f = 10 * f + (*e++ - '0');
1749 }
1750 if (((unsigned int)f) >= *s) {
1751 return NULL;
1752 }
1753 n = (*s) * n + f;
1754 f = 0;
1755 if (*e == ':') {
1756 ++e;
1757 --f;
1758 }
1759 } while (*s > 1);
1760
1761 *pn = n;
1762 return e;
1763}
1764
1765static const char *getnumber(register const char *e, int *pn)
1766{
1767#ifdef __BCC__
1768 /* bcc can optimize the counter if it thinks it is a pointer... */
1769 register const char *n = (const char *) 3;
1770 int f;
1771
1772 f = 0;
1773 while (n && __isdigit_char(*e)) {
1774 f = 10 * f + (*e++ - '0');
1775 --n;
1776 }
1777
1778 *pn = f;
1779 return (n == (const char *) 3) ? NULL : e;
1780#else /* __BCC__ */
1781 int n, f;
1782
1783 n = 3;
1784 f = 0;
1785 while (n && __isdigit_char(*e)) {
1786 f = 10 * f + (*e++ - '0');
1787 --n;
1788 }
1789
1790 *pn = f;
1791 return (n == 3) ? NULL : e;
1792#endif /* __BCC__ */
1793}
1794
1795
1796#ifdef __UCLIBC_MJN3_ONLY__
1797#warning CONSIDER: Should we preserve errno from open/read/close errors re TZ file?
1798#endif
1799
1800#ifdef __UCLIBC_HAS_TZ_FILE__
1801
1802#ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1803static smallint TZ_file_read; /* Let BSS initialization set this to 0. */
1804#endif
1805
1806static char *read_TZ_file(char *buf)
1807{
1808 int r;
1809 int fd;
1810 char *p = NULL;
1811
1812 fd = open(__UCLIBC_TZ_FILE_PATH__, O_RDONLY);
1813 if (fd >= 0) {
1814#if 0
1815 /* TZ are small *files*. On files, short reads
1816 * only occur on EOF (unlike, say, pipes).
1817 * The code below is pedanticallly more correct,
1818 * but this way we always read at least twice:
1819 * 1st read is short, 2nd one is zero bytes.
1820 */
1821 size_t todo = TZ_BUFLEN;
1822 p = buf;
1823 do {
1824 r = read(fd, p, todo);
1825 if (r < 0)
1826 goto ERROR;
1827 if (r == 0)
1828 break;
1829 p += r;
1830 todo -= r;
1831 } while (todo);
1832#else
1833 /* Shorter, and does one fewer read syscall */
1834 r = read(fd, buf, TZ_BUFLEN);
1835 if (r < 0)
1836 goto ERROR;
1837 p = buf + r;
1838#endif
1839 if ((p > buf) && (p[-1] == '\n')) { /* Must end with newline */
1840 p[-1] = 0;
1841 p = buf;
1842#ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1843 TZ_file_read = 1;
1844#endif
1845 } else {
1846ERROR:
1847 p = NULL;
1848 }
1849 close(fd);
1850 }
1851#ifdef __UCLIBC_FALLBACK_TO_ETC_LOCALTIME__
1852 else {
1853 fd = open("/etc/localtime", O_RDONLY);
1854 if (fd >= 0) {
1855 r = read(fd, buf, TZ_BUFLEN);
1856 if (r != TZ_BUFLEN
1857 || strncmp(buf, "TZif", 4) != 0
1858 || (unsigned char)buf[4] < 2
1859 || lseek(fd, -TZ_BUFLEN, SEEK_END) < 0
1860 ) {
1861 goto ERROR;
1862 }
1863 /* tzfile.h from tzcode database says about TZif2+ files:
1864 **
1865 ** If tzh_version is '2' or greater, the above is followed by a second instance
1866 ** of tzhead and a second instance of the data in which each coded transition
1867 ** time uses 8 rather than 4 chars,
1868 ** then a POSIX-TZ-environment-variable-style string for use in handling
1869 ** instants after the last transition time stored in the file
1870 ** (with nothing between the newlines if there is no POSIX representation for
1871 ** such instants).
1872 */
1873 r = read(fd, buf, TZ_BUFLEN);
1874 if (r <= 0 || buf[--r] != '\n')
1875 goto ERROR;
1876 buf[r] = 0;
1877 while (r != 0) {
1878 if (buf[--r] == '\n') {
1879 p = buf + r + 1;
1880#ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1881 TZ_file_read = 1;
1882#endif
1883 break;
1884 }
1885 } /* else ('\n' not found): p remains NULL */
1886 close(fd);
1887 }
1888 }
1889#endif /* __UCLIBC_FALLBACK_TO_ETC_LOCALTIME__ */
1890 return p;
1891}
1892
1893#endif /* __UCLIBC_HAS_TZ_FILE__ */
1894
1895void tzset(void)
1896{
1897 _time_tzset((time(NULL)) < new_rule_starts);
1898}
1899
1900void _time_tzset(int use_old_rules)
1901{
1902 register const char *e;
1903 register char *s;
1904 long off = 0;
1905 short *p;
1906 rule_struct new_rules[2];
1907 int n, count, f;
1908 char c;
1909#ifdef __UCLIBC_HAS_TZ_FILE__
1910 char buf[TZ_BUFLEN];
1911#endif
1912#ifdef __UCLIBC_HAS_TZ_CACHING__
1913 static char oldval[TZ_BUFLEN]; /* BSS-zero'd. */
1914#endif
1915
1916 /* Put this inside the lock to prevent the possibility of two different
1917 * timezones being used in a threaded app. */
1918 __UCLIBC_MUTEX_LOCK(_time_tzlock);
1919
1920 e = getenv(TZ); /* TZ env var always takes precedence. */
1921
1922#if defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__)
1923 if (e) {
1924 /* Never use TZfile if TZ env var is set. */
1925 TZ_file_read = 0;
1926 }
1927 if (TZ_file_read) {
1928 /* We already parsed TZfile before, skip everything. */
1929 goto FAST_DONE;
1930 }
1931#endif
1932
1933 /* Warning!!! Since uClibc doesn't do lib locking, the following is
1934 * potentially unsafe in a multi-threaded program since it is remotely
1935 * possible that another thread could call setenv() for TZ and overwrite
1936 * the string being parsed. So, don't do that... */
1937
1938#ifdef __UCLIBC_HAS_TZ_FILE__
1939 if (!e)
1940 e = read_TZ_file(buf);
1941#endif
1942 if (!e /* TZ env var not set and no TZfile (or bad TZfile) */
1943 || !*e /* or set to empty string. */
1944 ) {
1945 goto ILLEGAL;
1946 }
1947
1948 if (*e == ':') { /* Ignore leading ':'. */
1949 ++e;
1950 }
1951
1952#ifdef __UCLIBC_HAS_TZ_CACHING__
1953 if (strcmp(e, oldval) == 0) {
1954 /* Same string as last time... nothing to do. */
1955 goto FAST_DONE;
1956 }
1957 /* Make a copy of the TZ env string. It won't be nul-terminated if
1958 * it is too long, but it that case it will be illegal and will be reset
1959 * to the empty string anyway. */
1960 strncpy(oldval, e, TZ_BUFLEN);
1961#endif
1962
1963 count = 0;
1964 new_rules[1].tzname[0] = 0;
1965LOOP:
1966 /* Get std or dst name. */
1967 c = 0;
1968 if (*e == '<') {
1969 ++e;
1970 c = '>';
1971 }
1972
1973 s = new_rules[count].tzname;
1974 n = 0;
1975 while (*e
1976 && isascii(*e) /* SUSv3 requires char in portable char set. */
1977 && (isalpha(*e)
1978 || (c && (isalnum(*e) || (*e == '+') || (*e == '-')))
1979 )
1980 ) {
1981 *s++ = *e++;
1982 if (++n > TZNAME_MAX) {
1983 goto ILLEGAL;
1984 }
1985 }
1986 *s = 0;
1987
1988 if ((n < 3) /* Check for minimum length. */
1989 || (c && (*e++ != c)) /* Match any quoting '<'. */
1990 ) {
1991 goto ILLEGAL;
1992 }
1993
1994 /* Get offset */
1995 s = (char *) e;
1996 if ((*e != '-') && (*e != '+')) {
1997 if (count && !__isdigit_char(*e)) {
1998 off -= 3600; /* Default to 1 hour ahead of std. */
1999 goto SKIP_OFFSET;
2000 }
2001 --e;
2002 }
2003
2004 ++e;
2005 e = getoffset(e, &off);
2006 if (!e) {
2007 goto ILLEGAL;
2008 }
2009
2010 if (*s == '-') {
2011 off = -off; /* Save off in case needed for dst default. */
2012 }
2013SKIP_OFFSET:
2014 new_rules[count].gmt_offset = off;
2015
2016 if (!count) {
2017 new_rules[1].gmt_offset = off; /* Shouldn't be needed... */
2018 if (*e) {
2019 ++count;
2020 goto LOOP;
2021 }
2022 } else { /* OK, we have dst, so get some rules. */
2023 count = 0;
2024 if (!*e) { /* No rules so default to US rules. */
2025 e = use_old_rules ? DEFAULT_RULES : DEFAULT_2007_RULES;
2026#ifdef DEBUG_TZSET
2027 if (e == DEFAULT_RULES)
2028 printf("tzset: Using old rules.\n");
2029 else if (e == DEFAULT_2007_RULES)
2030 printf("tzset: Using new rules\n");
2031 else
2032 printf("tzset: Using undefined rules\n");
2033#endif
2034 }
2035
2036 do {
2037 if (*e++ != ',') {
2038 goto ILLEGAL;
2039 }
2040
2041 n = 365;
2042 s = (char *) RULE;
2043 c = *e++;
2044 if (c == 'M') {
2045 n = 12;
2046 } else if (c == 'J') {
2047 s += 8;
2048 } else {
2049 --e;
2050 c = 0;
2051 s += 6;
2052 }
2053
2054 p = &new_rules[count].rule_type;
2055 *p = c;
2056 if (c != 'M') {
2057 p -= 2;
2058 }
2059
2060 do {
2061 ++s;
2062 e = getnumber(e, &f);
2063 if (!e
2064 || ((unsigned int)(f - s[1]) > n)
2065 || (*s && (*e++ != *s))
2066 ) {
2067 goto ILLEGAL;
2068 }
2069 *--p = f;
2070 s += 2;
2071 n = *s;
2072 } while (n > 0);
2073
2074 off = 2 * 60 * 60; /* Default to 2:00:00 */
2075 if (*e == '/') {
2076 ++e;
2077 e = getoffset(e, &off);
2078 if (!e) {
2079 goto ILLEGAL;
2080 }
2081 }
2082 new_rules[count].dst_offset = off;
2083 } while (++count < 2);
2084
2085 if (*e) {
2086ILLEGAL:
2087#ifdef __UCLIBC_HAS_TZ_CACHING__
2088 oldval[0] = 0; /* oldval = "" */
2089#endif
2090 memset(_time_tzinfo, 0, sizeof(_time_tzinfo));
2091 strcpy(_time_tzinfo[0].tzname, UTC);
2092 goto DONE;
2093 }
2094 }
2095
2096 memcpy(_time_tzinfo, new_rules, sizeof(new_rules));
2097DONE:
2098 tzname[0] = _time_tzinfo[0].tzname;
2099 tzname[1] = _time_tzinfo[1].tzname;
2100 daylight = !!_time_tzinfo[1].tzname[0];
2101 timezone = _time_tzinfo[0].gmt_offset;
2102
2103#if defined(__UCLIBC_HAS_TZ_FILE__) || defined(__UCLIBC_HAS_TZ_CACHING__)
2104FAST_DONE:
2105#endif
2106 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
2107}
2108libc_hidden_def(tzset)
2109#endif
2110/**********************************************************************/
2111/* #ifdef L_utime */
2112
2113/* utime is a syscall in both linux and elks. */
2114/* int utime(const char *path, const struct utimbuf *times) */
2115
2116/* #endif */
2117/**********************************************************************/
2118/* Non-SUSv3 */
2119/**********************************************************************/
2120#ifdef L_utimes
2121
2122#ifndef __BCC__
2123#error The uClibc version of utimes is in sysdeps/linux/common.
2124#endif
2125
2126#include <utime.h>
2127
2128int utimes(const char *filename, register const struct timeval *tvp)
2129{
2130 register struct utimbuf *p = NULL;
2131 struct utimbuf utb;
2132
2133 if (tvp) {
2134 p = &utb;
2135 p->actime = tvp[0].tv_sec;
2136 p->modtime = tvp[1].tv_sec;
2137 }
2138 return utime(filename, p);
2139}
2140
2141#endif
2142/**********************************************************************/
2143#ifdef L__time_t2tm
2144
2145static const uint16_t _vals[] = {
2146 60, 60, 24, 7 /* special */, 36524, 1461, 365, 0
2147};
2148
2149static const unsigned char days[] = {
2150 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
2151 29,
2152};
2153
2154#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
2155static const char utc_string[] = "UTC";
2156#endif
2157
2158/* Notes:
2159 * If time_t is 32 bits, then no overflow is possible.
2160 * It time_t is > 32 bits, this needs to be adjusted to deal with overflow.
2161 */
2162
2163/* Note: offset is the correction in _days_ to *timer! */
2164
2165struct tm attribute_hidden *_time_t2tm(const time_t *__restrict timer,
2166 int offset, struct tm *__restrict result)
2167{
2168 register int *p;
2169 time_t t1, t, v;
2170 int wday = wday; /* ok to be uninitialized, shutting up warning */
2171
2172 {
2173 register const uint16_t *vp;
2174 t = *timer;
2175 p = (int *) result;
2176 p[7] = 0;
2177 vp = _vals;
2178 do {
2179 if ((v = *vp) == 7) {
2180 /* Overflow checking, assuming time_t is long int... */
2181#if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
2182#if (INT_MAX == 2147483647L) && (LONG_MAX == 9223372036854775807L)
2183 /* Valid range for t is [-784223472856L, 784223421720L].
2184 * Outside of this range, the tm_year field will overflow. */
2185 if (((unsigned long)(t + offset- -784223472856L))
2186 > (784223421720L - -784223472856L)
2187 ) {
2188 return NULL;
2189 }
2190#else
2191#error overflow conditions unknown
2192#endif
2193#endif
2194
2195 /* We have days since the epoch, so caluclate the weekday. */
2196#if defined(__BCC__) && TIME_T_IS_UNSIGNED
2197 wday = (t + 4) % (*vp); /* t is unsigned */
2198#else
2199 wday = ((int)((t % (*vp)) + 11)) % ((int)(*vp)); /* help bcc */
2200#endif
2201 /* Set divisor to days in 400 years. Be kind to bcc... */
2202 v = ((time_t)(vp[1])) << 2;
2203 ++v;
2204 /* Change to days since 1/1/1601 so that for 32 bit time_t
2205 * values, we'll have t >= 0. This should be changed for
2206 * archs with larger time_t types.
2207 * Also, correct for offset since a multiple of 7. */
2208
2209 /* TODO: Does this still work on archs with time_t > 32 bits? */
2210 t += (135140L - 366) + offset; /* 146097 - (365*30 + 7) -366 */
2211 }
2212#if defined(__BCC__) && TIME_T_IS_UNSIGNED
2213 t -= ((t1 = t / v) * v);
2214#else
2215 if ((t -= ((t1 = t / v) * v)) < 0) {
2216 t += v;
2217 --t1;
2218 }
2219#endif
2220
2221 if ((*vp == 7) && (t == v-1)) {
2222 --t; /* Correct for 400th year leap case */
2223 ++p[4]; /* Stash the extra day... */
2224 }
2225
2226#if defined(__BCC__) && 0
2227 *p = t1;
2228 if (v <= 60) {
2229 *p = t;
2230 t = t1;
2231 }
2232 ++p;
2233#else
2234 if (v <= 60) {
2235 *p++ = t;
2236 t = t1;
2237 } else {
2238 *p++ = t1;
2239 }
2240#endif
2241 } while (*++vp);
2242 }
2243
2244 if (p[-1] == 4) {
2245 --p[-1];
2246 t = 365;
2247 }
2248
2249 *p += ((int) t); /* result[7] .. tm_yday */
2250
2251 p -= 2; /* at result[5] */
2252
2253#if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
2254 /* Protect against overflow. TODO: Unecessary if int arith wraps? */
2255 *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + (p[1] - 299); /* tm_year */
2256#else
2257 *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + p[1] - 299; /* tm_year */
2258#endif
2259
2260 p[1] = wday; /* result[6] .. tm_wday */
2261
2262 {
2263 register const unsigned char *d = days;
2264
2265 wday = 1900 + *p;
2266 if (__isleap(wday)) {
2267 d += 11;
2268 }
2269
2270 wday = p[2] + 1; /* result[7] .. tm_yday */
2271 *--p = 0; /* at result[4] .. tm_mon */
2272 while (wday > *d) {
2273 wday -= *d;
2274 if (*d == 29) {
2275 d -= 11; /* Backup to non-leap Feb. */
2276 }
2277 ++d;
2278 ++*p; /* Increment tm_mon. */
2279 }
2280 p[-1] = wday; /* result[3] .. tm_mday */
2281 }
2282 /* TODO -- should this be 0? */
2283 p[4] = 0; /* result[8] .. tm_isdst */
2284#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
2285# ifdef __USE_BSD
2286 result->tm_gmtoff = 0;
2287 result->tm_zone = utc_string;
2288# else
2289 result->__tm_gmtoff = 0;
2290 result->__tm_zone = utc_string;
2291# endif
2292#endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
2293
2294 return result;
2295}
2296
2297#endif
2298/**********************************************************************/
2299#ifdef L___time_tm
2300
2301struct tm __time_tm; /* Global shared by gmtime() and localtime(). */
2302
2303#endif
2304/**********************************************************************/
2305#ifdef L__time_mktime
2306
2307time_t attribute_hidden _time_mktime(struct tm *timeptr, int store_on_success)
2308{
2309 time_t t;
2310
2311 __UCLIBC_MUTEX_LOCK(_time_tzlock);
2312
2313 tzset();
2314
2315 t = _time_mktime_tzi(timeptr, store_on_success, _time_tzinfo);
2316
2317 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
2318
2319 return t;
2320}
2321
2322#endif
2323/**********************************************************************/
2324#ifdef L__time_mktime_tzi
2325
2326static const unsigned char __vals[] = {
2327 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
2328 29,
2329};
2330
2331time_t attribute_hidden _time_mktime_tzi(struct tm *timeptr, int store_on_success,
2332 rule_struct *tzi)
2333{
2334#ifdef __BCC__
2335 long days, secs;
2336#else
2337 long long secs;
2338#endif
2339 time_t t;
2340 struct tm x;
2341 /* 0:sec 1:min 2:hour 3:mday 4:mon 5:year 6:wday 7:yday 8:isdst */
2342 register int *p = (int *) &x;
2343 register const unsigned char *s;
2344 int d, default_dst;
2345
2346 memcpy(p, timeptr, sizeof(struct tm));
2347
2348 if (!tzi[1].tzname[0]) { /* No dst in this timezone, */
2349 p[8] = 0; /* so set tm_isdst to 0. */
2350 }
2351
2352 default_dst = 0;
2353 if (p[8]) { /* Either dst or unknown? */
2354 default_dst = 1; /* Assume advancing (even if unknown). */
2355 p[8] = ((p[8] > 0) ? 1 : -1); /* Normalize so abs() <= 1. */
2356 }
2357
2358 d = 400;
2359 p[5] = (p[5] - ((p[6] = p[5]/d) * d)) + (p[7] = p[4]/12);
2360 if ((p[4] -= 12 * p[7]) < 0) {
2361 p[4] += 12;
2362 --p[5];
2363 }
2364
2365 s = __vals;
2366 d = (p[5] += 1900); /* Correct year. Now between 1900 and 2300. */
2367 if (__isleap(d)) {
2368 s += 11;
2369 }
2370
2371 p[7] = 0;
2372 d = p[4];
2373 while (d) {
2374 p[7] += *s;
2375 if (*s == 29) {
2376 s -= 11; /* Backup to non-leap Feb. */
2377 }
2378 ++s;
2379 --d;
2380 }
2381
2382 _time_tzset (x.tm_year < 2007); /* tm_year was expanded above */
2383
2384#ifdef __BCC__
2385 d = p[5] - 1;
2386 days = -719163L + ((long)d)*365 + ((d/4) - (d/100) + (d/400) + p[3] + p[7]);
2387 secs = p[0] + 60*( p[1] + 60*((long)(p[2])) )
2388 + tzi[default_dst].gmt_offset;
2389DST_CORRECT:
2390 if (secs < 0) {
2391 secs += 120009600L;
2392 days -= 1389;
2393 }
2394 if ( ((unsigned long)(days + secs/86400L)) > 49710L) {
2395 t = ((time_t)(-1));
2396 goto DONE;
2397 }
2398 secs += (days * 86400L);
2399#else
2400 d = p[5] - 1;
2401 d = -719163L + d*365 + (d/4) - (d/100) + (d/400);
2402 secs = p[0]
2403 + tzi[default_dst].gmt_offset
2404 + 60*( p[1]
2405 + 60*(p[2]
2406 + 24*(((146073L * ((long long)(p[6])) + d)
2407 + p[3]) + p[7])));
2408
2409DST_CORRECT:
2410 if (((unsigned long long)(secs - LONG_MIN))
2411 > (((unsigned long long)LONG_MAX) - LONG_MIN)
2412 ) {
2413 t = ((time_t)(-1));
2414 goto DONE;
2415 }
2416#endif
2417
2418 d = ((struct tm *)p)->tm_isdst;
2419 t = secs;
2420
2421 __time_localtime_tzi(&t, (struct tm *)p, tzi);
2422
2423 if (t == ((time_t)(-1))) { /* Remember, time_t can be unsigned. */
2424 goto DONE;
2425 }
2426
2427 if ((d < 0) && (((struct tm *)p)->tm_isdst != default_dst)) {
2428#ifdef __BCC__
2429 secs -= (days * 86400L);
2430#endif
2431 secs += (tzi[1-default_dst].gmt_offset
2432 - tzi[default_dst].gmt_offset);
2433 goto DST_CORRECT;
2434 }
2435
2436
2437 if (store_on_success) {
2438 memcpy(timeptr, p, sizeof(struct tm));
2439 }
2440
2441
2442DONE:
2443 return t;
2444}
2445
2446#endif
2447/**********************************************************************/
2448#if defined(L_wcsftime) || defined(L_wcsftime_l)
2449
2450#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
2451
2452size_t wcsftime(wchar_t *__restrict s, size_t maxsize,
2453 const wchar_t *__restrict format,
2454 const struct tm *__restrict timeptr)
2455{
2456 return wcsftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE);
2457}
2458
2459#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
2460
2461size_t __XL_NPP(wcsftime)(wchar_t *__restrict s, size_t maxsize,
2462 const wchar_t *__restrict format,
2463 const struct tm *__restrict timeptr __LOCALE_PARAM )
2464{
2465#warning wcsftime always fails
2466 return 0; /* always fail */
2467}
2468#ifdef L_wcsftime_l
2469libc_hidden_def(wcsftime_l)
2470#endif
2471
2472#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
2473
2474#endif
2475/**********************************************************************/
2476#ifdef L_dysize
2477/* Return the number of days in YEAR. */
2478
2479int dysize(int year)
2480{
2481 return __isleap(year) ? 366 : 365;
2482}
2483
2484#endif
2485/**********************************************************************/