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