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