OSDN Git Service

locale: Add wcsftime()
[uclinux-h8/uClibc.git] / libc / misc / time / time.c
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
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
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 }
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
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 }
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
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
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
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
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 }
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
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
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
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
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) */
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
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
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)
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
1036 #ifdef __UCLIBC_MJN3_ONLY__
1037 #warning TODO: Check multibyte format string validity.
1038 #endif
1039
1040 size_t __XL_NPP(strftime)(CHAR_T *__restrict s, size_t maxsize,
1041                                           const CHAR_T *__restrict format,
1042                                           const struct tm *__restrict timeptr   __LOCALE_PARAM )
1043 {
1044         long tzo;
1045         register const CHAR_T *p;
1046         const CHAR_T *o;
1047         const char *ccp;
1048 #ifndef __UCLIBC_HAS_TM_EXTENSIONS__
1049         const rule_struct *rsp;
1050 #endif
1051         const CHAR_T *stack[MAX_PUSH];
1052 #if defined __UCLIBC_HAS_WCHAR__ && (defined L_wcsftime || defined L_wcsftime_l)
1053         const CHAR_T *alloc[MAX_PUSH];
1054         int allocno = -1;
1055 #endif
1056         size_t count;
1057         size_t o_count;
1058         int field_val = 0, i = 0, j, lvl;
1059         int x[3];                       /* wday, yday, year */
1060         int isofm, days;
1061         char buf[__UIM_BUFLEN_LONG] = {0,};
1062         unsigned char mod;
1063         unsigned char code;
1064
1065         /* We'll, let's get this out of the way. */
1066         _time_tzset(_time_mktime((struct tm *) timeptr, 0) < new_rule_starts);
1067
1068         lvl = 0;
1069         p = format;
1070         count = maxsize;
1071
1072 LOOP:
1073         if (!count) {
1074                 return 0;
1075         }
1076         if (!*p) {
1077                 if (lvl == 0) {
1078                         *s = 0;                         /* nul-terminate */
1079                         return maxsize - count;
1080                 }
1081                 p = stack[--lvl];
1082                 goto LOOP;
1083         }
1084
1085         o_count = 1;
1086         if ((*(o = (CHAR_T *)p) == '%') && (*++p != '%')) {
1087                 o_count = 2;
1088                 mod = ILLEGAL_SPEC;
1089                 if ((*p == 'O') || (*p == 'E')) { /* modifier */
1090                         mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
1091                         ++o_count;
1092                         ++p;
1093                 }
1094                 if ((((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
1095                         || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
1096                         ) {
1097                         if (!*p) {
1098                                 --p;
1099                                 --o_count;
1100                         }
1101                         goto OUTPUT;
1102                 }
1103                 code &= ILLEGAL_SPEC;   /* modifiers are preserved in mod var. */
1104
1105                 if ((code & MASK_SPEC) == STACKED_SPEC) {
1106                         if (lvl == MAX_PUSH) {
1107                                 goto OUTPUT;    /* Stack full so treat as illegal spec. */
1108                         }
1109                         stack[lvl++] = ++p;
1110                         if ((code &= 0xf) < 8) {
1111                                 ccp = (const char *)(spec + STACKED_STRINGS_START + code);
1112                                 ccp += *ccp;
1113                                 fmt_to_wc(p, ccp);
1114                                 goto LOOP;
1115                         }
1116                         ccp = (const char *)spec + STACKED_STRINGS_NL_ITEM_START + (code & 7);
1117                         fmt_to_wc(p, ccp);
1118 #ifdef ENABLE_ERA_CODE
1119                         if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
1120                                 && (*(ccp = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1121                                                         (int)(((unsigned char *)p)[4]))
1122                                                         __LOCALE_ARG
1123                                                         )))
1124                                 ) {
1125                                 fmt_to_wc(p, ccp);
1126                                 goto LOOP;
1127                         }
1128 #endif
1129                         ccp = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1130                                                         (int)(*((unsigned char *)p)))
1131                                                         __LOCALE_ARG
1132                                                         );
1133                         fmt_to_wc(p, ccp);
1134                         goto LOOP;
1135                 }
1136
1137                 ccp = (const char *)(spec + 26);        /* set to "????" */
1138                 if ((code & MASK_SPEC) == CALC_SPEC) {
1139
1140                         if (*p == 's') {
1141                                 time_t t;
1142
1143                                 /* Use a cast to silence the warning since *timeptr won't
1144                                  * be changed. */
1145                                 if ((t = _time_mktime((struct tm *) timeptr, 0))
1146                                         == ((time_t) -1)
1147                                         ) {
1148                                         o_count = 1;
1149                                         goto OUTPUT;
1150                                 }
1151 #ifdef TIME_T_IS_UNSIGNED
1152                                 ccp = _uintmaxtostr(buf + sizeof(buf) - 1,
1153                                                                   (uintmax_t) t,
1154                                                                   10, __UIM_DECIMAL);
1155 #else
1156                                 ccp = _uintmaxtostr(buf + sizeof(buf) - 1,
1157                                                                   (uintmax_t) t,
1158                                                                   -10, __UIM_DECIMAL);
1159 #endif
1160                                 o_count = sizeof(buf);
1161                                 fmt_to_wc(o, ccp);
1162                                 goto OUTPUT;
1163                         } else if (((*p) | 0x20) == 'z') { /* 'z' or 'Z' */
1164
1165                                 if (timeptr->tm_isdst < 0) {
1166                                         /* SUSv3 specifies this behavior for 'z', but we'll also
1167                                          * treat it as "no timezone info" for 'Z' too. */
1168                                         o_count = 0;
1169                                         goto OUTPUT;
1170                                 }
1171
1172 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1173
1174 # ifdef __USE_BSD
1175 #  define RSP_TZNAME            timeptr->tm_zone
1176 #  define RSP_GMT_OFFSET        (-timeptr->tm_gmtoff)
1177 # else
1178 #  define RSP_TZNAME            timeptr->__tm_zone
1179 #  define RSP_GMT_OFFSET        (-timeptr->__tm_gmtoff)
1180 # endif
1181
1182 #else
1183
1184 #define RSP_TZNAME              rsp->tzname
1185 #define RSP_GMT_OFFSET  rsp->gmt_offset
1186
1187                                 __UCLIBC_MUTEX_LOCK(_time_tzlock);
1188
1189                                 rsp = _time_tzinfo;
1190                                 if (timeptr->tm_isdst > 0) {
1191                                         ++rsp;
1192                                 }
1193 #endif
1194
1195                                 if (*p == 'Z') {
1196                                         ccp = RSP_TZNAME;
1197 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1198                                         /* Sigh... blasted glibc extensions.  Of course we can't
1199                                          * count on the pointer being valid.  Best we can do is
1200                                          * handle NULL, which looks to be all that glibc does.
1201                                          * At least that catches the memset() with 0 case.
1202                                          * NOTE: We handle this case differently than glibc!
1203                                          * It uses system timezone name (based on tm_isdst) in this
1204                                          * case... although it always seems to use the embedded
1205                                          * tm_gmtoff value.  What we'll do instead is treat the
1206                                          * timezone name as unknown/invalid and return "???". */
1207                                         if (!ccp) {
1208                                                 ccp = (const char *)(spec + 27); /* "???" */
1209                                         }
1210 #endif
1211                                         assert(ccp != NULL);
1212 #if 0
1213                                         if (!ccp) {     /* PARANOIA */
1214                                                 ccp = spec+30; /* empty string */
1215                                         }
1216 #endif
1217                                         o_count = SIZE_MAX;
1218                                         fmt_to_wc(o, ccp);
1219 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1220                                         goto OUTPUT;
1221 #endif
1222                                 } else {                /* z */
1223                                         *s = '+';
1224                                         if ((tzo = -RSP_GMT_OFFSET) < 0) {
1225                                                 tzo = -tzo;
1226                                                 *s = '-';
1227                                         }
1228                                         ++s;
1229                                         --count;
1230
1231                                         i = tzo / 60;
1232                                         field_val = ((i / 60) * 100) + (i % 60);
1233
1234                                         i = 16 + 6;     /* 0-fill, width = 4 */
1235                                 }
1236 #ifndef __UCLIBC_HAS_TM_EXTENSIONS__
1237                                 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
1238                                 if (*p == 'Z') {
1239                                         goto OUTPUT;
1240                                 }
1241 #endif
1242                         } else {
1243                                 /* TODO: don't need year for U, W */
1244                                 for (i=0 ; i < 3 ; i++) {
1245                                         if ((x[i] = load_field(spec[CALC_OFFSETS+i],timeptr)) < 0) {
1246                                                 goto OUTPUT;
1247                                         }
1248                                 }
1249
1250                                 i = 16 + 2;             /* 0-fill, width = 2 */
1251
1252                                 if ((*p == 'U') || (*p == 'W')) {
1253                                         field_val = ((x[1] - x[0]) + 7);
1254                                         if (*p == 'W') {
1255                                                 ++field_val;
1256                                         }
1257                                         field_val /= 7;
1258                                         if ((*p == 'W') && !x[0]) {
1259                                                 --field_val;
1260                                         }
1261                                 } else {        /* ((*p == 'g') || (*p == 'G') || (*p == 'V')) */
1262 ISO_LOOP:
1263                                         isofm = (((x[1] - x[0]) + 11) % 7) - 3; /* [-3,3] */
1264
1265                                         if (x[1] < isofm) {     /* belongs to previous year */
1266                                                 --x[2];
1267                                                 x[1] += 365 + __isleap(x[2]);
1268                                                 goto ISO_LOOP;
1269                                         }
1270
1271                                         field_val = ((x[1] - isofm) / 7) + 1; /* week # */
1272                                         days = 365 + __isleap(x[2]);
1273                                         isofm = ((isofm + 7*53 + 3 - days)) % 7 + days - 3; /* next year */
1274                                         if (x[1] >= isofm) { /* next year */
1275                                                 x[1] -= days;
1276                                                 ++x[2];
1277                                                 goto ISO_LOOP;
1278                                         }
1279
1280                                         if (*p != 'V') { /* need year */
1281                                                 field_val = x[2]; /* TODO: what if x[2] now 10000 ?? */
1282                                                 if (*p == 'g') {
1283                                                         field_val %= 100;
1284                                                 } else {
1285                                                         i = 16 + 6;     /* 0-fill, width = 4 */
1286                                                 }
1287                                         }
1288                                 }
1289                         }
1290                 } else {
1291                         i = TP_OFFSETS + (code & 0x1f);
1292                         if ((field_val = load_field(spec[i], timeptr)) < 0) {
1293                                 goto OUTPUT;
1294                         }
1295
1296                         i = spec[i+(TP_CODES - TP_OFFSETS)];
1297
1298                         j = (i & 128) ? 100: 12;
1299                         if (i & 64) {
1300                                 field_val /= j;;
1301                         }
1302                         if (i & 32) {
1303                                 field_val %= j;
1304                                 if (((i & 128) + field_val) == 0) { /* mod 12? == 0 */
1305                                         field_val = j; /* set to 12 */
1306                                 }
1307                         }
1308                         field_val += (i & 1);
1309                         if ((i & 8) && !field_val) {
1310                                 field_val += 7;
1311                         }
1312                 }
1313
1314                 if ((code & MASK_SPEC) == STRING_SPEC) {
1315                         o_count = SIZE_MAX;
1316                         field_val += spec[STRINGS_NL_ITEM_START + (code & 0xf)];
1317                         ccp = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME, field_val)  __LOCALE_ARG);
1318                         fmt_to_wc(o, ccp);
1319                 } else {
1320                         o_count = ((i >> 1) & 3) + 1;
1321                         ccp = buf + o_count;
1322                         do {
1323                                 *(char *)(--ccp) = '0' + (field_val % 10);
1324                                 field_val /= 10;
1325                         } while (ccp > buf);
1326                         if (*buf == '0') {
1327                                 *buf = ' ' + (i & 16);
1328                         }
1329                         fmt_to_wc(o, ccp);
1330                 }
1331         }
1332
1333 OUTPUT:
1334         ++p;
1335         while (o_count && count && *o) {
1336                 *s++ = *o++;
1337                 --o_count;
1338                 --count;
1339         }
1340 #if defined __UCLIBC_HAS_WCHAR__ && (defined L_wcsftime || defined L_wcsftime_l)
1341         if (allocno >= 0)
1342                 free((void *)alloc[allocno--]);
1343 #endif
1344         goto LOOP;
1345 }
1346 # ifdef L_strftime_l
1347 libc_hidden_def(strftime_l)
1348 # endif
1349
1350 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1351
1352 #endif
1353 /**********************************************************************/
1354 #if defined(L_strptime) || defined(L_strptime_l)
1355
1356 #define ISDIGIT(C) __isdigit_char((C))
1357
1358 #ifdef __UCLIBC_DO_XLOCALE
1359 #define ISSPACE(C) isspace_l((C), locale_arg)
1360 #else
1361 #define ISSPACE(C) isspace((C))
1362 #endif
1363
1364 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
1365
1366 char *strptime(const char *__restrict buf, const char *__restrict format,
1367                            struct tm *__restrict tm)
1368 {
1369         return strptime_l(buf, format, tm, __UCLIBC_CURLOCALE);
1370 }
1371
1372 #else  /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1373
1374 /* TODO:
1375  * 1) %l and %k are space-padded, so "%l" by itself fails while " %l" succeeds.
1376  *    Both work for glibc.  So, should we always strip spaces?
1377  * 2) %Z
1378  */
1379
1380 /* Notes:
1381  * There are several differences between this strptime and glibc's strptime.
1382  * 1) glibc strips leading space before numeric conversions.
1383  * 2) glibc will read fields without whitespace in between.  SUSv3 states
1384  *    that you must have whitespace between conversion operators.  Besides,
1385  *    how do you know how long a number should be if there are leading 0s?
1386  * 3) glibc attempts to compute some the struct tm fields based on the
1387  *    data retrieved; tm_wday in particular.  I don't as I consider it
1388  *     another glibc attempt at mind-reading...
1389  */
1390
1391 #define NO_E_MOD                0x80
1392 #define NO_O_MOD                0x40
1393
1394 #define ILLEGAL_SPEC    0x3f
1395
1396 #define INT_SPEC                0x00    /* must be 0x00!! */
1397 #define STRING_SPEC             0x10    /* must be 0x10!! */
1398 #define CALC_SPEC               0x20
1399 #define STACKED_SPEC    0x30
1400
1401 #define MASK_SPEC               0x30
1402
1403 /* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
1404 static const unsigned char spec[] = {
1405         /* A */         0x02 |  STRING_SPEC | NO_E_MOD | NO_O_MOD,
1406         /* B */         0x01 |  STRING_SPEC | NO_E_MOD | NO_O_MOD,
1407         /* C */         0x08 |     INT_SPEC            | NO_O_MOD,
1408         /* D */         0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1409         /* E */                ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1410         /* F */         0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1411         /* G */         0x0f |     INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1412         /* H */         0x06 |     INT_SPEC | NO_E_MOD,
1413         /* I */         0x07 |     INT_SPEC | NO_E_MOD,
1414         /* J */                ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1415         /* K */                ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1416         /* L */                ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1417         /* M */         0x04 |     INT_SPEC | NO_E_MOD,
1418         /* N */                ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1419         /* O */                ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1420         /* P */         0x00 |  STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1421         /* Q */                ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1422         /* R */         0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1423         /* S */         0x05 |     INT_SPEC | NO_E_MOD,
1424         /* T */         0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1425         /* U */         0x0c |     INT_SPEC | NO_E_MOD,
1426         /* V */         0x0d |     INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1427         /* W */         0x0c |     INT_SPEC | NO_E_MOD,
1428         /* X */         0x0a | STACKED_SPEC            | NO_O_MOD,
1429         /* Y */         0x0a |     INT_SPEC            | NO_O_MOD,
1430         /* Z */         0x02 |    CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1431
1432         /* WARNING! This assumes orderings:
1433          *    AM,PM
1434          *    ABDAY_1-ABDAY-7,DAY_1-DAY_7
1435          *    ABMON_1-ABMON_12,MON_1-MON12
1436          * Also, there are exactly 6 bytes between 'Z' and 'a'.
1437          */
1438 #define STRINGS_NL_ITEM_START (26)
1439         _NL_ITEM_INDEX(AM_STR),         /* p (P) */
1440         _NL_ITEM_INDEX(ABMON_1),        /* B, b */
1441         _NL_ITEM_INDEX(ABDAY_1),        /* A, a */
1442         2,
1443         24,
1444         14,
1445
1446         /* a */         0x02 |  STRING_SPEC | NO_E_MOD | NO_O_MOD,
1447         /* b */         0x01 |  STRING_SPEC | NO_E_MOD | NO_O_MOD,
1448         /* c */         0x08 | STACKED_SPEC            | NO_O_MOD,
1449         /* d */         0x00 |     INT_SPEC | NO_E_MOD,
1450         /* e */         0x00 |     INT_SPEC | NO_E_MOD,
1451         /* f */                ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1452         /* g */         0x0e |     INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1453         /* h */         0x01 |  STRING_SPEC | NO_E_MOD | NO_O_MOD,
1454         /* i */                ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1455         /* j */         0x01 |     INT_SPEC | NO_E_MOD | NO_O_MOD,
1456         /* k */         0x06 |     INT_SPEC | NO_E_MOD,            /* glibc */
1457         /* l */         0x07 |     INT_SPEC | NO_E_MOD,            /* glibc */
1458         /* m */         0x02 |     INT_SPEC | NO_E_MOD,
1459         /* n */         0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1460         /* o */                ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1461         /* p */         0x00 |  STRING_SPEC | NO_E_MOD | NO_O_MOD,
1462         /* q */                ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1463         /* r */         0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1464         /* s */         0x00 |    CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1465         /* t */         0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1466         /* u */         0x0b |     INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1467         /* v */                ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1468         /* w */         0x03 |     INT_SPEC | NO_E_MOD,
1469         /* x */         0x09 | STACKED_SPEC            | NO_O_MOD,
1470         /* y */         0x09 |     INT_SPEC,
1471         /* z */         0x01 |    CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1472
1473 #define INT_FIELD_START (26+6+26)
1474         /* (field #) << 3  + lower bound (0|1) + correction 0:none, 2:-1, 4:-1900
1475          * followed by upper bound prior to correction with 1=>366 and 2=>9999. */
1476         /* d, e */      (3 << 3) + 1 + 0, 31,
1477         /* j */         (7 << 3) + 1 + 2, /* 366 */ 1,
1478         /* m */         (4 << 3) + 1 + 2, 12,
1479         /* w */         (6 << 3) + 0 + 0, 6,
1480         /* M */         (1 << 3) + 0 + 0, 59,
1481         /* S */         0        + 0 + 0, 60,
1482         /* H (k) */     (2 << 3) + 0 + 0, 23,
1483         /* I (l) */     (9 << 3) + 1 + 0, 12, /* goes with 8 -- am/pm */
1484         /* C */         (10<< 3) + 0 + 0, 99,
1485         /* y */         (11<< 3) + 0 + 0, 99,
1486         /* Y */         (5 << 3) + 0 + 4, /* 9999 */ 2,
1487         /* u */         (6 << 3) + 1 + 0, 7,
1488         /* The following are processed and range-checked, but ignored otherwise. */
1489         /* U, W */      (12<< 3) + 0 + 0, 53,
1490         /* V */         (12<< 3) + 1 + 0, 53,
1491         /* g */         (12<< 3) + 0 + 0, 99,
1492         /* G */         (12<< 3) + 0 /*+ 4*/, /* 9999 */ 2, /* Note: -1 or 10000? */
1493
1494 #define STACKED_STRINGS_START (INT_FIELD_START+32)
1495         5, 6, 14, 22, 27,                       /* 5 - offsets from offset-count to strings */
1496         ' ', 0,                                         /* 2 - %n or %t */
1497         '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
1498         '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
1499         '%', 'H', ':', '%', 'M', 0,     /* 6 - %R*/
1500         '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
1501
1502 #define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 40)
1503         _NL_ITEM_INDEX(D_T_FMT),        /* c */
1504         _NL_ITEM_INDEX(D_FMT),          /* x */
1505         _NL_ITEM_INDEX(T_FMT),          /* X */
1506         _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
1507 #ifdef ENABLE_ERA_CODE
1508         _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
1509         _NL_ITEM_INDEX(ERA_D_FMT),      /* Ex */
1510         _NL_ITEM_INDEX(ERA_T_FMT),      /* EX */
1511 #endif
1512 };
1513
1514 #define MAX_PUSH 4
1515
1516 char *__XL_NPP(strptime)(const char *__restrict buf, const char *__restrict format,
1517                                          struct tm *__restrict tm   __LOCALE_PARAM)
1518 {
1519         register const char *p;
1520         char *o;
1521         const char *stack[MAX_PUSH];
1522         int i, j, lvl;
1523         int fields[13];
1524         unsigned char mod;
1525         unsigned char code;
1526
1527         i = 0;
1528         do {
1529                 fields[i] = INT_MIN;
1530         } while (++i < 13);
1531
1532         lvl = 0;
1533         p = format;
1534
1535 LOOP:
1536         if (!*p) {
1537                 if (lvl == 0) {                 /* Done. */
1538                         if (fields[6] == 7) { /* Cleanup for %u here since just once. */
1539                                 fields[6] = 0;  /* Don't use mod in case unset. */
1540                         }
1541
1542                         i = 0;
1543                         do {                            /* Store the values into tm. */
1544                                 if (fields[i] != INT_MIN) {
1545                                         ((int *) tm)[i] = fields[i];
1546                                 }
1547                         } while (++i < 8);
1548
1549                         return (char *) buf; /* Success. */
1550                 }
1551                 p = stack[--lvl];
1552                 goto LOOP;
1553         }
1554
1555         if ((*p == '%') && (*++p != '%')) {
1556                 mod = ILLEGAL_SPEC;
1557                 if ((*p == 'O') || (*p == 'E')) { /* Modifier? */
1558                         mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
1559                         ++p;
1560                 }
1561
1562                 if (!*p
1563                         || (((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
1564                         || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
1565                         ) {
1566                         return NULL;            /* Illegal spec. */
1567                 }
1568
1569                 if ((code & MASK_SPEC) == STACKED_SPEC) {
1570                         if (lvl == MAX_PUSH) {
1571                                 return NULL;    /* Stack full so treat as illegal spec. */
1572                         }
1573                         stack[lvl++] = ++p;
1574                         if ((code &= 0xf) < 8) {
1575                                 p = ((const char *) spec) + STACKED_STRINGS_START + code;
1576                                 p += *((unsigned char *)p);
1577                                 goto LOOP;
1578                         }
1579
1580                         p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
1581                                 + (code & 7);
1582 #ifdef ENABLE_ERA_CODE
1583                         if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
1584                                 && (*(o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1585                                                         (int)(((unsigned char *)p)[4]))
1586                                                         __LOCALE_ARG
1587                                                         )))
1588                                 ) {
1589                                 p = o;
1590                                 goto LOOP;
1591                         }
1592 #endif
1593                         p = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1594                                                         (int)(*((unsigned char *)p)))
1595                                                         __LOCALE_ARG
1596                                                         );
1597                         goto LOOP;
1598                 }
1599
1600                 ++p;
1601
1602                 if ((code & MASK_SPEC) == STRING_SPEC) {
1603                         code &= 0xf;
1604                         j = spec[STRINGS_NL_ITEM_START + 3 + code];
1605                         i = _NL_ITEM(LC_TIME, spec[STRINGS_NL_ITEM_START + code]);
1606                         /* Go backwards to check full names before abreviations. */
1607                         do {
1608                                 --j;
1609                                 o = __XL_NPP(nl_langinfo)(i+j   __LOCALE_ARG);
1610                                 if (!__XL_NPP(strncasecmp)(buf, o, strlen(o)   __LOCALE_ARG) && *o) {
1611                                         do {            /* Found a match. */
1612                                                 ++buf;
1613                                         } while (*++o);
1614                                         if (!code) { /* am/pm */
1615                                                 fields[8] = j * 12;
1616                                                 if (fields[9] >= 0) { /* We have a previous %I or %l. */
1617                                                         fields[2] = fields[9] + fields[8];
1618                                                 }
1619                                         } else {        /* day (4) or month (6) */
1620                                                 fields[2 + (code << 1)]
1621                                                         = j % (spec[STRINGS_NL_ITEM_START + 3 + code] >> 1);
1622                                         }
1623                                         goto LOOP;
1624                                 }
1625                         } while (j);
1626                         return NULL;            /* Failed to match. */
1627                 }
1628
1629                 if ((code & MASK_SPEC) == CALC_SPEC) {
1630                         if ((code &= 0xf) < 1) { /* s or z*/
1631                                 time_t t;
1632
1633                                 o = (char *) buf;
1634                                 i = errno;
1635                                 __set_errno(0);
1636                                 if (!ISSPACE(*buf)) { /* Signal an error if whitespace. */
1637 #ifdef TIME_T_IS_UNSIGNED
1638                                         t = __XL_NPP(strtoul)(buf, &o, 10   __LOCALE_ARG);
1639 #else
1640                                         t = __XL_NPP(strtol)(buf, &o, 10   __LOCALE_ARG);
1641 #endif
1642                                 }
1643                                 if ((o == buf) || errno) { /* Not a number or overflow. */
1644                                         return NULL;
1645                                 }
1646                                 __set_errno(i); /* Restore errno. */
1647                                 buf = o;
1648
1649                                 if (!code) {    /* s */
1650                                         localtime_r(&t, tm); /* TODO: check for failure? */
1651                                         i = 0;
1652                                         do {            /* Now copy values from tm to fields. */
1653                                                  fields[i] = ((int *) tm)[i];
1654                                         } while (++i < 8);
1655                                 }
1656                         }
1657                         /* TODO: glibc treats %Z as a nop.  For now, do the same. */
1658                         goto LOOP;
1659                 }
1660
1661                 assert((code & MASK_SPEC) == INT_SPEC);
1662                 {
1663                         register const unsigned char *x;
1664                         code &= 0xf;
1665                         x = spec + INT_FIELD_START + (code << 1);
1666                         if ((j = x[1]) < 3) { /* upper bound (inclusive) */
1667                                 j = ((j==1) ? 366 : 9999);
1668                         }
1669                         i = -1;
1670                         while (ISDIGIT(*buf)) {
1671                                 if (i < 0) {
1672                                         i = 0;
1673                                 }
1674                                 if ((i = 10*i + (*buf - '0')) > j) { /* Overflow. */
1675                                         return NULL;
1676                                 }
1677                                 ++buf;
1678                         }
1679                         if (i < (*x & 1)) {     /* This catches no-digit case too. */
1680                                 return NULL;
1681                         }
1682                         if (*x & 2) {
1683                                 --i;
1684                         }
1685                         if (*x & 4) {
1686                                 i -= 1900;
1687                         }
1688
1689                         if (*x == (9 << 3) + 1 + 0) { /* %I or %l */
1690                                 if (i == 12) {
1691                                         i = 0;
1692                                 }
1693                                 if (fields[8] >= 0) { /* We have a previous %p or %P. */
1694                                         fields[2] = i + fields[8];
1695                                 }
1696                         }
1697
1698                         fields[(*x) >> 3] = i;
1699
1700                         if (((unsigned char)(*x - (10 << 3) + 0 + 0)) <= 8) { /* %C or %y */
1701                                 if ((j = fields[10]) < 0) {     /* No %C, so i must be %y data. */
1702                                         if (i <= 68) { /* Map [0-68] to 2000+i */
1703                                                 i += 100;
1704                                         }
1705                                 } else {                /* Have %C data, but what about %y? */
1706                                         if ((i = fields[11]) < 0) {     /* No %y data. */
1707                                                 i = 0;  /* Treat %y val as 0 following glibc's example. */
1708                                         }
1709                                         i += 100*(j - 19);
1710                                 }
1711                                 fields[5] = i;
1712                         }
1713                 }
1714                 goto LOOP;
1715         } else if (ISSPACE(*p)) {
1716                 ++p;
1717                 while (ISSPACE(*buf)) {
1718                         ++buf;
1719                 }
1720                 goto LOOP;
1721         } else if (*buf++ == *p++) {
1722                 goto LOOP;
1723         }
1724         return NULL;
1725 }
1726 # ifdef L_strptime_l
1727 libc_hidden_def(strptime_l)
1728 # endif
1729
1730 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1731
1732 #endif
1733 /**********************************************************************/
1734 #ifdef L_time
1735
1736 #ifndef __BCC__
1737 #error The uClibc version of time is in sysdeps/linux/common.
1738 #endif
1739
1740 time_t time(register time_t *tloc)
1741 {
1742         struct timeval tv;
1743         register struct timeval *p = &tv;
1744
1745         gettimeofday(p, NULL);          /* This should never fail... */
1746
1747         if (tloc) {
1748                 *tloc = p->tv_sec;
1749         }
1750
1751         return p->tv_sec;
1752 }
1753
1754 #endif
1755 /**********************************************************************/
1756 #ifdef L_tzset
1757
1758 static const char vals[] = {
1759         'T', 'Z', 0,                            /* 3 */
1760         'U', 'T', 'C', 0,                       /* 4 */
1761         25, 60, 60, 1,                          /* 4 */
1762         '.', 1,                                         /* M */
1763         5, '.', 1,
1764         6,  0,  0,                                      /* Note: overloaded for non-M non-J case... */
1765         0, 1, 0,                                        /* J */
1766         ',', 'M',      '4', '.', '1', '.', '0',
1767         ',', 'M', '1', '0', '.', '5', '.', '0', 0,
1768         ',', 'M',      '3', '.', '2', '.', '0',
1769         ',', 'M', '1', '1', '.', '1', '.', '0', 0
1770 };
1771
1772 #define TZ    vals
1773 #define UTC   (vals + 3)
1774 #define RANGE (vals + 7)
1775 #define RULE  (vals + 11 - 1)
1776 #define DEFAULT_RULES (vals + 22)
1777 #define DEFAULT_2007_RULES (vals + 38)
1778
1779 /* Initialize to UTC. */
1780 int daylight = 0;
1781 long timezone = 0;
1782 char *tzname[2] = { (char *) UTC, (char *) (UTC-1) };
1783
1784 __UCLIBC_MUTEX_INIT(_time_tzlock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
1785
1786 rule_struct _time_tzinfo[2];
1787
1788 static const char *getoffset(register const char *e, long *pn)
1789 {
1790         register const char *s = RANGE-1;
1791         long n;
1792         int f;
1793
1794         n = 0;
1795         f = -1;
1796         do {
1797                 ++s;
1798                 if (__isdigit_char(*e)) {
1799                         f = *e++ - '0';
1800                 }
1801                 if (__isdigit_char(*e)) {
1802                         f = 10 * f + (*e++ - '0');
1803                 }
1804                 if (((unsigned int)f) >= *s) {
1805                         return NULL;
1806                 }
1807                 n = (*s) * n + f;
1808                 f = 0;
1809                 if (*e == ':') {
1810                         ++e;
1811                         --f;
1812                 }
1813         } while (*s > 1);
1814
1815         *pn = n;
1816         return e;
1817 }
1818
1819 static const char *getnumber(register const char *e, int *pn)
1820 {
1821 #ifdef __BCC__
1822         /* bcc can optimize the counter if it thinks it is a pointer... */
1823         register const char *n = (const char *) 3;
1824         int f;
1825
1826         f = 0;
1827         while (n && __isdigit_char(*e)) {
1828                 f = 10 * f + (*e++ - '0');
1829                 --n;
1830         }
1831
1832         *pn = f;
1833         return (n == (const char *) 3) ? NULL : e;
1834 #else  /* __BCC__ */
1835         int n, f;
1836
1837         n = 3;
1838         f = 0;
1839         while (n && __isdigit_char(*e)) {
1840                 f = 10 * f + (*e++ - '0');
1841                 --n;
1842         }
1843
1844         *pn = f;
1845         return (n == 3) ? NULL : e;
1846 #endif /* __BCC__ */
1847 }
1848
1849
1850 #ifdef __UCLIBC_MJN3_ONLY__
1851 #warning CONSIDER: Should we preserve errno from open/read/close errors re TZ file?
1852 #endif
1853
1854 #ifdef __UCLIBC_HAS_TZ_FILE__
1855
1856 #ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1857 static smallint TZ_file_read;           /* Let BSS initialization set this to 0. */
1858 #endif
1859
1860 static char *read_TZ_file(char *buf)
1861 {
1862         int r;
1863         int fd;
1864         char *p = NULL;
1865
1866         fd = open(__UCLIBC_TZ_FILE_PATH__, O_RDONLY);
1867         if (fd >= 0) {
1868 #if 0
1869                 /* TZ are small *files*. On files, short reads
1870                  * only occur on EOF (unlike, say, pipes).
1871                  * The code below is pedanticallly more correct,
1872                  * but this way we always read at least twice:
1873                  * 1st read is short, 2nd one is zero bytes.
1874                  */
1875                 size_t todo = TZ_BUFLEN;
1876                 p = buf;
1877                 do {
1878                         r = read(fd, p, todo);
1879                         if (r < 0)
1880                                 goto ERROR;
1881                         if (r == 0)
1882                                 break;
1883                         p += r;
1884                         todo -= r;
1885                 } while (todo);
1886 #else
1887                 /* Shorter, and does one fewer read syscall */
1888                 r = read(fd, buf, TZ_BUFLEN);
1889                 if (r < 0)
1890                         goto ERROR;
1891                 p = buf + r;
1892 #endif
1893                 if ((p > buf) && (p[-1] == '\n')) { /* Must end with newline */
1894                         p[-1] = 0;
1895                         p = buf;
1896 #ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1897                         TZ_file_read = 1;
1898 #endif
1899                 } else {
1900 ERROR:
1901                         p = NULL;
1902                 }
1903                 close(fd);
1904         }
1905 #ifdef __UCLIBC_FALLBACK_TO_ETC_LOCALTIME__
1906         else {
1907                 fd = open("/etc/localtime", O_RDONLY);
1908                 if (fd >= 0) {
1909                         r = read(fd, buf, TZ_BUFLEN);
1910                         if (r != TZ_BUFLEN
1911                          || strncmp(buf, "TZif", 4) != 0
1912                          || (unsigned char)buf[4] < 2
1913                          || lseek(fd, -TZ_BUFLEN, SEEK_END) < 0
1914                         ) {
1915                                 goto ERROR;
1916                         }
1917                         /* tzfile.h from tzcode database says about TZif2+ files:
1918                         **
1919                         ** If tzh_version is '2' or greater, the above is followed by a second instance
1920                         ** of tzhead and a second instance of the data in which each coded transition
1921                         ** time uses 8 rather than 4 chars,
1922                         ** then a POSIX-TZ-environment-variable-style string for use in handling
1923                         ** instants after the last transition time stored in the file
1924                         ** (with nothing between the newlines if there is no POSIX representation for
1925                         ** such instants).
1926                         */
1927                         r = read(fd, buf, TZ_BUFLEN);
1928                         if (r <= 0 || buf[--r] != '\n')
1929                                 goto ERROR;
1930                         buf[r] = 0;
1931                         while (r != 0) {
1932                                 if (buf[--r] == '\n') {
1933                                         p = buf + r + 1;
1934 #ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1935                                         TZ_file_read = 1;
1936 #endif
1937                                         break;
1938                                 }
1939                         } /* else ('\n' not found): p remains NULL */
1940                         close(fd);
1941                 }
1942         }
1943 #endif /* __UCLIBC_FALLBACK_TO_ETC_LOCALTIME__ */
1944         return p;
1945 }
1946
1947 #endif /* __UCLIBC_HAS_TZ_FILE__ */
1948
1949 void tzset(void)
1950 {
1951         _time_tzset((time(NULL)) < new_rule_starts);
1952 }
1953
1954 void _time_tzset(int use_old_rules)
1955 {
1956         register const char *e;
1957         register char *s;
1958         long off = 0;
1959         short *p;
1960         rule_struct new_rules[2];
1961         int n, count, f;
1962         char c;
1963 #ifdef __UCLIBC_HAS_TZ_FILE__
1964         char buf[TZ_BUFLEN];
1965 #endif
1966 #ifdef __UCLIBC_HAS_TZ_CACHING__
1967         static char oldval[TZ_BUFLEN]; /* BSS-zero'd. */
1968 #endif
1969
1970         /* Put this inside the lock to prevent the possibility of two different
1971          * timezones being used in a threaded app. */
1972         __UCLIBC_MUTEX_LOCK(_time_tzlock);
1973
1974         e = getenv(TZ);                         /* TZ env var always takes precedence. */
1975
1976 #if defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__)
1977         if (e) {
1978                 /* Never use TZfile if TZ env var is set. */
1979                 TZ_file_read = 0;
1980         }
1981         if (TZ_file_read) {
1982                 /* We already parsed TZfile before, skip everything. */
1983                 goto FAST_DONE;
1984         }
1985 #endif
1986
1987         /* Warning!!!  Since uClibc doesn't do lib locking, the following is
1988          * potentially unsafe in a multi-threaded program since it is remotely
1989          * possible that another thread could call setenv() for TZ and overwrite
1990          * the string being parsed.  So, don't do that... */
1991
1992 #ifdef __UCLIBC_HAS_TZ_FILE__
1993         if (!e)
1994                 e = read_TZ_file(buf);
1995 #endif
1996         if (!e          /* TZ env var not set and no TZfile (or bad TZfile) */
1997          || !*e         /* or set to empty string. */
1998         ) {
1999                 goto ILLEGAL;
2000         }
2001
2002         if (*e == ':') {                        /* Ignore leading ':'. */
2003                 ++e;
2004         }
2005
2006 #ifdef __UCLIBC_HAS_TZ_CACHING__
2007         if (strcmp(e, oldval) == 0) {
2008                 /* Same string as last time... nothing to do. */
2009                 goto FAST_DONE;
2010         }
2011         /* Make a copy of the TZ env string.  It won't be nul-terminated if
2012          * it is too long, but it that case it will be illegal and will be reset
2013          * to the empty string anyway. */
2014         strncpy(oldval, e, TZ_BUFLEN);
2015 #endif
2016
2017         count = 0;
2018         new_rules[1].tzname[0] = 0;
2019 LOOP:
2020         /* Get std or dst name. */
2021         c = 0;
2022         if (*e == '<') {
2023                 ++e;
2024                 c = '>';
2025         }
2026
2027         s = new_rules[count].tzname;
2028         n = 0;
2029         while (*e
2030             && isascii(*e)              /* SUSv3 requires char in portable char set. */
2031             && (isalpha(*e)
2032                 || (c && (isalnum(*e) || (*e == '+') || (*e == '-')))
2033                )
2034         ) {
2035                 *s++ = *e++;
2036                 if (++n > TZNAME_MAX) {
2037                         goto ILLEGAL;
2038                 }
2039         }
2040         *s = 0;
2041
2042         if ((n < 3)                                     /* Check for minimum length. */
2043          || (c && (*e++ != c))  /* Match any quoting '<'. */
2044         ) {
2045                 goto ILLEGAL;
2046         }
2047
2048         /* Get offset */
2049         s = (char *) e;
2050         if ((*e != '-') && (*e != '+')) {
2051                 if (count && !__isdigit_char(*e)) {
2052                         off -= 3600;            /* Default to 1 hour ahead of std. */
2053                         goto SKIP_OFFSET;
2054                 }
2055                 --e;
2056         }
2057
2058         ++e;
2059         e = getoffset(e, &off);
2060         if (!e) {
2061                 goto ILLEGAL;
2062         }
2063
2064         if (*s == '-') {
2065                 off = -off;                             /* Save off in case needed for dst default. */
2066         }
2067 SKIP_OFFSET:
2068         new_rules[count].gmt_offset = off;
2069
2070         if (!count) {
2071                 new_rules[1].gmt_offset = off; /* Shouldn't be needed... */
2072                 if (*e) {
2073                         ++count;
2074                         goto LOOP;
2075                 }
2076         } else {                                        /* OK, we have dst, so get some rules. */
2077                 count = 0;
2078                 if (!*e) {                              /* No rules so default to US rules. */
2079                         e = use_old_rules ? DEFAULT_RULES : DEFAULT_2007_RULES;
2080 #ifdef DEBUG_TZSET
2081                         if (e == DEFAULT_RULES)
2082                                 printf("tzset: Using old rules.\n");
2083                         else if (e == DEFAULT_2007_RULES)
2084                                 printf("tzset: Using new rules\n");
2085                         else
2086                                 printf("tzset: Using undefined rules\n");
2087 #endif
2088                 }
2089
2090                 do {
2091                         if (*e++ != ',') {
2092                                 goto ILLEGAL;
2093                         }
2094
2095                         n = 365;
2096                         s = (char *) RULE;
2097                         c = *e++;
2098                         if (c == 'M') {
2099                                 n = 12;
2100                         } else if (c == 'J') {
2101                                 s += 8;
2102                         } else {
2103                                 --e;
2104                                 c = 0;
2105                                 s += 6;
2106                         }
2107
2108                         p = &new_rules[count].rule_type;
2109                         *p = c;
2110                         if (c != 'M') {
2111                                 p -= 2;
2112                         }
2113
2114                         do {
2115                                 ++s;
2116                                 e = getnumber(e, &f);
2117                                 if (!e
2118                                  || ((unsigned int)(f - s[1]) > n)
2119                                  || (*s && (*e++ != *s))
2120                                 ) {
2121                                         goto ILLEGAL;
2122                                 }
2123                                 *--p = f;
2124                                 s += 2;
2125                                 n = *s;
2126                         } while (n > 0);
2127
2128                         off = 2 * 60 * 60;      /* Default to 2:00:00 */
2129                         if (*e == '/') {
2130                                 ++e;
2131                                 e = getoffset(e, &off);
2132                                 if (!e) {
2133                                         goto ILLEGAL;
2134                                 }
2135                         }
2136                         new_rules[count].dst_offset = off;
2137                 } while (++count < 2);
2138
2139                 if (*e) {
2140 ILLEGAL:
2141 #ifdef __UCLIBC_HAS_TZ_CACHING__
2142                         oldval[0] = 0; /* oldval = "" */
2143 #endif
2144                         memset(_time_tzinfo, 0, sizeof(_time_tzinfo));
2145                         strcpy(_time_tzinfo[0].tzname, UTC);
2146                         goto DONE;
2147                 }
2148         }
2149
2150         memcpy(_time_tzinfo, new_rules, sizeof(new_rules));
2151 DONE:
2152         tzname[0] = _time_tzinfo[0].tzname;
2153         tzname[1] = _time_tzinfo[1].tzname;
2154         daylight = !!_time_tzinfo[1].tzname[0];
2155         timezone = _time_tzinfo[0].gmt_offset;
2156
2157 #if (defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__)) || \
2158         defined(__UCLIBC_HAS_TZ_CACHING__)
2159 FAST_DONE:
2160 #endif
2161         __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
2162 }
2163 libc_hidden_def(tzset)
2164 #endif
2165 /**********************************************************************/
2166 /*  #ifdef L_utime */
2167
2168 /* utime is a syscall in both linux and elks. */
2169 /*  int utime(const char *path, const struct utimbuf *times) */
2170
2171 /*  #endif */
2172 /**********************************************************************/
2173 /* Non-SUSv3 */
2174 /**********************************************************************/
2175 #ifdef L_utimes
2176
2177 #ifndef __BCC__
2178 #error The uClibc version of utimes is in sysdeps/linux/common.
2179 #endif
2180
2181 #include <utime.h>
2182
2183 int utimes(const char *filename, register const struct timeval *tvp)
2184 {
2185         register struct utimbuf *p = NULL;
2186         struct utimbuf utb;
2187
2188         if (tvp) {
2189                 p = &utb;
2190                 p->actime = tvp[0].tv_sec;
2191                 p->modtime = tvp[1].tv_sec;
2192         }
2193         return utime(filename, p);
2194 }
2195
2196 #endif
2197 /**********************************************************************/
2198 #ifdef L__time_t2tm
2199
2200 static const uint16_t _vals[] = {
2201         60, 60, 24, 7 /* special */, 36524, 1461, 365, 0
2202 };
2203
2204 static const unsigned char days[] = {
2205         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
2206             29,
2207 };
2208
2209 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
2210 static const char utc_string[] = "UTC";
2211 #endif
2212
2213 /* Notes:
2214  * If time_t is 32 bits, then no overflow is possible.
2215  * It time_t is > 32 bits, this needs to be adjusted to deal with overflow.
2216  */
2217
2218 /* Note: offset is the correction in _days_ to *timer! */
2219
2220 struct tm attribute_hidden *_time_t2tm(const time_t *__restrict timer,
2221                                           int offset, struct tm *__restrict result)
2222 {
2223         register int *p;
2224         time_t t1, t, v;
2225         int wday = wday; /* ok to be uninitialized, shutting up warning */
2226
2227         {
2228                 register const uint16_t *vp;
2229                 t = *timer;
2230                 p = (int *) result;
2231                 p[7] = 0;
2232                 vp = _vals;
2233                 do {
2234                         if ((v = *vp) == 7) {
2235                                 /* Overflow checking, assuming time_t is long int... */
2236 #if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
2237 #if (INT_MAX == 2147483647L) && (LONG_MAX == 9223372036854775807L)
2238                                 /* Valid range for t is [-784223472856L, 784223421720L].
2239                                  * Outside of this range, the tm_year field will overflow. */
2240                                 if (((unsigned long)(t + offset- -784223472856L))
2241                                         > (784223421720L - -784223472856L)
2242                                         ) {
2243                                         return NULL;
2244                                 }
2245 #else
2246 #error overflow conditions unknown
2247 #endif
2248 #endif
2249
2250                                 /* We have days since the epoch, so caluclate the weekday. */
2251 #if defined(__BCC__) && TIME_T_IS_UNSIGNED
2252                                 wday = (t + 4) % (*vp); /* t is unsigned */
2253 #else
2254                                 wday = ((int)((t % (*vp)) + 11)) % ((int)(*vp)); /* help bcc */
2255 #endif
2256                                 /* Set divisor to days in 400 years.  Be kind to bcc... */
2257                                 v = ((time_t)(vp[1])) << 2;
2258                                 ++v;
2259                                 /* Change to days since 1/1/1601 so that for 32 bit time_t
2260                                  * values, we'll have t >= 0.  This should be changed for
2261                                  * archs with larger time_t types.
2262                                  * Also, correct for offset since a multiple of 7. */
2263
2264                                 /* TODO: Does this still work on archs with time_t > 32 bits? */
2265                                 t += (135140L - 366) + offset; /* 146097 - (365*30 + 7) -366 */
2266                         }
2267 #if defined(__BCC__) && TIME_T_IS_UNSIGNED
2268                         t -= ((t1 = t / v) * v);
2269 #else
2270                         if ((t -= ((t1 = t / v) * v)) < 0) {
2271                                 t += v;
2272                                 --t1;
2273                         }
2274 #endif
2275
2276                         if ((*vp == 7) && (t == v-1)) {
2277                                 --t;                    /* Correct for 400th year leap case */
2278                                 ++p[4];                 /* Stash the extra day... */
2279                         }
2280
2281 #if defined(__BCC__) && 0
2282                         *p = t1;
2283                         if (v <= 60) {
2284                                 *p = t;
2285                                 t = t1;
2286                         }
2287                         ++p;
2288 #else
2289                         if (v <= 60) {
2290                                 *p++ = t;
2291                                 t = t1;
2292                         } else {
2293                                 *p++ = t1;
2294                         }
2295 #endif
2296                 } while (*++vp);
2297         }
2298
2299         if (p[-1] == 4) {
2300                 --p[-1];
2301                 t = 365;
2302         }
2303
2304         *p += ((int) t);                        /* result[7] .. tm_yday */
2305
2306         p -= 2;                                         /* at result[5] */
2307
2308 #if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
2309         /* Protect against overflow.  TODO: Unecessary if int arith wraps? */
2310         *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + (p[1] - 299); /* tm_year */
2311 #else
2312         *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + p[1] - 299; /* tm_year */
2313 #endif
2314
2315         p[1] = wday;                            /* result[6] .. tm_wday */
2316
2317         {
2318                 register const unsigned char *d = days;
2319
2320                 wday = 1900 + *p;
2321                 if (__isleap(wday)) {
2322                         d += 11;
2323                 }
2324
2325                 wday = p[2] + 1;                /* result[7] .. tm_yday */
2326                 *--p = 0;                               /* at result[4] .. tm_mon */
2327                 while (wday > *d) {
2328                         wday -= *d;
2329                         if (*d == 29) {
2330                                 d -= 11;                /* Backup to non-leap Feb. */
2331                         }
2332                         ++d;
2333                         ++*p;                           /* Increment tm_mon. */
2334                 }
2335                 p[-1] = wday;                   /* result[3] .. tm_mday */
2336         }
2337         /* TODO -- should this be 0? */
2338         p[4] = 0;                                       /* result[8] .. tm_isdst */
2339 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
2340 # ifdef __USE_BSD
2341         result->tm_gmtoff = 0;
2342         result->tm_zone = utc_string;
2343 # else
2344         result->__tm_gmtoff = 0;
2345         result->__tm_zone = utc_string;
2346 # endif
2347 #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
2348
2349         return result;
2350 }
2351
2352 #endif
2353 /**********************************************************************/
2354 #ifdef L___time_tm
2355
2356 struct tm __time_tm;    /* Global shared by gmtime() and localtime(). */
2357
2358 #endif
2359 /**********************************************************************/
2360 #ifdef L__time_mktime
2361
2362 time_t attribute_hidden _time_mktime(struct tm *timeptr, int store_on_success)
2363 {
2364         time_t t;
2365
2366         __UCLIBC_MUTEX_LOCK(_time_tzlock);
2367
2368         tzset();
2369
2370         t = _time_mktime_tzi(timeptr, store_on_success, _time_tzinfo);
2371
2372         __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
2373
2374         return t;
2375 }
2376
2377 #endif
2378 /**********************************************************************/
2379 #ifdef L__time_mktime_tzi
2380
2381 static const unsigned char __vals[] = {
2382         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
2383             29,
2384 };
2385
2386 time_t attribute_hidden _time_mktime_tzi(struct tm *timeptr, int store_on_success,
2387                                                 rule_struct *tzi)
2388 {
2389 #ifdef __BCC__
2390         long days, secs;
2391 #else
2392         long long secs;
2393 #endif
2394         time_t t;
2395         struct tm x;
2396         /* 0:sec  1:min  2:hour  3:mday  4:mon  5:year  6:wday  7:yday  8:isdst */
2397         register int *p = (int *) &x;
2398         register const unsigned char *s;
2399         int d, default_dst;
2400
2401         memcpy(p, timeptr, sizeof(struct tm));
2402
2403         if (!tzi[1].tzname[0]) { /* No dst in this timezone, */
2404                 p[8] = 0;                               /* so set tm_isdst to 0. */
2405         }
2406
2407         default_dst = 0;
2408         if (p[8]) {                                     /* Either dst or unknown? */
2409                 default_dst = 1;                /* Assume advancing (even if unknown). */
2410                 p[8] = ((p[8] > 0) ? 1 : -1); /* Normalize so abs() <= 1. */
2411         }
2412
2413         d = 400;
2414         p[5] = (p[5] - ((p[6] = p[5]/d) * d)) + (p[7] = p[4]/12);
2415         if ((p[4] -= 12 * p[7]) < 0) {
2416                 p[4] += 12;
2417                 --p[5];
2418         }
2419
2420         s = __vals;
2421         d = (p[5] += 1900);                     /* Correct year.  Now between 1900 and 2300. */
2422         if (__isleap(d)) {
2423                 s += 11;
2424         }
2425
2426         p[7] = 0;
2427         d = p[4];
2428         while (d) {
2429                 p[7] += *s;
2430                 if (*s == 29) {
2431                         s -= 11;                        /* Backup to non-leap Feb. */
2432                 }
2433                 ++s;
2434                 --d;
2435         }
2436
2437         _time_tzset (x.tm_year < 2007); /* tm_year was expanded above */
2438
2439 #ifdef __BCC__
2440         d = p[5] - 1;
2441         days = -719163L + ((long)d)*365 + ((d/4) - (d/100) + (d/400) + p[3] + p[7]);
2442         secs = p[0] + 60*( p[1] + 60*((long)(p[2])) )
2443                 + tzi[default_dst].gmt_offset;
2444 DST_CORRECT:
2445         if (secs < 0) {
2446                 secs += 120009600L;
2447                 days -= 1389;
2448         }
2449         if ( ((unsigned long)(days + secs/86400L)) > 49710L) {
2450                 t = ((time_t)(-1));
2451                 goto DONE;
2452         }
2453         secs += (days * 86400L);
2454 #else
2455         d = p[5] - 1;
2456         d = -719163L + d*365 + (d/4) - (d/100) + (d/400);
2457         secs = p[0]
2458                 + tzi[default_dst].gmt_offset
2459                 + 60*( p[1]
2460                            + 60*(p[2]
2461                                          + 24*(((146073L * ((long long)(p[6])) + d)
2462                                                         + p[3]) + p[7])));
2463
2464 DST_CORRECT:
2465         if (((unsigned long long)(secs - LONG_MIN))
2466                 > (((unsigned long long)LONG_MAX) - LONG_MIN)
2467                 ) {
2468                 t = ((time_t)(-1));
2469                 goto DONE;
2470         }
2471 #endif
2472
2473         d = ((struct tm *)p)->tm_isdst;
2474         t = secs;
2475
2476         __time_localtime_tzi(&t, (struct tm *)p, tzi);
2477
2478         if (t == ((time_t)(-1))) {      /* Remember, time_t can be unsigned. */
2479                 goto DONE;
2480         }
2481
2482         if ((d < 0) && (((struct tm *)p)->tm_isdst != default_dst)) {
2483 #ifdef __BCC__
2484                 secs -= (days * 86400L);
2485 #endif
2486                 secs += (tzi[1-default_dst].gmt_offset
2487                                  - tzi[default_dst].gmt_offset);
2488                 goto DST_CORRECT;
2489         }
2490
2491
2492         if (store_on_success) {
2493                 memcpy(timeptr, p, sizeof(struct tm));
2494         }
2495
2496
2497 DONE:
2498         return t;
2499 }
2500
2501 #endif
2502 /**********************************************************************/
2503 #if (defined(L_wcsftime) || defined(L_wcsftime_l))
2504
2505 /* Implemented via strftime / strftime_l wchar_t variants */
2506
2507 #endif
2508 /**********************************************************************/
2509 #ifdef L_dysize
2510 /* Return the number of days in YEAR.  */
2511
2512 int dysize(int year)
2513 {
2514         return __isleap(year) ? 366 : 365;
2515 }
2516
2517 #endif
2518 /**********************************************************************/