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